[
  {
    "path": ".gitignore",
    "content": ".DS_Store"
  },
  {
    "path": "README.md",
    "content": "斯坦福大学公开课：iOS 7 应用开发\n===============================\n\n# 剧终\n\nDemo\n----\n\n![](http://ww4.sinaimg.cn/large/69fe98c3gw1eelg25qchaj211y0lc0x1.jpg)\n\n![](http://ww2.sinaimg.cn/large/69fe98c3gw1eelg2b8yesj211y0lctdi.jpg)\n\n排版与格式\n---------\n\n* 字体为 Hiragino Sans GB W3。\n* 中文字体大小为 20 号，英文字体大小为 12 号。\n* Hiragino Sans GB W3.TTF 为「冬青黑体简体中文 W3」字体文件。\n\n成品\n----\n\n成品已上传百度网盘，基本可以与网易同步  \n链接: ~~http://pan.baidu.com/s/1bnF02Kn~~\n\n如果你想要的是原版英文视频：  \n请戳链接：链接: https://pan.baidu.com/s/1si5hs1qmpoS_dLu6HbUZGg 提取码: fdga \n\n说明\n----\n\n感谢 [@jannerchang](https://github.com/jannerchang) 提供的字幕。  \n感谢 [@Bayonetta](https://github.com/Bayonetta) 提供原版视频共享。  \n同步网易[斯坦福大学公开课：iOS 7 应用开发](http://v.163.com/special/opencourse/ios7.html)字幕文件。方便合成高清视频观看。\n\n\n"
  },
  {
    "path": "Subtitles/1. Class Logistics, Overview of iOS, MVC, Objective-C.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.1.2\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\nLast Style Storage: Default\r\nAegisub Scroll Position: 1114\r\nAegisub Active Line: 1120\r\nAegisub Video Zoom Percent: 1.000000\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.38,0:00:09.00,yin,,0,0,0,,斯坦福大学\\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:09.00,0:00:14.40,yin,,0,0,0,,好 欢迎来到 2013-14 学年斯坦福 CS193P 秋季课程\\N{\\fs12}Alright, so welcome to Stanford CS193p, fall of 2013-14 academic year.\r\nDialogue: 0,0:00:14.44,0:00:16.48,yin,,0,0,0,,这是我们的第一讲\\N{\\fs12}This is our very first lecture\r\nDialogue: 0,0:00:16.48,0:00:20.03,yin,,0,0,0,,我们要讲的是 iOS 应用开发\\N{\\fs12}and we are going to be covering developing applications for iOS,\r\nDialogue: 0,0:00:20.03,0:00:22.96,yin,,0,0,0,,这里将特别针对 iOS7\\N{\\fs12}so specifically iOS7.\r\nDialogue: 0,0:00:22.98,0:00:26.00,yin,,0,0,0,,今天的课分为上下两部分\\N{\\fs12}Today's lecture kind of has a first part and a second part.\r\nDialogue: 0,0:00:26.00,0:00:28.00,yin,,0,0,0,,前半部分是一些课务信息\\N{\\fs12}The first part is a little bit of logistics.\r\nDialogue: 0,0:00:28.00,0:00:30.99,yin,,0,0,0,,后半部分我将开始正式讲课\\N{\\fs12}The second part is I'm going to dive right into the course material\r\nDialogue: 0,0:00:30.99,0:00:33.00,yin,,0,0,0,,因为要讲的有很多\\N{\\fs12}because there's a lot to cover and so,\r\nDialogue: 0,0:00:33.00,0:00:36.00,yin,,0,0,0,,我需要尽早开始\\N{\\fs12}we need to start covering it.\r\nDialogue: 0,0:00:36.00,0:00:38.27,yin,,0,0,0,,这门课会学到一些什么呢\\N{\\fs12}So, what will I learn in this course?\r\nDialogue: 0,0:00:38.29,0:00:40.14,yin,,0,0,0,,你应该知道这门课会教些什么\\N{\\fs12}I think you know what you're going to learn in this course.\r\nDialogue: 0,0:00:40.14,0:00:42.57,yin,,0,0,0,,你们会学到如何创建很酷的 app\\N{\\fs12}You're going to learn how to build cool apps.\r\nDialogue: 0,0:00:42.59,0:00:45.70,yin,,0,0,0,,iOS 是一个很酷的 app 创建平台\\N{\\fs12}iOS is a really cool platform for building apps,\r\nDialogue: 0,0:00:45.72,0:00:47.00,yin,,0,0,0,,你们可能已经知道了\\N{\\fs12}you probably already know that.\r\nDialogue: 0,0:00:47.00,0:00:51.01,yin,,0,0,0,,app 非常酷 会有动画\\N{\\fs12}The apps look cool, they've got animation.\r\nDialogue: 0,0:00:51.01,0:00:53.35,yin,,0,0,0,,真正酷的是 它们就在你的口袋里\\N{\\fs12}What's really cool is they're in your pockets\r\nDialogue: 0,0:00:53.36,0:00:55.33,yin,,0,0,0,,你可以拿出来炫耀给朋友们\\N{\\fs12}so you can whip them out and show them to your friends.\r\nDialogue: 0,0:00:55.35,0:00:58.01,yin,,0,0,0,,你不需要发网址给他们 让他们去电脑上看\\N{\\fs12}You don't have to send them to a website or go get a computer.\r\nDialogue: 0,0:00:58.03,0:01:03.00,yin,,0,0,0,,而且你们将能在很短时间内轻松开发出强大的 app\\N{\\fs12}It's also really easy to develop really powerful apps in a really short amount of time,\r\nDialogue: 0,0:01:03.00,0:01:05.68,yin,,0,0,0,,这门课其实只有 10 周时间\\N{\\fs12}as you're going to find. This course is only 10 weeks long,\r\nDialogue: 0,0:01:05.70,0:01:08.00,yin,,0,0,0,,虽然这是斯坦福\\N{\\fs12}and while this is Stanford, I know,\r\nDialogue: 0,0:01:08.00,0:01:10.00,yin,,0,0,0,,你们都是很厉害的编程高手\\N{\\fs12}you're all really, really good programmers and all that,\r\nDialogue: 0,0:01:10.00,0:01:13.94,yin,,0,0,0,,但 10 周还是有点短 到最后\\N{\\fs12}it still, 10 weeks is not a lot of time, so when we get to the end,\r\nDialogue: 0,0:01:13.94,0:01:17.92,yin,,0,0,0,,你们会发现 这是一个很便于创建应用的平台\\N{\\fs12}you're going to see that it's a very leveraged platform for building things.\r\nDialogue: 0,0:01:17.94,0:01:20.62,yin,,0,0,0,,而且这个领域也非常活跃\\N{\\fs12}And, you know, the community is quite vibrant,\r\nDialogue: 0,0:01:20.64,0:01:23.51,yin,,0,0,0,,你可以通过 app 商店销售你的 app\\N{\\fs12}being able to distribute your apps via the app store\r\nDialogue: 0,0:01:23.53,0:01:26.70,yin,,0,0,0,,而不需要用盒子装起来在商店货架上出售\\N{\\fs12}and not have to put them in a box and put them on a shelf in a store,\r\nDialogue: 0,0:01:26.70,0:01:30.36,yin,,0,0,0,,这对于销售产品而言是一个巨大的不同\\N{\\fs12}is really a big, big difference when it comes to marketing a product.\r\nDialogue: 0,0:01:30.38,0:01:32.00,yin,,0,0,0,,你们会看到这个\\N{\\fs12}And you'll, you'll see that.\r\nDialogue: 0,0:01:32.00,0:01:36.51,yin,,0,0,0,,从这门课你们将学到的第二点是 现实世界应用\\N{\\fs12}The second thing you're going to learn in this course though is real-world application,\r\nDialogue: 0,0:01:36.53,0:01:40.22,yin,,0,0,0,,将其它课程中学到的很多计算机科学内容应用于现实\\N{\\fs12}a lot of the computer science things you're learning in other classes.\r\nDialogue: 0,0:01:40.73,0:01:42.50,yin,,0,0,0,,我们会用到网络\\N{\\fs12}So, we're going to be doing networking,\r\nDialogue: 0,0:01:42.50,0:01:44.50,yin,,0,0,0,,用到多线程\\N{\\fs12}we're going to do multithreaded,\r\nDialogue: 0,0:01:44.50,0:01:46.10,yin,,0,0,0,,用到各种图形\\N{\\fs12}we're going to be doing all kinds of graphics,\r\nDialogue: 0,0:01:46.10,0:01:47.50,yin,,0,0,0,,用到动画\\N{\\fs12}we're going to be doing animation,\r\nDialogue: 0,0:01:47.50,0:01:49.50,yin,,0,0,0,,用到面向对象的数据库\\N{\\fs12}we're going to do object-oriented databases,\r\nDialogue: 0,0:01:49.50,0:01:51.31,yin,,0,0,0,,这些东西都会被用于现实世界\\N{\\fs12}we're going to do all that stuff for real.\r\nDialogue: 0,0:01:51.31,0:01:55.50,yin,,0,0,0,,你们会了解到 如何应用所有这些计算机科学概念\\N{\\fs12}You're going to see what it looks like to apply all those computer science concepts,\r\nDialogue: 0,0:01:55.50,0:01:58.50,yin,,0,0,0,,特别是将它们结合到现实世界的舞台\\N{\\fs12}especially how to combine them into a real-world platform,\r\nDialogue: 0,0:01:58.50,0:02:00.50,yin,,0,0,0,,你制作的可是真正的 app\\N{\\fs12}where you're making real apps.\r\nDialogue: 0,0:02:00.50,0:02:04.96,yin,,0,0,0,,我原来的很多学生 成十上百\\N{\\fs12}And quite a few, many dozens of my former students have\r\nDialogue: 0,0:02:04.96,0:02:09.31,yin,,0,0,0,,都将他们的 app 发布到了 app 商店 你们应该也能做到\\N{\\fs12}shipped their apps on the app store and you may well too. So this is\r\nDialogue: 0,0:02:09.33,0:02:13.36,yin,,0,0,0,,这是一门很好的课程 让你们能够\\N{\\fs12}really, this is a good course to kind of combine or\r\nDialogue: 0,0:02:13.36,0:02:16.88,yin,,0,0,0,,将其它计算机科学课程上学到的很多知识\\N{\\fs12}synthesize all of the things you've learned in a lot of your other computer science classes\r\nDialogue: 0,0:02:16.88,0:02:20.68,yin,,0,0,0,,完美地结合到现实世界中\\N{\\fs12}and touch it up against the real world.\r\nDialogue: 0,0:02:20.68,0:02:24.44,yin,,0,0,0,,这门课的预备条件非常非常重要\\N{\\fs12}The prerequisites for this class are super duper important,\r\nDialogue: 0,0:02:24.44,0:02:27.77,yin,,0,0,0,,你们一定要确保满足这些预备条件\\N{\\fs12}This, it's just key to make sure you have these prerequisites\r\nDialogue: 0,0:02:27.77,0:02:31.50,yin,,0,0,0,,你们要想好 不满足这些条件的 不要选这门课\\N{\\fs12}and really think long and hard, if you don't, whether you want to give this class a go.\r\nDialogue: 0,0:02:31.50,0:02:36.99,yin,,0,0,0,,CS106 A 和 B 或 CS106X 肯定是需要的\\N{\\fs12}CS 106 A&B or, or CS106x are absolutely required.\r\nDialogue: 0,0:02:36.99,0:02:40.50,yin,,0,0,0,,如果没有相当的知识 想都不要想选这门课\\N{\\fs12}If you don't have that or equivalent, definitely, don't even think about it.\r\nDialogue: 0,0:02:40.50,0:02:44.12,yin,,0,0,0,,这学期我还基于经验加了第二个要求\\N{\\fs12}The second requirement I've added this quarter, based on experience,\r\nDialogue: 0,0:02:44.14,0:02:47.10,yin,,0,0,0,,也就是 CS107 或 CS108 更好\\N{\\fs12}is CS107 or CS108, which is great,\r\nDialogue: 0,0:02:47.10,0:02:50.50,yin,,0,0,0,,选修过 CS108 的同学 可以说为这门课做好了充分准备\\N{\\fs12}by the way, if you're taking CS108, you'll really be ready for this class.\r\nDialogue: 0,0:02:50.50,0:02:53.50,yin,,0,0,0,,或 CS110 就更好了\\N{\\fs12}Or even CS110, and part\r\nDialogue: 0,0:02:53.50,0:02:56.50,yin,,0,0,0,,我要求额外这些课程的原因在于\\N{\\fs12}of the reason I'm requiring these extra classes is just\r\nDialogue: 0,0:02:56.50,0:03:00.01,yin,,0,0,0,,希望你们有更多编程经验\\N{\\fs12}so you're farther along the programming experience curve\r\nDialogue: 0,0:03:00.03,0:03:02.25,yin,,0,0,0,,因为这门课中需要大量编程\\N{\\fs12}because this class is a lot of programming,\r\nDialogue: 0,0:03:02.25,0:03:06.50,yin,,0,0,0,,因此 习惯大量编程的同学 就能习惯这门课\\N{\\fs12}and so for those of you who are used to a lot of programming, you're used to it.\r\nDialogue: 0,0:03:06.50,0:03:10.50,yin,,0,0,0,,没有很多编程经验的同学会心想 喔 这里有很多编程\\N{\\fs12}But for those of you who aren't it's kind of like, whoa, do a lot of programming here.\r\nDialogue: 0,0:03:10.50,0:03:14.50,yin,,0,0,0,,这就有点让人心神不宁 所以我要求了这些条件\\N{\\fs12}It's going to be a little unbalancing. So, that's why I've required all those.\r\nDialogue: 0,0:03:14.50,0:03:16.50,yin,,0,0,0,,如果你做过暑期实习\\N{\\fs12}Now if you've done a summer internship\r\nDialogue: 0,0:03:16.50,0:03:18.50,yin,,0,0,0,,过程中做过一些编程\\N{\\fs12}of you've done some programming or something like that,\r\nDialogue: 0,0:03:18.50,0:03:23.50,yin,,0,0,0,,这显然也能替代 CS107 108 或 110 的作用\\N{\\fs12}that's definitely a substitute for CS107, 108, or 110, right?\r\nDialogue: 0,0:03:23.50,0:03:27.44,yin,,0,0,0,,或者如果你选修过更进阶的 CS 课程 当然也行\\N{\\fs12}Or if you've done some other CS class that's even more advanced than these, that's fine too.\r\nDialogue: 0,0:03:27.45,0:03:30.16,yin,,0,0,0,,你们需要了解这门课是一门\\N{\\fs12}You've just got to understand that this class is, you know,\r\nDialogue: 0,0:03:30.16,0:03:32.16,yin,,0,0,0,,编程课 有大量编程\\N{\\fs12}a programming class, there's a lot of programming.\r\nDialogue: 0,0:03:32.16,0:03:35.92,yin,,0,0,0,,最重要的是 你需要很熟悉面向对象编程\\N{\\fs12}And most importantly, you got to really be comfortable with object-oriented programming.\r\nDialogue: 0,0:03:35.94,0:03:38.05,yin,,0,0,0,,这里我列了一些术语\\N{\\fs12}So I put a bunch of terms up here,\r\nDialogue: 0,0:03:38.05,0:03:41.53,yin,,0,0,0,,如消息 实例变量 父类和子类\\N{\\fs12}like message and instance variable and superclass and subclass,\r\nDialogue: 0,0:03:41.53,0:03:44.50,yin,,0,0,0,,如果你不能像手心手背那样熟悉这些术语\\N{\\fs12}if you don't know these terms like the back of your hand,\r\nDialogue: 0,0:03:44.50,0:03:46.50,yin,,0,0,0,,要学好这门课将会很难\\N{\\fs12}it's going to be hard for you to get this class,\r\nDialogue: 0,0:03:46.50,0:03:48.79,yin,,0,0,0,,因为我会不断随口说出这些\\N{\\fs12}because I'm going to be throwing those terms out left, right, and center.\r\nDialogue: 0,0:03:48.81,0:03:51.50,yin,,0,0,0,,iOS7 完全是面向对象的\\N{\\fs12}iOS7 is completely object-oriented.\r\nDialogue: 0,0:03:51.50,0:03:54.50,yin,,0,0,0,,其整个结构 设计都是面向对象的\\N{\\fs12}Okay, the whole structure, the design of the thing, is object-oriented.\r\nDialogue: 0,0:03:54.50,0:03:57.50,yin,,0,0,0,,这是你必须知道的 如果你不知道\\N{\\fs12}So, you just got to know that, and if you don't know that,\r\nDialogue: 0,0:03:57.50,0:03:59.50,yin,,0,0,0,,你显然需要先学这些\\N{\\fs12}you definitely want to go get that first.\r\nDialogue: 0,0:03:59.50,0:04:02.50,yin,,0,0,0,,先去选 CS106A&B 或相当课程\\N{\\fs12}Okay? Take CS106a&b equivalent first,\r\nDialogue: 0,0:04:02.50,0:04:06.66,yin,,0,0,0,,然后再去增加一些编程经验才行\\N{\\fs12}and then get a little more programming experience and then you're good to go.\r\nDialogue: 0,0:04:06.68,0:04:10.27,yin,,0,0,0,,这门课需要大家编写 app\\N{\\fs12}We're going, you're going to be writing apps in this class\r\nDialogue: 0,0:04:10.27,0:04:15.50,yin,,0,0,0,,到第五周 第六周 你们需要写几十个类\\N{\\fs12}with dozens of classes that you're going to write by the fifth, sixth week so,\r\nDialogue: 0,0:04:15.50,0:04:19.86,yin,,0,0,0,,如果你原来写过的最大 app 只有 3 到 5 个类\\N{\\fs12}you know, if the biggest app you've ever written is got 3, or 4, or 5 classes in it,\r\nDialogue: 0,0:04:19.86,0:04:22.50,yin,,0,0,0,,这将是大幅的跨越\\N{\\fs12}oh, this is going to be a step up.\r\nDialogue: 0,0:04:23.95,0:04:28.50,yin,,0,0,0,,作业 前六七周是每周一次作业\\N{\\fs12}The assignments, we've got this weekly assignments for the first six or seven weeks,\r\nDialogue: 0,0:04:28.50,0:04:30.50,yin,,0,0,0,,最后是一个期末项目\\N{\\fs12}and then you've got a final project at the end.\r\nDialogue: 0,0:04:30.50,0:04:32.50,yin,,0,0,0,,所有作业都会详细给出 包括\\N{\\fs12}All of the homework assignments have detailed write-up\r\nDialogue: 0,0:04:32.50,0:04:36.01,yin,,0,0,0,,要求的任务是什么以及我们怎么评分\\N{\\fs12}of the required task and what we're evaluating you on.\r\nDialogue: 0,0:04:36.03,0:04:37.80,yin,,0,0,0,,而且我还会给出提示\\N{\\fs12}And they also have hints in there,\r\nDialogue: 0,0:04:37.81,0:04:40.50,yin,,0,0,0,,因为我不想把作业弄得奇难无比\\N{\\fs12}because I'm not trying to make the homework assignments be really, really hard,\r\nDialogue: 0,0:04:40.50,0:04:45.50,yin,,0,0,0,,而且所有作业基本上都是为了\\N{\\fs12}and all the homework assignments also directly are re --\r\nDialogue: 0,0:04:45.50,0:04:49.50,yin,,0,0,0,,巩固那一周课上所讲的知识\\N{\\fs12}they're basically reinforcing what has been taught in lecture in that week,\r\nDialogue: 0,0:04:49.50,0:04:52.18,yin,,0,0,0,,而不是一些随机布置的新学习任务\\N{\\fs12}they're not a bunch of random new stuff to learn.\r\nDialogue: 0,0:04:52.19,0:04:55.32,yin,,0,0,0,,我相信这种教学理念 也就是\\N{\\fs12}I'm a big believer in a teaching methodology, which is\r\nDialogue: 0,0:04:55.32,0:04:59.64,yin,,0,0,0,,首先我通过幻灯片给大家讲一个概念\\N{\\fs12}I'm going to tell you about a concept, via slides,\r\nDialogue: 0,0:04:59.64,0:05:02.50,yin,,0,0,0,,然后我再给大家演示例子\\N{\\fs12}and then I'm going to show you it by demoing it to you,\r\nDialogue: 0,0:05:02.50,0:05:04.50,yin,,0,0,0,,实际写一个用到此概念的应用\\N{\\fs12}actually writing an application that does it, then I'm going\r\nDialogue: 0,0:05:04.50,0:05:06.50,yin,,0,0,0,,然后再让你们在作业中做这个\\N{\\fs12}to ask you to do it on the homework.\r\nDialogue: 0,0:05:06.50,0:05:10.50,yin,,0,0,0,,课上的每一点内容我都会这么来讲\\N{\\fs12}So that's three times you're going to see every single thing pretty much in this class.\r\nDialogue: 0,0:05:10.50,0:05:13.08,yin,,0,0,0,,到最后 你们就知道怎么做了\\N{\\fs12}By the end of that, you're going to know how to do it.\r\nDialogue: 0,0:05:13.10,0:05:15.50,yin,,0,0,0,,你们就会很有信心 很有经验了\\N{\\fs12}Okay? And you're going to feel confident and experienced to do it.\r\nDialogue: 0,0:05:15.50,0:05:17.50,yin,,0,0,0,,作业都是这样的\\N{\\fs12}So the homework is all about that.\r\nDialogue: 0,0:05:17.50,0:05:22.50,yin,,0,0,0,,都是课堂上我讲过的 让你们去应用\\N{\\fs12}It's about just doing what you saw me do in class and talk about in class and apply it.\r\nDialogue: 0,0:05:22.50,0:05:27.25,yin,,0,0,0,,好 下面我将简要讲一下 iOS 中有些什么\\N{\\fs12}Alright. Now I'm going to really briefly go over what's in iOS,\r\nDialogue: 0,0:05:27.25,0:05:29.30,yin,,0,0,0,,我想你们大多数人知道 iOS 中有什么\\N{\\fs12}I think most of you know what's in iOS, hopefully\r\nDialogue: 0,0:05:29.30,0:05:31.77,yin,,0,0,0,,你们都见过 iOS 设备\\N{\\fs12}you've all seen an iOS device\r\nDialogue: 0,0:05:31.77,0:05:35.50,yin,,0,0,0,,我打赌 在座 90% 的人应该口袋里都有一个\\N{\\fs12}or you have one in your pocket, I bet 90 percent of you do in this room,\r\nDialogue: 0,0:05:35.50,0:05:38.50,yin,,0,0,0,,不过我准备总结一下\\N{\\fs12}but I'm going to try and summarize it,\r\nDialogue: 0,0:05:38.50,0:05:40.50,yin,,0,0,0,,这有些难\\N{\\fs12}this is really hard to do because I'm going to try\r\nDialogue: 0,0:05:40.50,0:05:43.50,yin,,0,0,0,,因为我要用四五分钟或更少时间来讲\\N{\\fs12}and do it in four minutes or less, or five minutes,\r\nDialogue: 0,0:05:43.50,0:05:46.27,yin,,0,0,0,,这里内容其实很多 真要讲清楚可能需要两节课时间\\N{\\fs12}and it's so big that, I mean, I could have two lectures\r\nDialogue: 0,0:05:46.27,0:05:49.19,yin,,0,0,0,,这里内容其实很多 真要讲清楚可能需要两节课时间\\N{\\fs12}where I just talk about all the different things and just summarize them.\r\nDialogue: 0,0:05:49.21,0:05:54.62,yin,,0,0,0,,这里我只是把事物组织成一些有意义的组\\N{\\fs12}So, this is going to try and group them into some sort of sensible groups\r\nDialogue: 0,0:05:54.62,0:05:58.38,yin,,0,0,0,,让你们理解从开发视角应该怎么看它们\\N{\\fs12}so you have an idea of what's there from a development standpoint,\r\nDialogue: 0,0:05:58.38,0:06:02.19,yin,,0,0,0,,然后我们就会开始做这些 你会开始意识到 哦\\N{\\fs12}then when we go off and start doing it all then you'll start realizing whoa,\r\nDialogue: 0,0:06:02.21,0:06:04.50,yin,,0,0,0,,你会开始学习如何查说明文档 你会意识到 哦\\N{\\fs12}and once you learn how to look in the documentation you'll see, oh,\r\nDialogue: 0,0:06:04.50,0:06:06.50,yin,,0,0,0,,查查这些 你就能知道怎么做\\N{\\fs12}look at all that stuff in there, and you'll figure it out.\r\nDialogue: 0,0:06:06.50,0:06:08.23,yin,,0,0,0,,这只是高层级的概览\\N{\\fs12}So this is just a high-level overview.\r\nDialogue: 0,0:06:08.25,0:06:13.50,yin,,0,0,0,,我将这些分为四组\\N{\\fs12}So, I've used this division into these four, kind of groups.\r\nDialogue: 0,0:06:13.50,0:06:17.19,yin,,0,0,0,,一是核心操作系统层 这是很接近硬件的一层\\N{\\fs12}Core OS, which is the stuff that's close to the hardware.\r\nDialogue: 0,0:06:17.19,0:06:20.50,yin,,0,0,0,,核心服务层 这是之上的面向对象的一层\\N{\\fs12}Core services, which is an object-oriented on top of that,\r\nDialogue: 0,0:06:20.50,0:06:24.01,yin,,0,0,0,,这让你总能在面向对象的层上进行编程\\N{\\fs12}that kind of makes it so you always are programming an object-oriented layer.\r\nDialogue: 0,0:06:24.01,0:06:27.75,yin,,0,0,0,,媒体层 因为这些设备基本上是 iPod\\N{\\fs12}Media, because these devices are basically iPods\r\nDialogue: 0,0:06:27.75,0:06:29.93,yin,,0,0,0,,带一个手机或者大屏幕\\N{\\fs12}with a phone in them or with a big screen on them,\r\nDialogue: 0,0:06:29.95,0:06:32.50,yin,,0,0,0,,媒体在这些设备上很重要\\N{\\fs12}but media is really important to these devices,\r\nDialogue: 0,0:06:32.50,0:06:35.01,yin,,0,0,0,,最后是触控应用层 这是 UI 层\\N{\\fs12}and then finally Cocoa Touch, which is the UI layer.\r\nDialogue: 0,0:06:35.03,0:06:37.50,yin,,0,0,0,,包括按钮和开关这些\\N{\\fs12}Of buttons and all the switches, things like that.\r\nDialogue: 0,0:06:37.50,0:06:40.50,yin,,0,0,0,,我们来谈谈这些层中都有什么\\N{\\fs12}So let's talk about what's in each of those layers, kind of,\r\nDialogue: 0,0:06:40.50,0:06:43.50,yin,,0,0,0,,浅析一下这些层\\N{\\fs12}little skimming the surface of what's in those layers.\r\nDialogue: 0,0:06:43.50,0:06:48.50,yin,,0,0,0,,在接近硬件的核心操作系统层 是一个 Unix 内核\\N{\\fs12}At the Core OS layer, near the hardware, is a Unix kernel.\r\nDialogue: 0,0:06:48.50,0:06:52.50,yin,,0,0,0,,这个设备上是 Unix 操作系统\\N{\\fs12}Okay? This is a Unix operating system on this device.\r\nDialogue: 0,0:06:52.50,0:06:55.86,yin,,0,0,0,,基于 BSD 的 Unix 版本\\N{\\fs12}And BSD-based mock,\r\nDialogue: 0,0:06:55.86,0:06:58.50,yin,,0,0,0,,Unix 有的一切它都有\\N{\\fs12}and so you get everything you get with Unix.\r\nDialogue: 0,0:06:58.50,0:07:01.50,yin,,0,0,0,,它有套接字 有文件系统\\N{\\fs12}You're getting sockets and you're getting file system,\r\nDialogue: 0,0:07:01.50,0:07:03.78,yin,,0,0,0,,权限 所有这些\\N{\\fs12}permissions, all that stuff,\r\nDialogue: 0,0:07:03.78,0:07:07.50,yin,,0,0,0,,另外 这里还有一些特别用于移动设备的东西\\N{\\fs12}plus you're getting a bunch of other stuff that's kind of specific to a mobile\r\nDialogue: 0,0:07:07.50,0:07:09.77,yin,,0,0,0,,例如电源管理\\N{\\fs12}device like this, like power management,\r\nDialogue: 0,0:07:09.77,0:07:14.50,yin,,0,0,0,,用于安全管理的钥匙串访问\\N{\\fs12}and key chain access to kind of manage the security of things.\r\nDialogue: 0,0:07:14.50,0:07:16.50,yin,,0,0,0,,Bonjour 这是这种网络\\N{\\fs12}Bonjour, which is this kind of network,\r\nDialogue: 0,0:07:16.50,0:07:18.50,yin,,0,0,0,,在网络上找其它东西\\N{\\fs12}finding other things on the network.\r\nDialogue: 0,0:07:18.50,0:07:23.04,yin,,0,0,0,,所有这些都有 下方是这个很强大的操作系统\\N{\\fs12}So it's got all that stuff, it's a very powerful underlying operating system.\r\nDialogue: 0,0:07:23.04,0:07:26.50,yin,,0,0,0,,但大多数 API 都是用 C 写的\\N{\\fs12}But all of that API or most of it is in C,\r\nDialogue: 0,0:07:26.50,0:07:29.50,yin,,0,0,0,,我们会完全在面向对象层进行编程\\N{\\fs12}and we want to be programming kind of purely object-oriented layer.\r\nDialogue: 0,0:07:29.50,0:07:32.50,yin,,0,0,0,,我们主要需要触及到的\\N{\\fs12}So we're going to be mostly operating when we're talking,\r\nDialogue: 0,0:07:32.50,0:07:35.50,yin,,0,0,0,,是核心服务层的这些东西\\N{\\fs12}touching those things at the Core Services layer.\r\nDialogue: 0,0:07:35.50,0:07:39.50,yin,,0,0,0,,这一层有让语言更加强劲的东西\\N{\\fs12}So this layer has things like language, things that,\r\nDialogue: 0,0:07:39.50,0:07:41.28,yin,,0,0,0,,这一层有让语言更加强劲的东西\\N{\\fs12}that kind of make the language more powerful,\r\nDialogue: 0,0:07:41.28,0:07:45.50,yin,,0,0,0,,例如数组 字典 字符串等等\\N{\\fs12}like arrays and dictionaries, and strings and things like that,\r\nDialogue: 0,0:07:45.50,0:07:49.08,yin,,0,0,0,,而且它还有面向对象的方式来访问文件系统\\N{\\fs12}plus it has object-oriented ways to access the file system,\r\nDialogue: 0,0:07:49.10,0:07:51.50,yin,,0,0,0,,例如 它有面向对象的方式\\N{\\fs12}it has object-oriented ways to find out the GPS\r\nDialogue: 0,0:07:51.50,0:07:53.99,yin,,0,0,0,,来寻找设备的 GPS 位置\\N{\\fs12}location of your device, for example.\r\nDialogue: 0,0:07:54.01,0:07:57.50,yin,,0,0,0,,它还有方式来进行多线程操作\\N{\\fs12}It has ways to do multithreading.\r\nDialogue: 0,0:07:57.50,0:08:00.45,yin,,0,0,0,,所有这些你想要能够做到的事情\\N{\\fs12}All this stuff what you want to be able to do,\r\nDialogue: 0,0:08:00.45,0:08:04.93,yin,,0,0,0,,不过所有这些你都希望以面向对象的方式来思考\\N{\\fs12}but you want to stay in an object-oriented kind of mindset as you're doing them all.\r\nDialogue: 0,0:08:04.95,0:08:09.97,yin,,0,0,0,,核心服务层有一个巨大的基础层用于做这些\\N{\\fs12}There's a huge layer, foundational layer there at Core services for doing that.\r\nDialogue: 0,0:08:09.97,0:08:12.99,yin,,0,0,0,,再看媒体层 不要小看这一层\\N{\\fs12}At the media layer, don't sleep on this layer,\r\nDialogue: 0,0:08:12.99,0:08:16.00,yin,,0,0,0,,这一层很重要 这里有视频 有视频编辑\\N{\\fs12}really important layer, you've got video here, you've got video editing,\r\nDialogue: 0,0:08:16.01,0:08:18.28,yin,,0,0,0,,当然 这里有能够显示的图像\\N{\\fs12}you got images, of course, that it can display,\r\nDialogue: 0,0:08:18.28,0:08:21.19,yin,,0,0,0,,有很强大音频 用于 3D 音效\\N{\\fs12}it's incredibly powerful audio for doing 3D audio,\r\nDialogue: 0,0:08:21.19,0:08:23.50,yin,,0,0,0,,例如游戏中 可以有泰拳打击的感觉\\N{\\fs12}if you have games, you can make the Thai fighters feel\r\nDialogue: 0,0:08:23.50,0:08:25.50,yin,,0,0,0,,就像真实的打斗一样\\N{\\fs12}like they're ripping by you and stuff.\r\nDialogue: 0,0:08:25.50,0:08:27.26,yin,,0,0,0,,所有这些都在这里\\N{\\fs12}All that stuff is in here.\r\nDialogue: 0,0:08:27.26,0:08:29.50,yin,,0,0,0,,iOS 的这部分\\N{\\fs12}This is part of, the part of iOS\r\nDialogue: 0,0:08:29.50,0:08:31.82,yin,,0,0,0,,我无法很深入讲解\\N{\\fs12}that really I can't cover in a lot of depth.\r\nDialogue: 0,0:08:31.84,0:08:35.15,yin,,0,0,0,,我只是想让你们知道有这么一层\\N{\\fs12}I'm just going to try and let you know that it's there and you're going to dive down\r\nDialogue: 0,0:08:35.15,0:08:39.50,yin,,0,0,0,,你们可以根据未来应用程序需求来使用它\\N{\\fs12}depending on what kind of applications, later in your life, you want to build.\r\nDialogue: 0,0:08:39.50,0:08:44.50,yin,,0,0,0,,不过这方面量很大 苹果设备根本上显然是多媒体设备\\N{\\fs12}But there's an enormous amount there. This is a fundamentally, a multimedia device, obviously,\r\nDialogue: 0,0:08:44.50,0:08:48.50,yin,,0,0,0,,最后是触控应用层 我们大多数时间都会花在这里\\N{\\fs12}and then, Cocoa Touch is where we're going to spend most of our time.\r\nDialogue: 0,0:08:48.50,0:08:53.69,yin,,0,0,0,,这里你会设计一些按钮 滑动条 文本框\\N{\\fs12}This is where you are going to be building buttons and sliders and text fields,\r\nDialogue: 0,0:08:53.69,0:08:57.58,yin,,0,0,0,,这里有交互 动画发生 事物滑进滑出\\N{\\fs12}talking to each other, and animation happening, things sliding in and out, and,\r\nDialogue: 0,0:08:57.58,0:09:00.50,yin,,0,0,0,,淡出淡入等等\\N{\\fs12}you know, fading out and fading in.\r\nDialogue: 0,0:09:00.50,0:09:04.88,yin,,0,0,0,,如果你要使用用户相机中的照片 你可以这样做\\N{\\fs12}If you want to get the, a picture from the camera from the user, you can do that.\r\nDialogue: 0,0:09:04.89,0:09:06.52,yin,,0,0,0,,还有本地化\\N{\\fs12}Things like localization\r\nDialogue: 0,0:09:06.52,0:09:08.89,yin,,0,0,0,,让你的 app 能够在世界上很多国家运行\\N{\\fs12}so that you're app can run in many countries in the world\r\nDialogue: 0,0:09:08.89,0:09:10.89,yin,,0,0,0,,由此来提高销量\\N{\\fs12}and up your sales by doing that.\r\nDialogue: 0,0:09:10.91,0:09:15.50,yin,,0,0,0,,还有一整套地图包 包括你们在 iOS7 中见过的 3D 地图\\N{\\fs12}A whole map kit for doing all the 3D maps that you've probably seen in iOS7 and all\r\nDialogue: 0,0:09:15.50,0:09:17.50,yin,,0,0,0,,所有这些都在这里\\N{\\fs12}that stuff is all in there.\r\nDialogue: 0,0:09:18.58,0:09:23.50,yin,,0,0,0,,视图中还可以将一整个网页浏览器放到一个小矩形中\\N{\\fs12}And, there's even a view in there that's an entire web browser in a little rectangle\r\nDialogue: 0,0:09:23.50,0:09:25.50,yin,,0,0,0,,让它显示在你的 app 中\\N{\\fs12}that you can just plop right into your app.\r\nDialogue: 0,0:09:25.50,0:09:28.74,yin,,0,0,0,,这些是高层级的对象\\N{\\fs12}So these are really high-level objects,\r\nDialogue: 0,0:09:28.75,0:09:31.80,yin,,0,0,0,,我们会深入探讨这一层\\N{\\fs12}and we're going to really be diving into this layer, alright?\r\nDialogue: 0,0:09:31.80,0:09:33.50,yin,,0,0,0,,这是最重要的内容\\N{\\fs12}So this is really the primary.\r\nDialogue: 0,0:09:33.50,0:09:36.78,yin,,0,0,0,,这里触控叫作 Cocoa Touch 是因为\\N{\\fs12}And it's called Cocoa Touch because\r\nDialogue: 0,0:09:36.78,0:09:40.50,yin,,0,0,0,,这里的 API 最初是为 Mac OS X 开发的\\N{\\fs12}the API in here was originally developed for Mac OS X,\r\nDialogue: 0,0:09:40.50,0:09:42.36,yin,,0,0,0,,它叫 Cocoa\\N{\\fs12}and it was called Cocoa,\r\nDialogue: 0,0:09:42.36,0:09:45.45,yin,,0,0,0,,之后当它们被适用于 iOS\\N{\\fs12}and of course then when they went to iOS, they adapted,\r\nDialogue: 0,0:09:45.45,0:09:48.50,yin,,0,0,0,,很多 API 都能在两平台之间共享\\N{\\fs12}and a lot of API is shared between the two platforms, and, in fact,\r\nDialogue: 0,0:09:48.50,0:09:51.50,yin,,0,0,0,,如果你开发了一个 iOS app 然后某天你想 哦\\N{\\fs12}if you develop an iOS app and then you say someday, oh,\r\nDialogue: 0,0:09:51.50,0:09:54.99,yin,,0,0,0,,我要为 Mac 开发一个 app 使用 Cocoa 这会非常类似\\N{\\fs12}I want to develop an app for the Mac using Cocoa, it's going to be very similar.\r\nDialogue: 0,0:09:55.00,0:09:58.50,yin,,0,0,0,,你会感觉非常熟悉\\N{\\fs12}Okay? You're going to be really, it's going to look familiar.\r\nDialogue: 0,0:09:58.50,0:10:03.50,yin,,0,0,0,,Cocoa Touch 显然是 Cocoa 的触控版本\\N{\\fs12}So Cocoa Touch, obviously, is the touchscreen version of that, of Cocoa.\r\nDialogue: 0,0:10:04.34,0:10:08.50,yin,,0,0,0,,Cocoa 这个技术已经存在很久了\\N{\\fs12}This technology, Cocoa, has been around a long time.\r\nDialogue: 0,0:10:08.50,0:10:11.50,yin,,0,0,0,,也许三十年了 难以置信吧\\N{\\fs12}Probably almost 30 years, believe it or not.\r\nDialogue: 0,0:10:11.50,0:10:15.97,yin,,0,0,0,,甚至在苹果开始使用 Mac OS 之前\\N{\\fs12}From even before Apple acquired it to make Mac OS,\r\nDialogue: 0,0:10:15.97,0:10:19.89,yin,,0,0,0,,现在是 Mac OS X 这是一种很成熟的API\\N{\\fs12}what is now Mac OS X, and so it's a very mature API.\r\nDialogue: 0,0:10:19.91,0:10:25.35,yin,,0,0,0,,它是经过深思熟虑的 如果你能顺着它来\\N{\\fs12}And it's very well thought out, so, especially if you go with the flow of it,\r\nDialogue: 0,0:10:25.36,0:10:28.50,yin,,0,0,0,,你会发现创建强大的程序是很容易的\\N{\\fs12}it's very easy to build really powerful things.\r\nDialogue: 0,0:10:28.50,0:10:30.50,yin,,0,0,0,,这就是这其中的内容\\N{\\fs12}So, that's what's in there.\r\nDialogue: 0,0:10:30.50,0:10:33.35,yin,,0,0,0,,下面再来看作为程序员 作为开发者\\N{\\fs12}So let's talk about the tools we use as programmers,\r\nDialogue: 0,0:10:33.36,0:10:36.19,yin,,0,0,0,,我们需要什么工具来创建 app\\N{\\fs12}as developers, to build these apps.\r\nDialogue: 0,0:10:36.19,0:10:38.50,yin,,0,0,0,,我把这些分成了四段\\N{\\fs12}And I've divided those into kind of four sections here.\r\nDialogue: 0,0:10:38.50,0:10:42.50,yin,,0,0,0,,一是实际编程用的工具\\N{\\fs12}One is the tools, the actual programming tools,\r\nDialogue: 0,0:10:42.50,0:10:47.86,yin,,0,0,0,,这个平台很好的地方在于 它是一个工具满足所有用途\\N{\\fs12}and what's great, on this platform, is it's pretty much a one-tool fits all.\r\nDialogue: 0,0:10:47.87,0:10:49.98,yin,,0,0,0,,只有一个工具 XCode 5\\N{\\fs12}Okay? There's this one tool, XCode 5,\r\nDialogue: 0,0:10:50.00,0:10:51.50,yin,,0,0,0,,一切都在这里面\\N{\\fs12}and everything's in there.\r\nDialogue: 0,0:10:51.50,0:10:53.50,yin,,0,0,0,,调试器在这里 源代码编辑\\N{\\fs12}Your debugger's in there, all your source code editing,\r\nDialogue: 0,0:10:53.50,0:10:57.85,yin,,0,0,0,,源代码控制 UI 构建 一切都在这个工具里\\N{\\fs12}your source code control, the UI building, everything is in this one app.\r\nDialogue: 0,0:10:57.87,0:11:00.50,yin,,0,0,0,,然后还有一个辅助的 Instruments\\N{\\fs12}There's a little adjunct there, instruments, which is for things\r\nDialogue: 0,0:11:00.50,0:11:05.50,yin,,0,0,0,,用于 app 代码分析 内存管理等等\\N{\\fs12}like profiling your app and things like that. Memory usage, those kind of things,\r\nDialogue: 0,0:11:05.50,0:11:08.61,yin,,0,0,0,,不过这些都包含在 XCode 5 中\\N{\\fs12}but you're really, all was inside XCode 5,\r\nDialogue: 0,0:11:08.61,0:11:10.50,yin,,0,0,0,,这很棒 因为 要知道\\N{\\fs12}which is really nice because, you know,\r\nDialogue: 0,0:11:10.50,0:11:13.39,yin,,0,0,0,,调试时 你一般是在同时编辑代码\\N{\\fs12}when you're debugging, you're usually editing your code at the same time,\r\nDialogue: 0,0:11:13.39,0:11:14.50,yin,,0,0,0,,来来回回\\N{\\fs12}back and forth, back and forth,\r\nDialogue: 0,0:11:14.50,0:11:17.26,yin,,0,0,0,,如果要在不同程序中来回切换 就会很烦人\\N{\\fs12}you're going to different apps and all that would be a pain in the neck,\r\nDialogue: 0,0:11:17.26,0:11:20.63,yin,,0,0,0,,这个工具对屏幕空间的分配也做得很好\\N{\\fs12}and they've really done a good job of arranging the screen space\r\nDialogue: 0,0:11:20.63,0:11:23.84,yin,,0,0,0,,所有不同任务很好地被分配到不同屏幕空间中\\N{\\fs12}so that it's sharing between all these different tasks that you need to do.\r\nDialogue: 0,0:11:23.85,0:11:25.98,yin,,0,0,0,,这是首要工具 XCode 5\\N{\\fs12}So that's the primary tool, XCode 5,\r\nDialogue: 0,0:11:25.98,0:11:30.50,yin,,0,0,0,,这堂课后 你们都应该到 Mac App 商店\\N{\\fs12}you should all, right after this class if you want, go to the Mac App store,\r\nDialogue: 0,0:11:30.50,0:11:34.04,yin,,0,0,0,,不是 iOS 设备商店 而是 Mac 上的 Mac App 商店\\N{\\fs12}not the store on you iOS device, the Mac App Store on your Mac,\r\nDialogue: 0,0:11:34.04,0:11:38.15,yin,,0,0,0,,下载这个 它是免费的 上周五刚出\\N{\\fs12}and download this. It's free, available, came out last Friday,\r\nDialogue: 0,0:11:38.15,0:11:42.02,yin,,0,0,0,,你们可以下载安装 然后开始倒弄\\N{\\fs12}and you can download it, install it, and, you know, start playing around with it.\r\nDialogue: 0,0:11:42.04,0:11:45.17,yin,,0,0,0,,有些人可能在 CS106 这样的课上用过 XCode\\N{\\fs12}Some of you might have already used XCode, like in CS106,\r\nDialogue: 0,0:11:45.19,0:11:47.50,yin,,0,0,0,,多少人用过 XCode 举手我看看\\N{\\fs12}raise your hand if you've used XCode before for anything.\r\nDialogue: 0,0:11:47.50,0:11:50.50,yin,,0,0,0,,好 2/3 或更多 大约 3/4 的人用过\\N{\\fs12}Okay, so two-thirds or more, three-quarters of you.\r\nDialogue: 0,0:11:50.50,0:11:53.50,yin,,0,0,0,,你们会很习惯它 你们将会把 XCode\\N{\\fs12}So, you're going to be used it. You're just going to start using XCode now\r\nDialogue: 0,0:11:53.50,0:11:55.50,yin,,0,0,0,,用于 iOS 应用\\N{\\fs12}to develop for iOS, alright?\r\nDialogue: 0,0:11:55.50,0:11:58.50,yin,,0,0,0,,有一个新语言需要你们学 Objective-C\\N{\\fs12}There's a new language for you to learn, objective C,\r\nDialogue: 0,0:11:58.50,0:12:00.50,yin,,0,0,0,,这个语言样子有点滑稽\\N{\\fs12}it's kind of a funny-looking language, okay,\r\nDialogue: 0,0:12:00.50,0:12:04.50,yin,,0,0,0,,它使用方括号和冒号 消息调用没有圆括号\\N{\\fs12}it's got square brackets and colons, no parentheses on message calls,\r\nDialogue: 0,0:12:04.50,0:12:08.96,yin,,0,0,0,,熟悉 Jave 或 C++ 的人会觉得这有些奇怪\\N{\\fs12}which is kind of weird for people who are coming from Java or C++ or whatever.\r\nDialogue: 0,0:12:08.96,0:12:11.50,yin,,0,0,0,,参数不是放在圆括号里\\N{\\fs12}The arguments are not put in parentheses or whatever,\r\nDialogue: 0,0:12:11.50,0:12:13.50,yin,,0,0,0,,我将详细讲解 Objective-C\\N{\\fs12}and I'm going to show you all about objective C,\r\nDialogue: 0,0:12:13.50,0:12:16.08,yin,,0,0,0,,我不指望你们对它有任何了解\\N{\\fs12}I don't expect you to know anything about it coming in,\r\nDialogue: 0,0:12:16.09,0:12:19.96,yin,,0,0,0,,你们应该都很熟悉 Java 和 C++ 这是 CS106A 和 B 的内容\\N{\\fs12}and if you know Java and C++, which you should if you've taken CS106A&B,\r\nDialogue: 0,0:12:19.96,0:12:23.39,yin,,0,0,0,,那么 Objective-C 将不会有太大难度\\N{\\fs12}then objective C is not going to be a big leap for you.\r\nDialogue: 0,0:12:23.39,0:12:24.72,yin,,0,0,0,,它有一点不同\\N{\\fs12}It's a little bit different language,\r\nDialogue: 0,0:12:24.72,0:12:27.50,yin,,0,0,0,,例如 它比 Java 更快更宽松\\N{\\fs12}it's a little more fast and loose than Java, for example,\r\nDialogue: 0,0:12:27.50,0:12:30.89,yin,,0,0,0,,比 C++ 更简单 更优美\\N{\\fs12}and it's a little more, kind of simple and elegant, than C++,\r\nDialogue: 0,0:12:30.91,0:12:32.63,yin,,0,0,0,,当涉及到面向对象的东西时\\N{\\fs12}when it comes to the object-oriented stuff. So,\r\nDialogue: 0,0:12:32.63,0:12:34.72,yin,,0,0,0,,我想 你们会喜欢它的\\N{\\fs12}I think you'll like it.\r\nDialogue: 0,0:12:34.74,0:12:39.09,yin,,0,0,0,,有些人可能很喜欢正确编程这类概念\\N{\\fs12}Some of you who are very, you know, correct programming kind of thing,\r\nDialogue: 0,0:12:39.09,0:12:42.28,yin,,0,0,0,,喜欢 Java 觉得 Objective-C 太过宽松\\N{\\fs12}you love Java, might find objective C a little wild west for you,\r\nDialogue: 0,0:12:42.28,0:12:44.50,yin,,0,0,0,,不过 你应该能够克服\\N{\\fs12}but you'll get over it.\r\nDialogue: 0,0:12:44.50,0:12:45.74,yin,,0,0,0,,框架\\N{\\fs12}Frameworks,\r\nDialogue: 0,0:12:45.74,0:12:50.50,yin,,0,0,0,,显然 任何像这样的大系统一般都会将对象组到库中\\N{\\fs12}obviously, any big system like this groups all of its objects into libraries, essentially.\r\nDialogue: 0,0:12:50.50,0:12:53.17,yin,,0,0,0,,iOS 中我们称之为框架\\N{\\fs12}We call them Frameworks in iOS,\r\nDialogue: 0,0:12:53.19,0:12:56.50,yin,,0,0,0,,iOS 中有数十个这样的框架\\N{\\fs12}so there are dozens of frameworks in iOS.\r\nDialogue: 0,0:12:56.50,0:12:59.24,yin,,0,0,0,,课程最开始我们要讲两个主要框架\\N{\\fs12}The two main ones we're going to look at, at the beginning of the course, are\r\nDialogue: 0,0:12:59.24,0:13:02.44,yin,,0,0,0,,一是 Foundation 框架 所有核心服务都在这里\\N{\\fs12}foundation, that's where all that core services stuff is,\r\nDialogue: 0,0:13:02.45,0:13:04.50,yin,,0,0,0,,例如数字和字典 所有这些\\N{\\fs12}like arrays and dictionaries and all that.\r\nDialogue: 0,0:13:04.50,0:13:05.74,yin,,0,0,0,,然后是UIKit\\N{\\fs12}And then UI kit, okay,\r\nDialogue: 0,0:13:05.74,0:13:08.06,yin,,0,0,0,,按钮 滑动条这些东西就在这里\\N{\\fs12}that's where buttons and sliders and all those things are,\r\nDialogue: 0,0:13:08.06,0:13:10.50,yin,,0,0,0,,这是两个主要框架 不过还有很多 例如\\N{\\fs12}so those are the two main ones, but, there's a whole bunch of other ones, like,\r\nDialogue: 0,0:13:10.50,0:13:12.50,yin,,0,0,0,,看到这里写的 Core Data 了吗\\N{\\fs12}you see the Core Data written up there,\r\nDialogue: 0,0:13:12.50,0:13:14.50,yin,,0,0,0,,这是面向对象的数据库\\N{\\fs12}that's the object-oriented database.\r\nDialogue: 0,0:13:14.50,0:13:16.50,yin,,0,0,0,,我们会谈到这个\\N{\\fs12}Okay? So we're going to be doing that.\r\nDialogue: 0,0:13:16.50,0:13:19.50,yin,,0,0,0,,Core Motion 这是陀螺仪和加速计\\N{\\fs12}Core Motion, that's the gyro and accelerometer.\r\nDialogue: 0,0:13:19.50,0:13:21.50,yin,,0,0,0,,Map Kit 显然是地图\\N{\\fs12}Map Kit, obviously the maps.\r\nDialogue: 0,0:13:21.50,0:13:23.50,yin,,0,0,0,,还有很多其它的\\N{\\fs12}And there's dozens more.\r\nDialogue: 0,0:13:23.50,0:13:25.50,yin,,0,0,0,,我们会尽可能多地讲到这些\\N{\\fs12}And we'll cover as many of them as we can,\r\nDialogue: 0,0:13:25.50,0:13:28.50,yin,,0,0,0,,显然我们只有 10 周 但我会尽可能地多讲\\N{\\fs12}obviously we can't do it all in 10 weeks, but we'll do as much as we can.\r\nDialogue: 0,0:13:28.50,0:13:31.93,yin,,0,0,0,,该平台中开发应用的最后一部分\\N{\\fs12}And then the last part of developing application in this platform\r\nDialogue: 0,0:13:31.93,0:13:34.50,yin,,0,0,0,,是一种叫作 MVC 的设计策略\\N{\\fs12}is a design strategy called MVC.\r\nDialogue: 0,0:13:35.11,0:13:38.89,yin,,0,0,0,,这并非 iOS 所独有的 其它平台也有使用 MVC\\N{\\fs12}Now, this is not unique to iOS, other platforms use MVC,\r\nDialogue: 0,0:13:38.91,0:13:40.37,yin,,0,0,0,,模型 视图 控制器\\N{\\fs12}Model View Controller,\r\nDialogue: 0,0:13:40.37,0:13:42.50,yin,,0,0,0,,作为基本设计策略\\N{\\fs12}as their fundamental design strategy.\r\nDialogue: 0,0:13:42.50,0:13:46.50,yin,,0,0,0,,在座有多少人曾使用过 MVC\\N{\\fs12}So how many people in this room have used MVC on any platform?\r\nDialogue: 0,0:13:46.50,0:13:48.85,yin,,0,0,0,,大约有一半 你们知道这是什么\\N{\\fs12}Okay, so about half, so you'll know what this is.\r\nDialogue: 0,0:13:48.87,0:13:52.07,yin,,0,0,0,,我会为不了解的同学简单讲一遍 MVC\\N{\\fs12}So, I'm actually going to go over MVC for those of you who haven't\r\nDialogue: 0,0:13:52.07,0:13:53.50,yin,,0,0,0,,我会讲得很快\\N{\\fs12}and I'll go through it pretty quickly, because\r\nDialogue: 0,0:13:53.50,0:13:56.72,yin,,0,0,0,,因为有一半的人都用过它\\N{\\fs12}it looks like most of you, half of you have done it,\r\nDialogue: 0,0:13:56.72,0:14:01.50,yin,,0,0,0,,对于已经知道 MVC 是什么的人 这里我讲 MVC\\N{\\fs12}and the main thing to see in MVC here, for those of you who already know what it is,\r\nDialogue: 0,0:14:01.50,0:14:03.96,yin,,0,0,0,,是为了让你们了解我怎么讲到这些\\N{\\fs12}is to see how I talk about it\r\nDialogue: 0,0:14:03.96,0:14:06.50,yin,,0,0,0,,从而当我在 iOS 语境下讲到它时\\N{\\fs12}so that when we get into iOS\r\nDialogue: 0,0:14:06.50,0:14:10.11,yin,,0,0,0,,比如我讲你的模型是独立于 UI 的\\N{\\fs12}and I start saying things like your model is UI independent,\r\nDialogue: 0,0:14:10.11,0:14:13.50,yin,,0,0,0,,你们知道我在讲什么\\N{\\fs12}you'll know what I'm talking about and we'll all be on the same page.\r\nDialogue: 0,0:14:13.50,0:14:18.50,yin,,0,0,0,,这里是为了让我们所有人在术语层面达成共识\\N{\\fs12}So this is mostly kind of getting us all on the same page terminology-wise.\r\nDialogue: 0,0:14:18.50,0:14:21.59,yin,,0,0,0,,MVC 模型 视图 控制器\\N{\\fs12}So MVC, Model View Controller,\r\nDialogue: 0,0:14:21.59,0:14:28.50,yin,,0,0,0,,也就是一种将应用中所有类组织起来的策略\\N{\\fs12}is essentially a strategy for how to organize all the classes in your application.\r\nDialogue: 0,0:14:28.50,0:14:34.50,yin,,0,0,0,,这里我们会将所有类归到三块中\\N{\\fs12}And what we do fundamentally is we divide all the classes into one of three camps.\r\nDialogue: 0,0:14:34.50,0:14:38.50,yin,,0,0,0,,一块是模型 一块是控制器 一块是视图\\N{\\fs12}The model camp, the controller camp, or the view camp,\r\nDialogue: 0,0:14:38.50,0:14:41.50,yin,,0,0,0,,那你怎么知道哪个类属于哪一块呢\\N{\\fs12}and what, how you decide what goes in each of these camps,\r\nDialogue: 0,0:14:41.50,0:14:46.50,yin,,0,0,0,,模型实际上考虑的是「什么」的问题 程序是什么\\N{\\fs12}well, the model is essentially the what of your program. What is your program?\r\nDialogue: 0,0:14:46.50,0:14:50.31,yin,,0,0,0,,讲 MVC 时 我将讲到我们的第一个应用\\N{\\fs12}So, as we're doing this MVC talk, I'm going to talk about our first application\r\nDialogue: 0,0:14:50.31,0:14:52.50,yin,,0,0,0,,也就是一个纸牌匹配游戏\\N{\\fs12}we're going to build which is a card matching game.\r\nDialogue: 0,0:14:52.50,0:14:54.16,yin,,0,0,0,,我们将创建这个游戏\\N{\\fs12}Okay? So we're going to build this game,\r\nDialogue: 0,0:14:54.17,0:14:56.50,yin,,0,0,0,,它会在屏幕上给出一些纸牌\\N{\\fs12}it's gotta bunch of cards on the screen, like playing cards, you know,\r\nDialogue: 0,0:14:56.50,0:14:58.78,yin,,0,0,0,,比如梅花 A 这些\\N{\\fs12}Ace of Clubs and all that,\r\nDialogue: 0,0:14:58.78,0:15:01.50,yin,,0,0,0,,你需要选择一些纸牌\\N{\\fs12}and you're going to be able to go choose the cards\r\nDialogue: 0,0:15:01.50,0:15:03.50,yin,,0,0,0,,匹配上的话就能得分\\N{\\fs12}and you'll get certain points if the match.\r\nDialogue: 0,0:15:03.50,0:15:05.91,yin,,0,0,0,,如花色匹配或大小匹配这些\\N{\\fs12}Like the suit matches or the rank matches, or whatever,\r\nDialogue: 0,0:15:05.91,0:15:08.87,yin,,0,0,0,,或多或少 反正匹配上你就会得分\\N{\\fs12}you get more points, less points whatever, but you're doing that.\r\nDialogue: 0,0:15:08.87,0:15:11.28,yin,,0,0,0,,在这样的纸牌匹配小游戏中\\N{\\fs12}In that kind of application, a little card matching game,\r\nDialogue: 0,0:15:11.28,0:15:16.39,yin,,0,0,0,,纸牌 牌堆 甚至游戏玩法的逻辑\\N{\\fs12}the cards and the deck, and even the logic for how the game is played\r\nDialogue: 0,0:15:16.39,0:15:20.50,yin,,0,0,0,,都是独立于 UI 且在模型中的\\N{\\fs12}are all UI independent and in the model.\r\nDialogue: 0,0:15:21.50,0:15:25.50,yin,,0,0,0,,纸牌如何抽取到屏幕上是控制器的工作\\N{\\fs12}So how the cards get drawn on screen is the job of the controller.\r\nDialogue: 0,0:15:25.50,0:15:28.50,yin,,0,0,0,,控制器的任务是弄清如何\\N{\\fs12}So the controller is, its job is to figure out how am I going,\r\nDialogue: 0,0:15:28.50,0:15:31.50,yin,,0,0,0,,将这些牌显示在屏幕上\\N{\\fs12}you know, take this set of cards and display them on screen,\r\nDialogue: 0,0:15:31.50,0:15:35.50,yin,,0,0,0,,然后将其运动用动画形式展现出来 等等\\N{\\fs12}and then animate their movement and things like that.\r\nDialogue: 0,0:15:35.50,0:15:36.78,yin,,0,0,0,,这是控制器的工作\\N{\\fs12}Okay? That's up to the controller.\r\nDialogue: 0,0:15:36.79,0:15:41.50,yin,,0,0,0,,控制器控制模型如何呈现在屏幕上\\N{\\fs12}So the controller controls how the model is presented on screen,\r\nDialogue: 0,0:15:41.50,0:15:44.05,yin,,0,0,0,,而视图则是「仆从」\\N{\\fs12}and the view is the minions,\r\nDialogue: 0,0:15:44.05,0:15:46.31,yin,,0,0,0,,是控制器要使用的类\\N{\\fs12}the classes that the controller is going to use,\r\nDialogue: 0,0:15:46.31,0:15:48.50,yin,,0,0,0,,就像是林肯积木一样\\N{\\fs12}kind of like the building blocks, the Lincoln Logs,\r\nDialogue: 0,0:15:48.50,0:15:51.50,yin,,0,0,0,,这种积木对于你们而言可能已经有点过时了\\N{\\fs12}I don't know maybe that's before all your time, but, you know,\r\nDialogue: 0,0:15:51.50,0:15:56.07,yin,,0,0,0,,视图中的东西 会被用于构建 UI\\N{\\fs12}the things we're going to do build our UI we're going to use in the view,\r\nDialogue: 0,0:15:56.07,0:15:59.50,yin,,0,0,0,,视图中的东西非常通用\\N{\\fs12}so, the stuff that's in the view is pretty generic.\r\nDialogue: 0,0:15:59.50,0:16:01.22,yin,,0,0,0,,通用 UI 元素\\N{\\fs12}Generic UI elements,\r\nDialogue: 0,0:16:01.22,0:16:04.50,yin,,0,0,0,,而控制器中的东西非常特定地用于 UI 的工作\\N{\\fs12}the stuff in the controller is very specific to how your UI works,\r\nDialogue: 0,0:16:04.50,0:16:08.50,yin,,0,0,0,,而模型中的东西完全独立于 UI 的工作\\N{\\fs12}and the stuff in the model is completely independent of how your UI works.\r\nDialogue: 0,0:16:10.29,0:16:15.50,yin,,0,0,0,,把 MVC 弄对需要知道事物怎么运行\\N{\\fs12}So, doing MVC right is about knowing where things go,\r\nDialogue: 0,0:16:15.50,0:16:19.03,yin,,0,0,0,,还需要知道这三块之间如何通信\\N{\\fs12}but also about how to communicate between these three camps\r\nDialogue: 0,0:16:19.04,0:16:22.48,yin,,0,0,0,,我将概述这三者之间的通信方式\\N{\\fs12}and so I'm going to try and summarize how the communication works between these camps\r\nDialogue: 0,0:16:22.48,0:16:25.61,yin,,0,0,0,,这里我用了一些道路标识 我画了双黄线\\N{\\fs12}and I've used road markings, you see the double yellow line\r\nDialogue: 0,0:16:25.61,0:16:29.26,yin,,0,0,0,,还有白色虚线 就像你开车时看到的一样\\N{\\fs12}and then the dashed white line, so that's like you're driving in your car,\r\nDialogue: 0,0:16:29.26,0:16:34.20,yin,,0,0,0,,我打算这样来表示通信发生的方式\\N{\\fs12}try to use them as that I have an image for how this communication happens,\r\nDialogue: 0,0:16:34.20,0:16:36.55,yin,,0,0,0,,哪里允许 哪里不允许\\N{\\fs12}where it's allowed, where it's not allowed. Okay?\r\nDialogue: 0,0:16:36.55,0:16:39.96,yin,,0,0,0,,首先来看控制器同模型的通信\\N{\\fs12}So let's talk about the controller talking to the model.\r\nDialogue: 0,0:16:39.98,0:16:44.50,yin,,0,0,0,,从道路这一侧到模型这一侧是白色虚线\\N{\\fs12}Okay? Going from that side of the road over to the model side is a dashed white line,\r\nDialogue: 0,0:16:44.50,0:16:46.50,yin,,0,0,0,,也就是说 你可以直接通过\\N{\\fs12}in other words, you can head right across there,\r\nDialogue: 0,0:16:46.50,0:16:49.50,yin,,0,0,0,,也许过马路之前要先左右看看 但是能过\\N{\\fs12}you probably want to look before you go, but you can go right across.\r\nDialogue: 0,0:16:49.50,0:16:52.77,yin,,0,0,0,,控制器需要知道模型的一切\\N{\\fs12}The controller has to know everything about the model\r\nDialogue: 0,0:16:52.78,0:16:56.50,yin,,0,0,0,,还需要有同模型完全通信的能力\\N{\\fs12}and it has to have complete ability to talk to the model,\r\nDialogue: 0,0:16:56.50,0:16:58.96,yin,,0,0,0,,按照任何方式使用其公共 API\\N{\\fs12}use its public API as much as it wants,\r\nDialogue: 0,0:16:58.98,0:17:00.74,yin,,0,0,0,,因为控制器的工作\\N{\\fs12}because the controller's job is to\r\nDialogue: 0,0:17:00.74,0:17:05.11,yin,,0,0,0,,就是将模型呈现给用户 使用视图作为其仆从\\N{\\fs12}present the model to the user using its view as its minions,\r\nDialogue: 0,0:17:05.11,0:17:06.50,yin,,0,0,0,,它需要能够这样访问\\N{\\fs12}so it has to have this access.\r\nDialogue: 0,0:17:06.50,0:17:10.79,yin,,0,0,0,,控制器需要能够完全 不受限地访问模型\\N{\\fs12}So that's full, unrestricted access the controller has talking to the model.\r\nDialogue: 0,0:17:10.81,0:17:15.50,yin,,0,0,0,,这是从控制器到模型的单向箭头\\N{\\fs12}This is a one-way arrow, from the controller to the model.\r\nDialogue: 0,0:17:15.50,0:17:20.50,yin,,0,0,0,,类似地 从控制器到视图 通信也是不受限的\\N{\\fs12}And similarly from the controller to the view, is also unlimited communication\r\nDialogue: 0,0:17:20.50,0:17:24.37,yin,,0,0,0,,因为控制器需要随意使唤自己的仆从\\N{\\fs12}because the controller is responsible for talking, using, it's own minions,\r\nDialogue: 0,0:17:24.37,0:17:29.09,yin,,0,0,0,,视图是控制器的仆从 来布局用户界面这些\\N{\\fs12}the view is the controllers' minions to lay out the user interface and all that stuff,\r\nDialogue: 0,0:17:29.11,0:17:31.25,yin,,0,0,0,,控制器可以做任何事情\\N{\\fs12}so the controller can do anything it wants,\r\nDialogue: 0,0:17:31.26,0:17:33.50,yin,,0,0,0,,这里我用绿色写了一个词 outlet(出口)\\N{\\fs12}I've put that little green word outlet up there\r\nDialogue: 0,0:17:33.50,0:17:37.94,yin,,0,0,0,,因为当我们有这样一个属性 从控制器指向视图时\\N{\\fs12}because when we have a property of a controller that points into the view,\r\nDialogue: 0,0:17:37.94,0:17:39.50,yin,,0,0,0,,我们将它称作 outlet\\N{\\fs12}we call it an outlet.\r\nDialogue: 0,0:17:39.50,0:17:41.74,yin,,0,0,0,,这还会在周三的 demo 中出现\\N{\\fs12}Okay? And you're going to see that in the demo on Wednesday,\r\nDialogue: 0,0:17:41.76,0:17:45.24,yin,,0,0,0,,我会说 让我们创建一个从控制器到视图的 outlet\\N{\\fs12}I'm going to say oh, let's create an outlet from our controller to our view\r\nDialogue: 0,0:17:45.24,0:17:47.50,yin,,0,0,0,,这样控制器就能同视图通信\\N{\\fs12}so our controller can talk to its view.\r\nDialogue: 0,0:17:48.64,0:17:50.96,yin,,0,0,0,,从模型到视图的通信呢\\N{\\fs12}What about this communication? Model to view,\r\nDialogue: 0,0:17:50.96,0:17:53.07,yin,,0,0,0,,从不 为什么\\N{\\fs12}never, and why is that?\r\nDialogue: 0,0:17:53.09,0:17:56.92,yin,,0,0,0,,100% 明显 模型完全是独立于 UI 的\\N{\\fs12}100 percent obvious. The model is completely UI independent.\r\nDialogue: 0,0:17:56.94,0:18:01.50,yin,,0,0,0,,它绝对不能同视图这一块中的对象进行沟通\\N{\\fs12}So there's absolutely no way it could talk to a view or object or anyone in that camp.\r\nDialogue: 0,0:18:01.50,0:18:04.83,yin,,0,0,0,,因为视图对象本质上是 UI 对象 它们是通用的\\N{\\fs12}Because the view objects are fundamentally UI objects, they're kind of generic,\r\nDialogue: 0,0:18:04.83,0:18:06.98,yin,,0,0,0,,但它们仍然是 UI 对象\\N{\\fs12}but they're still fundamentally UI objects.\r\nDialogue: 0,0:18:07.00,0:18:09.50,yin,,0,0,0,,类似地 由于视图对象是通用的\\N{\\fs12}Similarly, since the view objects are kind of generic,\r\nDialogue: 0,0:18:09.50,0:18:11.50,yin,,0,0,0,,它们无法同任何特定模型通信\\N{\\fs12}they can't be talking to any specific model.\r\nDialogue: 0,0:18:11.50,0:18:15.50,yin,,0,0,0,,它们需要控制器来为它们解释模型\\N{\\fs12}They need a controller to interpret a model for them.\r\nDialogue: 0,0:18:15.50,0:18:19.50,yin,,0,0,0,,这里没有任何通信发生 所以我用双黄线\\N{\\fs12}Okay? So there's never any communication this way, that's why it's a double yellow line,\r\nDialogue: 0,0:18:19.50,0:18:23.50,yin,,0,0,0,,所以箭头是红色的 所以这里用着火表示\\N{\\fs12}that's why these lines are red, that's why there's fire.\r\nDialogue: 0,0:18:23.50,0:18:26.50,yin,,0,0,0,,绝对不能越过这条线\\N{\\fs12}Never go across that line, ever.\r\nDialogue: 0,0:18:27.66,0:18:29.98,yin,,0,0,0,,视图往回同控制器通信呢\\N{\\fs12}What about the view talking back to the controller?\r\nDialogue: 0,0:18:29.98,0:18:32.27,yin,,0,0,0,,这里有一些通用视图对象 如按钮\\N{\\fs12}You got these generic view objects, like buttons,\r\nDialogue: 0,0:18:32.27,0:18:34.03,yin,,0,0,0,,它们能同控制器通信吗\\N{\\fs12}can they talk to the controller?\r\nDialogue: 0,0:18:34.07,0:18:38.83,yin,,0,0,0,,确实 它们能 但这里要小心\\N{\\fs12}Well...yes, they can, but they have to be careful\r\nDialogue: 0,0:18:38.83,0:18:41.11,yin,,0,0,0,,因为视图对象是通用的\\N{\\fs12}because the view objects are generic,\r\nDialogue: 0,0:18:41.11,0:18:44.50,yin,,0,0,0,,所以它们不能对控制器知道得太多\\N{\\fs12}so they can't really know much about the controller, so,\r\nDialogue: 0,0:18:44.50,0:18:47.61,yin,,0,0,0,,它们只能以一种「盲」的方式同控制器通信\\N{\\fs12}they can only communicate back to the controller in a blind way,\r\nDialogue: 0,0:18:47.61,0:18:50.68,yin,,0,0,0,,它们不知道通信对方的类\\N{\\fs12}where they don't know the class of the thing they're talking to,\r\nDialogue: 0,0:18:50.68,0:18:52.50,yin,,0,0,0,,而且这里需要一种结构化方式\\N{\\fs12}and, in a structured way,\r\nDialogue: 0,0:18:52.50,0:18:56.07,yin,,0,0,0,,也就是说 我们都同意能够这样通信\\N{\\fs12}a way where we all agree, we're going to communicate this way,\r\nDialogue: 0,0:18:56.07,0:18:59.16,yin,,0,0,0,,视图和控制器之间的结构化通信有哪些例子呢\\N{\\fs12}between the view and the controller, so what's an example of a structured way?\r\nDialogue: 0,0:18:59.16,0:19:01.14,yin,,0,0,0,,一种叫作目标动作\\N{\\fs12}Well one is called target action.\r\nDialogue: 0,0:19:01.18,0:19:04.14,yin,,0,0,0,,控制器在自身身上设置一个目标\\N{\\fs12}So the controller basically drops a target on itself\r\nDialogue: 0,0:19:04.14,0:19:08.50,yin,,0,0,0,,它会提供一个动作 就像一支箭一样\\N{\\fs12}and then it hands out an action, which is like an arrow,\r\nDialogue: 0,0:19:08.50,0:19:11.35,yin,,0,0,0,,给到视图 对视图说\\N{\\fs12}to the view and says to the view, okay,\r\nDialogue: 0,0:19:11.35,0:19:14.48,yin,,0,0,0,,当你要做什么时 例如你是按钮 有人按了你\\N{\\fs12}when you do what you do, like you're a button and someone touches you\r\nDialogue: 0,0:19:14.48,0:19:18.50,yin,,0,0,0,,或你是滑动条 有人动了你 发送这个动作给我\\N{\\fs12}or you're a slider and someone moves you, send me that action.\r\nDialogue: 0,0:19:18.50,0:19:22.50,yin,,0,0,0,,通过这种方式 通用的按钮或滑动条\\N{\\fs12}Okay? So in this way, the generic button, or slider,\r\nDialogue: 0,0:19:22.50,0:19:26.10,yin,,0,0,0,,就能往回同控制器通信 它不知道这是纸牌游戏控制器\\N{\\fs12}is communicating back to the controller, it has no idea that it's a card game controller\r\nDialogue: 0,0:19:26.11,0:19:29.50,yin,,0,0,0,,还是空间游戏控制器 它不知道这是什么样的控制器\\N{\\fs12}or a space game controller, it doesn't know what kind of controller it is,\r\nDialogue: 0,0:19:29.50,0:19:32.16,yin,,0,0,0,,它只知道自身发生什么之后\\N{\\fs12}All it knows is that when something happens in itself,\r\nDialogue: 0,0:19:32.18,0:19:33.50,yin,,0,0,0,,将消息发给目标\\N{\\fs12}boom, it sends messages to targets.\r\nDialogue: 0,0:19:33.50,0:19:37.50,yin,,0,0,0,,这是一种盲的 简单的 结构化的方式 让视图\\N{\\fs12}So that's a blind, simple, structured way for the view\r\nDialogue: 0,0:19:37.50,0:19:40.18,yin,,0,0,0,,能够同控制器通信\\N{\\fs12}to communicate with the controller.\r\nDialogue: 0,0:19:40.18,0:19:42.50,yin,,0,0,0,,还有更复杂的方式吗\\N{\\fs12}But what about more complicated ways?\r\nDialogue: 0,0:19:42.50,0:19:47.42,yin,,0,0,0,,有时 视图中发生的情况会更复杂一些\\N{\\fs12}Sometimes the view, things are happening in the view that are somewhat complicated\r\nDialogue: 0,0:19:47.42,0:19:50.10,yin,,0,0,0,,而控制器需要知道发生了什么\\N{\\fs12}and the controller needs to be informed of what's going on,\r\nDialogue: 0,0:19:50.11,0:19:52.23,yin,,0,0,0,,同步获知发生了什么\\N{\\fs12}synchronizing what's happening.\r\nDialogue: 0,0:19:52.24,0:19:57.66,yin,,0,0,0,,一种考虑方法就是我这里写的几个单词 将要 应该 已经\\N{\\fs12}And one way to think about this is these words I put here, will, should, and did,\r\nDialogue: 0,0:19:57.66,0:20:01.68,yin,,0,0,0,,以滚动视图为例\\N{\\fs12}when the view is kind of like -- let's say on the scroll view\r\nDialogue: 0,0:20:01.68,0:20:05.50,yin,,0,0,0,,我在滚动 我想要控制器\\N{\\fs12}and I'm scrolling around, and I want to let the controller,\r\nDialogue: 0,0:20:05.50,0:20:09.50,yin,,0,0,0,,知道用户刚才「已经」滚动过\\N{\\fs12}somebody, know that the user just did scroll. Okay?\r\nDialogue: 0,0:20:09.50,0:20:12.73,yin,,0,0,0,,或者用户刚按到这里准备滚动\\N{\\fs12}Or the user puts down the touch and is about to scroll,\r\nDialogue: 0,0:20:12.74,0:20:16.50,yin,,0,0,0,,我要让控制器知道用户「将要」滚动\\N{\\fs12}I want to let the controller know the user will be scrolling.\r\nDialogue: 0,0:20:16.50,0:20:19.50,yin,,0,0,0,,或者当用户触碰到后 滚动视图想知道\\N{\\fs12}Okay? Or the user puts a touch down and the scroll view wants to know,\r\nDialogue: 0,0:20:19.50,0:20:23.50,yin,,0,0,0,,我「应该」允许滚动吗 这是允许的吗\\N{\\fs12}should I allow the user to scroll here, is that allowed?\r\nDialogue: 0,0:20:23.50,0:20:25.42,yin,,0,0,0,,所有这些问题\\N{\\fs12}All those things,\r\nDialogue: 0,0:20:25.42,0:20:29.50,yin,,0,0,0,,滚动视图自身都没有足够的逻辑去知道答案\\N{\\fs12}the scroll view itself might not have enough logic to know the answer to those questions,\r\nDialogue: 0,0:20:29.50,0:20:36.21,yin,,0,0,0,,于是它会将回答这些问题的权力委托给其它对象\\N{\\fs12}so what it does is it delegates the authority to answer those questions to some other object.\r\nDialogue: 0,0:20:36.22,0:20:38.20,yin,,0,0,0,,它不知道这一对象的类\\N{\\fs12}Now it doesn't know the class of that object,\r\nDialogue: 0,0:20:38.20,0:20:40.73,yin,,0,0,0,,它只知道这种对象能够回答这些问题\\N{\\fs12}all it knows is that other object can answer these questions,\r\nDialogue: 0,0:20:40.73,0:20:43.21,yin,,0,0,0,,将要 应该 已经做这个或那个\\N{\\fs12}will, should, did, this, that or the other thing,\r\nDialogue: 0,0:20:43.22,0:20:48.14,yin,,0,0,0,,例如应该允许滚动 已经滚动过 诸如此类\\N{\\fs12}like, should allow scrolling, did scroll to point, things like that.\r\nDialogue: 0,0:20:48.14,0:20:52.25,yin,,0,0,0,,这些就是这类委托协议中你们会看到的方法\\N{\\fs12}So those are the kind of methods you're going to see in these delegate protocols.\r\nDialogue: 0,0:20:52.25,0:20:55.90,yin,,0,0,0,,我知道 CS106A 和 B 课程没有讲授协议\\N{\\fs12}Now I know that CS106A&B do not teach protocols,\r\nDialogue: 0,0:20:55.90,0:20:59.50,yin,,0,0,0,,多少人知道面向对象编程中协议表示什么\\N{\\fs12}how many people know what the word protocol means in object-oriented programming?\r\nDialogue: 0,0:20:59.50,0:21:02.50,yin,,0,0,0,,很少有人 那我就来讲了\\N{\\fs12}See, very few of you, so I will be teaching that.\r\nDialogue: 0,0:21:02.50,0:21:05.50,yin,,0,0,0,,协议是一种同另一对象通信的盲方式\\N{\\fs12}A protocol is just a blind way to talk to another object.\r\nDialogue: 0,0:21:05.50,0:21:08.50,yin,,0,0,0,,我给你讲时 你可能会想 哦 对 我知道这个\\N{\\fs12}You're going, when I teach you, you're going to be like, oh yeah, I know what that is,\r\nDialogue: 0,0:21:08.50,0:21:10.50,yin,,0,0,0,,我们不叫它协议 等等\\N{\\fs12}we didn't really call it protocol, or whatever.\r\nDialogue: 0,0:21:10.50,0:21:15.50,yin,,0,0,0,,不过 这就是我们进行委托的方式 这种盲的通信\\N{\\fs12}But, that's how we do delegation, this blind communication.\r\nDialogue: 0,0:21:15.50,0:21:18.50,yin,,0,0,0,,另外还有一点很重要\\N{\\fs12}Also, another important thing is\r\nDialogue: 0,0:21:18.50,0:21:22.90,yin,,0,0,0,,视图不应该「拥有」它们所显示的数据\\N{\\fs12}that views should not own the data that they're displaying. They should not own it.\r\nDialogue: 0,0:21:22.90,0:21:25.94,yin,,0,0,0,,也就是说 数据不应该是它们内部的属性\\N{\\fs12}In other words, it shouldn't be a property inside of them\r\nDialogue: 0,0:21:25.94,0:21:28.25,yin,,0,0,0,,数据是数据\\N{\\fs12}where that's the truth of that data.\r\nDialogue: 0,0:21:28.25,0:21:30.70,yin,,0,0,0,,最简单的例子是\\N{\\fs12}And the easiest example for this is\r\nDialogue: 0,0:21:30.70,0:21:34.29,yin,,0,0,0,,iPod iPhone 或 iPad 中的所有歌曲\\N{\\fs12}all the songs in your iPod, on your iPhone or your iPad, right?\r\nDialogue: 0,0:21:34.29,0:21:37.05,yin,,0,0,0,,你可能有一万首歌\\N{\\fs12}You might have 10,000 songs in there.\r\nDialogue: 0,0:21:37.05,0:21:40.50,yin,,0,0,0,,如果你有某种通用的列表视图在视图中\\N{\\fs12}So if you have some kind of generic list view in your view,\r\nDialogue: 0,0:21:40.50,0:21:44.99,yin,,0,0,0,,你不能将一万首歌转给它的实例变量\\N{\\fs12}you can't transfer all 10,000 songs to its instance variables\r\nDialogue: 0,0:21:44.99,0:21:48.50,yin,,0,0,0,,指望它能容纳一万首歌 然后逐个列出\\N{\\fs12}and expect it to hold 10,000 songs so it can list through it.\r\nDialogue: 0,0:21:48.50,0:21:50.40,yin,,0,0,0,,一 这很低效\\N{\\fs12}A, that would be inefficient,\r\nDialogue: 0,0:21:50.40,0:21:54.29,yin,,0,0,0,,二 这一万首歌属于哪里\\N{\\fs12}and B, that information, those 10,000 songs belongs where?\r\nDialogue: 0,0:21:54.70,0:21:55.88,yin,,0,0,0,,在模型里\\N{\\fs12}In the model.\r\nDialogue: 0,0:21:55.90,0:21:58.50,yin,,0,0,0,,因为音乐数据库是一个模型\\N{\\fs12}Because your song database is a model.\r\nDialogue: 0,0:21:58.50,0:22:02.14,yin,,0,0,0,,它无关于 UI 只是一个歌曲 艺术家 专辑列表\\N{\\fs12}It has nothing to do with UI's, just a list of songs and artists and albums and all that,\r\nDialogue: 0,0:22:02.14,0:22:03.31,yin,,0,0,0,,这在模型中\\N{\\fs12}it's in the model.\r\nDialogue: 0,0:22:03.31,0:22:05.50,yin,,0,0,0,,某控制器需要访问这个数据库\\N{\\fs12}Some controller has to look at that database\r\nDialogue: 0,0:22:05.50,0:22:09.77,yin,,0,0,0,,告诉视图如何显示这些歌曲\\N{\\fs12}and tell a view how to display all those songs.\r\nDialogue: 0,0:22:09.77,0:22:13.05,yin,,0,0,0,,我们需要这种通信在这里发生\\N{\\fs12}So, we need that communication to happen here\r\nDialogue: 0,0:22:13.07,0:22:15.50,yin,,0,0,0,,而视图要呈现某种列表\\N{\\fs12}and the view is displaying some sort of list,\r\nDialogue: 0,0:22:15.50,0:22:18.50,yin,,0,0,0,,你触控屏幕 轻按打开列表\\N{\\fs12}and you're touching down and you're flicking on the list\r\nDialogue: 0,0:22:18.50,0:22:20.16,yin,,0,0,0,,试图看到更多歌曲\\N{\\fs12}and trying to see more songs,\r\nDialogue: 0,0:22:20.16,0:22:23.05,yin,,0,0,0,,这种互动如何进行 答案是\\N{\\fs12}how does that communication happen, and the answer is,\r\nDialogue: 0,0:22:23.07,0:22:25.50,yin,,0,0,0,,我们另一种特殊的委托\\N{\\fs12}we have another special kind of delegate,\r\nDialogue: 0,0:22:25.50,0:22:27.50,yin,,0,0,0,,我们称之为数据源\\N{\\fs12}which we call a data source.\r\nDialogue: 0,0:22:27.50,0:22:30.50,yin,,0,0,0,,数据源不会考虑将要 已经 应该\\N{\\fs12}Now the data source doesn't do the will, did, should,\r\nDialogue: 0,0:22:30.50,0:22:32.50,yin,,0,0,0,,它会要求计数这些\\N{\\fs12}it's going to be asking questions like count,\r\nDialogue: 0,0:22:32.50,0:22:34.50,yin,,0,0,0,,例如有多少歌曲\\N{\\fs12}like how many songs are there?\r\nDialogue: 0,0:22:34.50,0:22:37.50,yin,,0,0,0,,控制器去模型中看 一万\\N{\\fs12}And the controller looks in the model, 10,000.\r\nDialogue: 0,0:22:37.50,0:22:39.50,yin,,0,0,0,,回给视图 有一万首\\N{\\fs12}Response to the view, there's 10,000.\r\nDialogue: 0,0:22:39.50,0:22:42.86,yin,,0,0,0,,视图会在内部预留一万个事物的空间\\N{\\fs12}The view makes space, internally, for 10,000 things,\r\nDialogue: 0,0:22:42.86,0:22:43.95,yin,,0,0,0,,它不知道具体是什么\\N{\\fs12}it doesn't know what they are,\r\nDialogue: 0,0:22:43.97,0:22:46.50,yin,,0,0,0,,将滚动条指示器移动一些\\N{\\fs12}moves the scroll bar indicator a little bit,\r\nDialogue: 0,0:22:46.50,0:22:48.01,yin,,0,0,0,,这样你就知道在哪\\N{\\fs12}so that you know where it is,\r\nDialogue: 0,0:22:48.01,0:22:50.29,yin,,0,0,0,,然后你开始滚动翻阅\\N{\\fs12}and then you start scrolling, flipping through it,\r\nDialogue: 0,0:22:50.29,0:22:52.08,yin,,0,0,0,,然后它开始向控制器发送消息\\N{\\fs12}and its start sending the message to the controller,\r\nDialogue: 0,0:22:52.08,0:22:57.51,yin,,0,0,0,,例如 给我第 150 行处的数据 后面 10 个项目\\N{\\fs12}give me the data at line 150, next 10 items.\r\nDialogue: 0,0:22:57.53,0:22:59.56,yin,,0,0,0,,明白吗 然后你继续往下 它会要求\\N{\\fs12}See what I mean? And then you flick down some more, now it's saying\r\nDialogue: 0,0:22:59.57,0:23:02.01,yin,,0,0,0,,250 行处的后面 10 个项目\\N{\\fs12}250, 10 more items,\r\nDialogue: 0,0:23:02.01,0:23:05.34,yin,,0,0,0,,控制器会回到模型 要求更多数据\\N{\\fs12}and so the controller is going back to the model and saying give me more, give me more data,\r\nDialogue: 0,0:23:05.34,0:23:07.88,yin,,0,0,0,,它会以这种盲的方式提供给视图\\N{\\fs12}and it's providing it to the view in this blind way.\r\nDialogue: 0,0:23:07.90,0:23:12.03,yin,,0,0,0,,这就是视图通过控制器从模型获取数据的方式\\N{\\fs12}So see how the view is getting data from the model through the controller,\r\nDialogue: 0,0:23:12.03,0:23:14.47,yin,,0,0,0,,这是一种盲的结构化方式\\N{\\fs12}in this kind of blind structured way.\r\nDialogue: 0,0:23:14.49,0:23:16.92,yin,,0,0,0,,大家都明白了吗\\N{\\fs12}Okay? That makes sense to everybody?\r\nDialogue: 0,0:23:16.94,0:23:18.97,yin,,0,0,0,,数据源其实是一种委托\\N{\\fs12}So data source is just a kind of delegate,\r\nDialogue: 0,0:23:18.97,0:23:20.88,yin,,0,0,0,,它是一类用于获取数据的特殊委托\\N{\\fs12}it's a specific kind of delegate for getting data.\r\nDialogue: 0,0:23:20.88,0:23:24.95,yin,,0,0,0,,你们会看到 iOS 中有一些类具有数据源\\N{\\fs12}So you're going to see that there are classes in iOS that have a data source,\r\nDialogue: 0,0:23:24.95,0:23:27.16,yin,,0,0,0,,它们通常也还有委托\\N{\\fs12}and they usually also have a delegate.\r\nDialogue: 0,0:23:27.18,0:23:29.68,yin,,0,0,0,,iOS 中大多数精密的类中都有委托\\N{\\fs12}Most sophisticated classes in iOS have a delegate,\r\nDialogue: 0,0:23:29.68,0:23:31.50,yin,,0,0,0,,将要 已经 应该这类东西\\N{\\fs12}the will, did, should kind of things.\r\nDialogue: 0,0:23:31.50,0:23:33.80,yin,,0,0,0,,有些类中还有数据源\\N{\\fs12}Some of them have a data source,\r\nDialogue: 0,0:23:33.81,0:23:36.73,yin,,0,0,0,,取决于它们是不是要展示出数据\\N{\\fs12}it depends on whether they're showing a lot of data or not.\r\nDialogue: 0,0:23:36.75,0:23:38.77,yin,,0,0,0,,简单数据 比如某个视图\\N{\\fs12}Now simple data, like if I had a view,\r\nDialogue: 0,0:23:38.77,0:23:42.50,yin,,0,0,0,,我在纸牌游戏中创建了一个视图叫 PlayingCard\\N{\\fs12}if I invented a view for my card game called playing card view,\r\nDialogue: 0,0:23:42.50,0:23:44.79,yin,,0,0,0,,它只有花色和大小\\N{\\fs12}and it just has a suit and a rank,\r\nDialogue: 0,0:23:44.79,0:23:47.86,yin,,0,0,0,,我们不会对花色和大小进行数据计数\\N{\\fs12}okay, we're not going to do count data at for just suit and rank,\r\nDialogue: 0,0:23:47.86,0:23:49.50,yin,,0,0,0,,我们会把它们设为属性\\N{\\fs12}we are going to set those properties.\r\nDialogue: 0,0:23:49.50,0:23:52.79,yin,,0,0,0,,视图中会设置有这些数据\\N{\\fs12}And so the view then would have those, that data set in it,\r\nDialogue: 0,0:23:52.79,0:23:55.06,yin,,0,0,0,,但它并不「拥有」它\\N{\\fs12}but it wouldn't be owning it, right?\r\nDialogue: 0,0:23:55.08,0:23:57.50,yin,,0,0,0,,模型仍然拥有花色和大小\\N{\\fs12}The model would still be owning the suit and rank,\r\nDialogue: 0,0:23:57.50,0:24:00.50,yin,,0,0,0,,视图只获得数据来进行显示\\N{\\fs12}the view is just getting that data to present it.\r\nDialogue: 0,0:24:00.50,0:24:06.50,yin,,0,0,0,,简单数据可以转给视图 但这只是给视图来显示\\N{\\fs12}So simple data we might transfer to the view, but it's merely for it to display it.\r\nDialogue: 0,0:24:06.50,0:24:12.17,yin,,0,0,0,,好 所有这些说的是 控制器的工作是为视图\\N{\\fs12}Okay. This all adds up to the controller's job being to interpret\r\nDialogue: 0,0:24:12.18,0:24:16.14,yin,,0,0,0,,解释并格式化提供模型数据\\N{\\fs12}and format the model data for the view.\r\nDialogue: 0,0:24:16.14,0:24:17.50,yin,,0,0,0,,这是控制器的工作\\N{\\fs12}That's the controller's job.\r\nDialogue: 0,0:24:17.50,0:24:20.50,yin,,0,0,0,,我们讲 demo 时 我会提醒你们注意\\N{\\fs12}And when we do our demo, I'm going to be marking\r\nDialogue: 0,0:24:20.50,0:24:22.50,yin,,0,0,0,,我写这些代码\\N{\\fs12}like, oh, see, I'm writing this code,\r\nDialogue: 0,0:24:22.50,0:24:25.12,yin,,0,0,0,,是为了让控制器执行它的工作\\N{\\fs12}this makes the controller perform its job,\r\nDialogue: 0,0:24:25.12,0:24:28.99,yin,,0,0,0,,也就是将模型数据用到视图中\\N{\\fs12}which is to take the model data and put it in, and using it to view minions,\r\nDialogue: 0,0:24:28.99,0:24:30.50,yin,,0,0,0,,然后显示到屏幕上\\N{\\fs12}put it on screen.\r\nDialogue: 0,0:24:30.50,0:24:32.25,yin,,0,0,0,,这就是控制器的作用\\N{\\fs12}That's what the controller does.\r\nDialogue: 0,0:24:32.25,0:24:36.50,yin,,0,0,0,,那从模型到控制器的通信呢\\N{\\fs12}What about this communication? Can the model talk to the controller?\r\nDialogue: 0,0:24:36.50,0:24:41.16,yin,,0,0,0,,还是一样 这显然也是不允许的 因为模型对UI一无所知\\N{\\fs12}Again, obviously that's verboten because model knows nothing about UI,\r\nDialogue: 0,0:24:41.17,0:24:44.23,yin,,0,0,0,,所以它不能同控制器这样的 UI 对象进行通信\\N{\\fs12}so it couldn't possibly talk to a UI object like the controller.\r\nDialogue: 0,0:24:44.23,0:24:46.50,yin,,0,0,0,,但有时 模型中的事物会发生变化\\N{\\fs12}But sometimes things change in the model\r\nDialogue: 0,0:24:46.50,0:24:48.08,yin,,0,0,0,,控制器需要知道它\\N{\\fs12}and the controller needs to know about it.\r\nDialogue: 0,0:24:48.10,0:24:52.50,yin,,0,0,0,,例如数据变化 数据库变化 或者模型是某种网络数据库\\N{\\fs12}Okay, data changes, a database changes or the model is some network database\r\nDialogue: 0,0:24:52.50,0:24:54.77,yin,,0,0,0,,某人改变了网络上的东西 造成它变化\\N{\\fs12}and somebody changes something on the network and it changes,\r\nDialogue: 0,0:24:54.79,0:24:56.50,yin,,0,0,0,,控制器需要知道这些\\N{\\fs12}and the controller needs to find out. So,\r\nDialogue: 0,0:24:56.50,0:24:59.50,yin,,0,0,0,,这种通信如何做到呢\\N{\\fs12}how do we do that communication?\r\nDialogue: 0,0:24:59.50,0:25:06.50,yin,,0,0,0,,这可以通过一种电台的概念来理解\\N{\\fs12}We do that using kind of a radio station model. So the model, a radio station concept,\r\nDialogue: 0,0:25:06.50,0:25:12.50,yin,,0,0,0,,模型会使用这一概念来广播信息\\N{\\fs12}the model will use this concept to essentially broadcast information\r\nDialogue: 0,0:25:12.50,0:25:14.50,yin,,0,0,0,,给任何感兴趣的人\\N{\\fs12}to anyone who's interested.\r\nDialogue: 0,0:25:14.50,0:25:18.77,yin,,0,0,0,,iOS 中执行这一功能的叫作通知\\N{\\fs12}And the mechanisms for doing this in iOS are called notification\r\nDialogue: 0,0:25:18.77,0:25:21.86,yin,,0,0,0,,和键值观察 键值观察简称 KVO\\N{\\fs12}and key value observing, KVO we call it,\r\nDialogue: 0,0:25:21.86,0:25:24.50,yin,,0,0,0,,模型可以说 哦\\N{\\fs12}and so the model can just say, oh,\r\nDialogue: 0,0:25:24.50,0:25:28.50,yin,,0,0,0,,模型中任何东西发生变化 我会通过我的电台进行广播\\N{\\fs12}anytime something changes in my model, I'm just going to broadcast on my radio station\r\nDialogue: 0,0:25:28.50,0:25:32.50,yin,,0,0,0,,然后控制器会接收来自电台的信息\\N{\\fs12}and then the controller simply tunes into that radio station.\r\nDialogue: 0,0:25:32.50,0:25:35.50,yin,,0,0,0,,它会发现事物正在变化 发现事物变化时\\N{\\fs12}And it can find out things are changing. And when it finds out something changes,\r\nDialogue: 0,0:25:35.50,0:25:39.50,yin,,0,0,0,,它会通过它的绿箭头同模型通信\\N{\\fs12}it's going to communicate via its green arrow to the model,\r\nDialogue: 0,0:25:39.50,0:25:42.50,yin,,0,0,0,,让模型把变化了的数据给它\\N{\\fs12}and say, okay, give me that data that changed.\r\nDialogue: 0,0:25:42.50,0:25:44.30,yin,,0,0,0,,能理解吗\\N{\\fs12}Alright? Does that make sense?\r\nDialogue: 0,0:25:44.30,0:25:45.50,yin,,0,0,0,,学期最后\\N{\\fs12}So towards the end of the quarter,\r\nDialogue: 0,0:25:45.50,0:25:48.71,yin,,0,0,0,,我们将会看到 例如通知如何知道\\N{\\fs12}we'll start seeing a little how to do notification to find out, for example,\r\nDialogue: 0,0:25:48.71,0:25:50.84,yin,,0,0,0,,数据库中的数据变化了\\N{\\fs12}if the data in the database changes.\r\nDialogue: 0,0:25:50.86,0:25:53.50,yin,,0,0,0,,我们获得通知 UI 然后\\N{\\fs12}We'll get a notification, the UI can then, you know,\r\nDialogue: 0,0:25:53.50,0:25:58.50,yin,,0,0,0,,控制器然后能够到模型去获取信息\\N{\\fs12}the controller can then go talk to the model to get the info.\r\nDialogue: 0,0:25:58.50,0:26:01.50,yin,,0,0,0,,有人问 视图能否接收电台信号\\N{\\fs12}Some people have asked, can a view tune into the radio station?\r\nDialogue: 0,0:26:01.50,0:26:04.50,yin,,0,0,0,,它们也许能 但你最好不要这样做\\N{\\fs12}They probably could, but you probably wouldn't want to do that.\r\nDialogue: 0,0:26:04.50,0:26:07.50,yin,,0,0,0,,这可能会违反 MVC\\N{\\fs12}That would probably be a violation of MVC.\r\nDialogue: 0,0:26:07.50,0:26:13.56,yin,,0,0,0,,好 我们这样做 我们有这些很好的通信和规则\\N{\\fs12}Alright, so, we do this, we have all this nice communication and all these rules,\r\nDialogue: 0,0:26:13.56,0:26:17.38,yin,,0,0,0,,我们可以设想使用这个创建一些简单的程序\\N{\\fs12}and we can imagine building something simple using this,\r\nDialogue: 0,0:26:17.38,0:26:19.86,yin,,0,0,0,,但如果我们想创建更大更复杂的 app 呢\\N{\\fs12}but what if we want to build a big, complicated app?\r\nDialogue: 0,0:26:19.88,0:26:23.23,yin,,0,0,0,,在 iPhone 或 iPad 上具有多屏幕的 app\\N{\\fs12}An app that has multiple screens on our iPhone or on an iPad\r\nDialogue: 0,0:26:23.23,0:26:26.50,yin,,0,0,0,,例如屏幕上有三四个不同区域\\N{\\fs12}it's got, you know, three or four different areas on screen\r\nDialogue: 0,0:26:26.50,0:26:28.97,yin,,0,0,0,,在发生着事情 如何做到呢\\N{\\fs12}where things are happening, how do we do that?\r\nDialogue: 0,0:26:28.99,0:26:33.50,yin,,0,0,0,,我们会合并多个 MVC\\N{\\fs12}Well, we're essentially going to combine multiple MVC's.\r\nDialogue: 0,0:26:33.50,0:26:40.50,yin,,0,0,0,,因为 MVC 能够将另一 MVC 作为其视图的一部分\\N{\\fs12}Because you, an MVC can use, as part of its view, another MVC.\r\nDialogue: 0,0:26:40.50,0:26:44.50,yin,,0,0,0,,所以 一整个 MVC\\N{\\fs12}Okay? So, an MVC, an entire MVC,\r\nDialogue: 0,0:26:44.50,0:26:49.60,yin,,0,0,0,,可以作为另一个较大 MVC 的仆从\\N{\\fs12}can be one of the minions of some bigger MVC.\r\nDialogue: 0,0:26:49.62,0:26:53.15,yin,,0,0,0,,这样可以一直往下串联\\N{\\fs12}Okay? And by doing that and cascading it down,\r\nDialogue: 0,0:26:53.15,0:26:55.89,yin,,0,0,0,,你就能创建越来越复杂的应用\\N{\\fs12}we can build more and more complicated applications. So,\r\nDialogue: 0,0:26:55.91,0:27:01.15,yin,,0,0,0,,例如 你可以有一个日历 app\\N{\\fs12}an example of this is you might have your calendar app,\r\nDialogue: 0,0:27:01.15,0:27:03.54,yin,,0,0,0,,它会显示出一整年\\N{\\fs12}and it's showing you the entire year,\r\nDialogue: 0,0:27:03.54,0:27:06.19,yin,,0,0,0,,你点击月 这时就会显示出月视图\\N{\\fs12}and you click on a month, and now it shows you a month view.\r\nDialogue: 0,0:27:06.19,0:27:08.50,yin,,0,0,0,,月视图会非常不同于年视图\\N{\\fs12}Well a month view looks a lot different than a year view.\r\nDialogue: 0,0:27:08.50,0:27:11.50,yin,,0,0,0,,月视图上有日期和一些圈\\N{\\fs12}Month view just has all the days and maybe some circle\r\nDialogue: 0,0:27:11.50,0:27:13.23,yin,,0,0,0,,告诉你哪天有预约\\N{\\fs12}that tells you where you have an appointment on a day,\r\nDialogue: 0,0:27:13.25,0:27:16.50,yin,,0,0,0,,然后点击日期 你会得到日视图\\N{\\fs12}and then when you click on a day, and now you get a day view.\r\nDialogue: 0,0:27:16.50,0:27:20.00,yin,,0,0,0,,日视图会显示给你不同时间的预约\\N{\\fs12}And the day is showing you the hours and what all your appointments are,\r\nDialogue: 0,0:27:20.01,0:27:22.50,yin,,0,0,0,,点击某一预约 你会进入预约视图\\N{\\fs12}and you click on an appointment, and now you get an appointment view\r\nDialogue: 0,0:27:22.50,0:27:25.50,yin,,0,0,0,,它会显示给你具体细节 包括时间地点这些\\N{\\fs12}and it's showing the detail of where you're going and when it is etc.\r\nDialogue: 0,0:27:25.50,0:27:29.02,yin,,0,0,0,,所有这些视图 年视图 月视图\\N{\\fs12}Well each of those views, the year view, the month view,\r\nDialogue: 0,0:27:29.02,0:27:33.50,yin,,0,0,0,,日视图 预约视图都是自身的 MVC\\N{\\fs12}the day view, and the appointment view are their own MVC's.\r\nDialogue: 0,0:27:33.50,0:27:38.32,yin,,0,0,0,,但是你可以看到 后三个视图被用作\\N{\\fs12}Okay? But you can see how the last three, okay, are used as,\r\nDialogue: 0,0:27:38.32,0:27:44.50,yin,,0,0,0,,顶级视图 即年视图的仆从 用以显示更多细节\\N{\\fs12}essentially, a minion of the top-level view, the year view, to show more detail.\r\nDialogue: 0,0:27:44.50,0:27:46.50,yin,,0,0,0,,年视图 你点击一个月\\N{\\fs12}So the year view, you click on a month,\r\nDialogue: 0,0:27:46.50,0:27:51.02,yin,,0,0,0,,它会使用一个月视图 MVC 来显示更多细节\\N{\\fs12}it's going to use the month view MVC to show more detail,\r\nDialogue: 0,0:27:51.04,0:27:53.50,yin,,0,0,0,,这是年视图的一部分\\N{\\fs12}so it's part of its view.\r\nDialogue: 0,0:27:53.50,0:27:57.50,yin,,0,0,0,,iOS 中这还被用于标签栏控制器\\N{\\fs12}So, you see this also in iOS with tab bar controllers.\r\nDialogue: 0,0:27:57.50,0:28:01.52,yin,,0,0,0,,标签栏列在下方 有四五个可以选\\N{\\fs12}You have the tab bar, along the bottom, I have four or five things you can choose,\r\nDialogue: 0,0:28:01.52,0:28:03.50,yin,,0,0,0,,上方有一些 MVC\\N{\\fs12}well there's some MVC at the top\r\nDialogue: 0,0:28:03.50,0:28:06.50,yin,,0,0,0,,它有四个指针指向四个仆从\\N{\\fs12}who has four pointers to four minions,\r\nDialogue: 0,0:28:06.50,0:28:11.06,yin,,0,0,0,,也就是四个出现在标签栏中的 MVC\\N{\\fs12}which are the four MVC's that are each going to appear in a tab bar.\r\nDialogue: 0,0:28:11.06,0:28:14.19,yin,,0,0,0,,我们在作业二或三中可能会做这个\\N{\\fs12}We'll be doing that, for example, in assignment number two or three,\r\nDialogue: 0,0:28:14.19,0:28:18.50,yin,,0,0,0,,我们会制作标签栏 你们需要使用多 MVC\\N{\\fs12}where we'll be making a tab bar and you're going to have to do multiple MVC's.\r\nDialogue: 0,0:28:18.50,0:28:23.50,yin,,0,0,0,,这就得到了一个大致是这样的图像\\N{\\fs12}So, that basically results in a picture that looks kind of like this.\r\nDialogue: 0,0:28:23.50,0:28:29.24,yin,,0,0,0,,这里有一个 MVC 看到 together 下的紫色那个了吗\\N{\\fs12}Alright? Where you got this MVC and you see the purple one that's like underneath the word together there,\r\nDialogue: 0,0:28:29.25,0:28:34.50,yin,,0,0,0,,它从视图指向三个其它 MVC\\N{\\fs12}and it points to three other MVC's outside of its view thing.\r\nDialogue: 0,0:28:34.50,0:28:37.50,yin,,0,0,0,,这就是我们创建标签栏控制器的方式\\N{\\fs12}That's how we're going to build this, that might be a tab bar controller\r\nDialogue: 0,0:28:37.50,0:28:39.50,yin,,0,0,0,,这些可能就是三个标签\\N{\\fs12}and those might be the three tabs.\r\nDialogue: 0,0:28:39.50,0:28:43.82,yin,,0,0,0,,每一个都是自己的 MVC 完全独立运行\\N{\\fs12}And each one is its own little MVC, completely independent, operates on its own,\r\nDialogue: 0,0:28:43.84,0:28:48.13,yin,,0,0,0,,这时它就是一个类似于通用 可重用视图的东西\\N{\\fs12}doesn't even know it's a generic, reusable view like thing at this point,\r\nDialogue: 0,0:28:48.13,0:28:50.50,yin,,0,0,0,,它甚至不知道它在标签栏中\\N{\\fs12}it doesn't even know that it's in a tab bar.\r\nDialogue: 0,0:28:50.50,0:28:53.10,yin,,0,0,0,,它只知道要做自己该做的事\\N{\\fs12}It just knows that it's supposed to do whatever it does.\r\nDialogue: 0,0:28:53.10,0:28:54.82,yin,,0,0,0,,这方面来看 它是模块化的\\N{\\fs12}And so it's modular in that way.\r\nDialogue: 0,0:28:54.82,0:28:58.50,yin,,0,0,0,,可以看到 这里不再有其它箭头\\N{\\fs12}You can also see that there's no communication between any other,\r\nDialogue: 0,0:28:58.50,0:29:01.12,yin,,0,0,0,,除了一些模型\\N{\\fs12}there's no other arrows, except for some of the models.\r\nDialogue: 0,0:29:01.13,0:29:03.50,yin,,0,0,0,,某些模型之间在相互通信\\N{\\fs12}You see some of the models are communicating with each other,\r\nDialogue: 0,0:29:03.50,0:29:07.11,yin,,0,0,0,,要知道 一个大的应用也许会有一单个共享的模型\\N{\\fs12}you know, a big application might have single, shared model.\r\nDialogue: 0,0:29:07.12,0:29:13.69,yin,,0,0,0,,或者 模型会被划分开来给子 MVC 使用\\N{\\fs12}Or, you know, the models might be split off into pieces to be used by sub MVC's.\r\nDialogue: 0,0:29:13.71,0:29:16.15,yin,,0,0,0,,但这里就只有这种通信了\\N{\\fs12}But that's the only kind of communication you're going to have there,\r\nDialogue: 0,0:29:16.15,0:29:20.17,yin,,0,0,0,,其它通信要么是我们看过的 MVC 中的结构化通信\\N{\\fs12}all other communication is either the structured communication we saw in the MVC\r\nDialogue: 0,0:29:20.17,0:29:24.50,yin,,0,0,0,,要么是将 MVC 用作另一个 MVC 视图的一部分\\N{\\fs12}or it's using MVC's as part of the view of another MVC.\r\nDialogue: 0,0:29:24.50,0:29:27.50,yin,,0,0,0,,关于这个有问题吗\\N{\\fs12}Any question about that?\r\nDialogue: 0,0:29:27.50,0:29:31.84,yin,,0,0,0,,当然 我们显然不希望设计像这样乱糟糟\\N{\\fs12}So we definitely don't want to be having designs that look like this.\r\nDialogue: 0,0:29:31.84,0:29:35.04,yin,,0,0,0,,所有人都在相互通信 我们不知道谁和什么在通信\\N{\\fs12}Where everybody's talking to everybody, we can't tell who's talking to what,\r\nDialogue: 0,0:29:35.04,0:29:38.50,yin,,0,0,0,,这无疑让程序调试变得很难 而且这无法规模化\\N{\\fs12}it's just impossible to debug a program like this and it doesn't scale.\r\nDialogue: 0,0:29:38.50,0:29:40.50,yin,,0,0,0,,你无法像这样创建出大程序\\N{\\fs12}You can't build really big programs this way,\r\nDialogue: 0,0:29:40.50,0:29:44.50,yin,,0,0,0,,这样做的话 你永远无法弄清什么地方容易崩溃掉\\N{\\fs12}it just becomes impossible to know how touching anything would break everything, right?\r\nDialogue: 0,0:29:44.50,0:29:48.50,yin,,0,0,0,,所以 我们肯定不要这样做\\N{\\fs12}So we're definitely not going to be doing that.\r\nDialogue: 0,0:29:50.21,0:29:53.50,yin,,0,0,0,,这是 MVC 关于这方面有问题吗\\N{\\fs12}Okay, so that's MVC. No questions about that?\r\nDialogue: 0,0:29:53.50,0:29:55.73,yin,,0,0,0,,好 再看 Objective-C\\N{\\fs12}Alright. Onto objective-C.\r\nDialogue: 0,0:29:55.74,0:29:59.32,yin,,0,0,0,,Objective-C 是 C 的严格父集\\N{\\fs12}So, objective C is a strict superset of C,\r\nDialogue: 0,0:29:59.32,0:30:02.50,yin,,0,0,0,,C 中能做的事 Objective-C 中都能做\\N{\\fs12}so everything you can do in C, you can do in objective-C.\r\nDialogue: 0,0:30:02.50,0:30:05.50,yin,,0,0,0,,这门课中我们会做很多 C 方面的事情\\N{\\fs12}And we'll do a lot of C things in this class.\r\nDialogue: 0,0:30:05.50,0:30:10.50,yin,,0,0,0,,我们也会做很多面向对象的东西 但 C 也会经常用到\\N{\\fs12}We'll do a lot of object-oriented stuff too, but we're going to do a lot of C things, as well.\r\nDialogue: 0,0:30:10.50,0:30:14.50,yin,,0,0,0,,但这里显然有些东西你们需要改变思考方式\\N{\\fs12}But, there's obviously a few things that you want to think differently\r\nDialogue: 0,0:30:14.50,0:30:17.98,yin,,0,0,0,,毕竟这里有面向对象性加入到一个语言中\\N{\\fs12}about because you have object-oriented stuff added onto a language,\r\nDialogue: 0,0:30:17.98,0:30:20.13,yin,,0,0,0,,今天我会讲到其中一点\\N{\\fs12}and we're going to talk about one of them today,\r\nDialogue: 0,0:30:20.15,0:30:24.50,yin,,0,0,0,,除了我会展示的一些语法外\\N{\\fs12}in addition to showing you a little bit of the syntax,\r\nDialogue: 0,0:30:24.50,0:30:26.39,yin,,0,0,0,,我会谈到 Objective-C 中不同于\\N{\\fs12}we're going to talk about one of these different,\r\nDialogue: 0,0:30:26.39,0:30:29.32,yin,,0,0,0,,我会谈到 Objective-C 中不同于\\N{\\fs12}think differently things about objective-C that's different\r\nDialogue: 0,0:30:29.32,0:30:33.11,yin,,0,0,0,,C++ 或 Java 的内容 也就是属性\\N{\\fs12}than C++ or Java, which is properties.\r\nDialogue: 0,0:30:33.11,0:30:36.26,yin,,0,0,0,,这些我就不读了 我会展示给你们\\N{\\fs12}And I'm not going to read through all of this, I'm just going to show it to you,\r\nDialogue: 0,0:30:36.26,0:30:40.50,yin,,0,0,0,,属性是我们访问实例变量的方式\\N{\\fs12}but properties are basically how we access our instance variables.\r\nDialogue: 0,0:30:40.50,0:30:45.30,yin,,0,0,0,,大家都懂吗 知道实例变量的请举手\\N{\\fs12}Everybody knows what I mean by, raise your hand if you know what I mean by instance variable?\r\nDialogue: 0,0:30:45.30,0:30:47.17,yin,,0,0,0,,很好 基本上所有人都懂\\N{\\fs12}Okay good. So pretty much everybody.\r\nDialogue: 0,0:30:47.17,0:30:52.50,yin,,0,0,0,,我们希望访问对象的实例数据\\N{\\fs12}So, we want to access the instance data of our objects.\r\nDialogue: 0,0:30:52.50,0:30:56.50,yin,,0,0,0,,通常 在 Java 或 C++ 中 你只需要\\N{\\fs12}And, normally, in Java or in C++, you just,\r\nDialogue: 0,0:30:56.50,0:31:00.50,yin,,0,0,0,,有一些访问它们的语法 然后访问它们\\N{\\fs12}have some syntax to access them and you just access them.\r\nDialogue: 0,0:31:00.50,0:31:02.50,yin,,0,0,0,,在 Objective-C 中 我们不这样做\\N{\\fs12}In objective-C we don't do that.\r\nDialogue: 0,0:31:02.50,0:31:05.22,yin,,0,0,0,,Objective-C 我们有所谓的属性\\N{\\fs12}In objective-C, we have what's called a property,\r\nDialogue: 0,0:31:05.24,0:31:09.50,yin,,0,0,0,,属性实际上是一个 setter 方法和一个 getter 方法\\N{\\fs12}and a property is basically a setter method and a getter method.\r\nDialogue: 0,0:31:09.50,0:31:12.50,yin,,0,0,0,,所有对实例变量的访问都是如此\\N{\\fs12}And that's how all access to the instance variable goes,\r\nDialogue: 0,0:31:12.50,0:31:15.50,yin,,0,0,0,,通过 setter 方法设置值 通过 getter 方法获取值\\N{\\fs12}through a setter method to set the value and a getter method to get it.\r\nDialogue: 0,0:31:15.50,0:31:21.15,yin,,0,0,0,,有些人可能很在意性能 会说 我的天\\N{\\fs12}And some people who maybe are kind of performance junkies might say, oh my gosh,\r\nDialogue: 0,0:31:21.15,0:31:24.24,yin,,0,0,0,,竟然每一个实例变量都需要调用方法来设置或获取\\N{\\fs12}every instance variable I have to call a method to set it or get it?\r\nDialogue: 0,0:31:24.24,0:31:27.50,yin,,0,0,0,,不过记住 这里是为用户界面系统创建的\\N{\\fs12}But, remember, you're building for a user interface system here,\r\nDialogue: 0,0:31:27.50,0:31:34.50,yin,,0,0,0,,当用户触到屏幕 这么一点时间内\\N{\\fs12}when the user touches down, that's taking million, a million code, you know,\r\nDialogue: 0,0:31:34.50,0:31:38.50,yin,,0,0,0,,就会执行上百万条指令\\N{\\fs12}you're executing a million instructions there in that amount of time.\r\nDialogue: 0,0:31:38.50,0:31:41.95,yin,,0,0,0,,多一点 setter 和 getter 方法根本不值得一提\\N{\\fs12}So, having a few extra setters and getters is completely irrelevant.\r\nDialogue: 0,0:31:41.96,0:31:44.50,yin,,0,0,0,,这仍然可行\\N{\\fs12}So it's the old [inaudible] thing, right?\r\nDialogue: 0,0:31:44.50,0:31:47.50,yin,,0,0,0,,你不需要去优化没有必要优化的事物\\N{\\fs12}You don't want to optimize things that don't need to be optimized.\r\nDialogue: 0,0:31:47.50,0:31:50.04,yin,,0,0,0,,你要优化的是很花时间的东西\\N{\\fs12}You want to optimize the things that are taking a lot of time\r\nDialogue: 0,0:31:50.04,0:31:53.11,yin,,0,0,0,,而访问实例变量不会花太多时间\\N{\\fs12}and accessing instance variable turns out not to be taking a lot of your time,\r\nDialogue: 0,0:31:53.11,0:31:56.13,yin,,0,0,0,,我们来看看这是怎样的\\N{\\fs12}so, let's look at what it looks like,\r\nDialogue: 0,0:31:56.13,0:31:59.30,yin,,0,0,0,,不要被这些语法所吓到\\N{\\fs12}don't get freaked out here by seeing this syntax.\r\nDialogue: 0,0:31:59.30,0:32:02.50,yin,,0,0,0,,这些都是新的 所以需要花点时间才能习惯\\N{\\fs12}It's all new, so, it's going to take some getting used to.\r\nDialogue: 0,0:32:02.50,0:32:05.67,yin,,0,0,0,,在 Objective-C 中 每一个类是这样的\\N{\\fs12}In objective-C, every class we have\r\nDialogue: 0,0:32:05.67,0:32:10.50,yin,,0,0,0,,我要展示的类实际上在我将创建的\\N{\\fs12}and the class I'm going to show you today is a, is in our, essentially our model\r\nDialogue: 0,0:32:10.50,0:32:13.50,yin,,0,0,0,,纸牌匹配游戏 app 的模型里\\N{\\fs12}that we're going to build for our card game matching app.\r\nDialogue: 0,0:32:13.50,0:32:16.50,yin,,0,0,0,,我们会有一个 Card 类和一个 Deck 类\\N{\\fs12}We're going to have a card and a deck,\r\nDialogue: 0,0:32:16.50,0:32:19.13,yin,,0,0,0,,我们还有一个 Card 的子类叫 PlayingCard\\N{\\fs12}and we're also going to have a subclass of card called playing card\r\nDialogue: 0,0:32:19.13,0:32:21.04,yin,,0,0,0,,还有一个 Deck 的子类叫作 PlayingCardDeck\\N{\\fs12}and a subclass of deck called playing card deck.\r\nDialogue: 0,0:32:21.04,0:32:23.91,yin,,0,0,0,,这是我们最开始的模型中的四个类\\N{\\fs12}Those are the four classes that are going to be in our model, to start.\r\nDialogue: 0,0:32:23.93,0:32:28.61,yin,,0,0,0,,今天的课上 我将只展示 Card 类\\N{\\fs12}And, so, I'm going to show you, in today's lecture I'm just going to show you card, only card,\r\nDialogue: 0,0:32:28.63,0:32:30.35,yin,,0,0,0,,周三我再展示 Deck\\N{\\fs12}and then on Wednesday I'll show you deck\r\nDialogue: 0,0:32:30.35,0:32:33.50,yin,,0,0,0,,PlayingCardDeck 和 PlayingCard\\N{\\fs12}and playing card deck and playing card.\r\nDialogue: 0,0:32:33.50,0:32:37.87,yin,,0,0,0,,Objective-C 中的每一个类都有一个头文件 如 Card.h\\N{\\fs12}So, every class in objective-C, you have a header file, card.h,\r\nDialogue: 0,0:32:37.89,0:32:40.50,yin,,0,0,0,,还有一个实现文件 Card.m\\N{\\fs12}and you have an implementation file, card.m.\r\nDialogue: 0,0:32:40.50,0:32:45.09,yin,,0,0,0,,就像 C++ 中你有 .h 和 .c 文件一样\\N{\\fs12}This is just like in C++ you might have dot h and dot c, or whatever,\r\nDialogue: 0,0:32:45.09,0:32:49.50,yin,,0,0,0,,这里 .m 我猜 m 表示的是实现 我不知道\\N{\\fs12}this is dot m, m I guess is for implementation, I don't know.\r\nDialogue: 0,0:32:49.50,0:32:53.28,yin,,0,0,0,,反正是 m 这些是分开的\\N{\\fs12}But it's m, and so you have these separate things,\r\nDialogue: 0,0:32:53.28,0:32:58.04,yin,,0,0,0,,不同之处在于 Card.h 是公共 API\\N{\\fs12}the difference here is card.h is the public API.\r\nDialogue: 0,0:32:58.04,0:33:03.02,yin,,0,0,0,,这就是 .h 它是公共 API\\N{\\fs12}That's what your dot h is. It's your public API.\r\nDialogue: 0,0:33:03.02,0:33:08.83,yin,,0,0,0,,Card.m 则是私有 API 以及你所有的实现\\N{\\fs12}Card.m is your private API and all your implementation.\r\nDialogue: 0,0:33:08.83,0:33:11.81,yin,,0,0,0,,不要把. h 和 .m 搞混\\N{\\fs12}Don't get confused about dot h and dot m.\r\nDialogue: 0,0:33:11.81,0:33:14.96,yin,,0,0,0,,.h 是你的公共 API 它就是这个\\N{\\fs12}All dot h is your public API, that's all it is.\r\nDialogue: 0,0:33:14.96,0:33:21.04,yin,,0,0,0,,它是类中你希望具有公共性质 让其他人能够调用的方法\\N{\\fs12}It's what methods in your class you want to make public so that other people can call them.\r\nDialogue: 0,0:33:21.04,0:33:23.98,yin,,0,0,0,,我们来看看语法是怎样的\\N{\\fs12}So, let's see what the syntax looks like.\r\nDialogue: 0,0:33:23.98,0:33:28.50,yin,,0,0,0,,公共 API 中 你必须说明父类是谁\\N{\\fs12}In your public API, you must say who your superclass is.\r\nDialogue: 0,0:33:28.50,0:33:33.50,yin,,0,0,0,,你不能够将父类保密\\N{\\fs12}You are not allowed to make your superclass be a secret.\r\nDialogue: 0,0:33:33.50,0:33:36.50,yin,,0,0,0,,它需要是公共的 需要放到头文件中\\N{\\fs12}It has to be public so we have to put it in the header file,\r\nDialogue: 0,0:33:36.50,0:33:39.50,yin,,0,0,0,,这里是使用的语法 我们使用 @interface\\N{\\fs12}and you can see the syntax we use is @interface,\r\nDialogue: 0,0:33:39.50,0:33:40.92,yin,,0,0,0,,然后是类名\\N{\\fs12}the name of our class,\r\nDialogue: 0,0:33:40.93,0:33:43.50,yin,,0,0,0,,这必须同文件名一样\\N{\\fs12}which should always match the name of the file, by the way,\r\nDialogue: 0,0:33:43.50,0:33:47.11,yin,,0,0,0,,Card.h 应该总是有 Card 类的接口\\N{\\fs12}card.h should always have the interface for the class card.\r\nDialogue: 0,0:33:47.11,0:33:49.50,yin,,0,0,0,,然后冒号 后面是父类\\N{\\fs12}And then a colon and then your superclass.\r\nDialogue: 0,0:33:49.50,0:33:52.50,yin,,0,0,0,,Card 类的父类是 NSObject\\N{\\fs12}Now the superclass of the card class is NSObject.\r\nDialogue: 0,0:33:52.50,0:33:57.11,yin,,0,0,0,,NSObject 在 Foundation 框架中\\N{\\fs12}NSObject is in the foundation framework\r\nDialogue: 0,0:33:57.11,0:34:01.54,yin,,0,0,0,,它可以说是 iOS 中每一个类的根类\\N{\\fs12}and it's pretty much the root class of every single class in all of iOS,\r\nDialogue: 0,0:34:01.54,0:34:03.50,yin,,0,0,0,,包括你所写的所有类\\N{\\fs12}including all the classes you write.\r\nDialogue: 0,0:34:03.50,0:34:07.11,yin,,0,0,0,,这是一种基本的类 我在 Foundation 中会讲到\\N{\\fs12}It's this kind of basic class, we'll talk about it when we talk about foundation,\r\nDialogue: 0,0:34:07.11,0:34:10.50,yin,,0,0,0,,总之 它是每一个类的最终父类\\N{\\fs12}but it's going to be the superclass eventually of every single class.\r\nDialogue: 0,0:34:10.50,0:34:13.50,yin,,0,0,0,,一切最终都是从 NSObject 继承\\N{\\fs12}Everything, eventually, inherits from NSObject.\r\nDialogue: 0,0:34:13.50,0:34:17.50,yin,,0,0,0,,在实现端 情况也很类似\\N{\\fs12}Now, on the implementation side, it looks very similar,\r\nDialogue: 0,0:34:17.50,0:34:19.50,yin,,0,0,0,,不过这里不说 @interface\\N{\\fs12}but instead of saying at sign interface, you say\r\nDialogue: 0,0:34:19.50,0:34:22.50,yin,,0,0,0,,而说 @implementation 后跟类名\\N{\\fs12}@implementation and the name of the class.\r\nDialogue: 0,0:34:22.50,0:34:25.50,yin,,0,0,0,,这里不需要指定父类\\N{\\fs12}And here you don't specify your superclass.\r\nDialogue: 0,0:34:25.50,0:34:28.74,yin,,0,0,0,,因为这只需要指定一次 而它是公共的\\N{\\fs12}Because you're only allowed to specify that once, and it's public,\r\nDialogue: 0,0:34:28.74,0:34:30.50,yin,,0,0,0,,所以是在头文件中\\N{\\fs12}so it goes in your header file.\r\nDialogue: 0,0:34:30.50,0:34:34.50,yin,,0,0,0,,注意到两者的底部都有 @end\\N{\\fs12}Notice that the bottom of both of these, little at sign end, do you see that?\r\nDialogue: 0,0:34:34.50,0:34:38.50,yin,,0,0,0,,这里表示的是接口或实现的结束\\N{\\fs12}Okay, that just means that's the end of the interface or of the implantation.\r\nDialogue: 0,0:34:38.50,0:34:43.89,yin,,0,0,0,,所有公共 API 都在 @interface 和 @end 之间\\N{\\fs12}So all of your public API goes inside this at sign interface block, at sign interface,\r\nDialogue: 0,0:34:43.89,0:34:47.50,yin,,0,0,0,,而所有私有实现都在\\N{\\fs12}and all of your implementation, your private implementation goes\r\nDialogue: 0,0:34:47.50,0:34:49.92,yin,,0,0,0,,@implementation 和 @end 之间\\N{\\fs12}in the at sign implementation part.\r\nDialogue: 0,0:34:49.94,0:34:56.02,yin,,0,0,0,,要指定父类 你需要导入\\N{\\fs12}Now, if you import, if you have specified your superclass here, you have to import it.\r\nDialogue: 0,0:34:56.02,0:34:58.37,yin,,0,0,0,,这就像是 #include 一样\\N{\\fs12}Which is like pound sign, include.\r\nDialogue: 0,0:34:58.37,0:35:00.33,yin,,0,0,0,,不过它比 #include 要强大\\N{\\fs12}It's a little more powerful than pound sign, include,\r\nDialogue: 0,0:35:00.33,0:35:03.11,yin,,0,0,0,,强大很多 等下我就会讲到\\N{\\fs12}in fact, it's a lot more powerful, as I'll talk about in a second here.\r\nDialogue: 0,0:35:03.11,0:35:04.50,yin,,0,0,0,,你必须导入\\N{\\fs12}But you must import it,\r\nDialogue: 0,0:35:04.50,0:35:08.11,yin,,0,0,0,,否则 Objective-C 编译器就不知道你的父类是什么\\N{\\fs12}otherwise the objective-C compiler won't know what that superclass is,\r\nDialogue: 0,0:35:08.11,0:35:10.24,yin,,0,0,0,,所以你必须导入父类\\N{\\fs12}so you have to, obviously, import your superclass.\r\nDialogue: 0,0:35:10.24,0:35:15.00,yin,,0,0,0,,不过 通常对于 iOS 中的父类\\N{\\fs12}However, we don't usually, when our superclass is something that's in iOS,\r\nDialogue: 0,0:35:15.02,0:35:19.50,yin,,0,0,0,,我们不会只导入类的头文件 这里是 Foundation\\N{\\fs12}we don't usually import just that class's header file, which in this case is foundation,\r\nDialogue: 0,0:35:19.50,0:35:23.50,yin,,0,0,0,,我们会导入整个框架\\N{\\fs12}we actually import the entire framework.\r\nDialogue: 0,0:35:23.50,0:35:26.50,yin,,0,0,0,,你也许会说 这太低效了吧\\N{\\fs12}Now you might say, oh, that's inefficient.\r\nDialogue: 0,0:35:26.50,0:35:29.15,yin,,0,0,0,,框架得有多大\\N{\\fs12}A huge framework,\r\nDialogue: 0,0:35:29.16,0:35:32.50,yin,,0,0,0,,当然 这是已经经过预编译和优化的\\N{\\fs12}but of course this is all precompiled and optimized.\r\nDialogue: 0,0:35:32.50,0:35:39.13,yin,,0,0,0,,iOS7 中实际语法是 @import Foundation\\N{\\fs12}And, in fact, in iOS7, the syntax for this is really to say at sign import foundation.\r\nDialogue: 0,0:35:39.13,0:35:44.50,yin,,0,0,0,,这意味着我将使用 Foundation 框架中的所有公共类\\N{\\fs12}That means I'm going to use all the public classes in the foundation framework.\r\nDialogue: 0,0:35:44.50,0:35:47.24,yin,,0,0,0,,iOS7 仍然支持原来的\\N{\\fs12}iOS7 still supports the old\r\nDialogue: 0,0:35:47.24,0:35:49.44,yin,,0,0,0,,import Foundation/Foundation.h\\N{\\fs12}import foundation slash foundation.h\r\nDialogue: 0,0:35:49.44,0:35:51.50,yin,,0,0,0,,希望的话 你也可以用这个\\N{\\fs12}so you can use that if you want.\r\nDialogue: 0,0:35:51.50,0:35:57.50,yin,,0,0,0,,在实现文件中 我们显然需要导入头文件\\N{\\fs12}Now on our implementation file, we have to import our header file, obviously.\r\nDialogue: 0,0:35:57.50,0:35:59.70,yin,,0,0,0,,因为实现文件需要知道\\N{\\fs12}Because our implementation file needs to know\r\nDialogue: 0,0:35:59.70,0:36:03.85,yin,,0,0,0,,就 API 而言 我们使用的什么公共 API\\N{\\fs12}what we're committing to publicly, in terms of our API,\r\nDialogue: 0,0:36:03.85,0:36:07.05,yin,,0,0,0,,我们需要把这个导入 很好理解\\N{\\fs12}so we have to import that. Makes perfect sense.\r\nDialogue: 0,0:36:07.05,0:36:11.50,yin,,0,0,0,,我们还可以有私有声明\\N{\\fs12}We can also have private declarations.\r\nDialogue: 0,0:36:11.50,0:36:16.50,yin,,0,0,0,,声明私有的属性和方法\\N{\\fs12}Declarations of properties and methods that are private\r\nDialogue: 0,0:36:16.50,0:36:20.13,yin,,0,0,0,,在实现文件内 使用这种 @interface\\N{\\fs12}inside of our implementation file by putting this little at sign interface,\r\nDialogue: 0,0:36:20.13,0:36:23.50,yin,,0,0,0,,类名 开闭圆括号\\N{\\fs12}name of our class, open parentheses, closed parentheses.\r\nDialogue: 0,0:36:23.50,0:36:25.20,yin,,0,0,0,,@end 结尾\\N{\\fs12}And then at sign end.\r\nDialogue: 0,0:36:25.22,0:36:27.87,yin,,0,0,0,,这里我们可以加入私有声明\\N{\\fs12}So we can have a little space here where we can put little private declarations.\r\nDialogue: 0,0:36:27.89,0:36:30.50,yin,,0,0,0,,Objective-C 并不要求你\\N{\\fs12}Now, objective-C does not require you\r\nDialogue: 0,0:36:30.50,0:36:33.87,yin,,0,0,0,,在实际使用之前进行声明\\N{\\fs12}to declare something before you use it in a file,\r\nDialogue: 0,0:36:33.89,0:36:35.29,yin,,0,0,0,,知道我说的什么吗\\N{\\fs12}you know what I mean by that?\r\nDialogue: 0,0:36:35.31,0:36:37.50,yin,,0,0,0,,很多语言中\\N{\\fs12}And there's a lot, a lot of languages,\r\nDialogue: 0,0:36:37.50,0:36:40.50,yin,,0,0,0,,在调用一个方法前 你需要声明这个函数\\N{\\fs12}you have to declare a method before you can call it, right?\r\nDialogue: 0,0:36:40.50,0:36:42.50,yin,,0,0,0,,但 Objective-C 中你可以颠倒过来\\N{\\fs12}But you can do it out of order in objective-C,\r\nDialogue: 0,0:36:42.50,0:36:45.00,yin,,0,0,0,,例如你可以实现一个方法 A 调用方法 B\\N{\\fs12}you can implement a method here that calls,\r\nDialogue: 0,0:36:45.00,0:36:47.50,yin,,0,0,0,,例如你可以实现一个方法 A 调用方法 B\\N{\\fs12}you can implement method A, calls method B,\r\nDialogue: 0,0:36:47.50,0:36:50.50,yin,,0,0,0,,然后方法 B 在文件后面某处才实现\\N{\\fs12}and then method B is implemented down here later in the file.\r\nDialogue: 0,0:36:50.50,0:36:52.50,yin,,0,0,0,,你不需要在前面声明方法 B\\N{\\fs12}So you don't have to declare method B first,\r\nDialogue: 0,0:36:52.50,0:36:56.50,yin,,0,0,0,,再去实现方法 A 再实现方法 B\\N{\\fs12}then implement method A, and then implement method B.\r\nDialogue: 0,0:36:56.50,0:37:01.50,yin,,0,0,0,,这种私有 @interface 主要被用于属性\\N{\\fs12}So, this little private at sign interface we're mostly going to use for properties.\r\nDialogue: 0,0:37:01.50,0:37:03.81,yin,,0,0,0,,因为当我们声明属性时\\N{\\fs12}Okay? Because when we declare a property,\r\nDialogue: 0,0:37:03.81,0:37:06.50,yin,,0,0,0,,setter 和 getter 会为我们写好\\N{\\fs12}as you'll see, that setter and getter get written for us.\r\nDialogue: 0,0:37:06.50,0:37:10.50,yin,,0,0,0,,我们来看看怎么声明属性\\N{\\fs12}So let's see what that looks like to declare a property.\r\nDialogue: 0,0:37:10.50,0:37:13.50,yin,,0,0,0,,这里是一个简单属性 叫作 contents\\N{\\fs12}So here's a simple property. It's called contents.\r\nDialogue: 0,0:37:13.50,0:37:17.11,yin,,0,0,0,,表示纸牌的内容 纸牌上印有什么\\N{\\fs12}So this is the content of the card. This is what's on the card.\r\nDialogue: 0,0:37:17.11,0:37:19.50,yin,,0,0,0,,可以是梅花 A\\N{\\fs12}So this might be ace of clubs.\r\nDialogue: 0,0:37:19.50,0:37:23.50,yin,,0,0,0,,由于这是你们第一天上课\\N{\\fs12}Okay? And because this is your first day,\r\nDialogue: 0,0:37:23.50,0:37:26.50,yin,,0,0,0,,我们会让内容非常简单 仅仅是一个字符串\\N{\\fs12}we're going to make the contents be very simple, just a string.\r\nDialogue: 0,0:37:26.50,0:37:29.50,yin,,0,0,0,,这些纸牌可能是抽认卡\\N{\\fs12}Okay? So these cards, they can be like a flashcard,\r\nDialogue: 0,0:37:29.50,0:37:31.50,yin,,0,0,0,,也许是用于学外语用的\\N{\\fs12}maybe, for learning a foreign language, maybe this is\r\nDialogue: 0,0:37:31.50,0:37:34.50,yin,,0,0,0,,也许内容是你要学的单词\\N{\\fs12}the contents are the word that you're trying to learn\r\nDialogue: 0,0:37:34.50,0:37:36.50,yin,,0,0,0,,也许它是图像抽认卡\\N{\\fs12}and maybe it's a flashcard of images\r\nDialogue: 0,0:37:36.50,0:37:40.50,yin,,0,0,0,,内容是图像的名字\\N{\\fs12}where this content is the name of some image and\r\nDialogue: 0,0:37:40.50,0:37:43.50,yin,,0,0,0,,交给 UI 来显示匹配的图像\\N{\\fs12}it's up to UI to display an image that matches it.\r\nDialogue: 0,0:37:43.50,0:37:45.50,yin,,0,0,0,,在我们的纸牌游戏中\\N{\\fs12}Or in the case of our playing cards,\r\nDialogue: 0,0:37:45.50,0:37:48.14,yin,,0,0,0,,我们的内容是字母 A\\N{\\fs12}we're going to have this be like, literally the character A\r\nDialogue: 0,0:37:48.14,0:37:49.50,yin,,0,0,0,,及梅花符号\\N{\\fs12}and then the character clubs,\r\nDialogue: 0,0:37:49.50,0:37:51.98,yin,,0,0,0,,有一个 Unicode 字符表示梅花\\N{\\fs12}because there's Unicode character clubs,\r\nDialogue: 0,0:37:51.98,0:37:54.01,yin,,0,0,0,,梅花 A 这就是内容\\N{\\fs12}so the A clubs, that would be the content.\r\nDialogue: 0,0:37:54.05,0:37:56.50,yin,,0,0,0,,这是纸牌内容 纸牌上印有什么\\N{\\fs12}So this is the content of the card, what's on the card.\r\nDialogue: 0,0:37:56.50,0:38:00.22,yin,,0,0,0,,这里可以看到有 NSString\\N{\\fs12}And you can see that it's an NSString star.\r\nDialogue: 0,0:38:00.22,0:38:02.38,yin,,0,0,0,,前面有 @property\\N{\\fs12}You see at sign property\r\nDialogue: 0,0:38:02.38,0:38:06.49,yin,,0,0,0,,这会声明每一个纸牌实例都需要空间\\N{\\fs12}is how we're going to declare that we need storage, per instance of card,\r\nDialogue: 0,0:38:06.50,0:38:10.50,yin,,0,0,0,,换言之 每一张纸牌都有自己的内容 contents\\N{\\fs12}in other words every card has its own contents, and\r\nDialogue: 0,0:38:10.50,0:38:13.01,yin,,0,0,0,,这是一个字符串 所以我们说\\N{\\fs12}it's going to be a string, and so we say\r\nDialogue: 0,0:38:13.01,0:38:15.20,yin,,0,0,0,,property NSString\\N{\\fs12}property NSString star, now,\r\nDialogue: 0,0:38:15.20,0:38:19.50,yin,,0,0,0,,在 Objective-C 中理解这个很重要 所有对象\\N{\\fs12}it's important to understand that in objective-C all objects,\r\nDialogue: 0,0:38:19.50,0:38:23.50,yin,,0,0,0,,都在堆中 我们有指针指向它们\\N{\\fs12}all of them, live in the heap and we have pointers to them.\r\nDialogue: 0,0:38:23.50,0:38:29.50,yin,,0,0,0,,这里没有将对象放到栈上等等这样的情况\\N{\\fs12}There's no such thing as making an object on the stack or anything like that.\r\nDialogue: 0,0:38:29.50,0:38:32.50,yin,,0,0,0,,它们都在堆中 大家知道什么是堆吗 有问题吗\\N{\\fs12}They're all in the heap. Everyone knows what the heap is? Any questions about that?\r\nDialogue: 0,0:38:32.50,0:38:34.98,yin,,0,0,0,,也就是分配闲置内存的地方\\N{\\fs12}That's just where you allocate free memory.\r\nDialogue: 0,0:38:34.99,0:38:36.50,yin,,0,0,0,,所有对象都在那里\\N{\\fs12}So all objects are there.\r\nDialogue: 0,0:38:36.50,0:38:38.94,yin,,0,0,0,,Objective-C 很酷的地方在于\\N{\\fs12}What's' really cool about objective-C is,\r\nDialogue: 0,0:38:38.96,0:38:43.07,yin,,0,0,0,,Objective-C 会为你管理所有这些存储\\N{\\fs12}objective-C will manage all that storage for you.\r\nDialogue: 0,0:38:43.09,0:38:45.98,yin,,0,0,0,,它会进行分配 也会进行释放\\N{\\fs12}It will allocate for you and free it for you.\r\nDialogue: 0,0:38:45.99,0:38:49.50,yin,,0,0,0,,它怎么知道何时释放呢\\N{\\fs12}Now how does it know when to free it?\r\nDialogue: 0,0:38:49.50,0:38:51.50,yin,,0,0,0,,答案就是这个 strong\\N{\\fs12}And the answer is this strong thing,\r\nDialogue: 0,0:38:51.50,0:38:54.50,yin,,0,0,0,,看到 strong 了吗\\N{\\fs12}you see the word strong there?\r\nDialogue: 0,0:38:54.50,0:38:57.31,yin,,0,0,0,,属性可以是强的 就像这个这样\\N{\\fs12}If, your properties can either be strong, like this one,\r\nDialogue: 0,0:38:57.31,0:38:58.73,yin,,0,0,0,,或者弱的\\N{\\fs12}or weak,\r\nDialogue: 0,0:38:58.74,0:39:00.50,yin,,0,0,0,,就两种 强或弱\\N{\\fs12}two things, strong or weak.\r\nDialogue: 0,0:39:00.50,0:39:03.05,yin,,0,0,0,,所有指针属性要么强 要么弱\\N{\\fs12}And all pointer properties have to be strong or weak\r\nDialogue: 0,0:39:03.05,0:39:06.29,yin,,0,0,0,,因为 Objective-C 需要知道怎么处理内存和堆\\N{\\fs12}because the objective-C has to know what to do with the memory and the heap.\r\nDialogue: 0,0:39:06.31,0:39:09.50,yin,,0,0,0,,强表示保持对这个的存储\\N{\\fs12}Strong means keep the memory for this,\r\nDialogue: 0,0:39:09.50,0:39:13.18,yin,,0,0,0,,在堆中 保持这个所指的东西\\N{\\fs12}for the thing this points to, in the heap,\r\nDialogue: 0,0:39:13.20,0:39:18.16,yin,,0,0,0,,只要我或其他任何人有一个强指针指向它\\N{\\fs12}as long as I or anyone else has a strong pointer to it.\r\nDialogue: 0,0:39:18.16,0:39:20.50,yin,,0,0,0,,这被叫作引用计数\\N{\\fs12}So, this is called reference counting,\r\nDialogue: 0,0:39:20.50,0:39:22.50,yin,,0,0,0,,这不是垃圾收集 而是引用计数\\N{\\fs12}it's not garbage collection, it's reference counting.\r\nDialogue: 0,0:39:22.50,0:39:25.09,yin,,0,0,0,,Objective-C 会追踪\\N{\\fs12}So the objective-C is going to keep track\r\nDialogue: 0,0:39:25.09,0:39:28.44,yin,,0,0,0,,每一个指向堆中对象的强指针\\N{\\fs12}of every single strong pointer to an object in the heap\r\nDialogue: 0,0:39:28.44,0:39:31.59,yin,,0,0,0,,只要有一个强指针存在\\N{\\fs12}and as long as at least one strong pointer exists,\r\nDialogue: 0,0:39:31.59,0:39:33.22,yin,,0,0,0,,它就会把其留在堆中\\N{\\fs12}it's going to keep that thing in heap.\r\nDialogue: 0,0:39:33.22,0:39:35.50,yin,,0,0,0,,只有不再存在任何强指针时\\N{\\fs12}As soon as there are no strong pointers left,\r\nDialogue: 0,0:39:35.50,0:39:37.86,yin,,0,0,0,,它才会从堆中释放内存 立刻释放\\N{\\fs12}it will free the memory out of the heap, instantly.\r\nDialogue: 0,0:39:37.88,0:39:39.50,yin,,0,0,0,,不是之后的垃圾收集\\N{\\fs12}Not garbage collected later.\r\nDialogue: 0,0:39:39.50,0:39:43.14,yin,,0,0,0,,而立刻释放内存\\N{\\fs12}But actually instantly, reclaim that memory.\r\nDialogue: 0,0:39:43.20,0:39:45.50,yin,,0,0,0,,这对你们而言可能是新东西\\N{\\fs12}So this is probably new to you, you're\r\nDialogue: 0,0:39:45.50,0:39:48.50,yin,,0,0,0,,你们可能习惯了 Java 中的垃圾收集\\N{\\fs12}probably used to like garbage collection in Java, for example,\r\nDialogue: 0,0:39:48.50,0:39:52.50,yin,,0,0,0,,或其它语言中的显式内存管理\\N{\\fs12}or explicit memory management in other languages.\r\nDialogue: 0,0:39:52.50,0:39:55.14,yin,,0,0,0,,这个叫作自动引用计数 它非常棒\\N{\\fs12}This is called automatic reference counting and it's awesome.\r\nDialogue: 0,0:39:55.14,0:39:58.50,yin,,0,0,0,,可预见性很强 比垃圾收集要好很多\\N{\\fs12}It's really very predictable, this is much better than garbage collection,\r\nDialogue: 0,0:39:58.50,0:40:01.50,yin,,0,0,0,,因为垃圾收集器会在之后过来\\N{\\fs12}because, you know, the garbage collector can come along later and\r\nDialogue: 0,0:40:01.50,0:40:04.05,yin,,0,0,0,,在从堆中收集垃圾时\\N{\\fs12}do, wreak havoc on the performance of your application\r\nDialogue: 0,0:40:04.05,0:40:06.27,yin,,0,0,0,,对应用性能会造成严重影响\\N{\\fs12}as it goes and collects things from the heap.\r\nDialogue: 0,0:40:06.27,0:40:09.16,yin,,0,0,0,,这个可预见性很强 你知道什么时候内存会释放\\N{\\fs12}This is very predictable, you know exactly when things are going to be released,\r\nDialogue: 0,0:40:09.16,0:40:11.50,yin,,0,0,0,,也就是不再有强指针存在时\\N{\\fs12}it's when there's no strong pointers left to it.\r\nDialogue: 0,0:40:11.50,0:40:13.27,yin,,0,0,0,,如果是弱呢\\N{\\fs12}What would it mean if this was weak?\r\nDialogue: 0,0:40:13.27,0:40:16.12,yin,,0,0,0,,弱指针会告诉 Objective-C\\N{\\fs12}Okay, if you have a weak pointer, that tells objective-C,\r\nDialogue: 0,0:40:16.14,0:40:18.50,yin,,0,0,0,,我有一个指针指向堆中的这个\\N{\\fs12}okay, I have a pointer to this thing in the heap and\r\nDialogue: 0,0:40:18.50,0:40:22.29,yin,,0,0,0,,只要还有强指针指向它 就将它留在内存中\\N{\\fs12}keep it in memory as long as someone else has a strong pointer to it.\r\nDialogue: 0,0:40:22.29,0:40:26.45,yin,,0,0,0,,只要不再有强指针指向它 内存就会释放\\N{\\fs12}But as soon as no one else has a strong pointer to that thing, it gets freed from memory\r\nDialogue: 0,0:40:26.46,0:40:30.16,yin,,0,0,0,,此时这个弱指针 会被设置为 nil\\N{\\fs12}and this pointer, if it was weak, gets set to nil.\r\nDialogue: 0,0:40:30.16,0:40:33.50,yin,,0,0,0,,nil 表示 这个指针不指向任何东西\\N{\\fs12}Nil means this pointer doesn't point to anything.\r\nDialogue: 0,0:40:33.50,0:40:36.50,yin,,0,0,0,,nil 也就是零\\N{\\fs12}Nil is the same as zero.\r\nDialogue: 0,0:40:36.50,0:40:40.96,yin,,0,0,0,,在其它语言中 你们可能会害怕 nil 指针\\N{\\fs12}In other languages, you're probably afraid of nil pointers.\r\nDialogue: 0,0:40:40.97,0:40:45.50,yin,,0,0,0,,因为引用 nil 指针会让你的程序崩溃\\N{\\fs12}Because you do reference a nil pointer, it crashes your program, right?\r\nDialogue: 0,0:40:45.50,0:40:49.50,yin,,0,0,0,,在 Objective-C 中 你可以发送消息给 nil 指针\\N{\\fs12}In objective-C, you can send messages to nil pointers even\r\nDialogue: 0,0:40:49.50,0:40:51.58,yin,,0,0,0,,这不会让你的程序崩溃掉\\N{\\fs12}and it will not crash your program.\r\nDialogue: 0,0:40:51.59,0:40:55.92,yin,,0,0,0,,实际上 如果你将消息发送给 nil 指针\\N{\\fs12}In fact, if you send a message to a nil pointer,\r\nDialogue: 0,0:40:55.92,0:40:58.23,yin,,0,0,0,,它显然不会执行任何代码\\N{\\fs12}it will not execute any code, obviously,\r\nDialogue: 0,0:40:58.23,0:41:00.50,yin,,0,0,0,,因为这里没有实例\\N{\\fs12}because there's no instance there.\r\nDialogue: 0,0:41:00.50,0:41:02.32,yin,,0,0,0,,而且它会返回 0\\N{\\fs12}And it will return zero from,\r\nDialogue: 0,0:41:02.33,0:41:05.50,yin,,0,0,0,,如果那个消息有返回值 它会返回 0\\N{\\fs12}if that message had a return value, it'll return zero.\r\nDialogue: 0,0:41:05.50,0:41:09.50,yin,,0,0,0,,你需要小心返回 struct 类型的消息\\N{\\fs12}So you have to be a little careful of messages that return structs,\r\nDialogue: 0,0:41:09.50,0:41:12.50,yin,,0,0,0,,但只要它返回的是原始类型或指针\\N{\\fs12}but as long as it returns a primitive type or a pointer,\r\nDialogue: 0,0:41:12.50,0:41:13.99,yin,,0,0,0,,它会返回 0\\N{\\fs12}it'll just return zero.\r\nDialogue: 0,0:41:14.01,0:41:16.50,yin,,0,0,0,,这需要时间才能习惯\\N{\\fs12}So, this is going to take getting used to.\r\nDialogue: 0,0:41:16.50,0:41:18.50,yin,,0,0,0,,我们在编程过程中\\N{\\fs12}The fact that we are going to program\r\nDialogue: 0,0:41:18.50,0:41:23.50,yin,,0,0,0,,知道能发消息给 nil 指针 这是有好处的\\N{\\fs12}knowing that we can send messages to nil, to pointers that are nil and that that's good.\r\nDialogue: 0,0:41:23.50,0:41:27.94,yin,,0,0,0,,我们会利用这个让代码工作得更好\\N{\\fs12}We'll actually make our code work nicely and we'll use that to our advantage.\r\nDialogue: 0,0:41:27.96,0:41:30.16,yin,,0,0,0,,这对于你们来说是个改变\\N{\\fs12}And that is definitely going to be a change for you\r\nDialogue: 0,0:41:30.16,0:41:31.25,yin,,0,0,0,,你们原来都习惯\\N{\\fs12}who are used to\r\nDialogue: 0,0:41:31.25,0:41:34.40,yin,,0,0,0,,如果指针非 nil 那么发送消息这些\\N{\\fs12}if pointers not nil, then send message all the time, right?\r\nDialogue: 0,0:41:34.40,0:41:35.88,yin,,0,0,0,,以此来防止崩溃\\N{\\fs12}Protecting against crashes,\r\nDialogue: 0,0:41:35.88,0:41:39.50,yin,,0,0,0,,Objective-C 中不需要这样编写代码\\N{\\fs12}you don't do that in objective-C, you just don't code it that way.\r\nDialogue: 0,0:41:39.50,0:41:44.18,yin,,0,0,0,,这个指针可以有值 nil\\N{\\fs12}So, this pointer could have the value nil, n-i-l,\r\nDialogue: 0,0:41:44.18,0:41:46.50,yin,,0,0,0,,也就是说它不指向任何东西\\N{\\fs12}which means it doesn't point to anything.\r\nDialogue: 0,0:41:46.50,0:41:49.31,yin,,0,0,0,,如果你有一个强指针 它指向什么东西\\N{\\fs12}So if you have a strong pointer and it points to something\r\nDialogue: 0,0:41:49.31,0:41:50.73,yin,,0,0,0,,然后你把它设为 nil\\N{\\fs12}and then you set it to nil,\r\nDialogue: 0,0:41:50.75,0:41:52.68,yin,,0,0,0,,那个强指针不再指向那个东西\\N{\\fs12}now that strong pointer doesn't point to that thing,\r\nDialogue: 0,0:41:52.68,0:41:54.14,yin,,0,0,0,,只要没有其它指针指向它\\N{\\fs12}as long as no one else points to it,\r\nDialogue: 0,0:41:54.14,0:41:57.50,yin,,0,0,0,,你就能够释放这里的内存 Objective-C 会帮你释放内存\\N{\\fs12}you can clean up that memory, objective-C will clean the memory up for you.\r\nDialogue: 0,0:41:57.50,0:41:59.50,yin,,0,0,0,,或者 如果你有一个指针指向堆中某东西\\N{\\fs12}Or if you have a pointer that points to something in the heap,\r\nDialogue: 0,0:41:59.50,0:42:01.50,yin,,0,0,0,,你让它指向堆中别的东西\\N{\\fs12}then you make it point to something else in the heap,\r\nDialogue: 0,0:42:01.50,0:42:04.50,yin,,0,0,0,,然后不再有强指针指向原来那个东西\\N{\\fs12}then you no longer have a strong pointer to that other thing\r\nDialogue: 0,0:42:04.50,0:42:07.50,yin,,0,0,0,,只要不再有强指针如此 内存就会释放\\N{\\fs12}in the heap and as long as no one does, it'll get cleaned up.\r\nDialogue: 0,0:42:07.50,0:42:10.50,yin,,0,0,0,,记住 弱的情况 不仅是释放\\N{\\fs12}And remember weak not only cleans it up,\r\nDialogue: 0,0:42:10.50,0:42:12.18,yin,,0,0,0,,指针还会被设为 nil\\N{\\fs12}but it sets your pointer to nil,\r\nDialogue: 0,0:42:12.18,0:42:13.86,yin,,0,0,0,,因为你只想要一个弱指针\\N{\\fs12}because you only wanted a weak pointer,\r\nDialogue: 0,0:42:13.86,0:42:16.50,yin,,0,0,0,,你只希望有强指针指向对象时它才指向对象\\N{\\fs12}you only wanted it to point to that thing as long as someone else does.\r\nDialogue: 0,0:42:16.50,0:42:19.50,yin,,0,0,0,,这就是强和弱\\N{\\fs12}So that's the strong versus weak.\r\nDialogue: 0,0:42:19.50,0:42:24.12,yin,,0,0,0,,括号里我们还要加一个 nonatomic(非原子)\\N{\\fs12}The other thing we're going to put in this little parentheses is nonatomic.\r\nDialogue: 0,0:42:24.12,0:42:29.53,yin,,0,0,0,,非原子是说同该属性一同的 setter 和 getter\\N{\\fs12}Nonatomic means calling this setter and getter that go along with this property\r\nDialogue: 0,0:42:29.53,0:42:31.50,yin,,0,0,0,,不是线程安全的\\N{\\fs12}is not thread safe.\r\nDialogue: 0,0:42:31.50,0:42:36.14,yin,,0,0,0,,你不能有两个线程 同时尝试设置该属性\\N{\\fs12}So you can't have two threads trying to set this property at the same time.\r\nDialogue: 0,0:42:36.14,0:42:39.50,yin,,0,0,0,,为什么这里要非原子呢 为什么不能是线程安全的呢\\N{\\fs12}Why do we say nonatomic here, why do we want this to not be thread safe?\r\nDialogue: 0,0:42:39.50,0:42:42.93,yin,,0,0,0,,因为 iOS 中的多线程\\N{\\fs12}Because the way we do multithreading in iOS\r\nDialogue: 0,0:42:42.94,0:42:46.14,yin,,0,0,0,,不是一个对象上多个线程在设置\\N{\\fs12}is not by having a single object that multiple threads are setting on,\r\nDialogue: 0,0:42:46.14,0:42:49.27,yin,,0,0,0,,我们通常有另外一组对象 运行在另外一个线程\\N{\\fs12}we usually have a separate set of objects that are running in another thread,\r\nDialogue: 0,0:42:49.27,0:42:51.03,yin,,0,0,0,,例如你的模型\\N{\\fs12}like your model,\r\nDialogue: 0,0:42:51.03,0:42:54.50,yin,,0,0,0,,然后 UI 这些东西运行在 UI 线程\\N{\\fs12}and then other, then your UI stuff is running in the UI thread\r\nDialogue: 0,0:42:54.50,0:42:57.03,yin,,0,0,0,,它们在线程间进行通信\\N{\\fs12}and they're talking thread to thread.\r\nDialogue: 0,0:42:57.05,0:43:00.50,yin,,0,0,0,,所以我们不需要这个 不仅如此\\N{\\fs12}So we don't need this and not only that,\r\nDialogue: 0,0:43:00.50,0:43:03.25,yin,,0,0,0,,这里使用 @property 时\\N{\\fs12}what's going to happen here when we do this at sign property\r\nDialogue: 0,0:43:03.25,0:43:06.50,yin,,0,0,0,,Objective-C 会创建我讲过的 getter 和 setter 方法\\N{\\fs12}is objective-C is going to create that getter and setter methods that I told\r\nDialogue: 0,0:43:06.50,0:43:09.50,yin,,0,0,0,,来自动为我们设置 contents\\N{\\fs12}you about to set these contents automatically for us,\r\nDialogue: 0,0:43:09.50,0:43:12.50,yin,,0,0,0,,而我们希望它们很简单\\N{\\fs12}and we want them to be simple.\r\nDialogue: 0,0:43:12.50,0:43:14.50,yin,,0,0,0,,它们是这样的\\N{\\fs12}This is what they're going to look like.\r\nDialogue: 0,0:43:14.50,0:43:16.50,yin,,0,0,0,,我们希望它们很简单\\N{\\fs12}We want them to be simple.\r\nDialogue: 0,0:43:16.50,0:43:20.21,yin,,0,0,0,,如果我们不说 nonatomic 这里会有各种锁定代码\\N{\\fs12}If we don't say nonatomic, there's going to be all kinds of locking code in there, right?\r\nDialogue: 0,0:43:20.21,0:43:22.36,yin,,0,0,0,,如果你有多线程\\N{\\fs12}If you have multiple threads and you're\r\nDialogue: 0,0:43:22.36,0:43:26.01,yin,,0,0,0,,你允许多线程访问这里的 setter 和 getter\\N{\\fs12}allowing multiple threads to access the setter and getter here,\r\nDialogue: 0,0:43:26.03,0:43:28.50,yin,,0,0,0,,那你就需要锁定代码 我们不想要锁定代码\\N{\\fs12}then you need locking code, and we don't want locking code,\r\nDialogue: 0,0:43:28.50,0:43:31.82,yin,,0,0,0,,尤其是我们要自己实现 setter 和 getter 时\\N{\\fs12}especially if we're going to implement the setter and getter ourselves,\r\nDialogue: 0,0:43:31.82,0:43:34.50,yin,,0,0,0,,有时我们确实会这样做\\N{\\fs12}which we're going to, sometimes.\r\nDialogue: 0,0:43:34.50,0:43:38.50,yin,,0,0,0,,不过默认情况下 我们不用实现 setter 和 getter\\N{\\fs12}But the default here is that we don't implement this setter and getter,\r\nDialogue: 0,0:43:38.50,0:43:40.50,yin,,0,0,0,,它会自动为我们实现\\N{\\fs12}it's automatically in there for us.\r\nDialogue: 0,0:43:40.50,0:43:42.50,yin,,0,0,0,,可以看到这里的三部分\\N{\\fs12}So you can see there's three parts to this.\r\nDialogue: 0,0:43:42.50,0:43:45.03,yin,,0,0,0,,这里有 @synthesize(合成) 看到了吗\\N{\\fs12}There's the at sign synthesize, you see that?\r\nDialogue: 0,0:43:45.05,0:43:50.50,yin,,0,0,0,,这里 _contents 是实例变量的名字\\N{\\fs12}That's basically just saying underbar contents is the name of the instance variable\r\nDialogue: 0,0:43:50.50,0:43:53.50,yin,,0,0,0,,属性 contents 将存储于此\\N{\\fs12}in which the property contents is going to be stored.\r\nDialogue: 0,0:43:53.50,0:43:57.21,yin,,0,0,0,,我们也可以说 @synthesize contents = foo\\N{\\fs12}Now we could say at sign synthesize contents equals foo,\r\nDialogue: 0,0:43:57.21,0:44:00.50,yin,,0,0,0,,然后 contents 属性会被存在这个实例变量 foo中\\N{\\fs12}and then contents property would be stored in an instance variable called foo.\r\nDialogue: 0,0:44:00.50,0:44:02.21,yin,,0,0,0,,但这很让人犯迷糊\\N{\\fs12}But that would be very confusing,\r\nDialogue: 0,0:44:02.21,0:44:05.50,yin,,0,0,0,,所以我们总是使用下划线属性名\\N{\\fs12}so we always use underbar name of the property.\r\nDialogue: 0,0:44:05.50,0:44:07.66,yin,,0,0,0,,这是第一部分\\N{\\fs12}And so that's part one,\r\nDialogue: 0,0:44:07.66,0:44:12.50,yin,,0,0,0,,只是分配实例变量来存储 contents 属性\\N{\\fs12}just basically allocating an instance variable to store this contents property.\r\nDialogue: 0,0:44:12.50,0:44:14.06,yin,,0,0,0,,然后是 getter\\N{\\fs12}Then there's the getter,\r\nDialogue: 0,0:44:14.06,0:44:15.97,yin,,0,0,0,,也就是 (NSString *)contents\\N{\\fs12}that's NSString contents,\r\nDialogue: 0,0:44:15.97,0:44:17.27,yin,,0,0,0,,return _contents\\N{\\fs12}return contents,\r\nDialogue: 0,0:44:17.27,0:44:20.43,yin,,0,0,0,,- (NSString *)contents\\N{\\fs12}so the dash, parentheses, NSString contents\r\nDialogue: 0,0:44:20.43,0:44:23.50,yin,,0,0,0,,是 Objective-C 中的一个方法声明\\N{\\fs12}is a method declaration in objective-C,\r\nDialogue: 0,0:44:23.50,0:44:25.50,yin,,0,0,0,,- 表示这是一个方法\\N{\\fs12}the dash means this is a method,\r\nDialogue: 0,0:44:25.50,0:44:27.40,yin,,0,0,0,,(NSString *) 表示\\N{\\fs12}parentheses NSString star means\r\nDialogue: 0,0:44:27.40,0:44:30.50,yin,,0,0,0,,这一方法返回指向字符串的指针\\N{\\fs12}this is a method that returns a pointer to a string,\r\nDialogue: 0,0:44:30.50,0:44:33.50,yin,,0,0,0,,contents 则是方法名\\N{\\fs12}and contents is the name of the method.\r\nDialogue: 0,0:44:33.50,0:44:37.50,yin,,0,0,0,,getter 的方法名同属性名一样\\N{\\fs12}So the name of the method of the getter is the same as the name of the property.\r\nDialogue: 0,0:44:37.50,0:44:43.50,yin,,0,0,0,,然后 实现就是返回我们所合成的实例变量\\N{\\fs12}Then, the implementation is just return that instance variable that we synthesized.\r\nDialogue: 0,0:44:43.50,0:44:49.17,yin,,0,0,0,,类似地 下一个方法是 Objective-C 中设置的方法\\N{\\fs12}And similarly, the next method is a method in objective-C for setting it.\r\nDialogue: 0,0:44:49.17,0:44:51.50,yin,,0,0,0,,还是一样 - 表示这是一个方法\\N{\\fs12}And, again, dash because this is a method.\r\nDialogue: 0,0:44:51.50,0:44:55.50,yin,,0,0,0,,(void) 表示这个方法不返回任何东西\\N{\\fs12}Parentheses void means this method does not return anything.\r\nDialogue: 0,0:44:55.50,0:44:57.50,yin,,0,0,0,,(void) 就是这个意思\\N{\\fs12}That's what parentheses void means.\r\nDialogue: 0,0:44:57.50,0:45:00.88,yin,,0,0,0,,然后 setContents: 这是该方法的名\\N{\\fs12}Then set contents colon, that's the name of this method,\r\nDialogue: 0,0:45:00.88,0:45:03.08,yin,,0,0,0,,意思是设置内容\\N{\\fs12}set contents colon.\r\nDialogue: 0,0:45:03.08,0:45:07.50,yin,,0,0,0,,(NSString *) 是该方法的参数\\N{\\fs12}Parentheses NSString star is the argument to this method.\r\nDialogue: 0,0:45:07.50,0:45:10.91,yin,,0,0,0,,contents 则是参数名\\N{\\fs12}Contents is just the name of the argument, the local name of the\r\nDialogue: 0,0:45:10.91,0:45:14.23,yin,,0,0,0,,局部环境下变量的局部名\\N{\\fs12}variable in the local contents, context,\r\nDialogue: 0,0:45:14.23,0:45:17.21,yin,,0,0,0,,实现是 _contents\\N{\\fs12}and the implementation is just underbar contents,\r\nDialogue: 0,0:45:17.21,0:45:20.50,yin,,0,0,0,,我们的实例变量 = 那个参数\\N{\\fs12}our instance variable equals that argument.\r\nDialogue: 0,0:45:20.50,0:45:25.64,yin,,0,0,0,,在我继续推进之前 大家是否都理解了这两个方法\\N{\\fs12}So, before I move on, does everyone understand how these two methods\r\nDialogue: 0,0:45:25.64,0:45:33.50,yin,,0,0,0,,它们让你能够在 Card 内设置和获取 NSString 存储空间\\N{\\fs12}are allowing you to set and get an NSString storage space inside your card?\r\nDialogue: 0,0:45:33.50,0:45:35.50,yin,,0,0,0,,大家都明白这个了吗\\N{\\fs12}Everyone understand that?\r\nDialogue: 0,0:45:35.50,0:45:36.78,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:45:38.50,0:45:41.06,yin,,0,0,0,,好 synthesize 这一行\\N{\\fs12}Okay, so the synthesize line, again,\r\nDialogue: 0,0:45:41.06,0:45:44.30,yin,,0,0,0,,只是指定实例变量名\\N{\\fs12}is just specifying the name of the instance variable\r\nDialogue: 0,0:45:44.30,0:45:47.50,yin,,0,0,0,,用以存储这个 _contents\\N{\\fs12}that we're going to use to store this stuff in, underbar contents.\r\nDialogue: 0,0:45:47.50,0:45:50.99,yin,,0,0,0,,这有些奇怪 也许更好的说法是\\N{\\fs12}It's kind of weird, you could maybe, it might be better saying\r\nDialogue: 0,0:45:50.99,0:45:53.38,yin,,0,0,0,,@synthesize contents\\N{\\fs12}at sign synthesize contents\r\nDialogue: 0,0:45:53.38,0:45:56.50,yin,,0,0,0,,去使用名为 _contents 的实例变量\\N{\\fs12}to use instance variable with name, underbar contents.\r\nDialogue: 0,0:45:56.50,0:45:58.26,yin,,0,0,0,,我知道 这个等号有点奇怪\\N{\\fs12}That equals, I know, is a little weird.\r\nDialogue: 0,0:45:58.27,0:46:03.08,yin,,0,0,0,,看起来就像赋值语句 不过你们可以把这个等号看成\\N{\\fs12}It sounds like it's assigning something, but it's just, that's what, think about equals as,\r\nDialogue: 0,0:46:03.08,0:46:07.08,yin,,0,0,0,,使用名为 _contents 的实例变量\\N{\\fs12}you know, we'll use the instance variable with the name, underbar contents.\r\nDialogue: 0,0:46:07.10,0:46:08.50,yin,,0,0,0,,这就是 synthesize\\N{\\fs12}So that's what the synthesize is doing.\r\nDialogue: 0,0:46:08.50,0:46:12.86,yin,,0,0,0,,没有 synthesize 你将无法为 Card 实例创建空间\\N{\\fs12}If you don't put the synthesize, it's not going to create the space in your card instance,\r\nDialogue: 0,0:46:12.86,0:46:17.50,yin,,0,0,0,,而且它没有名 你无法在 getter 和 setter 中引用它\\N{\\fs12}and there won't be any name for it so you can't refer to it in your getter and setter.\r\nDialogue: 0,0:46:17.50,0:46:19.50,yin,,0,0,0,,大家都懂了吗\\N{\\fs12}Everyone understand this?\r\nDialogue: 0,0:46:19.50,0:46:21.30,yin,,0,0,0,,还有问题吗\\N{\\fs12}Any other questions?\r\nDialogue: 0,0:46:21.30,0:46:26.06,yin,,0,0,0,,好 当你在左侧键入 @property 时\\N{\\fs12}Okay, now, the thing about it is, when you type the at sign property on the left,\r\nDialogue: 0,0:46:26.06,0:46:28.45,yin,,0,0,0,,这会添加到你的 @implementation\\N{\\fs12}this gets added to your at sign implementation;\r\nDialogue: 0,0:46:28.45,0:46:31.50,yin,,0,0,0,,但是 你不会在那里看到它\\N{\\fs12}however, you will not see it there.\r\nDialogue: 0,0:46:32.23,0:46:34.50,yin,,0,0,0,,它在那里 但你看不到\\N{\\fs12}So it's there, but you don't see it.\r\nDialogue: 0,0:46:34.50,0:46:38.91,yin,,0,0,0,,Objective-C 为你做了那些 但它不会显示出来\\N{\\fs12}Okay, objective-C is, made it for you, but it doesn't show it to you,\r\nDialogue: 0,0:46:38.93,0:46:44.23,yin,,0,0,0,,不过它在那里 setter 和 getter 方法都在那里\\N{\\fs12}but it's there, okay, that setter method and that getter method are there.\r\nDialogue: 0,0:46:44.23,0:46:45.30,yin,,0,0,0,,它们存在\\N{\\fs12}They exist.\r\nDialogue: 0,0:46:45.30,0:46:47.50,yin,,0,0,0,,不仅这样 它们还是公共的\\N{\\fs12}And not only that, they're public,\r\nDialogue: 0,0:46:47.50,0:46:51.50,yin,,0,0,0,,因为你在头文件中用了 @property 声明\\N{\\fs12}because you put that at sign property declaration in your header file.\r\nDialogue: 0,0:46:51.50,0:46:53.50,yin,,0,0,0,,都明白吗\\N{\\fs12}Everyone got that?\r\nDialogue: 0,0:46:53.50,0:46:56.50,yin,,0,0,0,,我们再来看另一个属性 以此进一步熟悉语法\\N{\\fs12}So let's look at another couple properties just to see the syntax a little more.\r\nDialogue: 0,0:46:56.50,0:46:59.50,yin,,0,0,0,,这里有两个属性 它们是布尔型的\\N{\\fs12}So here's two properties that are Boolean.\r\nDialogue: 0,0:46:59.50,0:47:02.50,yin,,0,0,0,,C 中没有布尔原始类型\\N{\\fs12}There's no Boolean primitive in C,\r\nDialogue: 0,0:47:02.50,0:47:06.50,yin,,0,0,0,,所以 Objective-C 使用类型定义全大写的 BOOL\\N{\\fs12}so objective-C has to find, typedef all caps BOOL,\r\nDialogue: 0,0:47:06.50,0:47:09.50,yin,,0,0,0,,也许是一个短整型 或整型 或字符型\\N{\\fs12}probably a short or something or an int or a char,\r\nDialogue: 0,0:47:09.50,0:47:12.50,yin,,0,0,0,,我不知道具体是什么 不过你可以把它当作原始类型\\N{\\fs12}I don't know what, but you can think of it as a primitive type,\r\nDialogue: 0,0:47:12.50,0:47:15.50,yin,,0,0,0,,布尔型的值可以是真\\N{\\fs12}it's a Boolean, it's value can either be yes,\r\nDialogue: 0,0:47:15.50,0:47:18.50,yin,,0,0,0,,用某非 0 值表示 也可以是非 用 0 表示\\N{\\fs12}which is some non-zero value, or no which is zero.\r\nDialogue: 0,0:47:18.50,0:47:21.50,yin,,0,0,0,,这些属性不需要强或弱来修饰\\N{\\fs12}And these properties don't need the strong or weak.\r\nDialogue: 0,0:47:22.17,0:47:24.26,yin,,0,0,0,,能理解为什么吗\\N{\\fs12}Do you understand why that is?\r\nDialogue: 0,0:47:24.26,0:47:25.50,yin,,0,0,0,,因为它们是原始类型\\N{\\fs12}Because they're primitive types,\r\nDialogue: 0,0:47:25.50,0:47:27.50,yin,,0,0,0,,它们没有存储在堆中\\N{\\fs12}they're not stored in the heap.\r\nDialogue: 0,0:47:27.50,0:47:31.06,yin,,0,0,0,,这里只是整型或浮点型 没有内存需要管理\\N{\\fs12}They're just a int or a float, so there's no memory to manage\r\nDialogue: 0,0:47:31.08,0:47:34.26,yin,,0,0,0,,所以不需要强或弱指针 这里不涉及到指针\\N{\\fs12}so you don't need to know about strong and weak pointers, there's no pointers involved here,\r\nDialogue: 0,0:47:34.26,0:47:35.99,yin,,0,0,0,,只是 BOOL 布尔型\\N{\\fs12}this is just a BOOL, a Boolean.\r\nDialogue: 0,0:47:36.00,0:47:39.06,yin,,0,0,0,,所以没有强或弱 但这里仍然有非原子性\\N{\\fs12}So there's no strong or weak, but we still have the nonatomic,\r\nDialogue: 0,0:47:39.08,0:47:41.50,yin,,0,0,0,,因为我们仍然希望 setter 和 getter 简单\\N{\\fs12}because we still want the setter and the getter to be simple,\r\nDialogue: 0,0:47:41.50,0:47:43.10,yin,,0,0,0,,没有锁定代码这些\\N{\\fs12}not having any locking code or any of that business.\r\nDialogue: 0,0:47:43.12,0:47:46.89,yin,,0,0,0,,这个类中的每一种属性我们都用非原子性来修饰\\N{\\fs12}So we're always going to have nonatomic on every property in this class.\r\nDialogue: 0,0:47:46.91,0:47:50.04,yin,,0,0,0,,这个类中没有任何一个属性不是非原子的\\N{\\fs12}We will not have a single property in this entire class that is not nonatomic.\r\nDialogue: 0,0:47:50.06,0:47:52.43,yin,,0,0,0,,这里写下它 我希望它是默认的\\N{\\fs12}So just put it in there, I wish it were the default.\r\nDialogue: 0,0:47:52.45,0:47:54.50,yin,,0,0,0,,这就是我们这里的做法\\N{\\fs12}So that's what we're going to do.\r\nDialogue: 0,0:47:54.50,0:47:57.50,yin,,0,0,0,,可以看到这里两者都会合成\\N{\\fs12}You can see we've synthesized them both\r\nDialogue: 0,0:47:57.50,0:47:59.50,yin,,0,0,0,,两者都能得到 setter 和 getter\\N{\\fs12}and we've got the setter and the getter for them both,\r\nDialogue: 0,0:47:59.50,0:48:02.50,yin,,0,0,0,,这些都由 Objective-C 为我们自动完成\\N{\\fs12}and this is all being done for us by objective-C.\r\nDialogue: 0,0:48:02.50,0:48:04.91,yin,,0,0,0,,这里有一点很酷\\N{\\fs12}Now, one thing that's kind of cool is\r\nDialogue: 0,0:48:04.91,0:48:07.23,yin,,0,0,0,,我们并不一定喜欢 getter 的名字\\N{\\fs12}we may not like the name of this getter,\r\nDialogue: 0,0:48:07.23,0:48:12.87,yin,,0,0,0,,因为我们希望 当纸牌被选择时 做点什么\\N{\\fs12}because we want our code to read something like if card is chosen, then do something.\r\nDialogue: 0,0:48:12.89,0:48:14.91,yin,,0,0,0,,如果纸牌匹配时 做点什么\\N{\\fs12}If card is matched, then do something.\r\nDialogue: 0,0:48:14.91,0:48:18.50,yin,,0,0,0,,所以我们更愿意 getter 叫 isChosen 而不是只是 chosen\\N{\\fs12}So we really want the getter called is chosen, not just chosen.\r\nDialogue: 0,0:48:18.50,0:48:22.50,yin,,0,0,0,,isChosen 强调纸牌是否「是」被选择\\N{\\fs12}You know, if card chosen, not as nice as if card is chosen.\r\nDialogue: 0,0:48:22.50,0:48:25.50,yin,,0,0,0,,我们可以为 getter 重命名\\N{\\fs12}So it's actually possible to rename the getter\r\nDialogue: 0,0:48:25.50,0:48:29.10,yin,,0,0,0,,只需要在这里加上 getter = 你想要的新名字\\N{\\fs12}by saying getter equals the new name you want.\r\nDialogue: 0,0:48:29.10,0:48:31.50,yin,,0,0,0,,这就是重命名\\N{\\fs12}And that's essentially renamed it,\r\nDialogue: 0,0:48:31.50,0:48:34.50,yin,,0,0,0,,下面这个也一样 重命名 getter = isMatched\\N{\\fs12}same thing, we'll do the same thing with this one. Getter equals is matched,\r\nDialogue: 0,0:48:34.50,0:48:37.17,yin,,0,0,0,,这时 getter 就叫 isMatched 了\\N{\\fs12}now that getter is called is matched.\r\nDialogue: 0,0:48:37.19,0:48:38.65,yin,,0,0,0,,我讲这个是想告诉你们\\N{\\fs12}And I bring this up because you're going to see\r\nDialogue: 0,0:48:38.65,0:48:40.50,yin,,0,0,0,,iOS 如何像这样处理布尔型属性\\N{\\fs12}how iOS does this with Boolean properties,\r\nDialogue: 0,0:48:40.50,0:48:43.87,yin,,0,0,0,,它会重命名它们为「是」这个 或「有」这个\\N{\\fs12}it tends to rename them to is this or has this,\r\nDialogue: 0,0:48:43.87,0:48:46.50,yin,,0,0,0,,取决于动词是什么\\N{\\fs12}depending on what the verb there is.\r\nDialogue: 0,0:48:46.50,0:48:51.76,yin,,0,0,0,,还是一样 Objective-C 会把所有这些代码写到实现中\\N{\\fs12}And again, objective-C is writing all this code on, in the implementation,\r\nDialogue: 0,0:48:51.78,0:48:53.50,yin,,0,0,0,,但你看不到\\N{\\fs12}but you don't see it.\r\nDialogue: 0,0:48:53.50,0:48:55.50,yin,,0,0,0,,不过它在那里\\N{\\fs12}But it's there.\r\nDialogue: 0,0:48:55.50,0:49:00.19,yin,,0,0,0,,以后的课上我会讲到为什么说属性很好\\N{\\fs12}Now, we're going to talk about why properties are good\r\nDialogue: 0,0:49:00.19,0:49:05.54,yin,,0,0,0,,为什么说它比直接访问实例变量要好\\N{\\fs12}and why it's better than just accessing instance variables directly, in later lectures,\r\nDialogue: 0,0:49:05.56,0:49:09.50,yin,,0,0,0,,总的来说 它便于平衡检验\\N{\\fs12}but the bottom-line is it's good for doing things like balance checking,\r\nDialogue: 0,0:49:09.50,0:49:13.50,yin,,0,0,0,,便于你设置属性后更新 UI\\N{\\fs12}it's good for doing things like when you set a property and you want to updated the UI.\r\nDialogue: 0,0:49:13.50,0:49:16.50,yin,,0,0,0,,便于初始化指针\\N{\\fs12}It's doing good for things for initializing pointers.\r\nDialogue: 0,0:49:16.50,0:49:21.24,yin,,0,0,0,,比如 NSString *contents 属性将以 nil 开始\\N{\\fs12}Like that NSString star contents property is going to start off nil.\r\nDialogue: 0,0:49:21.24,0:49:25.50,yin,,0,0,0,,Objective-C 中所有属性都是以 0 开始\\N{\\fs12}All properties, in objective-C, all of them, start off zero.\r\nDialogue: 0,0:49:25.50,0:49:27.50,yin,,0,0,0,,对于指针 也就是 nil\\N{\\fs12}So for pointer, that's nil.\r\nDialogue: 0,0:49:27.50,0:49:30.80,yin,,0,0,0,,这是我们创建新纸牌时的 contents 属性\\N{\\fs12}So that contents property, when we create a new card,\r\nDialogue: 0,0:49:30.80,0:49:32.82,yin,,0,0,0,,它不会指向任何内容\\N{\\fs12}it's going to not point to any contents.\r\nDialogue: 0,0:49:32.84,0:49:35.50,yin,,0,0,0,,纸牌是空的 上面什么都没有\\N{\\fs12}That card's going to be blank, okay, it's not going to have anything on it.\r\nDialogue: 0,0:49:35.50,0:49:38.50,yin,,0,0,0,,能使用 setter 和 getter 很好\\N{\\fs12}So, it's nice to use the setter and getter,\r\nDialogue: 0,0:49:38.50,0:49:41.50,yin,,0,0,0,,我们实现我们自己的 setter 和 getter 来检验\\N{\\fs12}we implement our own setter and getter that will check to see\r\nDialogue: 0,0:49:41.50,0:49:43.83,yin,,0,0,0,,是不是 nil 如果不是 有时\\N{\\fs12}if it's nil, and if it's not, and sometimes,\r\nDialogue: 0,0:49:43.84,0:49:46.21,yin,,0,0,0,,不是对于 contents 而是对于其它属性\\N{\\fs12}not with contents, but with some properties,\r\nDialogue: 0,0:49:46.21,0:49:49.50,yin,,0,0,0,,如果是 nil 我们将在内存中创建一些东西\\N{\\fs12}if it's nil, we'll create something in memory.\r\nDialogue: 0,0:49:49.50,0:49:50.85,yin,,0,0,0,,这是另一个用它的原因\\N{\\fs12}So that's another reason you use it.\r\nDialogue: 0,0:49:50.87,0:49:55.50,yin,,0,0,0,,下一讲 你会看到我们使用属性是有各种原因的\\N{\\fs12}So you'll see all these reasons why we want properties in the next lecture basically.\r\nDialogue: 0,0:49:55.50,0:49:59.50,yin,,0,0,0,,下面 我们来看一个方法\\N{\\fs12}Alright, so now, let's look at a method.\r\nDialogue: 0,0:49:59.50,0:50:01.24,yin,,0,0,0,,一个很常规的方法\\N{\\fs12}Okay? Just a regular, old method.\r\nDialogue: 0,0:50:01.24,0:50:03.50,yin,,0,0,0,,你们见过一些方法 setter 和 getter 方法\\N{\\fs12}You've seen some methods, the setter and getter methods,\r\nDialogue: 0,0:50:03.50,0:50:06.82,yin,,0,0,0,,但我们希望有自己的方法 公共方法\\N{\\fs12}but what if we wanted to find our own method, our own public method,\r\nDialogue: 0,0:50:06.82,0:50:09.28,yin,,0,0,0,,我将定义这个方法为 match(匹配)\\N{\\fs12}so I'm going to define this method called match.\r\nDialogue: 0,0:50:09.28,0:50:12.59,yin,,0,0,0,,记得吧 我这里要为纸牌匹配游戏创建一个模型\\N{\\fs12}Remember that I'm building a model here for a card matching game,\r\nDialogue: 0,0:50:12.61,0:50:14.69,yin,,0,0,0,,我需要将所有纸牌放到屏幕上\\N{\\fs12}where I'm going to put all these cards on the screen\r\nDialogue: 0,0:50:14.69,0:50:16.50,yin,,0,0,0,,用户需要进行匹配\\N{\\fs12}and the user is going to try and match them.\r\nDialogue: 0,0:50:16.50,0:50:18.02,yin,,0,0,0,,选取匹配的那些\\N{\\fs12}Pick ones that match, alright?\r\nDialogue: 0,0:50:18.02,0:50:19.50,yin,,0,0,0,,所以我需要一个 match 方法\\N{\\fs12}So I need a match method.\r\nDialogue: 0,0:50:19.50,0:50:23.50,yin,,0,0,0,,这个方法告诉我两张纸牌是否匹配\\N{\\fs12}A method that tells me whether two cards match.\r\nDialogue: 0,0:50:23.50,0:50:26.50,yin,,0,0,0,,我想要让它保持简单\\N{\\fs12}Okay? So, I'm trying to make this simple,\r\nDialogue: 0,0:50:26.50,0:50:29.50,yin,,0,0,0,,所以我写了一个简单方法 语义如下\\N{\\fs12}so I've made a simple match method that has the following semantics.\r\nDialogue: 0,0:50:29.50,0:50:31.91,yin,,0,0,0,,它将另一张纸牌作为参数\\N{\\fs12}It takes another card as the argument,\r\nDialogue: 0,0:50:31.93,0:50:33.50,yin,,0,0,0,,它返回一个整数\\N{\\fs12}and it returns it an integer.\r\nDialogue: 0,0:50:33.50,0:50:36.96,yin,,0,0,0,,如果纸牌不匹配 该整数为 0\\N{\\fs12}That integer is zero if the cards don't match,\r\nDialogue: 0,0:50:36.96,0:50:42.50,yin,,0,0,0,,否则 匹配越好 整数值就越大\\N{\\fs12}otherwise, it's an integer that is higher, the better a match it is.\r\nDialogue: 0,0:50:42.50,0:50:45.50,yin,,0,0,0,,非常好的匹配可能是 1000\\N{\\fs12}Okay? So like a really good match might be a thousand,\r\nDialogue: 0,0:50:45.50,0:50:49.50,yin,,0,0,0,,不过不算很好的匹配可能只有 100 甚至 1\\N{\\fs12}but a not so good match might only be a hundred, and, or, or it could be one.\r\nDialogue: 0,0:50:49.50,0:50:53.67,yin,,0,0,0,,这个数字是多少的语义 完全取决于纸牌\\N{\\fs12}Now, the semantics of what that number is, totally depends on the cards,\r\nDialogue: 0,0:50:53.67,0:50:56.50,yin,,0,0,0,,因为我们只会将纸牌和其它纸牌进行匹配\\N{\\fs12}because we're only going to match cards against other cards, alright?\r\nDialogue: 0,0:50:56.50,0:50:58.91,yin,,0,0,0,,我们会弄清它们匹配得有多好\\N{\\fs12}And we're going to find out how good a match they are\r\nDialogue: 0,0:50:58.93,0:51:01.50,yin,,0,0,0,,不管 Card 类是什么\\N{\\fs12}by how that, whatever that card class is,\r\nDialogue: 0,0:51:01.50,0:51:05.50,yin,,0,0,0,,我们会有一个子类 叫作 PlayingCard\\N{\\fs12}and we're going to make a subclass of this class, called playing card,\r\nDialogue: 0,0:51:05.50,0:51:09.06,yin,,0,0,0,,它会给大小匹配更多分\\N{\\fs12}that's going to give more points for matching the rank, okay,\r\nDialogue: 0,0:51:09.06,0:51:11.50,yin,,0,0,0,,花色匹配得分相对较少\\N{\\fs12}than it is for matching the suit.\r\nDialogue: 0,0:51:11.50,0:51:16.50,yin,,0,0,0,,分数系统由 Card 的这个子类决定\\N{\\fs12}But that's up to subclasses of card to determine what the point system is.\r\nDialogue: 0,0:51:16.50,0:51:20.06,yin,,0,0,0,,这里我们的 match 方法\\N{\\fs12}So, for our implementation of match,\r\nDialogue: 0,0:51:20.06,0:51:23.06,yin,,0,0,0,,实现会非常简单\\N{\\fs12}we're going to do a really simple implementation, so,\r\nDialogue: 0,0:51:23.06,0:51:25.50,yin,,0,0,0,,首先假设它们不匹配\\N{\\fs12}first let's assume that they don't match.\r\nDialogue: 0,0:51:25.50,0:51:28.50,yin,,0,0,0,,这里设分数的局部变量 int score = 0\\N{\\fs12}Okay, so I just made this local variable int score equals zero,\r\nDialogue: 0,0:51:28.50,0:51:30.50,yin,,0,0,0,,这里是给变量赋值\\N{\\fs12}you can see that you can assign a variable,\r\nDialogue: 0,0:51:30.50,0:51:33.50,yin,,0,0,0,,实际上 所有局部变量默认值都是 0\\N{\\fs12}actually all local variables also start out zero,\r\nDialogue: 0,0:51:33.50,0:51:35.50,yin,,0,0,0,,所以这里其实并不真的需要 =0\\N{\\fs12}so I don't even really need that equals zero,\r\nDialogue: 0,0:51:35.50,0:51:37.50,yin,,0,0,0,,但我认为写明会更好\\N{\\fs12}but I'm a big believer in putting that in\r\nDialogue: 0,0:51:37.50,0:51:39.96,yin,,0,0,0,,毕竟这就是你想要的值\\N{\\fs12}if that's really, you know, what you intend,\r\nDialogue: 0,0:51:39.98,0:51:42.95,yin,,0,0,0,,这里我确实要让分数为 0\\N{\\fs12}and in this case I intend the score to be actually zero.\r\nDialogue: 0,0:51:42.96,0:51:46.50,yin,,0,0,0,,分数一直为 0 直到有纸牌匹配成功\\N{\\fs12}The score of this match until I go and see if these cards match, right?\r\nDialogue: 0,0:51:46.50,0:51:48.83,yin,,0,0,0,,这更多的是一种编程风格\\N{\\fs12}So it's just a kind of programming style thing here.\r\nDialogue: 0,0:51:48.85,0:51:51.50,yin,,0,0,0,,我怎么知道\\N{\\fs12}So, how am I going to tell\r\nDialogue: 0,0:51:51.50,0:51:56.96,yin,,0,0,0,,纸牌能够匹配和它比较的纸牌呢\\N{\\fs12}if this card that's been passed in match, matches the card that it's being sent to?\r\nDialogue: 0,0:51:56.98,0:52:02.13,yin,,0,0,0,,答案是 我将发送一些消息\\N{\\fs12}And the answer is I'm going to send some messages.\r\nDialogue: 0,0:52:02.28,0:52:04.50,yin,,0,0,0,,看到这里的开方括号了吗\\N{\\fs12}You see the open square brackets notation there,\r\nDialogue: 0,0:52:04.50,0:52:09.59,yin,,0,0,0,,这是你们第一次看到我在 Objective-C 中发送消息\\N{\\fs12}that's the first time you're seeing me send a message in objective-C,\r\nDialogue: 0,0:52:09.59,0:52:13.50,yin,,0,0,0,,这一行中我还将发送另外两条消息\\N{\\fs12}and I'm also sending two other messages in this one line.\r\nDialogue: 0,0:52:13.50,0:52:18.24,yin,,0,0,0,,card.contents 和 self.contents 看到它俩了吗\\N{\\fs12}Card.contents and self.contents, you see both of those,\r\nDialogue: 0,0:52:18.24,0:52:20.35,yin,,0,0,0,,这些也是消息发送\\N{\\fs12}those are message sends, as well.\r\nDialogue: 0,0:52:20.35,0:52:23.28,yin,,0,0,0,,这里有两种发送消息的语法\\N{\\fs12}So there's two different syntaxes here for sending a message.\r\nDialogue: 0,0:52:23.28,0:52:27.50,yin,,0,0,0,,一种是开方括号 等下我会具体讲到\\N{\\fs12}One is open square brackets, okay, and we'll talk about that one in a second.\r\nDialogue: 0,0:52:27.50,0:52:31.50,yin,,0,0,0,,另一种是点符号 例如 card.contents\\N{\\fs12}And another one is dot notation, card.contents.\r\nDialogue: 0,0:52:31.50,0:52:32.94,yin,,0,0,0,,什么时候使用呢\\N{\\fs12}When do we use them?\r\nDialogue: 0,0:52:32.96,0:52:37.50,yin,,0,0,0,,点符号只用于属性\\N{\\fs12}We only use the dot notation for properties.\r\nDialogue: 0,0:52:37.50,0:52:41.50,yin,,0,0,0,,这是调用属性 setter 和 getter 的方式 使用点符号\\N{\\fs12}That's how we call the setter and getter of properties, using dot notation.\r\nDialogue: 0,0:52:41.50,0:52:44.76,yin,,0,0,0,,这里我们调用的是 getter\\N{\\fs12}Okay? Now, here we're calling the getter,\r\nDialogue: 0,0:52:44.78,0:52:46.67,yin,,0,0,0,,card.contents 调用的是\\N{\\fs12}card.contents is calling\r\nDialogue: 0,0:52:46.67,0:52:52.50,yin,,0,0,0,,card 实例 contents 属性的 getter 方法\\N{\\fs12}the getter of the contents property on the card instance.\r\nDialogue: 0,0:52:52.50,0:52:54.50,yin,,0,0,0,,如何调用 setter 呢\\N{\\fs12}How do we call the setter?\r\nDialogue: 0,0:52:54.50,0:52:55.50,yin,,0,0,0,,完全一样\\N{\\fs12}Exactly the same.\r\nDialogue: 0,0:52:55.50,0:52:59.50,yin,,0,0,0,,card.contents 但是要放在等号左侧\\N{\\fs12}Card.contents, but we put it on the left-hand side of the equals.\r\nDialogue: 0,0:52:59.50,0:53:01.15,yin,,0,0,0,,card.contents =\\N{\\fs12}Card.contents equals,\r\nDialogue: 0,0:53:01.15,0:53:04.50,yin,,0,0,0,,这就是调用 contents 的 setter 明白吗\\N{\\fs12}now we're calling the setter for contents. You see?\r\nDialogue: 0,0:53:04.50,0:53:06.07,yin,,0,0,0,,这里我们在调用 getter\\N{\\fs12}So here we're calling the getter.\r\nDialogue: 0,0:53:06.09,0:53:09.76,yin,,0,0,0,,我们还为 self(自身) 的 contents 调用了 getter\\N{\\fs12}We're also calling the getter for contents on self, on our self.\r\nDialogue: 0,0:53:09.78,0:53:12.50,yin,,0,0,0,,其它语言中 这个可能用的是 this\\N{\\fs12}So, in other language this might be called this, right,\r\nDialogue: 0,0:53:12.50,0:53:14.33,yin,,0,0,0,,但你们知道 self 是什么\\N{\\fs12}but you know what self is, right, self is\r\nDialogue: 0,0:53:14.33,0:53:17.50,yin,,0,0,0,,self 也就是这段代码正在起作用的实例\\N{\\fs12}this instance that this code is operating on.\r\nDialogue: 0,0:53:17.50,0:53:20.78,yin,,0,0,0,,我们将对比这两个字符串\\N{\\fs12}So, we are going to compare these two strings,\r\nDialogue: 0,0:53:20.78,0:53:23.15,yin,,0,0,0,,card.contents 和 self.contents\\N{\\fs12}card.contents and self.contents\r\nDialogue: 0,0:53:23.15,0:53:25.50,yin,,0,0,0,,看它们是否相等\\N{\\fs12}to see if they are equal and we are going to do\r\nDialogue: 0,0:53:25.50,0:53:30.03,yin,,0,0,0,,使用的是 NSString 方法 isEqualToString:\\N{\\fs12}that with the NSString method is equal to string colon.\r\nDialogue: 0,0:53:30.04,0:53:34.41,yin,,0,0,0,,isEqualToString: 只能被发送给一个字符串\\N{\\fs12}So isEqualToString colon can only be sent to a string,\r\nDialogue: 0,0:53:35.18,0:53:38.35,yin,,0,0,0,,isEqualToString 只能被发送给一个字符串\\N{\\fs12}so isEqualToString can only be sent to a string\r\nDialogue: 0,0:53:38.35,0:53:40.16,yin,,0,0,0,,而 card.contents\\N{\\fs12}and card.contents\r\nDialogue: 0,0:53:40.17,0:53:42.85,yin,,0,0,0,,是一个返回 NSString 的 getter 方法\\N{\\fs12}is a getter method that returns a NSString,\r\nDialogue: 0,0:53:42.85,0:53:43.83,yin,,0,0,0,,这很好\\N{\\fs12}so we're good to go, right?\r\nDialogue: 0,0:53:43.85,0:53:46.63,yin,,0,0,0,,我们将 isEqualToString 发送给一个字符串\\N{\\fs12}We're sending is equal string to a string,\r\nDialogue: 0,0:53:46.63,0:53:50.79,yin,,0,0,0,,而且 isEqualToString 将一个 NSString 作为参数\\N{\\fs12}and isEqualToString takes as an argument, an NSString\r\nDialogue: 0,0:53:50.79,0:53:52.09,yin,,0,0,0,,重复一次 self.contents\\N{\\fs12}and, again, self.contents\r\nDialogue: 0,0:53:52.09,0:53:54.50,yin,,0,0,0,,是返回 NSString 的 getter 方法\\N{\\fs12}is a getter method that returns NSString;\r\nDialogue: 0,0:53:54.50,0:53:58.41,yin,,0,0,0,,这样 我们就满足了 isEqualToString 的所有要求\\N{\\fs12}therefore, we have satisfied all the requirements of is equal to string\r\nDialogue: 0,0:53:58.42,0:54:00.50,yin,,0,0,0,,外面打上方括号\\N{\\fs12}and we put square brackets around it,\r\nDialogue: 0,0:54:00.50,0:54:02.50,yin,,0,0,0,,这会返回一个布尔值\\N{\\fs12}and it's going to return a Boolean is\r\nDialogue: 0,0:54:02.50,0:54:05.15,yin,,0,0,0,,isEqualToString 的作用是返回布尔值\\N{\\fs12}equal to string is defined to return a Boolean\r\nDialogue: 0,0:54:05.15,0:54:07.50,yin,,0,0,0,,看两个字符串是否相同\\N{\\fs12}whether the contents of those two strings are the same.\r\nDialogue: 0,0:54:07.50,0:54:10.50,yin,,0,0,0,,注意到这里用的不是 ==\\N{\\fs12}Notice we did not say equals equals.\r\nDialogue: 0,0:54:10.50,0:54:14.29,yin,,0,0,0,,我们没有说 card.contents == self.contents\\N{\\fs12}We did not say card.contents equals equals self.contents.\r\nDialogue: 0,0:54:14.29,0:54:16.50,yin,,0,0,0,,因为 == 比较的是指针\\N{\\fs12}Because we'd just be comparing the pointers then,\r\nDialogue: 0,0:54:16.50,0:54:20.50,yin,,0,0,0,,而不是指针指向的内容\\N{\\fs12}not what the pointers point to.\r\nDialogue: 0,0:54:20.50,0:54:24.13,yin,,0,0,0,,大家明白为什么不用 == 来看两字符串是否相等了吗\\N{\\fs12}Everyone understand why we didn't use == to see if those two strings are the same?\r\nDialogue: 0,0:54:24.15,0:54:27.50,yin,,0,0,0,,如果两个字符串相等 我将给 1 分\\N{\\fs12}So if those strings are the same, I'm going to give one point.\r\nDialogue: 0,0:54:27.50,0:54:32.18,yin,,0,0,0,,这是一种极度简单化的匹配实现\\N{\\fs12}So this is either the dirt simple implementation of match,\r\nDialogue: 0,0:54:32.18,0:54:35.50,yin,,0,0,0,,也就是 如果纸牌内容完全相同\\N{\\fs12}which is if the cards are exactly the same, their contents are exactly the same,\r\nDialogue: 0,0:54:35.50,0:54:38.13,yin,,0,0,0,,我得到 1 分 否则得 0 分\\N{\\fs12}I'll get one point, otherwise I get zero.\r\nDialogue: 0,0:54:38.15,0:54:42.50,yin,,0,0,0,,后面在 PlayingCard 中 匹配实现会更好一些\\N{\\fs12}Now we're going to do much better implementation in match when we do playing card,\r\nDialogue: 0,0:54:42.50,0:54:44.50,yin,,0,0,0,,这里只是一个极简单的例子\\N{\\fs12}but this is our kind of dirt simple one.\r\nDialogue: 0,0:54:44.50,0:54:48.50,yin,,0,0,0,,关于 Objective-C 我再讲一点\\N{\\fs12}Now, to give you just a little more about objective-C,\r\nDialogue: 0,0:54:48.50,0:54:50.50,yin,,0,0,0,,如果我们改变这个方法… 哦 对\\N{\\fs12}what if we changed this method, oh, so, yeah,\r\nDialogue: 0,0:54:50.50,0:54:55.50,yin,,0,0,0,,这是关于谁是发送者 谁是接收者的一点内容\\N{\\fs12}here's a little bit about who's the sender and who's the receiver here.\r\nDialogue: 0,0:54:55.50,0:54:57.50,yin,,0,0,0,,你们可以自己看这些幻灯片\\N{\\fs12}You can look at this in the slides later.\r\nDialogue: 0,0:54:57.50,0:55:00.50,yin,,0,0,0,,不过我打算让这个更复杂一些\\N{\\fs12}Okay? But I'm going to make this a little more complicated.\r\nDialogue: 0,0:55:00.50,0:55:04.50,yin,,0,0,0,,我将让 match 的参数是一个纸牌的数组\\N{\\fs12}I'm going to make the argument to match be an array of cards.\r\nDialogue: 0,0:55:04.50,0:55:09.50,yin,,0,0,0,,现在我要将这张牌 同其它很多牌进行匹配\\N{\\fs12}So now I'm matching this card that I'm sending this to, to a whole bunch of other cards.\r\nDialogue: 0,0:55:10.07,0:55:14.50,yin,,0,0,0,,现在我需要新的算法来匹配\\N{\\fs12}So now I'm going to need some new algorithm to match, right?\r\nDialogue: 0,0:55:14.50,0:55:16.50,yin,,0,0,0,,这里纸牌的匹配还是\\N{\\fs12}So, again, a playing card match,\r\nDialogue: 0,0:55:16.50,0:55:18.50,yin,,0,0,0,,假设要匹配三张牌\\N{\\fs12}if let's say you had matching three cards,\r\nDialogue: 0,0:55:18.50,0:55:21.70,yin,,0,0,0,,如果三张牌大小都一样 你能得很多分\\N{\\fs12}you might give a lot of points if all three cards are the same rank,\r\nDialogue: 0,0:55:21.70,0:55:24.11,yin,,0,0,0,,例如都是 J 你会得到很多分\\N{\\fs12}they're all jacks, you get a lot of points.\r\nDialogue: 0,0:55:24.13,0:55:26.50,yin,,0,0,0,,如果只有两张是 J 其它都是别的\\N{\\fs12}If only two of them are jacks and the other one is something else,\r\nDialogue: 0,0:55:26.50,0:55:28.50,yin,,0,0,0,,你就没有之前得分多\\N{\\fs12}well you don't get very many points at all.\r\nDialogue: 0,0:55:28.50,0:55:31.11,yin,,0,0,0,,如果它们都是相同花色 你会得到中等量的分\\N{\\fs12}If they're all through the same suit, you kind of get a medium amount of points,\r\nDialogue: 0,0:55:31.11,0:55:32.50,yin,,0,0,0,,知道我讲的什么吗\\N{\\fs12}you see what I mean? So,\r\nDialogue: 0,0:55:32.50,0:55:37.50,yin,,0,0,0,,这里 match 的参数是一整个数组 而不只是一张牌\\N{\\fs12}here I'm changing match to take an array as the argument instead of just a single card.\r\nDialogue: 0,0:55:37.50,0:55:41.20,yin,,0,0,0,,如何改变实现来应对这个呢\\N{\\fs12}And how would I change my implementation to deal with that?\r\nDialogue: 0,0:55:41.20,0:55:44.50,yin,,0,0,0,,这里我将使用一个 for 循环在if外\\N{\\fs12}Well, I'm just going to put a for-loop around my if\r\nDialogue: 0,0:55:44.50,0:55:47.02,yin,,0,0,0,,遍历所有纸牌\\N{\\fs12}and iterate through all the cards\r\nDialogue: 0,0:55:47.03,0:55:51.20,yin,,0,0,0,,这种实现 但愿你们能很快反应过来\\N{\\fs12}and so this implementation, hopefully those of you who are quick thinkers,\r\nDialogue: 0,0:55:51.20,0:55:52.50,yin,,0,0,0,,这有什么用\\N{\\fs12}you can know what this does,\r\nDialogue: 0,0:55:52.50,0:55:53.85,yin,,0,0,0,,这会在\\N{\\fs12}this gives you one point\r\nDialogue: 0,0:55:53.85,0:55:58.50,yin,,0,0,0,,纸牌同数组中任何一张纸牌匹配时给你 1 分\\N{\\fs12}if the card that's receiving this matches any of the cards in the array.\r\nDialogue: 0,0:55:58.50,0:56:01.09,yin,,0,0,0,,任何一张 不是所有 而是任一\\N{\\fs12}Any, not all, any.\r\nDialogue: 0,0:56:01.09,0:56:03.50,yin,,0,0,0,,当然 你们也可以想象更好的算法\\N{\\fs12}Now you can imagine a lot better algorithms here.\r\nDialogue: 0,0:56:03.50,0:56:07.00,yin,,0,0,0,,例如数组中每匹配上一张牌就得 1 分\\N{\\fs12}Maybe you get one point for every card you match in the array\r\nDialogue: 0,0:56:07.01,0:56:10.89,yin,,0,0,0,,或者匹配一个得 2 分 两个 4 分 三个 8 分\\N{\\fs12}or you get two points for one match and four points for two and eight points for three,\r\nDialogue: 0,0:56:10.90,0:56:14.50,yin,,0,0,0,,使用某种指数得分算法\\N{\\fs12}some sort of binary thing, exponential point, whatever,\r\nDialogue: 0,0:56:14.50,0:56:16.53,yin,,0,0,0,,但今天只是第一天课\\N{\\fs12}this is first day of lecture,\r\nDialogue: 0,0:56:16.53,0:56:19.14,yin,,0,0,0,,弄简单一些 有任意一个匹配就得 1 分\\N{\\fs12}we're just going to give one point if it matches any.\r\nDialogue: 0,0:56:19.16,0:56:21.42,yin,,0,0,0,,这里我只是想展示给大家\\N{\\fs12}But mostly what I wanted to show you here is\r\nDialogue: 0,0:56:21.42,0:56:25.50,yin,,0,0,0,,参数中如果是一个数组 而不是一张牌时会怎样\\N{\\fs12}what it looks like to have an array as the argument instead of a single card.\r\nDialogue: 0,0:56:25.50,0:56:29.07,yin,,0,0,0,,让你们理解方法的参数是什么\\N{\\fs12}So that you understand that the argument, what the argument to the method is\r\nDialogue: 0,0:56:29.07,0:56:31.87,yin,,0,0,0,,同时我还想展示 for 循环\\N{\\fs12}and also so I can show you the for-loop there.\r\nDialogue: 0,0:56:31.88,0:56:35.50,yin,,0,0,0,,这里有 for in 很多语言中现在都有这样的结构\\N{\\fs12}You see that for in, a lot of languages have that these days.\r\nDialogue: 0,0:56:35.50,0:56:37.77,yin,,0,0,0,,也就是说它是一个 for 循环\\N{\\fs12}That just basically means it's a for-loop\r\nDialogue: 0,0:56:37.77,0:56:41.37,yin,,0,0,0,,它会遍历 NSArray 中的每一个对象\\N{\\fs12}where it's going to go through every object in that NSArray\r\nDialogue: 0,0:56:41.37,0:56:43.00,yin,,0,0,0,,将它赋值给 card\\N{\\fs12}and assign it to card,\r\nDialogue: 0,0:56:43.01,0:56:44.75,yin,,0,0,0,,card 是迭代变量\\N{\\fs12}card is the iteration variable,\r\nDialogue: 0,0:56:44.75,0:56:48.00,yin,,0,0,0,,对于数组中每一张牌执行一次 if\\N{\\fs12}and execute that if once for each of the cards in the array.\r\nDialogue: 0,0:56:48.01,0:56:49.94,yin,,0,0,0,,大家都能理解这个吗\\N{\\fs12}Everyone understand that?\r\nDialogue: 0,0:56:49.94,0:56:52.50,yin,,0,0,0,,有问题的话请提出来\\N{\\fs12}If you have a question about that, ask?\r\nDialogue: 0,0:56:53.01,0:56:54.38,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,0:56:58.57,0:57:00.50,yin,,0,0,0,,哦 好 问得很好\\N{\\fs12}Oh, okay. That's a great question.\r\nDialogue: 0,0:57:00.50,0:57:04.50,yin,,0,0,0,,问题是 for 行如果写 for Card card\\N{\\fs12}So the question is if I just have that for line, but I said for card card,\r\nDialogue: 0,0:57:04.50,0:57:09.12,yin,,0,0,0,,而不是 for Card *card in otherCards 会怎样\\N{\\fs12}not for card star card in other cards.\r\nDialogue: 0,0:57:09.12,0:57:11.70,yin,,0,0,0,,我们会得到语法错误 为什么\\N{\\fs12}We'd get a syntax error. Why?\r\nDialogue: 0,0:57:11.74,0:57:15.50,yin,,0,0,0,,因为所有对象都有指针指着 所以总有这个星号\\N{\\fs12}Because all objects are always pointed to so we always have that star.\r\nDialogue: 0,0:57:15.50,0:57:17.50,yin,,0,0,0,,总是\\N{\\fs12}Always.\r\nDialogue: 0,0:57:17.50,0:57:22.00,yin,,0,0,0,,没有哪张牌没有指针指着\\N{\\fs12}You can't have a card not being a pointer to it,\r\nDialogue: 0,0:57:22.03,0:57:25.50,yin,,0,0,0,,所以这里 Objective-C 会告诉你语法错误\\N{\\fs12}so the, you know, objective-C would give you a syntax error there,\r\nDialogue: 0,0:57:25.50,0:57:27.50,yin,,0,0,0,,不能没有这个星号\\N{\\fs12}it's impossible to not have that star.\r\nDialogue: 0,0:57:27.50,0:57:31.18,yin,,0,0,0,,有类名时 就总得有这个星号 请讲\\N{\\fs12}Whenever you have the name of the class, it's always going to have that star. Yeah?\r\nDialogue: 0,0:57:35.72,0:57:37.94,yin,,0,0,0,,是 问题问得很好\\N{\\fs12}Yes. The question is, another great one,\r\nDialogue: 0,0:57:37.96,0:57:41.25,yin,,0,0,0,,我能否使用方括号来调用 setter 和 getter\\N{\\fs12}can I use the square brackets to call the setter and getter\r\nDialogue: 0,0:57:41.25,0:57:43.16,yin,,0,0,0,,来代替点符号\\N{\\fs12}instead of using that dot notation?\r\nDialogue: 0,0:57:43.18,0:57:46.81,yin,,0,0,0,,这个问题很有深度 答案是完全可以\\N{\\fs12}And that's a really insightful question and the answer is absolutely you can,\r\nDialogue: 0,0:57:46.81,0:57:50.50,yin,,0,0,0,,这完全是合法的 因为 setter 和 getter 也是正常的方法\\N{\\fs12}it's perfectly legal, because that setter and getter are completely normal methods.\r\nDialogue: 0,0:57:50.50,0:57:52.50,yin,,0,0,0,,它们没有什么特殊之处\\N{\\fs12}There's nothing special about them whatsoever.\r\nDialogue: 0,0:57:52.50,0:57:57.50,yin,,0,0,0,,点符号只是语法上一点精简 一点甜头\\N{\\fs12}That dot notation is a nicety, syntactic sugar only.\r\nDialogue: 0,0:57:57.50,0:58:00.86,yin,,0,0,0,,如果问题是 sette r和 getter 是否应该用方括号\\N{\\fs12}The question is should you use square brackets for setter and getter,\r\nDialogue: 0,0:58:00.86,0:58:02.90,yin,,0,0,0,,我想这是风格问题\\N{\\fs12}and I think it's a matter of style.\r\nDialogue: 0,0:58:02.90,0:58:05.14,yin,,0,0,0,,反正你需要 100% 保持一致\\N{\\fs12}You would definitely would want to be 100 percent consistent,\r\nDialogue: 0,0:58:05.14,0:58:06.50,yin,,0,0,0,,不要混用\\N{\\fs12}you would never want to mix them.\r\nDialogue: 0,0:58:06.50,0:58:10.31,yin,,0,0,0,,我想大多数人都会用点符号\\N{\\fs12}And I think most people, most people would say use the dot notation.\r\nDialogue: 0,0:58:10.31,0:58:13.50,yin,,0,0,0,,这会更清楚 更简单 更美观\\N{\\fs12}It makes it clearer, it's a little simpler, nicer,\r\nDialogue: 0,0:58:13.50,0:58:15.29,yin,,0,0,0,,但是你也可以不这样\\N{\\fs12}but, you know, you could.\r\nDialogue: 0,0:58:15.29,0:58:17.18,yin,,0,0,0,,这门课中请使用点符号\\N{\\fs12}In this class, please use the dot notation\r\nDialogue: 0,0:58:17.18,0:58:19.50,yin,,0,0,0,,我要确保你们懂得如何用点符号\\N{\\fs12}just so I know you know how to use dot notation.\r\nDialogue: 0,0:58:19.50,0:58:20.42,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:58:24.86,0:58:26.50,yin,,0,0,0,,又是一个很棒的问题\\N{\\fs12}OK, awesome question again.\r\nDialogue: 0,0:58:26.50,0:58:28.12,yin,,0,0,0,,天啊 你们太厉害了\\N{\\fs12}Gosh, you guys are so good.\r\nDialogue: 0,0:58:28.14,0:58:32.50,yin,,0,0,0,,我能否将点符号用于 getter 和 setter 之外\\N{\\fs12}Can I use dot notation for a method that takes no arguments,\r\nDialogue: 0,0:58:32.50,0:58:34.50,yin,,0,0,0,,一个没有参数的方法\\N{\\fs12}but is not a getter or a setter?\r\nDialogue: 0,0:58:34.50,0:58:37.92,yin,,0,0,0,,答案是这样做的话 Objective-C 会警告你\\N{\\fs12}And the answer is objective-C will warn you about that,\r\nDialogue: 0,0:58:37.94,0:58:39.83,yin,,0,0,0,,不是错误 而是警告\\N{\\fs12}not give you an error, but warn you,\r\nDialogue: 0,0:58:39.85,0:58:41.88,yin,,0,0,0,,这门课中不可以这样做\\N{\\fs12}and you should never do that in this class.\r\nDialogue: 0,0:58:41.90,0:58:44.31,yin,,0,0,0,,这不是一个很好的做法\\N{\\fs12}Okay? That is really not that good form,\r\nDialogue: 0,0:58:44.31,0:58:46.88,yin,,0,0,0,,他所讲的那个还可以探讨\\N{\\fs12}whereas his question was kind of like you can argue,\r\nDialogue: 0,0:58:46.90,0:58:48.75,yin,,0,0,0,,但你这个 不要这样做\\N{\\fs12}that one, don't do it.\r\nDialogue: 0,0:58:48.77,0:58:52.50,yin,,0,0,0,,点符号只能用于 setter 和 getter\\N{\\fs12}So. Use dot notations only for setters and getters.\r\nDialogue: 0,0:58:52.50,0:58:53.50,yin,,0,0,0,,还有问题吗\\N{\\fs12}Other questions?\r\nDialogue: 0,0:58:55.07,0:58:56.05,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,0:58:59.50,0:59:02.50,yin,,0,0,0,,问题是 如何用点符号来使用 setter\\N{\\fs12}So, yeah, question is how do you use a setter with dot notation?\r\nDialogue: 0,0:59:02.50,0:59:04.50,yin,,0,0,0,,同 getter 完全一样\\N{\\fs12}And it's exactly the same as a getter,\r\nDialogue: 0,0:59:04.50,0:59:07.50,yin,,0,0,0,,只是需要用到等号的左边\\N{\\fs12}it's just that you're using it on the left-hand side of an equals.\r\nDialogue: 0,0:59:07.50,0:59:12.16,yin,,0,0,0,,例如 card.contents 等号 梅花 A\\N{\\fs12}So card.contents equals, you know, A of clubs,\r\nDialogue: 0,0:59:12.16,0:59:15.50,yin,,0,0,0,,这就会调用 contents 的 setter\\N{\\fs12}that would call the setter of contents, whereas, you know,\r\nDialogue: 0,0:59:15.50,0:59:19.84,yin,,0,0,0,,这里则会调用 getter 因为它没在等号左侧\\N{\\fs12}this is calling the getter, because it's not on the left-hand side of the equal.\r\nDialogue: 0,0:59:21.47,0:59:23.36,yin,,0,0,0,,很好 今天就这些了\\N{\\fs12}Excellent! That's all I had today, so\r\nDialogue: 0,0:59:23.36,0:59:26.81,yin,,0,0,0,,周三 我会讲 Deck\\N{\\fs12}on Wednesday, we will do deck\r\nDialogue: 0,0:59:26.83,0:59:29.53,yin,,0,0,0,,PlayingCard 和 PlayingCardDeck\\N{\\fs12}and playing card and playing card\r\nDialogue: 0,0:59:29.53,0:59:33.50,yin,,0,0,0,,我会详细讲解 XCode 5 中的一个经典 demo\\N{\\fs12}and I'm going to dive right into a big old demo of XCode 5\r\nDialogue: 0,0:59:33.50,0:59:35.50,yin,,0,0,0,,看这些实际是怎么做到的\\N{\\fs12}and show you how all this stuff is actually done,\r\nDialogue: 0,0:59:35.50,0:59:38.50,yin,,0,0,0,,下周 我们会更进一步讲 Objective-C\\N{\\fs12}and then next week we'll do, yet more objective-C.\r\nDialogue: 0,0:59:38.50,0:59:40.40,yin,,0,0,0,,非常感谢大家\\N{\\fs12}Thank you very much!\r\nDialogue: 0,0:59:41.72,0:59:45.66,yin,,0,0,0,,更多内容 请访问我校官网 stanford.edu\\N{\\fs12}For more, please visit us at stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/10. Multithreading, Scroll View.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.2.0\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage]\r\nLast Style Storage: Default\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.41,0:00:06.41,yin,,0,0,0,,斯坦福大学\\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:08.62,0:00:13.34,yin,,0,0,0,,欢迎来到2013至2014秋季学期\\N{\\fs12}Okay, well, welcome then to lecture 10, yes 10,\r\nDialogue: 0,0:00:13.63,0:00:17.62,yin,,0,0,0,,CS193P第十讲\\N{\\fs12}of CS193P, fall of 2013/14 academic year,\r\nDialogue: 0,0:00:17.63,0:00:20.77,yin,,0,0,0,,今天我们要讲的是多线程\\N{\\fs12}and today, we are going to talk about multithreading.\r\nDialogue: 0,0:00:20.87,0:00:22.75,yin,,0,0,0,,我只会简单地讲一下\\N{\\fs12}Okay? I'm only going to talk about it briefly,\r\nDialogue: 0,0:00:24.43,0:00:26.87,yin,,0,0,0,,因为很多多线程的内容\\N{\\fs12}but, because you'll learn a lot from multithreading\r\nDialogue: 0,0:00:26.88,0:00:28.29,yin,,0,0,0,,都会通过实际体验学到\\N{\\fs12}kind of through experience.\r\nDialogue: 0,0:00:28.98,0:00:30.48,yin,,0,0,0,,然后我们会讲UIScrollView滚动视图\\N{\\fs12}Then we're going to talk about UIScrollView,\r\nDialogue: 0,0:00:30.48,0:00:32.32,yin,,0,0,0,,非常重要的视图\\N{\\fs12}a very important view that allows you\r\nDialogue: 0,0:00:32.32,0:00:36.28,yin,,0,0,0,,能够扩大手机小屏幕的范围\\N{\\fs12}to expand what you can see on that little phone screen,\r\nDialogue: 0,0:00:36.37,0:00:38.09,yin,,0,0,0,,让你看到更大的内容\\N{\\fs12}to let you look at larger things.\r\nDialogue: 0,0:00:38.39,0:00:40.88,yin,,0,0,0,,然后我会做一个示例演示 包含这两项内容\\N{\\fs12}I'll do a demo that's gonna cover both of those things,\r\nDialogue: 0,0:00:40.88,0:00:42.17,yin,,0,0,0,,多线程和滚动视图\\N{\\fs12}multithreading and scrolling.\r\nDialogue: 0,0:00:42.43,0:00:44.14,yin,,0,0,0,,然后剩下的时间\\N{\\fs12}And then however much time we'll have left\r\nDialogue: 0,0:00:44.15,0:00:46.86,yin,,0,0,0,,我们会开始讲下一个主题UITableView表视图\\N{\\fs12}we'll get started on our next topic which is UITableView,\r\nDialogue: 0,0:00:46.86,0:00:49.75,yin,,0,0,0,,周三再继续\\N{\\fs12}we'll continue that on Wednesday.\r\nDialogue: 0,0:00:51.97,0:00:53.40,yin,,0,0,0,,先来看多线程\\N{\\fs12}So multithreading, okay.\r\nDialogue: 0,0:00:54.13,0:00:56.48,yin,,0,0,0,,多线程就是\\N{\\fs12}The idea with multithreading is\r\nDialogue: 0,0:00:56.67,0:01:00.80,yin,,0,0,0,,将程序的执行路径\\N{\\fs12}that you want to divide up the execution paths of your program\r\nDialogue: 0,0:01:00.81,0:01:04.00,yin,,0,0,0,,分为不同的路径\\N{\\fs12}into different and distinct paths\r\nDialogue: 0,0:01:04.01,0:01:06.64,yin,,0,0,0,,可能在同一时间运行\\N{\\fs12}that are possibly running at the same time.\r\nDialogue: 0,0:01:06.64,0:01:09.63,yin,,0,0,0,,我说\"可能\" 因为从程序员的角度看\\N{\\fs12}Now I say possibly, from your standpoint as a programmer,\r\nDialogue: 0,0:01:09.63,0:01:11.49,yin,,0,0,0,,各个线程都是同时运行的\\N{\\fs12}they look like they're all running at the same time.\r\nDialogue: 0,0:01:11.74,0:01:14.09,yin,,0,0,0,,但是 如果你的电脑或者手机\\N{\\fs12}But, of course, if you have a computer or a phone\r\nDialogue: 0,0:01:14.09,0:01:15.72,yin,,0,0,0,,只有一个处理器\\N{\\fs12}that only has one processor,\r\nDialogue: 0,0:01:15.90,0:01:17.90,yin,,0,0,0,,根本不可能同时运行\\N{\\fs12}there's no way for them to run at the same time.\r\nDialogue: 0,0:01:18.19,0:01:20.42,yin,,0,0,0,,但是操作系统让它们看起来是同时处理的\\N{\\fs12}But the OS makes it appear that they are\r\nDialogue: 0,0:01:20.42,0:01:22.26,yin,,0,0,0,,方法主要是时间分片\\N{\\fs12}by basically time slicing,\r\nDialogue: 0,0:01:22.27,0:01:24.58,yin,,0,0,0,,分给每个进程一点时间\\N{\\fs12}giving each one of them a little bit of time\r\nDialogue: 0,0:01:25.64,0:01:28.16,yin,,0,0,0,,这样看起来它们都是同时运行的\\N{\\fs12}to make it seem like they're all running at the same time, okay?\r\nDialogue: 0,0:01:28.78,0:01:33.00,yin,,0,0,0,,如果你确实有多个处理器\\N{\\fs12}And, so, if you did have a multiprocessor,\r\nDialogue: 0,0:01:33.00,0:01:35.45,yin,,0,0,0,,它们可能会同时运行 可能不会\\N{\\fs12}maybe they would actually running at the same time, or maybe not,\r\nDialogue: 0,0:01:35.46,0:01:36.86,yin,,0,0,0,,但我们不在意也不知道\\N{\\fs12}but you don't care and you don't know.\r\nDialogue: 0,0:01:37.14,0:01:39.82,yin,,0,0,0,,不是我们要知道的内容\\N{\\fs12}Okay? It's totally not for you to know.\r\nDialogue: 0,0:01:40.01,0:01:41.95,yin,,0,0,0,,我们为什么需要这种行为呢\\N{\\fs12}Why do we want this kind of behavior\r\nDialogue: 0,0:01:41.95,0:01:43.69,yin,,0,0,0,,这种多线程执行\\N{\\fs12}where we have these multiple threads of execution?\r\nDialogue: 0,0:01:43.69,0:01:45.40,yin,,0,0,0,,有一些原因\\N{\\fs12}Well, a couple of reasons.\r\nDialogue: 0,0:01:45.40,0:01:47.26,yin,,0,0,0,,有一个执行线程\\N{\\fs12}One, we've got one thread of execution\r\nDialogue: 0,0:01:47.27,0:01:49.39,yin,,0,0,0,,也就是主执行线程\\N{\\fs12}which is that main thread of execution\r\nDialogue: 0,0:01:49.50,0:01:51.73,yin,,0,0,0,,用户在其中互动 执行触控事件\\N{\\fs12}where the user is interacting, doing touch events,\r\nDialogue: 0,0:01:51.74,0:01:53.74,yin,,0,0,0,,我们希望它有很好的响应能力\\N{\\fs12}we want thing to be very responsive.\r\nDialogue: 0,0:01:53.90,0:01:55.85,yin,,0,0,0,,我们想让它始终在监听\\N{\\fs12}We want that to always be listening,\r\nDialogue: 0,0:01:55.87,0:01:57.49,yin,,0,0,0,,不想让它停止监听\\N{\\fs12}we never want that to not be listening.\r\nDialogue: 0,0:01:58.06,0:01:59.94,yin,,0,0,0,,另外一个原因就是其他执行线程\\N{\\fs12}The other thing is we have other threads of execution\r\nDialogue: 0,0:01:59.94,0:02:02.27,yin,,0,0,0,,可能会阻塞\\N{\\fs12}that actually might block, okay?\r\nDialogue: 0,0:02:02.27,0:02:03.34,yin,,0,0,0,,为什么会阻塞呢\\N{\\fs12}Why would they block?\r\nDialogue: 0,0:02:03.34,0:02:04.25,yin,,0,0,0,,为什么会停下来\\N{\\fs12}Why would they stop?\r\nDialogue: 0,0:02:04.32,0:02:06.27,yin,,0,0,0,,比如说执行了一个网络调用\\N{\\fs12}Well, let's say they do a network call\r\nDialogue: 0,0:02:06.29,0:02:08.28,yin,,0,0,0,,等待返回网络数据\\N{\\fs12}and they're waiting for something to come back over the network.\r\nDialogue: 0,0:02:08.28,0:02:10.71,yin,,0,0,0,,需要等待返回的内容\\N{\\fs12}Well, they have to wait for that thing to come back.\r\nDialogue: 0,0:02:10.71,0:02:12.36,yin,,0,0,0,,所以线程会被阻塞 会停住\\N{\\fs12}So they are blocked, they're stopped.\r\nDialogue: 0,0:02:12.80,0:02:14.81,yin,,0,0,0,,我们不会希望主线程\\N{\\fs12}Okay? We would never want that main execution\r\nDialogue: 0,0:02:14.82,0:02:16.17,yin,,0,0,0,,监听触控事件的主线程\\N{\\fs12}that's listening for touch events\r\nDialogue: 0,0:02:16.18,0:02:19.13,yin,,0,0,0,,被停住或被阻塞\\N{\\fs12}to be stopped, okay, or blocked, right?\r\nDialogue: 0,0:02:19.18,0:02:21.07,yin,,0,0,0,,但是其他线程阻塞就没关系了\\N{\\fs12}But these other ones, it's okay if they're blocked.\r\nDialogue: 0,0:02:21.07,0:02:22.17,yin,,0,0,0,,如果它们在等待返回数据\\N{\\fs12}If they're waiting for something,\r\nDialogue: 0,0:02:22.20,0:02:24.01,yin,,0,0,0,,等待就可以了\\N{\\fs12}they're waiting for something. Okay?\r\nDialogue: 0,0:02:24.59,0:02:28.02,yin,,0,0,0,,想要理解iOS中多线程的实现方法\\N{\\fs12}So to understand how we do multithreading, in iOS,\r\nDialogue: 0,0:02:28.16,0:02:31.19,yin,,0,0,0,,有一点要理解 也就是queue队列\\N{\\fs12}there's one thing you have to understand and that's queues.\r\nDialogue: 0,0:02:31.73,0:02:34.92,yin,,0,0,0,,队列和现实世界中的队列是一样的\\N{\\fs12}Okay? A queue, just like a queue in the real world,\r\nDialogue: 0,0:02:34.93,0:02:35.95,yin,,0,0,0,,队列表示排成一队\\N{\\fs12}queue means like a line,\r\nDialogue: 0,0:02:35.96,0:02:38.01,yin,,0,0,0,,比如你去电影院 人们会排成一队\\N{\\fs12}like you go to the movie theater and there's a line of people,\r\nDialogue: 0,0:02:38.02,0:02:38.93,yin,,0,0,0,,这叫做队列\\N{\\fs12}that's called a queue.\r\nDialogue: 0,0:02:39.29,0:02:40.52,yin,,0,0,0,,向不知道这个词的同学解释一下\\N{\\fs12}For those of you who don't know that word.\r\nDialogue: 0,0:02:41.30,0:02:42.86,yin,,0,0,0,,如果理解了这个队列的意思\\N{\\fs12}And so you got that queue\r\nDialogue: 0,0:02:42.87,0:02:46.02,yin,,0,0,0,,iOS多线程这里的队列也是一样的\\N{\\fs12}and the same thing is happening here with iOS multithreading.\r\nDialogue: 0,0:02:46.02,0:02:48.10,yin,,0,0,0,,这里也有队列 但在这些队列中\\N{\\fs12}You have these queues, but in these queues,\r\nDialogue: 0,0:02:48.10,0:02:51.70,yin,,0,0,0,,不是等着看电影的人 而是block\\N{\\fs12}instead of people waiting for the theater, there are blocks.\r\nDialogue: 0,0:02:51.88,0:02:53.99,yin,,0,0,0,,上周我们讲过的block\\N{\\fs12}Blocks in the way we talked about last week.\r\nDialogue: 0,0:02:53.99,0:02:56.24,yin,,0,0,0,,用大括号表示的block\\N{\\fs12}You know, the curly, curly brace thing, okay?\r\nDialogue: 0,0:02:56.57,0:02:59.10,yin,,0,0,0,,所以这个队列中都是block\\N{\\fs12}So you got this queue, in line, you have these blocks,\r\nDialogue: 0,0:02:59.17,0:03:01.72,yin,,0,0,0,,block排着队等着被执行\\N{\\fs12}and they're all waiting in line to be executed.\r\nDialogue: 0,0:03:02.11,0:03:04.26,yin,,0,0,0,,根据所在队列的不同\\N{\\fs12}And depending on which queue they're in,\r\nDialogue: 0,0:03:04.40,0:03:06.67,yin,,0,0,0,,当轮到它们 排到了队列前面\\N{\\fs12}when it's their turn, when they get to the front of the line,\r\nDialogue: 0,0:03:06.82,0:03:09.69,yin,,0,0,0,,它们会被取出队列 开始执行\\N{\\fs12}they get taken off the queue and they get to run.\r\nDialogue: 0,0:03:10.56,0:03:13.08,yin,,0,0,0,,可能是在单独的线程中\\N{\\fs12}Okay? Possibly in a separate thread.\r\nDialogue: 0,0:03:13.63,0:03:16.31,yin,,0,0,0,,通常情况下\\N{\\fs12}Okay? Usually there might be\r\nDialogue: 0,0:03:16.56,0:03:19.21,yin,,0,0,0,,一个队列会分配单个或多个线程\\N{\\fs12}multiple threads assigned to one queue, or single thread,\r\nDialogue: 0,0:03:19.22,0:03:20.65,yin,,0,0,0,,同样的 你并不知道会怎样\\N{\\fs12}again, you don't know what's going on,\r\nDialogue: 0,0:03:20.65,0:03:23.13,yin,,0,0,0,,你只知道自己将这些block放入了队列\\N{\\fs12}all you know is you're putting these blocks in a queue\r\nDialogue: 0,0:03:23.31,0:03:25.79,yin,,0,0,0,,它们会被取出并运行\\N{\\fs12}and they are being taken off and allowed to run.\r\nDialogue: 0,0:03:26.02,0:03:29.70,yin,,0,0,0,,队列允许一次放一个人\\N{\\fs12}And people can be allowed to come off the queue one at a time,\r\nDialogue: 0,0:03:29.71,0:03:30.67,yin,,0,0,0,,所以在电影院中\\N{\\fs12}so at the movie theater,\r\nDialogue: 0,0:03:30.68,0:03:32.83,yin,,0,0,0,,一个人进去看电影\\N{\\fs12}one person gets to go and watch the whole movie,\r\nDialogue: 0,0:03:32.95,0:03:34.87,yin,,0,0,0,,他看完之后 后面那个人再进去\\N{\\fs12}and when they're done, the next person goes in.\r\nDialogue: 0,0:03:34.96,0:03:36.93,yin,,0,0,0,,这叫做串行队列\\N{\\fs12}Okay? That's called a serial queue,\r\nDialogue: 0,0:03:36.93,0:03:38.97,yin,,0,0,0,,这就是我们要讲的队列\\N{\\fs12}that's what the queues we're going to talk about are,\r\nDialogue: 0,0:03:38.97,0:03:39.81,yin,,0,0,0,,是一个非常简单的队列\\N{\\fs12}it's a very simple queue.\r\nDialogue: 0,0:03:39.98,0:03:41.48,yin,,0,0,0,,但还有一种并发队列\\N{\\fs12}There's also concurrent queues, however,\r\nDialogue: 0,0:03:41.49,0:03:43.23,yin,,0,0,0,,可以让一群人进电影院\\N{\\fs12}where a whole bunch of people get to go into a theater\r\nDialogue: 0,0:03:43.24,0:03:46.74,yin,,0,0,0,,可以同时做某事\\N{\\fs12}and they're all get to be doing stuff simultaneously.\r\nDialogue: 0,0:03:46.86,0:03:48.19,yin,,0,0,0,,这种略微复杂些\\N{\\fs12}Okay? It's a little more complicated,\r\nDialogue: 0,0:03:48.19,0:03:49.92,yin,,0,0,0,,因为你得到这个队列 从中取出block\\N{\\fs12}because you got this queue, you're pulling off these blocks\r\nDialogue: 0,0:03:49.92,0:03:51.03,yin,,0,0,0,,它们一起运行\\N{\\fs12}and they're all running together,\r\nDialogue: 0,0:03:51.04,0:03:53.87,yin,,0,0,0,,如果它们想要共享资源等等\\N{\\fs12}if they ever want to share resources or something\r\nDialogue: 0,0:03:53.89,0:03:55.90,yin,,0,0,0,,需要更高级一些的多线程编程\\N{\\fs12}they need a little more advanced multithreaded programming\r\nDialogue: 0,0:03:55.93,0:03:57.21,yin,,0,0,0,,我们要用的是简单的队列\\N{\\fs12}and we're going to do the simple kind\r\nDialogue: 0,0:03:57.43,0:03:59.40,yin,,0,0,0,,一次只有一个人从队列中出来\\N{\\fs12}where one person coming out of the queue,\r\nDialogue: 0,0:03:59.51,0:04:01.59,yin,,0,0,0,,一次只从队列中取出一个block\\N{\\fs12}one block coming out of the queue at the same time.\r\nDialogue: 0,0:04:02.05,0:04:03.72,yin,,0,0,0,,这就是大家要理解的内容\\N{\\fs12}Okay? So that's really what you understand,\r\nDialogue: 0,0:04:03.72,0:04:05.31,yin,,0,0,0,,多线程的工作原理就是这样的\\N{\\fs12}is that's how this multithreading works.\r\nDialogue: 0,0:04:05.36,0:04:07.15,yin,,0,0,0,,由block组成的队列\\N{\\fs12}Queues of blocks, okay?\r\nDialogue: 0,0:04:07.47,0:04:10.62,yin,,0,0,0,,有一个很重要的队列 就是主队列\\N{\\fs12}Now there's a very important queue, which is the main queue,\r\nDialogue: 0,0:04:10.62,0:04:13.22,yin,,0,0,0,,在这个队列中处理多点触控\\N{\\fs12}that's the queue on which multi-touch is happening\r\nDialogue: 0,0:04:13.22,0:04:15.13,yin,,0,0,0,,以及所有UI操作等等\\N{\\fs12}and all the UI stuff is happening,\r\nDialogue: 0,0:04:15.44,0:04:17.16,yin,,0,0,0,,它很特殊 原因有两点\\N{\\fs12}and this is special for two reasons.\r\nDialogue: 0,0:04:17.16,0:04:20.58,yin,,0,0,0,,一是我们绝不想让它阻塞\\N{\\fs12}Alright? One is that we never want to block it, okay?\r\nDialogue: 0,0:04:20.58,0:04:23.04,yin,,0,0,0,,我们不会将需要执行很长时间的线程\\N{\\fs12}So we never want to do anything that's gonna take very long\r\nDialogue: 0,0:04:23.47,0:04:24.89,yin,,0,0,0,,放在主队列上\\N{\\fs12}on that main queue.\r\nDialogue: 0,0:04:25.13,0:04:27.55,yin,,0,0,0,,二是我们将其用于同步\\N{\\fs12}And the second thing is we use it for synchronization\r\nDialogue: 0,0:04:27.72,0:04:30.96,yin,,0,0,0,,所有UI相关内容的同步\\N{\\fs12}for everything that is UI related, okay?\r\nDialogue: 0,0:04:31.12,0:04:34.68,yin,,0,0,0,,全部方法 也不是全部 UIKit中大部分方法\\N{\\fs12}So all the methods, not all, but most of the methods in UIKit,\r\nDialogue: 0,0:04:34.93,0:04:36.69,yin,,0,0,0,,只能在主线程中调用它们\\N{\\fs12}you want to call them only on the main queue,\r\nDialogue: 0,0:04:36.70,0:04:39.49,yin,,0,0,0,,实际上 如果你在其他block中调用它们\\N{\\fs12}and in fact, if you call them on some other, some block\r\nDialogue: 0,0:04:39.68,0:04:41.91,yin,,0,0,0,,从其他队列中取出的block中 可能不会正常运行的\\N{\\fs12}that came off from some other queue probably wouldn't work.\r\nDialogue: 0,0:04:42.33,0:04:46.21,yin,,0,0,0,,而有一些对象 比如UIImage UIFont UIColor\\N{\\fs12}Now there's a few, like UIImage, UIFont, UIColor,\r\nDialogue: 0,0:04:46.39,0:04:49.47,yin,,0,0,0,,它们不在主线程上一样可以正常运行\\N{\\fs12}a couple of those things, they'll work off the main queue,\r\nDialogue: 0,0:04:49.58,0:04:53.02,yin,,0,0,0,,但任何能够或可能引起\\N{\\fs12}but anything that is going to cause the screen to have to change\r\nDialogue: 0,0:04:53.03,0:04:56.32,yin,,0,0,0,,屏幕改变或同步等的操作\\N{\\fs12}or synchronize or anything like that, or that might cause that,\r\nDialogue: 0,0:04:56.48,0:04:57.90,yin,,0,0,0,,都要发生在主队列上\\N{\\fs12}that all needs to happen on the main queue,\r\nDialogue: 0,0:04:57.92,0:04:59.00,yin,,0,0,0,,所以我们要用主队列\\N{\\fs12}so we use that main queue,\r\nDialogue: 0,0:04:59.16,0:05:02.09,yin,,0,0,0,,不断响应用户操作\\N{\\fs12}both to have something that's constantly responsive to the user\r\nDialogue: 0,0:05:02.10,0:05:03.26,yin,,0,0,0,,和进行同步\\N{\\fs12}and for synchronization,\r\nDialogue: 0,0:05:03.26,0:05:06.25,yin,,0,0,0,,让一切和UI同步\\N{\\fs12}to keep everything in sync of what's going on in the UI side.\r\nDialogue: 0,0:05:06.42,0:05:08.64,yin,,0,0,0,,其他操作可以放在其他队列中执行\\N{\\fs12}Everything else we could do in other queues,\r\nDialogue: 0,0:05:08.65,0:05:10.05,yin,,0,0,0,,实际上 令人惊讶的是\\N{\\fs12}and actually, amazingly,\r\nDialogue: 0,0:05:10.06,0:05:13.78,yin,,0,0,0,,iOS会在其他队列中执行绘制等操作\\N{\\fs12}iOS is doing things like actually drawing in another queue.\r\nDialogue: 0,0:05:14.13,0:05:16.25,yin,,0,0,0,,你并不知道 不知道是什么队列\\N{\\fs12}Okay, you don't know that, you don't know what queue it is,\r\nDialogue: 0,0:05:16.25,0:05:18.38,yin,,0,0,0,,你看不到 但实际上是在其他队列中执行的\\N{\\fs12}you don't see it, but it's actually doing the other queue,\r\nDialogue: 0,0:05:18.38,0:05:18.97,yin,,0,0,0,,为什么呢\\N{\\fs12}why?\r\nDialogue: 0,0:05:19.08,0:05:21.16,yin,,0,0,0,,因为如果绘制某些复杂图形时\\N{\\fs12}Because if it's drawing something very graphic-intensive\r\nDialogue: 0,0:05:21.16,0:05:23.21,yin,,0,0,0,,用户在主队列中用了多点触控\\N{\\fs12}and the user multi-touches in the main queue,\r\nDialogue: 0,0:05:23.41,0:05:24.91,yin,,0,0,0,,就要切换回主队列\\N{\\fs12}you want to switch back to that main queue\r\nDialogue: 0,0:05:24.92,0:05:27.10,yin,,0,0,0,,赋予优先级\\N{\\fs12}and give it the, the priority\r\nDialogue: 0,0:05:27.11,0:05:31.26,yin,,0,0,0,,先完成多点触控 绘制稍后执行\\N{\\fs12}and the drawing can wait a little bit while that multi-touch gets done.\r\nDialogue: 0,0:05:32.92,0:05:35.43,yin,,0,0,0,,所以不要阻塞主队列\\N{\\fs12}Okay? So this main queue doesn't want to be blocked,\r\nDialogue: 0,0:05:35.43,0:05:36.94,yin,,0,0,0,,我们用主队列来进行同步\\N{\\fs12}it's where we do the synchronization,\r\nDialogue: 0,0:05:37.04,0:05:40.40,yin,,0,0,0,,我会演示 如何编写代码\\N{\\fs12}and I'm gonna show you how you can write code\r\nDialogue: 0,0:05:40.41,0:05:43.37,yin,,0,0,0,,让它运行在其他队列中 但还要更新UI\\N{\\fs12}that is running on other queues, but needs to do UI,\r\nDialogue: 0,0:05:43.61,0:05:44.60,yin,,0,0,0,,因为这是个问题对吧\\N{\\fs12}because that's a problem, right?\r\nDialogue: 0,0:05:44.60,0:05:47.20,yin,,0,0,0,,如果在其他队列上有block\\N{\\fs12}If your got a block that's on another queue,\r\nDialogue: 0,0:05:47.20,0:05:51.08,yin,,0,0,0,,不在主队列上\\N{\\fs12}non-main thread queue, non-main queue,\r\nDialogue: 0,0:05:51.13,0:05:52.41,yin,,0,0,0,,然后还要对UI进行操作\\N{\\fs12}then, and you want to do some UI,\r\nDialogue: 0,0:05:52.42,0:05:54.07,yin,,0,0,0,,就必须向主队列通信\\N{\\fs12}you got to somehow talk to that main queue,\r\nDialogue: 0,0:05:54.07,0:05:56.50,yin,,0,0,0,,要在主队列上放一个block\\N{\\fs12}you got put a block, basically, on that main queue.\r\nDialogue: 0,0:05:57.24,0:05:58.40,yin,,0,0,0,,还有其他队列\\N{\\fs12}There are other queues,\r\nDialogue: 0,0:05:58.41,0:06:00.68,yin,,0,0,0,,大部分都是iOS在后台创建的\\N{\\fs12}mostly they're created by iOS behind the scenes,\r\nDialogue: 0,0:06:00.68,0:06:02.97,yin,,0,0,0,,幻灯片中有个示例\\N{\\fs12}I'm going to show you an example here in the slides\r\nDialogue: 0,0:06:03.09,0:06:06.78,yin,,0,0,0,,会介绍一个API中可以看到的队列\\N{\\fs12}of a queue that is visible to you in the API\r\nDialogue: 0,0:06:06.90,0:06:08.13,yin,,0,0,0,,以及我们处理的方法\\N{\\fs12}and how we deal with that.\r\nDialogue: 0,0:06:08.97,0:06:11.84,yin,,0,0,0,,那么如何在其他队列上执行block呢\\N{\\fs12}Alright, so how do you execute a block on another queue?\r\nDialogue: 0,0:06:12.13,0:06:16.19,yin,,0,0,0,,这是C层API 非常底层的API\\N{\\fs12}Okay? This is a C-level API, it's a very low-level API,\r\nDialogue: 0,0:06:16.19,0:06:19.02,yin,,0,0,0,,在对象之下 所以在最底这层API中\\N{\\fs12}below object, so you're not going to see any object stuff\r\nDialogue: 0,0:06:19.42,0:06:21.10,yin,,0,0,0,,不会看到任何对象内容\\N{\\fs12}in this lowest level API.\r\nDialogue: 0,0:06:21.10,0:06:23.16,yin,,0,0,0,,在这层之上 有一个面向对象层\\N{\\fs12}There is an object-oriented layer on top of it\r\nDialogue: 0,0:06:23.17,0:06:25.74,yin,,0,0,0,,叫NSOperationQueue\\N{\\fs12}called NSOperation, NSOperationQueue,\r\nDialogue: 0,0:06:26.31,0:06:28.07,yin,,0,0,0,,但那是内容很少的面向对象层\\N{\\fs12}but it's kind of a thin object-oriented layer.\r\nDialogue: 0,0:06:28.07,0:06:29.49,yin,,0,0,0,,这是核心层\\N{\\fs12}This is the core layer.\r\nDialogue: 0,0:06:29.84,0:06:33.23,yin,,0,0,0,,这是最基本的方法\\N{\\fs12}And this is the fundamental method, dis, or, sorry,\r\nDialogue: 0,0:06:33.23,0:06:36.34,yin,,0,0,0,,基本的C函数 dispatch_async\\N{\\fs12}this is fundamental C function, dispatch, underbar, async,\r\nDialogue: 0,0:06:36.75,0:06:39.95,yin,,0,0,0,,表示将这个block以异步方式\\N{\\fs12}and that means asynchronously put this block\r\nDialogue: 0,0:06:40.23,0:06:41.97,yin,,0,0,0,,放入这个队列中\\N{\\fs12}on this queue, okay?\r\nDialogue: 0,0:06:42.32,0:06:44.79,yin,,0,0,0,,可以看到 我声明了一个队列 局部变量queue\\N{\\fs12}So you see I've declared a queue there, local variable queue,\r\nDialogue: 0,0:06:44.79,0:06:47.73,yin,,0,0,0,,是dispatch_queue_t类型的 是个typedef\\N{\\fs12}it's a of type dispatch queue t, which is a typedef,\r\nDialogue: 0,0:06:48.15,0:06:50.70,yin,,0,0,0,,我稍后会介绍如何获取队列\\N{\\fs12}and I'll, I'll talk about how to get a queue in a second.\r\nDialogue: 0,0:06:50.84,0:06:52.55,yin,,0,0,0,,然后用dispatch_async\\N{\\fs12}And then you just say dispatch async,\r\nDialogue: 0,0:06:52.58,0:06:55.05,yin,,0,0,0,,然后是目标队列和将要加入队列的block\\N{\\fs12}the queue you want to put the block on and then the block.\r\nDialogue: 0,0:06:55.05,0:06:57.46,yin,,0,0,0,,block没有参数 无返回值\\N{\\fs12}And the block takes no arguments and it returns no values,\r\nDialogue: 0,0:06:57.46,0:07:00.62,yin,,0,0,0,,只是一个block 可以随意加入代码\\N{\\fs12}it's just a block, and you can put any code you want in there,\r\nDialogue: 0,0:07:00.82,0:07:03.87,yin,,0,0,0,,block会在队列中找到位置\\N{\\fs12}and that block will take its place in line on that queue,\r\nDialogue: 0,0:07:03.87,0:07:06.74,yin,,0,0,0,,队列排到它时 它就会被取出执行\\N{\\fs12}and when that queue gets around it, it will take it off.\r\nDialogue: 0,0:07:06.82,0:07:08.38,yin,,0,0,0,,关于主队列 还有一件事\\N{\\fs12}One thing, by the way, about the main queue,\r\nDialogue: 0,0:07:08.47,0:07:12.06,yin,,0,0,0,,它只在安静时才会执行队列中的内容\\N{\\fs12}it never takes anything out of its queue to run until its quiet,\r\nDialogue: 0,0:07:12.30,0:07:14.45,yin,,0,0,0,,安静指的是当前没有触控事件\\N{\\fs12}meaning whatever current touch events\r\nDialogue: 0,0:07:14.51,0:07:15.83,yin,,0,0,0,,正在被处理\\N{\\fs12}have been processed, okay?\r\nDialogue: 0,0:07:15.84,0:07:17.69,yin,,0,0,0,,它不会在处理触控事件时\\N{\\fs12}It's not going to right in the middle of a touch event\r\nDialogue: 0,0:07:17.76,0:07:18.95,yin,,0,0,0,,从队列中获取某个block\\N{\\fs12}take something off its queue\r\nDialogue: 0,0:07:18.95,0:07:19.99,yin,,0,0,0,,然后去执行它\\N{\\fs12}and go do something, right?\r\nDialogue: 0,0:07:20.29,0:07:23.41,yin,,0,0,0,,主队列会等到安静一些时\\N{\\fs12}So the main queue waits till its a little quieter\r\nDialogue: 0,0:07:23.41,0:07:25.12,yin,,0,0,0,,再从队列中获取操作并执行\\N{\\fs12}and then it'll take things off the queue and run it,\r\nDialogue: 0,0:07:25.17,0:07:27.56,yin,,0,0,0,,所以你可以向主队列中增加任意操作\\N{\\fs12}so you can always post things on the main queue\r\nDialogue: 0,0:07:27.57,0:07:30.25,yin,,0,0,0,,肯定不会打断用户操作\\N{\\fs12}and be sure that it's not gonna interrupt the user in anyway.\r\nDialogue: 0,0:07:31.35,0:07:33.83,yin,,0,0,0,,那么我们如何获取一个队列\\N{\\fs12}Alright, so how do we get a queue to send this,\r\nDialogue: 0,0:07:33.83,0:07:35.34,yin,,0,0,0,,来执行这个dispatch_async呢\\N{\\fs12}to do this dispatch async with?\r\nDialogue: 0,0:07:35.65,0:07:37.18,yin,,0,0,0,,先来讲讲如何获取主队列\\N{\\fs12}Well, let's talk about the main queue first\r\nDialogue: 0,0:07:37.18,0:07:38.56,yin,,0,0,0,,因为要分派操作\\N{\\fs12}because that's the most important queue\r\nDialogue: 0,0:07:38.69,0:07:40.19,yin,,0,0,0,,它是最重要的队列\\N{\\fs12}that we need to dispatch things,\r\nDialogue: 0,0:07:40.29,0:07:41.21,yin,,0,0,0,,方法是\\N{\\fs12}and the way you do that\r\nDialogue: 0,0:07:41.22,0:07:43.97,yin,,0,0,0,,dispatch_get_main_queue\\N{\\fs12}is dispatch underbar get, underbar main, underbar queue,\r\nDialogue: 0,0:07:43.97,0:07:45.69,yin,,0,0,0,,这个方法会返回主队列\\N{\\fs12}that will return the main queue to you\r\nDialogue: 0,0:07:45.95,0:07:49.36,yin,,0,0,0,,然后可以对它调用带block参数的dispatch_async\\N{\\fs12}and then you can call dispatch async with a block on that.\r\nDialogue: 0,0:07:49.56,0:07:52.45,yin,,0,0,0,,在更高的NSOperationQueue层上\\N{\\fs12}At the higher level, that NSOperationQueue level,\r\nDialogue: 0,0:07:52.45,0:07:55.28,yin,,0,0,0,,可以使用NSOperationQueue mainQueue 它是个类方法\\N{\\fs12}you can do NSOperation mainQueue, it's a class method,\r\nDialogue: 0,0:07:55.34,0:07:57.58,yin,,0,0,0,,会返回NSOperationQueue对象\\N{\\fs12}it'll return NSOperationQueue object,\r\nDialogue: 0,0:07:57.58,0:07:58.89,yin,,0,0,0,,代表主队列\\N{\\fs12}which represents the main queue.\r\nDialogue: 0,0:07:59.17,0:08:01.08,yin,,0,0,0,,它只是内容很少的面向对象层\\N{\\fs12}Again, it's just a thin object-oriented layer,\r\nDialogue: 0,0:08:01.37,0:08:03.72,yin,,0,0,0,,在C层上\\N{\\fs12}pretty much, on this C layer,\r\nDialogue: 0,0:08:03.73,0:08:05.97,yin,,0,0,0,,我们会讲到它在API中的使用\\N{\\fs12}and we'll, we'll see where that comes into the API.\r\nDialogue: 0,0:08:07.43,0:08:09.06,yin,,0,0,0,,如果想要再创建一个队列呢\\N{\\fs12}What if you wanted to create another queue.\r\nDialogue: 0,0:08:09.06,0:08:11.53,yin,,0,0,0,,假设你要执行大型数学运算\\N{\\fs12}Let's say you're gonna do some big math calculation\r\nDialogue: 0,0:08:11.53,0:08:13.64,yin,,0,0,0,,或者大型图像处理运算\\N{\\fs12}or some big image processing calculation\r\nDialogue: 0,0:08:13.66,0:08:17.01,yin,,0,0,0,,而你不想阻塞主队列 主线程\\N{\\fs12}you don't want to block the main queue, the main thread,\r\nDialogue: 0,0:08:17.15,0:08:18.67,yin,,0,0,0,,这时你就可以再创建一个队列\\N{\\fs12}so you can create another queue.\r\nDialogue: 0,0:08:18.73,0:08:21.78,yin,,0,0,0,,非常简单 只要用dispatch_queue_create\\N{\\fs12}Very simple, you just say dispatch underbar queue, underbar create,\r\nDialogue: 0,0:08:22.14,0:08:25.86,yin,,0,0,0,,这个函数的第一个参数是队列的名称\\N{\\fs12}and the first argument to that function is the name of the queue\r\nDialogue: 0,0:08:25.87,0:08:27.80,yin,,0,0,0,,它会出现在调试程序等之中\\N{\\fs12}and that's like going to show up in the debugger and stuff,\r\nDialogue: 0,0:08:27.81,0:08:29.26,yin,,0,0,0,,是个内部名称\\N{\\fs12}so this is kind of an internal name,\r\nDialogue: 0,0:08:29.51,0:08:31.31,yin,,0,0,0,,注意它不是一个NSString\\N{\\fs12}notice that's not an NSString,\r\nDialogue: 0,0:08:31.65,0:08:33.33,yin,,0,0,0,,因为这是底层API\\N{\\fs12}because this is a low-level API,\r\nDialogue: 0,0:08:33.39,0:08:35.89,yin,,0,0,0,,这是这门课上\\N{\\fs12}this is about the only non-NSString string\r\nDialogue: 0,0:08:35.90,0:08:36.92,yin,,0,0,0,,唯一一处使用非NSString字符串的地方\\N{\\fs12}you're ever going to see in this class,\r\nDialogue: 0,0:08:36.93,0:08:38.74,yin,,0,0,0,,因为这是我们用到的最底层\\N{\\fs12}because this is the lowest level we'll go.\r\nDialogue: 0,0:08:39.21,0:08:40.76,yin,,0,0,0,,它是个const char\\N{\\fs12}It's a const char star,\r\nDialogue: 0,0:08:40.98,0:08:43.28,yin,,0,0,0,,这里我就直接用name了\\N{\\fs12}and here I'm just using the name name, okay?\r\nDialogue: 0,0:08:43.30,0:08:45.49,yin,,0,0,0,,命名时要选择好辨认的名字\\N{\\fs12}You just want to give it a name so you can recognize this queue\r\nDialogue: 0,0:08:45.49,0:08:47.36,yin,,0,0,0,,方便在调试程序等中认出这个队列\\N{\\fs12}when you see it in the debugger or something like that.\r\nDialogue: 0,0:08:47.64,0:08:50.25,yin,,0,0,0,,第二个参数代表它是串行队列\\N{\\fs12}And then the second argument is whether it's a serial queue\r\nDialogue: 0,0:08:50.25,0:08:51.96,yin,,0,0,0,,还是并发队列\\N{\\fs12}or a concurrent queue, right?\r\nDialogue: 0,0:08:52.19,0:08:54.39,yin,,0,0,0,,NULL代表串行队列\\N{\\fs12}So, NULL means it's a serial queue,\r\nDialogue: 0,0:08:54.86,0:08:57.43,yin,,0,0,0,,我们要讲的就是这类队列\\N{\\fs12}and so, that's the kind of queue we're gonna talk about,\r\nDialogue: 0,0:08:57.49,0:09:00.24,yin,,0,0,0,,一次从队列中出来一个人\\N{\\fs12}again, so one person comes out of the line at a time.\r\nDialogue: 0,0:09:01.16,0:09:03.30,yin,,0,0,0,,对于分派回主队列\\N{\\fs12}And there's kind of an easy mode\r\nDialogue: 0,0:09:03.30,0:09:05.36,yin,,0,0,0,,有一个简单模式\\N{\\fs12}for dispatching back to the main queue,\r\nDialogue: 0,0:09:05.47,0:09:07.68,yin,,0,0,0,,就是用performSelectorOnMainThread\\N{\\fs12}which is performSelectorOnMainThread,\r\nDialogue: 0,0:09:07.69,0:09:09.56,yin,,0,0,0,,它是一个NSObject方法\\N{\\fs12}it's an NSObject method.\r\nDialogue: 0,0:09:09.77,0:09:11.15,yin,,0,0,0,,可以将它发给任意NSObject\\N{\\fs12}You can send it to any NSObject.\r\nDialogue: 0,0:09:11.38,0:09:14.31,yin,,0,0,0,,只要直接传递一个selector和它的参数\\N{\\fs12}And you just pass a selector and its argument,\r\nDialogue: 0,0:09:14.31,0:09:16.47,yin,,0,0,0,,withObject参数 可以为nil\\N{\\fs12}the withObject argument, it could be nil\r\nDialogue: 0,0:09:16.47,0:09:18.01,yin,,0,0,0,,代表没有参数 是可以的\\N{\\fs12}and then it has no arguments, that's fine.\r\nDialogue: 0,0:09:18.89,0:09:21.23,yin,,0,0,0,,waitUntilDone代表是否要等待\\N{\\fs12}And the waitUntilDone is whether you're gonna wait\r\nDialogue: 0,0:09:21.24,0:09:23.29,yin,,0,0,0,,调用它的这个线程执行之后\\N{\\fs12}until this thing gets pulled off the main queue\r\nDialogue: 0,0:09:23.30,0:09:25.65,yin,,0,0,0,,再将它从主队列调出\\N{\\fs12}and run on the main queue and then finishes\r\nDialogue: 0,0:09:25.66,0:09:29.80,yin,,0,0,0,,并在主队列上运行\\N{\\fs12}before this thread, that's calling this, goes or not,\r\nDialogue: 0,0:09:29.82,0:09:32.48,yin,,0,0,0,,waitUntilDone通常设为NO 不需要等待\\N{\\fs12}usually waitUntilDone you would say no, we don't need to wait,\r\nDialogue: 0,0:09:32.48,0:09:35.31,yin,,0,0,0,,我们会在主队列上调用这个方法\\N{\\fs12}we're going to put this, call this method on the main queue,\r\nDialogue: 0,0:09:35.64,0:09:38.53,yin,,0,0,0,,轮到它执行时就执行\\N{\\fs12}and whenever it executes is when it executes.\r\nDialogue: 0,0:09:38.53,0:09:41.12,yin,,0,0,0,,这个performSelectorOnMainThread方法\\N{\\fs12}So, this performSelectorOnMainThread is just\r\nDialogue: 0,0:09:41.14,0:09:44.34,yin,,0,0,0,,就相当于对主队列调用dispatch_async\\N{\\fs12}like saying dispatch async onto the main queue,\r\nDialogue: 0,0:09:44.61,0:09:46.34,yin,,0,0,0,,一个调用了该方法的block\\N{\\fs12}a block that just calls that method.\r\nDialogue: 0,0:09:47.48,0:09:48.87,yin,,0,0,0,,这个方法就是这样\\N{\\fs12}Okay? That's all it is really,\r\nDialogue: 0,0:09:49.22,0:09:50.23,yin,,0,0,0,,基本上算是个简易模式\\N{\\fs12}bascially it's kind of an easy mode,\r\nDialogue: 0,0:09:50.24,0:09:51.59,yin,,0,0,0,,看起来很好用\\N{\\fs12}it looks nice, and so, you know,\r\nDialogue: 0,0:09:51.75,0:09:53.72,yin,,0,0,0,,不用再用dispatch_async方法了\\N{\\fs12}you don't have to do the dispatch async business,\r\nDialogue: 0,0:09:54.00,0:09:56.15,yin,,0,0,0,,可以直接调用一个方法\\N{\\fs12}but you got to be able to have one method to call,\r\nDialogue: 0,0:09:56.45,0:09:58.54,yin,,0,0,0,,将所有要执行的操作放到一个方法中\\N{\\fs12}put all the stuff you want to do on one method.\r\nDialogue: 0,0:10:00.04,0:10:01.73,yin,,0,0,0,,我们看一个使用它的例子\\N{\\fs12}So let's look at an example that uses this, okay?\r\nDialogue: 0,0:10:01.77,0:10:04.77,yin,,0,0,0,,通过示例演示 更容易理解\\N{\\fs12}This is more understandable, probably much more by example.\r\nDialogue: 0,0:10:04.91,0:10:10.19,yin,,0,0,0,,这个例子是要下载网上某个URL\\N{\\fs12}So, this example is I want to download the contents of an URL\r\nDialogue: 0,0:10:10.37,0:10:11.40,yin,,0,0,0,,对应的内容\\N{\\fs12}from somewhere on the internet.\r\nDialogue: 0,0:10:11.79,0:10:14.79,yin,,0,0,0,,我有一个URL http://或者其他格式\\N{\\fs12}So I have a URL, http:// something or other,\r\nDialogue: 0,0:10:14.98,0:10:16.79,yin,,0,0,0,,我想要将它从网上下载下来\\N{\\fs12}and I want to download that from the internet.\r\nDialogue: 0,0:10:16.79,0:10:18.75,yin,,0,0,0,,可能我用的是蜂窝移动网\\N{\\fs12}Well, I might be on cellular,\r\nDialogue: 0,0:10:18.77,0:10:21.58,yin,,0,0,0,,甚至目前不在网络范围\\N{\\fs12}I might even be out of network range right now,\r\nDialogue: 0,0:10:21.58,0:10:22.98,yin,,0,0,0,,下载会花费很长时间\\N{\\fs12}that could take a very long time.\r\nDialogue: 0,0:10:22.98,0:10:24.38,yin,,0,0,0,,可能要几分钟\\N{\\fs12}It could take minutes, okay,\r\nDialogue: 0,0:10:24.38,0:10:27.02,yin,,0,0,0,,我当然不希望在等待获取URL内容时\\N{\\fs12}well clearly I don't want my user interface, for example,\r\nDialogue: 0,0:10:27.02,0:10:28.90,yin,,0,0,0,,我的用户界面\\N{\\fs12}to be blocked waiting for the network\r\nDialogue: 0,0:10:28.96,0:10:30.55,yin,,0,0,0,,被卡主 无法操作\\N{\\fs12}to give me that URL back. Okay?\r\nDialogue: 0,0:10:30.57,0:10:34.65,yin,,0,0,0,,所以在调用下载操作时\\N{\\fs12}So I have to, basically, call this, do this download,\r\nDialogue: 0,0:10:34.66,0:10:37.14,yin,,0,0,0,,要将网络下载操作放到另一个队列中执行\\N{\\fs12}network download, in a different queue,\r\nDialogue: 0,0:10:37.14,0:10:39.48,yin,,0,0,0,,另一个线程 而非主队列\\N{\\fs12}in a different thread, not the main queue. Okay?\r\nDialogue: 0,0:10:39.97,0:10:43.44,yin,,0,0,0,,iOS中有一个API可以实现这个操作\\N{\\fs12}So there's an API in iOS for doing exactly this,\r\nDialogue: 0,0:10:43.44,0:10:46.25,yin,,0,0,0,,给它一个URL 它就会在另一个线程中执行\\N{\\fs12}you give it a URL and it will go do it in a different thread.\r\nDialogue: 0,0:10:46.53,0:10:49.70,yin,,0,0,0,,当它完成时 需要再调用你\\N{\\fs12}Now, when it's done though, it needs to call you back,\r\nDialogue: 0,0:10:49.80,0:10:51.72,yin,,0,0,0,,告诉你说 我下好这个URL了\\N{\\fs12}and tell you hey, I got that URL,\r\nDialogue: 0,0:10:51.73,0:10:53.26,yin,,0,0,0,,方法很酷\\N{\\fs12}and the way it does that is kind of cool,\r\nDialogue: 0,0:10:53.41,0:10:55.92,yin,,0,0,0,,它会将URL内容下载到一个本地文件中\\N{\\fs12}it downloads the URL to a local file,\r\nDialogue: 0,0:10:56.12,0:10:57.14,yin,,0,0,0,,然后再调用你\\N{\\fs12}and then it calls you back\r\nDialogue: 0,0:10:57.53,0:10:59.44,yin,,0,0,0,,给你一个本地文件的URL\\N{\\fs12}and gives you a URL to the local file.\r\nDialogue: 0,0:10:59.60,0:11:00.77,yin,,0,0,0,,这样就变成本地操作了\\N{\\fs12}So now it's all local,\r\nDialogue: 0,0:11:00.85,0:11:02.77,yin,,0,0,0,,你可以打开文件做各种操作\\N{\\fs12}and so now you can open up the file and do all you want\r\nDialogue: 0,0:11:02.78,0:11:04.07,yin,,0,0,0,,不会阻塞用户界面操作\\N{\\fs12}and it's not going to be blocking\r\nDialogue: 0,0:11:04.09,0:11:06.52,yin,,0,0,0,,因为这时不涉及网络因素了\\N{\\fs12}because you, the network is not a part of it anymore,\r\nDialogue: 0,0:11:06.52,0:11:08.24,yin,,0,0,0,,已经下载好了URL的内容\\N{\\fs12}it's download the contents of the URL.\r\nDialogue: 0,0:11:08.68,0:11:09.93,yin,,0,0,0,,这是它的具体方法\\N{\\fs12}Okay, so here's how that works.\r\nDialogue: 0,0:11:10.21,0:11:11.95,yin,,0,0,0,,先创建一个URL请求\\N{\\fs12}First we create a URL request,\r\nDialogue: 0,0:11:11.97,0:11:14.21,yin,,0,0,0,,URL请求是URL的封装\\N{\\fs12}a URL request is just a wrapper on URL,\r\nDialogue: 0,0:11:14.23,0:11:15.32,yin,,0,0,0,,是这样创建的\\N{\\fs12}you can see I created there,\r\nDialogue: 0,0:11:15.34,0:11:19.89,yin,,0,0,0,,requestWithURL:[NSURL urlWithString以及某个URL\\N{\\fs12}requestWithURL, NSURL, object, urlWithString, some URL.\r\nDialogue: 0,0:11:19.90,0:11:21.60,yin,,0,0,0,,这就是创建URL请求的方法\\N{\\fs12}Okay? So that's how we create a URL request.\r\nDialogue: 0,0:11:21.82,0:11:24.07,yin,,0,0,0,,URL请求比URL功能更多\\N{\\fs12}A URL request is a little more than URL\r\nDialogue: 0,0:11:24.09,0:11:26.70,yin,,0,0,0,,你可以为请求指定其他内容\\N{\\fs12}because you can specify some other things about that request,\r\nDialogue: 0,0:11:26.70,0:11:27.45,yin,,0,0,0,,其他操作\\N{\\fs12}things you want to do,\r\nDialogue: 0,0:11:27.46,0:11:29.34,yin,,0,0,0,,我们通常会直接创建 就像这里一样\\N{\\fs12}and most of the time we just create it, just like this,\r\nDialogue: 0,0:11:29.35,0:11:30.68,yin,,0,0,0,,请求没有其他内容了\\N{\\fs12}and we don't do anything else to the request.\r\nDialogue: 0,0:11:30.68,0:11:35.91,yin,,0,0,0,,现在我们得到了一个URL请求\\N{\\fs12}So now we have a request, a URL, a URL request, and,\r\nDialogue: 0,0:11:35.91,0:11:38.97,yin,,0,0,0,,抱歉 我发不好URL这个音\\N{\\fs12}I apologize in advance for URL, I have trouble saying that,\r\nDialogue: 0,0:11:38.97,0:11:41.34,yin,,0,0,0,,后面我要说好多遍\\N{\\fs12}I'm gonna be saying that 100 times in the next few slides.\r\nDialogue: 0,0:11:42.19,0:11:43.81,yin,,0,0,0,,然后是Configuration配置部分\\N{\\fs12}Then we have this configuration thing,\r\nDialogue: 0,0:11:43.81,0:11:45.22,yin,,0,0,0,,现在不用担心这部分\\N{\\fs12}don't worry about that for now.\r\nDialogue: 0,0:11:45.65,0:11:48.74,yin,,0,0,0,,然后创建的是URLSession会话\\N{\\fs12}And then we have, we create what's called a URLSession.\r\nDialogue: 0,0:11:49.06,0:11:54.31,yin,,0,0,0,,URLSession是一个对象 用来管理一个会话的时间\\N{\\fs12}So URLSession is an object that manages a session of time\r\nDialogue: 0,0:11:54.43,0:11:55.82,yin,,0,0,0,,开始与网络通信\\N{\\fs12}that goes out and talks to the internet\r\nDialogue: 0,0:11:55.83,0:11:57.20,yin,,0,0,0,,得到答案等等\\N{\\fs12}and gets the answer and all this stuff,\r\nDialogue: 0,0:11:57.21,0:11:59.25,yin,,0,0,0,,session会话就是这里要做的主要内容\\N{\\fs12}so the session is the main thing that it's doing here\r\nDialogue: 0,0:11:59.26,0:12:00.93,yin,,0,0,0,,我们会讲讲创建的方法\\N{\\fs12}and we're going to talk about how we create that,\r\nDialogue: 0,0:12:00.93,0:12:05.04,yin,,0,0,0,,因为创建NSURLSession的方法\\N{\\fs12}because how we create the NSURLSession determines where,\r\nDialogue: 0,0:12:05.17,0:12:09.61,yin,,0,0,0,,决定了代码会在哪个线程队列上执行\\N{\\fs12}what thread, which queue, our code is gonna be executed on,\r\nDialogue: 0,0:12:10.01,0:12:12.94,yin,,0,0,0,,现在我们创建了session 我们可以请求它\\N{\\fs12}and so now we have a session and we can ask the session,\r\nDialogue: 0,0:12:12.94,0:12:16.53,yin,,0,0,0,,请创建一个任务 下载该URL\\N{\\fs12}please create us a task which downloads that URL,\r\nDialogue: 0,0:12:16.88,0:12:19.58,yin,,0,0,0,,非常简单 就用downloadTaskWithRequest方法\\N{\\fs12}very simple downloadTaskWithRequest,\r\nDialogue: 0,0:12:19.74,0:12:20.90,yin,,0,0,0,,给它一个URL请求\\N{\\fs12}you give it the URLRequest,\r\nDialogue: 0,0:12:21.16,0:12:22.95,yin,,0,0,0,,然后是一个完成处理程序completionHandler\\N{\\fs12}and then you give it a completionHandler.\r\nDialogue: 0,0:12:23.15,0:12:25.26,yin,,0,0,0,,理解这个completionHandler很重要\\N{\\fs12}Now that completion handler very important to understand,\r\nDialogue: 0,0:12:25.26,0:12:27.49,yin,,0,0,0,,可以看到 它是一个block 对吧\\N{\\fs12}you can see that it's a block. Right?\r\nDialogue: 0,0:12:27.82,0:12:29.29,yin,,0,0,0,,block的参数\\N{\\fs12}The arguments to that block,\r\nDialogue: 0,0:12:29.39,0:12:31.20,yin,,0,0,0,,第一个参数最重要\\N{\\fs12}the first argument is the most important argument,\r\nDialogue: 0,0:12:31.39,0:12:33.87,yin,,0,0,0,,是本地文件URL\\N{\\fs12}that's the URL of the local file\r\nDialogue: 0,0:12:33.87,0:12:35.56,yin,,0,0,0,,网络URL的保存地址\\N{\\fs12}that it put the URL into for you.\r\nDialogue: 0,0:12:36.14,0:12:38.32,yin,,0,0,0,,它将URL内容从网上下载下来\\N{\\fs12}So it downloaded this URL off your internet\r\nDialogue: 0,0:12:38.33,0:12:41.44,yin,,0,0,0,,保存在本地文件中 再返回文件URL\\N{\\fs12}and it put it in a local file and now it's giving you a file URL,\r\nDialogue: 0,0:12:41.44,0:12:45.19,yin,,0,0,0,,不是http:// 而是file:文件URL\\N{\\fs12}not an http// URL, but a file, colon, URL, right?\r\nDialogue: 0,0:12:45.20,0:12:46.74,yin,,0,0,0,,指向本地文件的URL\\N{\\fs12}URL that points to a local file.\r\nDialogue: 0,0:12:47.00,0:12:49.58,yin,,0,0,0,,还有错误和响应参数\\N{\\fs12}And then the other arguments are about errors and responses,\r\nDialogue: 0,0:12:49.58,0:12:50.29,yin,,0,0,0,,不用担心\\N{\\fs12}don't worry about those,\r\nDialogue: 0,0:12:50.30,0:12:52.77,yin,,0,0,0,,主要就是得到这个本地文件\\N{\\fs12}the main thing is you got this local file.\r\nDialogue: 0,0:12:53.01,0:12:55.29,yin,,0,0,0,,然后 在block中\\N{\\fs12}And then inside this block, okay,\r\nDialogue: 0,0:12:55.85,0:12:59.19,yin,,0,0,0,,如果要在这里做UI操作呢\\N{\\fs12}what if you wanted to do UI things here? Okay?\r\nDialogue: 0,0:12:59.68,0:13:03.61,yin,,0,0,0,,如果这个block是在主队列上被执行的\\N{\\fs12}Well, if this block is being executed on the main queue,\r\nDialogue: 0,0:13:03.79,0:13:04.66,yin,,0,0,0,,你就可以这样做\\N{\\fs12}you're good to go.\r\nDialogue: 0,0:13:05.14,0:13:06.92,yin,,0,0,0,,但如果是在其他队列上执行的\\N{\\fs12}But if it's being executed on some other queue,\r\nDialogue: 0,0:13:06.92,0:13:08.75,yin,,0,0,0,,都不能这样做\\N{\\fs12}any other queue, you're not good to go,\r\nDialogue: 0,0:13:08.76,0:13:11.11,yin,,0,0,0,,需要向主队列通信\\N{\\fs12}you're gonna have to talk back to the main queue.\r\nDialogue: 0,0:13:11.28,0:13:12.78,yin,,0,0,0,,我们来看一下这两个示例\\N{\\fs12}So let's look at those two examples.\r\nDialogue: 0,0:13:13.03,0:13:15.19,yin,,0,0,0,,先看一下session会话的创建方法\\N{\\fs12}First of all, let's look at creating the session\r\nDialogue: 0,0:13:15.85,0:13:19.16,yin,,0,0,0,,用这个方法 sessionWithConfiguration\\N{\\fs12}using this method, sessionWithConfiguration,\r\nDialogue: 0,0:13:19.16,0:13:20.42,yin,,0,0,0,,这里也不用考虑配置部分\\N{\\fs12}again, don't worry about configuration,\r\nDialogue: 0,0:13:20.60,0:13:24.87,yin,,0,0,0,,delegate:nil delegateQueue:某个队列\\N{\\fs12}delegate, colon, nil, delegateQueue, colon, some queue.\r\nDialogue: 0,0:13:25.55,0:13:29.60,yin,,0,0,0,,这个NSURLSession有一个委托\\N{\\fs12}Okay? So this NSURLSession thing, it has a delegate.\r\nDialogue: 0,0:13:29.60,0:13:32.53,yin,,0,0,0,,还记得委托吗 我们逐渐熟悉了委托\\N{\\fs12}Remember delegates, we're just getting used to delegates now,\r\nDialogue: 0,0:13:32.53,0:13:35.87,yin,,0,0,0,,希望大家还记得我们用过的动力动画者委托\\N{\\fs12}hopefully you are, remember the dynamic animator delegate that we set\r\nDialogue: 0,0:13:36.01,0:13:38.80,yin,,0,0,0,,它可以告诉我们动画在何时停止\\N{\\fs12}and it told us when all the animation stopped\r\nDialogue: 0,0:13:38.81,0:13:40.90,yin,,0,0,0,,然后将方块炸飞\\N{\\fs12}and then we blew up the blocks? Okay?\r\nDialogue: 0,0:13:40.93,0:13:44.74,yin,,0,0,0,,我们将动画者的一个委托设为控制器\\N{\\fs12}So we just set a delegate of the animator to be the controller\r\nDialogue: 0,0:13:44.77,0:13:46.07,yin,,0,0,0,,控制器实现方法\\N{\\fs12}and the controller implemented the method.\r\nDialogue: 0,0:13:46.07,0:13:46.83,yin,,0,0,0,,这里也是一样\\N{\\fs12}Same thing here.\r\nDialogue: 0,0:13:46.98,0:13:50.10,yin,,0,0,0,,你可以将自己设为这个URLSession的委托\\N{\\fs12}You can set yourself as a delegate to this URLSession,\r\nDialogue: 0,0:13:50.22,0:13:51.89,yin,,0,0,0,,在进行下载时\\N{\\fs12}and as its doing all its downloading,\r\nDialogue: 0,0:13:51.98,0:13:54.82,yin,,0,0,0,,它会向你更新状态 我下载了5000字节\\N{\\fs12}it'll give you updates, oh, I loaded it at 5,000 bytes,\r\nDialogue: 0,0:13:54.82,0:13:57.87,yin,,0,0,0,,又下载了一些 现在下好了文件\\N{\\fs12}I just loaded some more bytes, oh, I've got the file now.\r\nDialogue: 0,0:13:57.87,0:14:00.30,yin,,0,0,0,,我将它保存在了本地磁盘的一个文件中\\N{\\fs12}Okay, I'm putting it into a file, a local disc,\r\nDialogue: 0,0:14:00.30,0:14:01.49,yin,,0,0,0,,它会告诉你这些消息\\N{\\fs12}it'll tell you all these things.\r\nDialogue: 0,0:14:01.73,0:14:03.13,yin,,0,0,0,,你通常不会在意这些内容\\N{\\fs12}Usually you don't care about any of that,\r\nDialogue: 0,0:14:03.14,0:14:04.82,yin,,0,0,0,,只需要它告诉你什么时候完成了\\N{\\fs12}you just want it to tell you when you're done,\r\nDialogue: 0,0:14:04.83,0:14:06.52,yin,,0,0,0,,也就是completionHandler的作用\\N{\\fs12}which is what that completion handler is for.\r\nDialogue: 0,0:14:06.83,0:14:08.55,yin,,0,0,0,,这里我要将委托delegate设为nil\\N{\\fs12}So here I'm going to set my delegate to nil.\r\nDialogue: 0,0:14:08.81,0:14:10.67,yin,,0,0,0,,我不想得到这些杂乱的消息\\N{\\fs12}I don't even want to hear any of that mess,\r\nDialogue: 0,0:14:10.67,0:14:12.95,yin,,0,0,0,,我只希望我的完成处理程序\\N{\\fs12}I just want my completion handler\r\nDialogue: 0,0:14:13.49,0:14:14.96,yin,,0,0,0,,中间的这个 被调用\\N{\\fs12}that you see here, called.\r\nDialogue: 0,0:14:15.56,0:14:18.27,yin,,0,0,0,,而delegateQueue\\N{\\fs12}But, the delegateQueue, okay,\r\nDialogue: 0,0:14:18.27,0:14:21.61,yin,,0,0,0,,代表你所有的委托方法\\N{\\fs12}tells you which queue are all your delegate methods\r\nDialogue: 0,0:14:21.62,0:14:24.11,yin,,0,0,0,,会在哪个队列上被调用\\N{\\fs12}going to be called on, okay?\r\nDialogue: 0,0:14:24.31,0:14:26.60,yin,,0,0,0,,可以指定为主队列 这里就是\\N{\\fs12}And you can specify the main queue, as we have here,\r\nDialogue: 0,0:14:26.60,0:14:28.18,yin,,0,0,0,,还可以指定其他队列\\N{\\fs12}or you can specify some other queue.\r\nDialogue: 0,0:14:29.15,0:14:31.32,yin,,0,0,0,,这里还可以用nil\\N{\\fs12}Okay? You can even pass nil here\r\nDialogue: 0,0:14:31.33,0:14:33.47,yin,,0,0,0,,它会为你随机分配一个队列\\N{\\fs12}and it'll just make up a queue for you, a random queue.\r\nDialogue: 0,0:14:34.14,0:14:36.34,yin,,0,0,0,,所以即便这里没有使用委托方法\\N{\\fs12}So even though we're not doing delegate methods here,\r\nDialogue: 0,0:14:36.34,0:14:38.05,yin,,0,0,0,,也有完成处理程序\\N{\\fs12}we are having that completion handler,\r\nDialogue: 0,0:14:38.05,0:14:39.70,yin,,0,0,0,,它会在委托的那个队列上\\N{\\fs12}and it calls your completion handler\r\nDialogue: 0,0:14:39.70,0:14:41.41,yin,,0,0,0,,调用完成处理程序\\N{\\fs12}on the same queue as the delegates.\r\nDialogue: 0,0:14:41.49,0:14:43.53,yin,,0,0,0,,所以delegateQueue这行代码\\N{\\fs12}So that's why that delegateQueue line there\r\nDialogue: 0,0:14:43.54,0:14:44.34,yin,,0,0,0,,非常重要\\N{\\fs12}is really important.\r\nDialogue: 0,0:14:44.61,0:14:47.13,yin,,0,0,0,,这行代码表示调用我的完成处理程序\\N{\\fs12}What that says is call my completion handler,\r\nDialogue: 0,0:14:47.18,0:14:48.85,yin,,0,0,0,,如果有委托方法 同样调用\\N{\\fs12}and all my delegate methods if I had them,\r\nDialogue: 0,0:14:49.17,0:14:51.61,yin,,0,0,0,,在这个队列上调用我的完成处理程序\\N{\\fs12}call my completion handler on this queue,\r\nDialogue: 0,0:14:51.61,0:14:53.45,yin,,0,0,0,,我指定了主队列\\N{\\fs12}and I've specified the main queue.\r\nDialogue: 0,0:14:53.81,0:14:55.05,yin,,0,0,0,,代表下面这里\\N{\\fs12}So that means the code\r\nDialogue: 0,0:14:55.07,0:14:57.81,yin,,0,0,0,,completionHandler中的代码\\N{\\fs12}that's inside my completion handler block down there,\r\nDialogue: 0,0:14:57.89,0:15:00.96,yin,,0,0,0,,黄色部分 写着可以直接做UI操作\\N{\\fs12}the part in yellow that says yes, can do UI things directly,\r\nDialogue: 0,0:15:01.23,0:15:02.96,yin,,0,0,0,,这段代码会在主队列上被执行\\N{\\fs12}that's being executed on the main queue.\r\nDialogue: 0,0:15:02.96,0:15:05.06,yin,,0,0,0,,它会被放到主队列的待运行队列上\\N{\\fs12}It gets put in line to run on the main queue,\r\nDialogue: 0,0:15:05.06,0:15:06.20,yin,,0,0,0,,主队列无操作时\\N{\\fs12}and when the main queue is quiet,\r\nDialogue: 0,0:15:06.58,0:15:07.97,yin,,0,0,0,,会抓取这段代码并执行它\\N{\\fs12}it'll grab it and execute it.\r\nDialogue: 0,0:15:08.21,0:15:10.33,yin,,0,0,0,,所以我可以在这里做任意UI操作\\N{\\fs12}So I can do whatever I want UI-wise in here.\r\nDialogue: 0,0:15:10.33,0:15:11.27,yin,,0,0,0,,因为我在主队列中\\N{\\fs12}I'm on the main queue.\r\nDialogue: 0,0:15:11.54,0:15:14.28,yin,,0,0,0,,反过来说 不要在这里做开销大的操作\\N{\\fs12}Now, conversely, I wouldn't want to do anything expensive here,\r\nDialogue: 0,0:15:14.28,0:15:16.70,yin,,0,0,0,,比如查看和解析URL\\N{\\fs12}like, look in the URL and parse it\r\nDialogue: 0,0:15:16.70,0:15:19.09,yin,,0,0,0,,构建大型数据结构等等\\N{\\fs12}and build some huge data structure and all this stuff,\r\nDialogue: 0,0:15:19.09,0:15:21.09,yin,,0,0,0,,有可能会阻塞主队列的操作\\N{\\fs12}something that might block the main queue, right?\r\nDialogue: 0,0:15:21.22,0:15:22.72,yin,,0,0,0,,会花费很长时间\\N{\\fs12}By being, taking a long time.\r\nDialogue: 0,0:15:23.01,0:15:25.97,yin,,0,0,0,,真的会花费很长时间\\N{\\fs12}I mean, it would have to really take a long time, but, you know,\r\nDialogue: 0,0:15:26.19,0:15:27.13,yin,,0,0,0,,你肯定不想在那个block中\\N{\\fs12}or you certainly wouldn't want\r\nDialogue: 0,0:15:27.14,0:15:29.89,yin,,0,0,0,,再增加一个网络调用\\N{\\fs12}to make another network call in that block, okay?\r\nDialogue: 0,0:15:31.22,0:15:33.14,yin,,0,0,0,,但最重要的是\\N{\\fs12}But, mostly, most importantly,\r\nDialogue: 0,0:15:33.15,0:15:35.05,yin,,0,0,0,,可以在这里使用UI调用\\N{\\fs12}I can make UI calls here, I could update,\r\nDialogue: 0,0:15:35.05,0:15:38.27,yin,,0,0,0,,如果这是个图片URL 我可以更新UI显示出来\\N{\\fs12}if this was an image URL, I could update my UI to show the image\r\nDialogue: 0,0:15:38.27,0:15:39.29,yin,,0,0,0,,或者其他操作\\N{\\fs12}or whatever I want it to do.\r\nDialogue: 0,0:15:39.57,0:15:41.89,yin,,0,0,0,,因为我已经指定了它会在主队列上执行\\N{\\fs12}Because I've specified that it's gonna run in the main queue.\r\nDialogue: 0,0:15:43.08,0:15:43.73,yin,,0,0,0,,有问题吗\\N{\\fs12}Okay? Question?\r\nDialogue: 0,0:15:45.52,0:15:49.71,yin,,0,0,0,,学生提问\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,0:15:49.71,0:15:51.96,yin,,0,0,0,,问题是 队列是否会\\N{\\fs12}The question is does a queue finish a block\r\nDialogue: 0,0:15:51.98,0:15:53.76,yin,,0,0,0,,先完成队列中的一个block\\N{\\fs12}that it takes out of the queue first\r\nDialogue: 0,0:15:53.77,0:15:55.05,yin,,0,0,0,,然后再抓取下一个\\N{\\fs12}before it grabs another one?\r\nDialogue: 0,0:15:55.30,0:15:56.85,yin,,0,0,0,,是的 串行队列是这样的\\N{\\fs12}Yes. If it's a serial queue,\r\nDialogue: 0,0:15:56.86,0:15:58.38,yin,,0,0,0,,我们讲的就是这种队列\\N{\\fs12}which is the kind of queues we're talking about.\r\nDialogue: 0,0:15:58.71,0:16:00.92,yin,,0,0,0,,会连续地按照顺序执行\\N{\\fs12}Yes. It, it does them in order, serially.\r\nDialogue: 0,0:16:02.69,0:16:05.30,yin,,0,0,0,,我们来看另一个例子\\N{\\fs12}Okay. So now let's look at a different case.\r\nDialogue: 0,0:16:05.45,0:16:07.45,yin,,0,0,0,,如果创建NSURLSession时\\N{\\fs12}What if we created NSURLSession\r\nDialogue: 0,0:16:07.65,0:16:09.58,yin,,0,0,0,,不指定委托队列delegateQueue呢\\N{\\fs12}that does not specify the delegateQueue?\r\nDialogue: 0,0:16:09.69,0:16:12.63,yin,,0,0,0,,直接用NSURLSession sessionWithConfiguration\\N{\\fs12}So I just use NSURLSession, sessionWithConfiguration,\r\nDialogue: 0,0:16:12.91,0:16:15.22,yin,,0,0,0,,没有delegat或delegateQueue参数\\N{\\fs12}no delegate, or delegateQueue argument there.\r\nDialogue: 0,0:16:15.63,0:16:17.82,yin,,0,0,0,,这个例子不用主队列\\N{\\fs12}This case does not use the main queue,\r\nDialogue: 0,0:16:17.82,0:16:18.95,yin,,0,0,0,,而是另外一个队列\\N{\\fs12}it uses a different queue.\r\nDialogue: 0,0:16:19.37,0:16:20.58,yin,,0,0,0,,没有委托\\N{\\fs12}Okay? There's no delegate,\r\nDialogue: 0,0:16:20.80,0:16:25.58,yin,,0,0,0,,所以也不用指定委托方法\\N{\\fs12}so, there's no need to have the delegate method specified.\r\nDialogue: 0,0:16:25.78,0:16:28.88,yin,,0,0,0,,但回调函数 这个completionHandler\\N{\\fs12}But, the callback, okay, this completion handler\r\nDialogue: 0,0:16:29.03,0:16:32.15,yin,,0,0,0,,会在另一个队列上执行 而不是主队列\\N{\\fs12}gets executed on a different queue, not on the main queue.\r\nDialogue: 0,0:16:32.53,0:16:34.03,yin,,0,0,0,,因为我没有指定主队列\\N{\\fs12}Okay? Because I haven't specified the main queue\r\nDialogue: 0,0:16:34.03,0:16:35.54,yin,,0,0,0,,为其所在执行队列\\N{\\fs12}as the queue I want it to execute on.\r\nDialogue: 0,0:16:36.07,0:16:38.55,yin,,0,0,0,,所以在这个例子中 如果我要做UI操作\\N{\\fs12}So in this case, if I want to do UI stuff,\r\nDialogue: 0,0:16:39.06,0:16:42.82,yin,,0,0,0,,需要再增加一个block\\N{\\fs12}I have to make another block of stuff\r\nDialogue: 0,0:16:42.97,0:16:45.03,yin,,0,0,0,,将其放到主队列上\\N{\\fs12}and put it onto the main queue.\r\nDialogue: 0,0:16:45.70,0:16:47.87,yin,,0,0,0,,我可以用dispatch_async\\N{\\fs12}And I can do that either with dispatch async,\r\nDialogue: 0,0:16:47.94,0:16:50.43,yin,,0,0,0,,dispatch_get_main_queue 加一个block\\N{\\fs12}dispatch_get_main_queue, a block,\r\nDialogue: 0,0:16:50.55,0:16:52.60,yin,,0,0,0,,里面是要做的UI操作\\N{\\fs12}with this stuff, UI stuff I want to do,\r\nDialogue: 0,0:16:52.79,0:16:55.43,yin,,0,0,0,,或者用self performSelectorOnMainThread\\N{\\fs12}or I could do self performSelectorOnMainThread\r\nDialogue: 0,0:16:55.59,0:16:57.67,yin,,0,0,0,,加上主队列上的方法\\N{\\fs12}with some method on the main queue,\r\nDialogue: 0,0:16:57.97,0:17:00.18,yin,,0,0,0,,或者是要执行的方法\\N{\\fs12}or method that I want to execute,\r\nDialogue: 0,0:17:00.18,0:17:01.72,yin,,0,0,0,,它就会在主队列上被调用\\N{\\fs12}and it'll be called on the main queue.\r\nDialogue: 0,0:17:02.56,0:17:05.42,yin,,0,0,0,,知道为什么这里我要这样做吗\\N{\\fs12}Okay? So do you see why I had to do that in this case?\r\nDialogue: 0,0:17:05.73,0:17:07.23,yin,,0,0,0,,因为这个completionHandler\\N{\\fs12}Because this completionHandler\r\nDialogue: 0,0:17:07.34,0:17:08.69,yin,,0,0,0,,不是在主队列上被调用的\\N{\\fs12}is not being called on the main queue,\r\nDialogue: 0,0:17:08.70,0:17:10.06,yin,,0,0,0,,是在另外一个队列上\\N{\\fs12}it's being called on a different queue.\r\nDialogue: 0,0:17:10.40,0:17:12.78,yin,,0,0,0,,这就是iOS中要理解的一点\\N{\\fs12}So this is what, what you need to understand in iOS is,\r\nDialogue: 0,0:17:13.03,0:17:16.62,yin,,0,0,0,,将block传递给某个方法时\\N{\\fs12}when I have a block that's passed to some method,\r\nDialogue: 0,0:17:16.88,0:17:18.70,yin,,0,0,0,,要知道它会在哪个队列上被调用\\N{\\fs12}what queue is it going to be called on.\r\nDialogue: 0,0:17:18.90,0:17:21.44,yin,,0,0,0,,大多数情况下 向iOS方法传递block时\\N{\\fs12}Now most time when you pass a block to an iOS method,\r\nDialogue: 0,0:17:21.50,0:17:23.50,yin,,0,0,0,,会在调用该方法的那个队列上\\N{\\fs12}it's going to call it on the same queue\r\nDialogue: 0,0:17:23.65,0:17:24.96,yin,,0,0,0,,调用这个block\\N{\\fs12}that you called that method on.\r\nDialogue: 0,0:17:25.15,0:17:27.19,yin,,0,0,0,,调用任意方法 给它一个block\\N{\\fs12}Whatever method you called and you handed it a block,\r\nDialogue: 0,0:17:27.44,0:17:29.34,yin,,0,0,0,,大多数情况下 会在同一个队列上进行回调\\N{\\fs12}it'll call you back on the same queue, most of the time.\r\nDialogue: 0,0:17:29.82,0:17:32.60,yin,,0,0,0,,但如果是像这里的这个方法一样\\N{\\fs12}But if the method, like this one,\r\nDialogue: 0,0:17:32.61,0:17:34.74,yin,,0,0,0,,在执行过程中 在其他队列上做了操作\\N{\\fs12}goes off and does something in another queue,\r\nDialogue: 0,0:17:34.84,0:17:37.02,yin,,0,0,0,,就可能会在另一个队列上进行回调\\N{\\fs12}then it's probably gonna call you back in some other queue,\r\nDialogue: 0,0:17:37.03,0:17:39.54,yin,,0,0,0,,除非你为其指定了主队列\\N{\\fs12}unless you specify the main queue, okay?\r\nDialogue: 0,0:17:40.07,0:17:40.51,yin,,0,0,0,,有问题吗\\N{\\fs12}Question?\r\nDialogue: 0,0:17:41.35,0:17:43.93,yin,,0,0,0,,[学生提问]\\N{\\fs12}[Student: inaudible]\r\nDialogue: 0,0:17:44.39,0:17:46.91,yin,,0,0,0,,dispatch_async调用是线程安全的吗\\N{\\fs12}Is the call dispatch async thread safe?\r\nDialogue: 0,0:17:46.91,0:17:48.30,yin,,0,0,0,,是的\\N{\\fs12}And the answer is yes it is.\r\nDialogue: 0,0:17:48.38,0:17:50.85,yin,,0,0,0,,实际上 你可以将其用于线程同步\\N{\\fs12}And so you can use it for thread synchronization, actually,\r\nDialogue: 0,0:17:50.95,0:17:52.14,yin,,0,0,0,,因为它是线程安全的\\N{\\fs12}because it is thread safe.\r\nDialogue: 0,0:17:52.14,0:17:54.89,yin,,0,0,0,,它是原子调用 是原子的\\N{\\fs12}It's an atomic call, okay, it happens atomically.\r\nDialogue: 0,0:17:54.90,0:17:55.93,yin,,0,0,0,,其他操作出现时\\N{\\fs12}It can't be interrupted\r\nDialogue: 0,0:17:56.27,0:17:58.00,yin,,0,0,0,,它不会被中断\\N{\\fs12}by something else coming in and doing it.\r\nDialogue: 0,0:17:58.16,0:17:59.43,yin,,0,0,0,,这是个好问题\\N{\\fs12}So, that's a good question.\r\nDialogue: 0,0:18:00.51,0:18:03.62,yin,,0,0,0,,大家注意到这个task resume了吗\\N{\\fs12}Notice all, the small thing, you notice I have task resume,\r\nDialogue: 0,0:18:03.62,0:18:04.68,yin,,0,0,0,,看到这个恢复任务了吗\\N{\\fs12}you see that task resume?\r\nDialogue: 0,0:18:04.90,0:18:07.30,yin,,0,0,0,,如果用它创建了一个下载任务\\N{\\fs12}When you create a download task using this,\r\nDialogue: 0,0:18:07.47,0:18:10.78,yin,,0,0,0,,开始时会被挂起 也就是暂停下载\\N{\\fs12}it starts out suspended, in other words, not downloaded.\r\nDialogue: 0,0:18:11.23,0:18:14.20,yin,,0,0,0,,所以你需要立刻重新开始下载\\N{\\fs12}So you have to immediately resume it to start it, okay?\r\nDialogue: 0,0:18:14.20,0:18:16.04,yin,,0,0,0,,重新开始操作\\N{\\fs12}Now that resume is going to start something\r\nDialogue: 0,0:18:16.06,0:18:18.18,yin,,0,0,0,,会在另一个线程执行 而非主队列\\N{\\fs12}happening in a different thread, not on a main thread,\r\nDialogue: 0,0:18:18.46,0:18:20.11,yin,,0,0,0,,但也要恢复任务\\N{\\fs12}but still, task resume,\r\nDialogue: 0,0:18:20.12,0:18:22.55,yin,,0,0,0,,不要忘了task resume\\N{\\fs12}don't forget the task resume, okay?\r\nDialogue: 0,0:18:23.40,0:18:24.66,yin,,0,0,0,,这就是多线程的内容\\N{\\fs12}Okay, that's it for multithreading.\r\nDialogue: 0,0:18:24.69,0:18:25.93,yin,,0,0,0,,我会在示例中演示\\N{\\fs12}I'm going to do it in the demo,\r\nDialogue: 0,0:18:26.09,0:18:27.44,yin,,0,0,0,,大家还会再看一遍\\N{\\fs12}so you'll get another look at it.\r\nDialogue: 0,0:18:27.81,0:18:29.06,yin,,0,0,0,,大家要在作业中实现这部分\\N{\\fs12}You'll be doing it in your homework\r\nDialogue: 0,0:18:29.06,0:18:30.15,yin,,0,0,0,,所以你们会熟悉它的\\N{\\fs12}so you'll get a feel for it.\r\nDialogue: 0,0:18:30.42,0:18:32.02,yin,,0,0,0,,主要就是要理解这个思路\\N{\\fs12}The idea here is to get this idea,\r\nDialogue: 0,0:18:32.03,0:18:33.43,yin,,0,0,0,,主队列和其他队列\\N{\\fs12}this main queue and these other queues,\r\nDialogue: 0,0:18:33.44,0:18:35.73,yin,,0,0,0,,在其他队列中做任何操作时\\N{\\fs12}and that I have to post back to the main queue\r\nDialogue: 0,0:18:35.74,0:18:37.52,yin,,0,0,0,,都要向主队列回传消息\\N{\\fs12}anytime I'm doing something on another queue.\r\nDialogue: 0,0:18:38.79,0:18:40.37,yin,,0,0,0,,然后是UIScrollView滚动视图\\N{\\fs12}Okay. UIScrollView.\r\nDialogue: 0,0:18:40.37,0:18:42.56,yin,,0,0,0,,UIScrollView是一个很重要的视图\\N{\\fs12}So UIScrollView is a really important view.\r\nDialogue: 0,0:18:42.98,0:18:45.02,yin,,0,0,0,,iPhone屏幕很小\\N{\\fs12}You know, the iPhone screen,\r\nDialogue: 0,0:18:45.04,0:18:46.89,yin,,0,0,0,,任何能装进口袋的设备\\N{\\fs12}anything that's going to fit in your pocket\r\nDialogue: 0,0:18:46.90,0:18:48.02,yin,,0,0,0,,屏幕都很小\\N{\\fs12}is going to have a small screen,\r\nDialogue: 0,0:18:48.23,0:18:49.27,yin,,0,0,0,,但你可能想用它\\N{\\fs12}but you might want to have it\r\nDialogue: 0,0:18:49.28,0:18:51.69,yin,,0,0,0,,看很多信息\\N{\\fs12}looking at a lot of information, okay?\r\nDialogue: 0,0:18:51.88,0:18:53.32,yin,,0,0,0,,希望能够轻松导航至所需位置\\N{\\fs12}And you want to easily navigate through that.\r\nDialogue: 0,0:18:53.32,0:18:54.73,yin,,0,0,0,,这里有一小段视频\\N{\\fs12}Now I have this little video here,\r\nDialogue: 0,0:18:54.74,0:18:56.77,yin,,0,0,0,,好像是iOS4的\\N{\\fs12}this is like from iOS 4, or something,\r\nDialogue: 0,0:18:56.78,0:18:57.80,yin,,0,0,0,,所以这里...\\N{\\fs12}that's why I left it with the...\r\nDialogue: 0,0:18:58.16,0:19:00.89,yin,,0,0,0,,所以用的是旧款iPhone的背景\\N{\\fs12}or it has the old background, the old kind of phone,\r\nDialogue: 0,0:19:01.15,0:19:03.45,yin,,0,0,0,,但它能很好地展示滚动视图的作用\\N{\\fs12}but it's really good at showing what scroll view can do,\r\nDialogue: 0,0:19:03.45,0:19:06.95,yin,,0,0,0,,滚动视图中可以添加任意视图\\N{\\fs12}because you can put any kind of view in a scroll view,\r\nDialogue: 0,0:19:06.95,0:19:08.47,yin,,0,0,0,,包括另一个滚动视图\\N{\\fs12}including another scroll view.\r\nDialogue: 0,0:19:09.17,0:19:10.65,yin,,0,0,0,,可以看到这里的滚动视图\\N{\\fs12}So you can see that I've got a scroll view\r\nDialogue: 0,0:19:10.66,0:19:11.94,yin,,0,0,0,,是水平滚动的\\N{\\fs12}that's scrolling horizontally,\r\nDialogue: 0,0:19:11.96,0:19:14.05,yin,,0,0,0,,而其中内容是垂直滚动的\\N{\\fs12}and the things in it are scrolling vertically.\r\nDialogue: 0,0:19:14.48,0:19:15.97,yin,,0,0,0,,这是一个股票应用\\N{\\fs12}Okay? Or here's a stock app\r\nDialogue: 0,0:19:16.14,0:19:17.63,yin,,0,0,0,,多个滚动视图\\N{\\fs12}where I'm going scrolling horizontally\r\nDialogue: 0,0:19:17.88,0:19:19.69,yin,,0,0,0,,可以水平滚动\\N{\\fs12}through other scroll views\r\nDialogue: 0,0:19:19.76,0:19:21.69,yin,,0,0,0,,而每个视图内部可以垂直滚动\\N{\\fs12}that can scroll vertically inside of them.\r\nDialogue: 0,0:19:22.17,0:19:22.71,yin,,0,0,0,,看到了吗\\N{\\fs12}You see that?\r\nDialogue: 0,0:19:23.00,0:19:24.91,yin,,0,0,0,,所以这里可以显示出很多信息\\N{\\fs12}So I can present a lot of information here,\r\nDialogue: 0,0:19:24.91,0:19:26.42,yin,,0,0,0,,不只有股票报价\\N{\\fs12}not just the stock ticker value,\r\nDialogue: 0,0:19:26.55,0:19:29.40,yin,,0,0,0,,还有某只股票的新闻 图表等等\\N{\\fs12}but news about a stock, charts, etc.,\r\nDialogue: 0,0:19:29.51,0:19:31.42,yin,,0,0,0,,通过滚动可以轻松获取\\N{\\fs12}and I can just easily get at them by scrolling through.\r\nDialogue: 0,0:19:31.42,0:19:34.48,yin,,0,0,0,,滚动视图是一个非常强大的设计视图\\N{\\fs12}So scroll view is a really powerfully designed view\r\nDialogue: 0,0:19:34.49,0:19:37.71,yin,,0,0,0,,可以在滚动区域放几乎任何对象\\N{\\fs12}that lets you put almost anything in the area it scrolls,\r\nDialogue: 0,0:19:37.85,0:19:39.14,yin,,0,0,0,,包括其他滚动视图\\N{\\fs12}including other scroll views.\r\nDialogue: 0,0:19:39.78,0:19:43.07,yin,,0,0,0,,我们来看一下滚动视图的用法\\N{\\fs12}Okay? So, let's look at how scroll view works.\r\nDialogue: 0,0:19:43.74,0:19:47.70,yin,,0,0,0,,可以为滚动视图添加子视图\\N{\\fs12}Scroll view is really just a view that you add subviews to,\r\nDialogue: 0,0:19:47.70,0:19:49.31,yin,,0,0,0,,但它会特别处理这些子视图\\N{\\fs12}but it treats those subviews specially,\r\nDialogue: 0,0:19:49.31,0:19:51.36,yin,,0,0,0,,因为它允许你对其进行滚动和缩放\\N{\\fs12}because it lets you scroll around them and zoom in on them.\r\nDialogue: 0,0:19:51.48,0:19:54.96,yin,,0,0,0,,大家知道如何向普通UIView添加子视图吧\\N{\\fs12}So you know how to add a subview to a normal UIView, right?\r\nDialogue: 0,0:19:54.96,0:19:57.58,yin,,0,0,0,,只要设好子视图的frame 调用addSubview\\N{\\fs12}You just set the frame to subview, you call addSubview,\r\nDialogue: 0,0:19:57.58,0:20:00.32,yin,,0,0,0,,它就会显示在视图中了 很简单\\N{\\fs12}bloop, it appears in the view, easy.\r\nDialogue: 0,0:20:00.54,0:20:04.83,yin,,0,0,0,,即使你对一个很大的视图使用addSubview\\N{\\fs12}Even if you have a huge view and you say addSubview,\r\nDialogue: 0,0:20:05.24,0:20:07.42,yin,,0,0,0,,它会添加这个子视图\\N{\\fs12}somewhere down there, oop, it gets added,\r\nDialogue: 0,0:20:07.43,0:20:08.87,yin,,0,0,0,,但是当然了 你没有办法看到整个视图\\N{\\fs12}but, of course, you can't see the whole view.\r\nDialogue: 0,0:20:08.87,0:20:11.73,yin,,0,0,0,,你可以缩小它\\N{\\fs12}Now you could shrink the view way down small,\r\nDialogue: 0,0:20:11.74,0:20:13.59,yin,,0,0,0,,但那样就会像这幅斯坦福的图片一样\\N{\\fs12}but then, like this Stanford picture,\r\nDialogue: 0,0:20:13.59,0:20:15.60,yin,,0,0,0,,几乎什么都看不清楚\\N{\\fs12}you'd hardly even be able to see anything. Okay?\r\nDialogue: 0,0:20:15.84,0:20:16.59,yin,,0,0,0,,所以这里我们真正想要做的是\\N{\\fs12}So really what we want to do\r\nDialogue: 0,0:20:16.60,0:20:18.59,yin,,0,0,0,,滚动查看它们\\N{\\fs12}is be able to scroll around on these things.\r\nDialogue: 0,0:20:18.59,0:20:22.14,yin,,0,0,0,,如何向UIScrollView添加子视图呢\\N{\\fs12}So, how does this work adding subviews to UIScrollView?\r\nDialogue: 0,0:20:22.39,0:20:24.28,yin,,0,0,0,,有一点很重要\\N{\\fs12}Well, there's one really important thing,\r\nDialogue: 0,0:20:24.28,0:20:26.86,yin,,0,0,0,,这是UIScrollview的要点\\N{\\fs12}this is the take-home point on UIScrollview.\r\nDialogue: 0,0:20:28.03,0:20:29.68,yin,,0,0,0,,要设置它的contentSize\\N{\\fs12}You got to set its contentSize.\r\nDialogue: 0,0:20:30.06,0:20:32.49,yin,,0,0,0,,它有一个属性叫做contentSize\\N{\\fs12}So it has a property, called contentSize,\r\nDialogue: 0,0:20:32.61,0:20:35.47,yin,,0,0,0,,尺寸很大\\N{\\fs12}which is just a big size, and it makes the area\r\nDialogue: 0,0:20:35.55,0:20:37.43,yin,,0,0,0,,它代表滚动视图要滚动的区域\\N{\\fs12}that the scroll view is going to scroll around on.\r\nDialogue: 0,0:20:37.85,0:20:42.23,yin,,0,0,0,,我设置了一个很大的contentSize 3000*2000\\N{\\fs12}Okay? This, I made a big contentSize here, 3,000 by 2,000.\r\nDialogue: 0,0:20:42.53,0:20:47.49,yin,,0,0,0,,现在再向滚动视图添加子视图时\\N{\\fs12}Then, now when you add subview to the scroll view,\r\nDialogue: 0,0:20:47.89,0:20:50.24,yin,,0,0,0,,它会将它放入其内容区域中\\N{\\fs12}it puts it in its content area, essentially.\r\nDialogue: 0,0:20:50.43,0:20:53.58,yin,,0,0,0,,这里我添加了subview1 是斯坦福的标志\\N{\\fs12}So here I put this subview1, which is the Stanford logo,\r\nDialogue: 0,0:20:53.68,0:20:56.62,yin,,0,0,0,,向右2700 向下100 看到了吗\\N{\\fs12}2,700 across, 100 hundred down, you see that?\r\nDialogue: 0,0:20:57.03,0:20:59.69,yin,,0,0,0,,再将那个大的子视图放进去\\N{\\fs12}And then let's put that big one in there, somewhere.\r\nDialogue: 0,0:21:00.12,0:21:03.65,yin,,0,0,0,,放到50,100的位置上\\N{\\fs12}Okay, I put it 50 by 100 in there.\r\nDialogue: 0,0:21:04.19,0:21:05.49,yin,,0,0,0,,这时滚动视图要做的是\\N{\\fs12}And now what the scroll view is going to do\r\nDialogue: 0,0:21:05.50,0:21:09.06,yin,,0,0,0,,为内容区域提供一个窗口\\N{\\fs12}is really kind of provide a window on that content area.\r\nDialogue: 0,0:21:09.48,0:21:12.55,yin,,0,0,0,,随着用户用手指来回滚动\\N{\\fs12}So as the user scrolls around, with their finger,\r\nDialogue: 0,0:21:12.90,0:21:15.05,yin,,0,0,0,,它就会随着移动\\N{\\fs12}it's essentially going to move around\r\nDialogue: 0,0:21:15.18,0:21:18.35,yin,,0,0,0,,显示出内容区域的内容\\N{\\fs12}showing you what's in that content area, alright?\r\nDialogue: 0,0:21:19.15,0:21:19.69,yin,,0,0,0,,明白吗\\N{\\fs12}Does that make sense?\r\nDialogue: 0,0:21:19.69,0:21:21.57,yin,,0,0,0,,滚动视图就是这样的\\N{\\fs12}So that's all scrolling is, really,\r\nDialogue: 0,0:21:21.87,0:21:23.61,yin,,0,0,0,,对它进行拖动时就是这样的\\N{\\fs12}when it comes to the panning part of it.\r\nDialogue: 0,0:21:24.81,0:21:26.97,yin,,0,0,0,,这些视图的位置可以随意更改\\N{\\fs12}And you can position these views anywhere you want,\r\nDialogue: 0,0:21:26.97,0:21:29.06,yin,,0,0,0,,所以如果我将斯坦福标志移到这里\\N{\\fs12}so if I move this Stanford logo here\r\nDialogue: 0,0:21:29.22,0:21:32.13,yin,,0,0,0,,将大的子视图移到左上角\\N{\\fs12}and then I move that huge thing to the upper corner,\r\nDialogue: 0,0:21:32.23,0:21:34.84,yin,,0,0,0,,将contentSize缩小一点\\N{\\fs12}maybe I change my contentSize to be smaller,\r\nDialogue: 0,0:21:35.17,0:21:36.86,yin,,0,0,0,,包含两个子视图\\N{\\fs12}to include the views, okay,\r\nDialogue: 0,0:21:37.07,0:21:39.09,yin,,0,0,0,,现在依旧可以来回滚动\\N{\\fs12}now, again, I can scroll around,\r\nDialogue: 0,0:21:40.26,0:21:42.93,yin,,0,0,0,,可以看到各部分 这里是斯坦福标志\\N{\\fs12}and you can see various parts, there's that Stanford logo,\r\nDialogue: 0,0:21:42.94,0:21:44.80,yin,,0,0,0,,它与下面的视图重叠了\\N{\\fs12}it's kind of overlapping the, the view here,\r\nDialogue: 0,0:21:44.80,0:21:48.29,yin,,0,0,0,,因为这两个视图与内容区域重叠了\\N{\\fs12}because those two views overlapping the content area, etc.\r\nDialogue: 0,0:21:48.30,0:21:49.33,yin,,0,0,0,,就是这么简单\\N{\\fs12}So it's as simple as that.\r\nDialogue: 0,0:21:49.36,0:21:51.07,yin,,0,0,0,,只要设置好contentSize\\N{\\fs12}It's all about that contentSize thing.\r\nDialogue: 0,0:21:51.60,0:21:54.06,yin,,0,0,0,,作为程序员 你可能想要知道\\N{\\fs12}Now, as a programmer, you might want to know\r\nDialogue: 0,0:21:54.06,0:21:56.84,yin,,0,0,0,,用户当前所视位置\\N{\\fs12}where is the current, the user currently looking,\r\nDialogue: 0,0:21:56.98,0:21:58.65,yin,,0,0,0,,是内容区域的哪部分\\N{\\fs12}okay, in my content area.\r\nDialogue: 0,0:21:58.96,0:22:01.98,yin,,0,0,0,,可以通过滚动视图的一个属性得到\\N{\\fs12}And the way to get that is the scroll view property\r\nDialogue: 0,0:22:01.98,0:22:03.11,yin,,0,0,0,,contentOffset\\N{\\fs12}contentOffset.\r\nDialogue: 0,0:22:03.65,0:22:06.48,yin,,0,0,0,,它可以告诉你当前显示区域\\N{\\fs12}It tells you the X and Y of the upper left corner\r\nDialogue: 0,0:22:06.79,0:22:08.61,yin,,0,0,0,,左上角的X和Y的坐标\\N{\\fs12}of the area that's being viewed.\r\nDialogue: 0,0:22:09.46,0:22:11.20,yin,,0,0,0,,这是很重要的一部分\\N{\\fs12}Okay? So that's an important part of it.\r\nDialogue: 0,0:22:11.43,0:22:12.76,yin,,0,0,0,,另外一项你要知道的内容是\\N{\\fs12}The other thing you want to know is\r\nDialogue: 0,0:22:12.87,0:22:16.11,yin,,0,0,0,,用户所示区域的边界bounds\\N{\\fs12}what's the bounds of the area the user is looking at,\r\nDialogue: 0,0:22:16.27,0:22:17.44,yin,,0,0,0,,这部分有点...\\N{\\fs12}and somewhat,\r\nDialogue: 0,0:22:18.52,0:22:20.22,yin,,0,0,0,,有些人在理解这部分时遇到了困难\\N{\\fs12}some people had a little trouble understanding this,\r\nDialogue: 0,0:22:20.22,0:22:20.95,yin,,0,0,0,,但其实很简单\\N{\\fs12}but it's very simple,\r\nDialogue: 0,0:22:21.11,0:22:23.72,yin,,0,0,0,,就是滚动视图的边界\\N{\\fs12}that bounds is actually just the scroll views bounds.\r\nDialogue: 0,0:22:23.88,0:22:25.26,yin,,0,0,0,,滚动视图是个视图\\N{\\fs12}Okay? The scroll view is a view,\r\nDialogue: 0,0:22:25.41,0:22:27.57,yin,,0,0,0,,它有边界 self.bounds\\N{\\fs12}it has bounds, self dot bounds,\r\nDialogue: 0,0:22:27.78,0:22:30.97,yin,,0,0,0,,它的边界就是用户所视区域的范围\\N{\\fs12}and that bounds is the area that's being looked at.\r\nDialogue: 0,0:22:31.15,0:22:35.12,yin,,0,0,0,,这个边界是在内容区域的坐标系中的\\N{\\fs12}Now that bounds is in the content areas coordinate system,\r\nDialogue: 0,0:22:35.57,0:22:37.91,yin,,0,0,0,,你可能不想要它 你想要知道的是\\N{\\fs12}okay, and you may not want that, you might want to know\r\nDialogue: 0,0:22:38.08,0:22:41.47,yin,,0,0,0,,图像中哪部分是当前显示出来的\\N{\\fs12}in that image what is being looked at.\r\nDialogue: 0,0:22:41.80,0:22:44.58,yin,,0,0,0,,要实现它 只要转换坐标\\N{\\fs12}And to do that, you simply convert those coordinates\r\nDialogue: 0,0:22:44.59,0:22:47.64,yin,,0,0,0,,用这个视图方法convertRect toView\\N{\\fs12}using this view method, convertRect toView.\r\nDialogue: 0,0:22:48.22,0:22:51.17,yin,,0,0,0,,得到滚动视图的边界 使用convertRect toView\\N{\\fs12}So you take those scroll view bounds, you convertRect toView,\r\nDialogue: 0,0:22:51.32,0:22:52.39,yin,,0,0,0,,后面是其子视图\\N{\\fs12}whatever subview in there,\r\nDialogue: 0,0:22:52.39,0:22:54.46,yin,,0,0,0,,比如当前显示\\N{\\fs12}like the UIImageView that's displaying,\r\nDialogue: 0,0:22:54.50,0:22:57.29,yin,,0,0,0,,斯坦福图片的这个UIImageView\\N{\\fs12}displaying that Stanford picture,\r\nDialogue: 0,0:22:57.30,0:22:59.37,yin,,0,0,0,,这样你就可以知道\\N{\\fs12}and you can find out where...\r\nDialogue: 0,0:22:59.38,0:23:01.02,yin,,0,0,0,,在视图坐标系中的范围\\N{\\fs12}what it is in that view's coordinate system.\r\nDialogue: 0,0:23:01.02,0:23:02.57,yin,,0,0,0,,为什么会不一样呢\\N{\\fs12}Now why would those be different?\r\nDialogue: 0,0:23:02.87,0:23:04.76,yin,,0,0,0,,这里的斯坦福图片\\N{\\fs12}Well, okay, that Stanford thing happens to be\r\nDialogue: 0,0:23:04.76,0:23:06.64,yin,,0,0,0,,正好在左上角(0,0)的位置\\N{\\fs12}up in the upper left corner at 0, 0,\r\nDialogue: 0,0:23:06.64,0:23:07.97,yin,,0,0,0,,所以看起来是一样的\\N{\\fs12}so it looks like it would be the same,\r\nDialogue: 0,0:23:07.98,0:23:10.82,yin,,0,0,0,,如果不是在(0,0)的位置 就要区别了\\N{\\fs12}but if that were not at 0, 0, then that would matter.\r\nDialogue: 0,0:23:10.94,0:23:12.11,yin,,0,0,0,,而且它还可以被缩放\\N{\\fs12}Also it could be zoomed.\r\nDialogue: 0,0:23:12.61,0:23:13.91,yin,,0,0,0,,我们稍后会讲缩放部分\\N{\\fs12}We'll talk about zooming in a second,\r\nDialogue: 0,0:23:13.92,0:23:15.50,yin,,0,0,0,,因为滚动视图也可以被放大\\N{\\fs12}because scroll views can also zoom in,\r\nDialogue: 0,0:23:15.66,0:23:17.79,yin,,0,0,0,,假设你把它放大了\\N{\\fs12}and so if you imagined if you were zoomed way in,\r\nDialogue: 0,0:23:17.80,0:23:19.69,yin,,0,0,0,,放大显示一扇窗户\\N{\\fs12}looking in a window there,\r\nDialogue: 0,0:23:19.98,0:23:23.95,yin,,0,0,0,,斯坦福图片视图中的矩形区域\\N{\\fs12}that the rectangle inside the Stanford view's view\r\nDialogue: 0,0:23:23.96,0:23:26.40,yin,,0,0,0,,会是一个很小的矩形\\N{\\fs12}would be a very small rectangle, right,\r\nDialogue: 0,0:23:26.41,0:23:28.96,yin,,0,0,0,,而在滚动视图中会包含很大范围\\N{\\fs12}where as in scroll view it's containing huge amounts.\r\nDialogue: 0,0:23:28.96,0:23:31.28,yin,,0,0,0,,所以这二者\\N{\\fs12}So that's why it makes a difference\r\nDialogue: 0,0:23:31.28,0:23:32.40,yin,,0,0,0,,是有区别的\\N{\\fs12}what those two things are.\r\nDialogue: 0,0:23:33.43,0:23:38.10,yin,,0,0,0,,我们来讲一下如何创建滚动视图\\N{\\fs12}Okay? So let's talk about how you create a scroll view.\r\nDialogue: 0,0:23:38.39,0:23:39.30,yin,,0,0,0,,非常简单\\N{\\fs12}Very easy.\r\nDialogue: 0,0:23:39.40,0:23:41.14,yin,,0,0,0,,直接从storyboard中拖出就可以了\\N{\\fs12}You just drag it out from your storyboard.\r\nDialogue: 0,0:23:41.57,0:23:43.59,yin,,0,0,0,,这是创建滚动视图的首选方法\\N{\\fs12}Okay? That's the number one way to create scroll view,\r\nDialogue: 0,0:23:43.61,0:23:45.26,yin,,0,0,0,,还可以用alloc initWithFrame\\N{\\fs12}you can also do alloc initWithFrame,\r\nDialogue: 0,0:23:45.27,0:23:46.71,yin,,0,0,0,,它也只是个视图 和其他视图一样\\N{\\fs12}it's just a view like any other view,\r\nDialogue: 0,0:23:46.72,0:23:48.09,yin,,0,0,0,,但通常会直接拖出来\\N{\\fs12}but usually you drag it out.\r\nDialogue: 0,0:23:48.36,0:23:51.83,yin,,0,0,0,,如果storyboard中有一个视图\\N{\\fs12}It is possible to have a view sitting in your storyboard\r\nDialogue: 0,0:23:52.02,0:23:56.60,yin,,0,0,0,,还可以选择编辑菜单中的嵌入滚动视图\\N{\\fs12}and do edit menu, embed in scroll view,\r\nDialogue: 0,0:23:56.60,0:23:58.80,yin,,0,0,0,,和嵌入导航控制器类似\\N{\\fs12}just like you do embed in navigation controller.\r\nDialogue: 0,0:23:59.42,0:24:01.19,yin,,0,0,0,,也许是我没理解\\N{\\fs12}You know, maybe I don't understand exactly\r\nDialogue: 0,0:24:01.20,0:24:02.16,yin,,0,0,0,,它究竟应该是怎样的\\N{\\fs12}how that's supposed to work,\r\nDialogue: 0,0:24:02.17,0:24:03.22,yin,,0,0,0,,但就我看来\\N{\\fs12}but it seems to me like\r\nDialogue: 0,0:24:03.23,0:24:05.02,yin,,0,0,0,,很多情况下都会出问题\\N{\\fs12}it doesn't do the right thing a lot of the time.\r\nDialogue: 0,0:24:05.33,0:24:05.93,yin,,0,0,0,,比如说\\N{\\fs12}For example,\r\nDialogue: 0,0:24:05.95,0:24:08.47,yin,,0,0,0,,它会在周围留出额外的空间\\N{\\fs12}it seems to put like a little extra space around it,\r\nDialogue: 0,0:24:08.48,0:24:10.95,yin,,0,0,0,,我也不知道原因 我不推荐使用嵌入滚动视图\\N{\\fs12}I'm not sure, I don't recommend embed in scroll view.\r\nDialogue: 0,0:24:11.09,0:24:12.83,yin,,0,0,0,,我推荐添加好滚动视图之后\\N{\\fs12}I recommend just put your scroll view there\r\nDialogue: 0,0:24:13.12,0:24:16.68,yin,,0,0,0,,然后用代码增加子视图\\N{\\fs12}and then add your subviews in code, okay?\r\nDialogue: 0,0:24:17.14,0:24:20.82,yin,,0,0,0,,或者将它们拖入storyboard中的滚动视图中\\N{\\fs12}Or, drag them in to a scroll view that's in your storyboard\r\nDialogue: 0,0:24:20.99,0:24:22.01,yin,,0,0,0,,将它们放到那里\\N{\\fs12}to put them in there, okay?\r\nDialogue: 0,0:24:22.24,0:24:24.37,yin,,0,0,0,,但是子视图直接拖拽进滚动视图有点奇怪\\N{\\fs12}But dragging them into your scroll view it kind of weird,\r\nDialogue: 0,0:24:24.61,0:24:26.24,yin,,0,0,0,,因为storyboard中的滚动视图\\N{\\fs12}because your scroll view in the storyboard\r\nDialogue: 0,0:24:26.25,0:24:28.37,yin,,0,0,0,,只能显示出其可视区域\\N{\\fs12}can only show you its visible area,\r\nDialogue: 0,0:24:28.37,0:24:30.42,yin,,0,0,0,,不能将整个contentSize的内容显示出来\\N{\\fs12}it can't show you that huge contentSize.\r\nDialogue: 0,0:24:30.80,0:24:31.99,yin,,0,0,0,,所以我更倾向于用代码\\N{\\fs12}So I'm kind of a fan of\r\nDialogue: 0,0:24:32.16,0:24:34.35,yin,,0,0,0,,添加滚动视图的子视图\\N{\\fs12}put your scroll view's subviews in code.\r\nDialogue: 0,0:24:35.02,0:24:36.92,yin,,0,0,0,,添加滚动视图时\\N{\\fs12}Okay? You put the scroll view itself in,\r\nDialogue: 0,0:24:37.23,0:24:38.83,yin,,0,0,0,,可以在storyboard中使用拖放完成\\N{\\fs12}drag and drop, into your storyboard,\r\nDialogue: 0,0:24:38.85,0:24:39.83,yin,,0,0,0,,然后用代码添加子视图\\N{\\fs12}but then, put your things in code,\r\nDialogue: 0,0:24:39.83,0:24:40.94,yin,,0,0,0,,我推荐这种方法\\N{\\fs12}I kind of recommend that.\r\nDialogue: 0,0:24:41.18,0:24:42.81,yin,,0,0,0,,实现方法就是使用addSubview方法\\N{\\fs12}And the way you do that is just with addSubview.\r\nDialogue: 0,0:24:42.93,0:24:44.73,yin,,0,0,0,,只要设置好视图的frame\\N{\\fs12}Just set the frame you want for your view,\r\nDialogue: 0,0:24:44.74,0:24:47.33,yin,,0,0,0,,是在内容区域的坐标系中的\\N{\\fs12}which is in that content area, coordinate system,\r\nDialogue: 0,0:24:47.46,0:24:48.32,yin,,0,0,0,,然后用addSubview\\N{\\fs12}and there's addSubview.\r\nDialogue: 0,0:24:48.70,0:24:49.59,yin,,0,0,0,,就是这么简单\\N{\\fs12}Simple as that.\r\nDialogue: 0,0:24:50.57,0:24:52.48,yin,,0,0,0,,不要忘记设置contentSize\\N{\\fs12}Don't forget to set that contentSize.\r\nDialogue: 0,0:24:52.61,0:24:53.96,yin,,0,0,0,,这是我讲的第一项内容\\N{\\fs12}That's the very first thing I talked about\r\nDialogue: 0,0:24:53.96,0:24:54.90,yin,,0,0,0,,我要再强调一遍\\N{\\fs12}and I'm talking about it again.\r\nDialogue: 0,0:24:55.05,0:24:58.12,yin,,0,0,0,,如果不设置contentSize 就是那个大的白色区域\\N{\\fs12}If you don't set that contentSize, that big white area,\r\nDialogue: 0,0:24:58.32,0:24:59.89,yin,,0,0,0,,滚动视图就没有滚动显示内容了\\N{\\fs12}the scroll view is going to be scrolling over nothing.\r\nDialogue: 0,0:25:00.01,0:25:02.10,yin,,0,0,0,,无论子视图添加的是哪个视图\\N{\\fs12}It doesn't matter what views you've added a subview,\r\nDialogue: 0,0:25:02.53,0:25:04.54,yin,,0,0,0,,contentSize是它滚动显示的对象\\N{\\fs12}that contentSize is what it scrolls over.\r\nDialogue: 0,0:25:04.54,0:25:05.88,yin,,0,0,0,,并不是在视图上滚动\\N{\\fs12}It doesn't scroll over the views,\r\nDialogue: 0,0:25:05.89,0:25:07.36,yin,,0,0,0,,视图只是正好在那里\\N{\\fs12}the views just happen to be there\r\nDialogue: 0,0:25:07.37,0:25:09.87,yin,,0,0,0,,如果它们是在contentSize坐标系中的话\\N{\\fs12}if they're in the contentSize coordinate system,\r\nDialogue: 0,0:25:09.87,0:25:11.35,yin,,0,0,0,,contentSize才是关键\\N{\\fs12}but it's that contentSize that's key,\r\nDialogue: 0,0:25:11.35,0:25:12.23,yin,,0,0,0,,不要忘了设置它\\N{\\fs12}don't forget to set that.\r\nDialogue: 0,0:25:12.26,0:25:13.15,yin,,0,0,0,,要想重置它\\N{\\fs12}And to reset it,\r\nDialogue: 0,0:25:13.16,0:25:15.02,yin,,0,0,0,,如果滚动显示的对象大小发生变化\\N{\\fs12}if you're gonna scroll over something that changes size,\r\nDialogue: 0,0:25:15.04,0:25:16.64,yin,,0,0,0,,放大缩小等等\\N{\\fs12}it gets larger or smaller or whatever,\r\nDialogue: 0,0:25:17.12,0:25:18.71,yin,,0,0,0,,重置那个contentSize\\N{\\fs12}reset that contentSize.\r\nDialogue: 0,0:25:20.38,0:25:21.86,yin,,0,0,0,,大多数情况下\\N{\\fs12}Most of the scrolling around\r\nDialogue: 0,0:25:21.87,0:25:24.24,yin,,0,0,0,,滚动操作是由用户的拖动手势控制的\\N{\\fs12}is the user with a touch gesture panning,\r\nDialogue: 0,0:25:24.47,0:25:27.32,yin,,0,0,0,,但还可以用代码完成滚动\\N{\\fs12}but you can also scroll around using code.\r\nDialogue: 0,0:25:27.59,0:25:29.44,yin,,0,0,0,,比如scrollRectToVisible\\N{\\fs12}For example, scrollRectToVisible.\r\nDialogue: 0,0:25:29.64,0:25:32.24,yin,,0,0,0,,你在内容区域指定一个矩形\\N{\\fs12}You specify a rectangle in the content area,\r\nDialogue: 0,0:25:32.25,0:25:36.83,yin,,0,0,0,,它会滚动以显示那个矩形\\N{\\fs12}and it will scroll that to make that rectangle visible,\r\nDialogue: 0,0:25:36.84,0:25:39.54,yin,,0,0,0,,也许要为其添加动画 让它划过去\\N{\\fs12}and you probably want it to be animated so it slides over,\r\nDialogue: 0,0:25:39.54,0:25:41.15,yin,,0,0,0,,而不是突然蹦出来\\N{\\fs12}instead of just jumps, right?\r\nDialogue: 0,0:25:42.06,0:25:43.46,yin,,0,0,0,,对于滚动视图\\N{\\fs12}And there's a ton of other things\r\nDialogue: 0,0:25:43.47,0:25:45.02,yin,,0,0,0,,还可以控制很多其他操作\\N{\\fs12}you can control in a scroll view,\r\nDialogue: 0,0:25:45.15,0:25:46.30,yin,,0,0,0,,我们就不讲了\\N{\\fs12}which we're not going to talk about,\r\nDialogue: 0,0:25:46.32,0:25:47.26,yin,,0,0,0,,时间有限\\N{\\fs12}just time constraints,\r\nDialogue: 0,0:25:47.27,0:25:49.65,yin,,0,0,0,,大家可以回去查看UIScrollView的文档\\N{\\fs12}but you can go look at UIScrollView's documentation,\r\nDialogue: 0,0:25:49.93,0:25:52.34,yin,,0,0,0,,比如滚动在何时启用\\N{\\fs12}things like whether scrolling is enabled at a given time,\r\nDialogue: 0,0:25:52.56,0:25:55.17,yin,,0,0,0,,是水平滚动还是垂直滚动 还是二者兼有\\N{\\fs12}whether you can scroll horizontally or vertically or both,\r\nDialogue: 0,0:25:57.18,0:25:59.86,yin,,0,0,0,,iOS中没有滚动条\\N{\\fs12}there's no scroll bars in iOS,\r\nDialogue: 0,0:26:00.01,0:26:01.40,yin,,0,0,0,,但有滚动指示器\\N{\\fs12}but there are scroll indicators,\r\nDialogue: 0,0:26:01.41,0:26:02.40,yin,,0,0,0,,不用滚动条\\N{\\fs12}you don't use scroll bars,\r\nDialogue: 0,0:26:02.40,0:26:03.87,yin,,0,0,0,,因为是直接用手指滚动\\N{\\fs12}because you just scroll with your finger,\r\nDialogue: 0,0:26:03.87,0:26:05.16,yin,,0,0,0,,或者是用拖动触控手势\\N{\\fs12}or you pan around with a touch gesture,\r\nDialogue: 0,0:26:05.45,0:26:06.91,yin,,0,0,0,,但会出现小标志\\N{\\fs12}but there are little things that flash on\r\nDialogue: 0,0:26:06.93,0:26:08.73,yin,,0,0,0,,告诉你当前所在内容区域的位置\\N{\\fs12}that kind of show you where you are on the content area,\r\nDialogue: 0,0:26:08.74,0:26:11.13,yin,,0,0,0,,这些内容都可以在文档中找到\\N{\\fs12}you can look at all that stuff in the documentation.\r\nDialogue: 0,0:26:12.31,0:26:13.79,yin,,0,0,0,,现在我们来讲一下缩放\\N{\\fs12}Alright, so now let's talk about zooming.\r\nDialogue: 0,0:26:13.91,0:26:15.92,yin,,0,0,0,,我们讲过了在滚动视图上拖动\\N{\\fs12}Okay, so we've talked about panning around the scroll view,\r\nDialogue: 0,0:26:15.92,0:26:18.48,yin,,0,0,0,,如果想要对内容进行缩放呢\\N{\\fs12}what if we want to zoom in on the content and zoom out?\r\nDialogue: 0,0:26:19.68,0:26:23.87,yin,,0,0,0,,要记得 所有UIView都有transform变换属性\\N{\\fs12}Remember that all UIViews have this transform property.\r\nDialogue: 0,0:26:23.87,0:26:27.10,yin,,0,0,0,,在动画部分 我们将其用于了评分效果\\N{\\fs12}Okay? We used it to grade effect in the animating world,\r\nDialogue: 0,0:26:27.39,0:26:31.06,yin,,0,0,0,,变换可以对视图进行任意的\\N{\\fs12}and the transform let's you rotate and scale\r\nDialogue: 0,0:26:31.06,0:26:34.86,yin,,0,0,0,,旋转 缩放和平移\\N{\\fs12}and translate a view, arbitrarily, okay,\r\nDialogue: 0,0:26:34.86,0:26:37.32,yin,,0,0,0,,是基于比特位的缩放\\N{\\fs12}it's doing bits, though, bit-wise zooming,\r\nDialogue: 0,0:26:37.72,0:26:39.60,yin,,0,0,0,,UIScrollView利用它\\N{\\fs12}and UIScrollView takes advantage of that\r\nDialogue: 0,0:26:39.87,0:26:42.38,yin,,0,0,0,,实现缩放\\N{\\fs12}to do its view, do its zooming\r\nDialogue: 0,0:26:42.38,0:26:45.04,yin,,0,0,0,,方法是通过修改变换属性的缩放比例\\N{\\fs12}by changing the scale of the transform.\r\nDialogue: 0,0:26:45.44,0:26:46.77,yin,,0,0,0,,按缩放比例进行变换\\N{\\fs12}Okay? So it scales the transform.\r\nDialogue: 0,0:26:46.77,0:26:48.39,yin,,0,0,0,,也就意味着你的视图\\N{\\fs12}So that means that your view,\r\nDialogue: 0,0:26:48.40,0:26:51.35,yin,,0,0,0,,如果放大太多 可能会看不清楚\\N{\\fs12}if it's zoomed in a lot could be kind of greeny,\r\nDialogue: 0,0:26:51.61,0:26:52.87,yin,,0,0,0,,除非你的视图\\N{\\fs12}unless your view doesn't know\r\nDialogue: 0,0:26:52.88,0:26:55.60,yin,,0,0,0,,不知道在缩放时如何进行调整\\N{\\fs12}how to adjust itself once it's zoomed in,\r\nDialogue: 0,0:26:55.62,0:26:56.92,yin,,0,0,0,,我们稍后会讲\\N{\\fs12}and we'll talk about that in a second.\r\nDialogue: 0,0:26:57.70,0:27:00.53,yin,,0,0,0,,要实现缩放 要设置两项重要的内容\\N{\\fs12}Zooming requires two very important things to be set,\r\nDialogue: 0,0:27:00.53,0:27:03.23,yin,,0,0,0,,首先是最大最小缩放比例\\N{\\fs12}the first thing is the minimum and maximum zoom scale,\r\nDialogue: 0,0:27:03.23,0:27:04.95,yin,,0,0,0,,它们的默认值是1\\N{\\fs12}by default these are one,\r\nDialogue: 0,0:27:05.51,0:27:07.20,yin,,0,0,0,,代表无法进行缩放\\N{\\fs12}meaning you can't zoom in or out.\r\nDialogue: 0,0:27:07.39,0:27:09.77,yin,,0,0,0,,显示的缩放比例为1\\N{\\fs12}Okay? It's just gonna show you a zoom scale of one,\r\nDialogue: 0,0:27:10.24,0:27:13.27,yin,,0,0,0,,也就是说 用户看到的内容\\N{\\fs12}in other words, the thing the user sees is one times the size\r\nDialogue: 0,0:27:13.27,0:27:16.18,yin,,0,0,0,,是它的实际大小\\N{\\fs12}of the thing as it really, it's actual size, right?\r\nDialogue: 0,0:27:16.50,0:27:18.64,yin,,0,0,0,,所以如果你想要让它们实现缩放\\N{\\fs12}So, if you want them to be able to zoom in or zoom out,\r\nDialogue: 0,0:27:18.64,0:27:21.19,yin,,0,0,0,,就要设置最大最小缩放比例\\N{\\fs12}you have to set the minimum or maximum zoom scale.\r\nDialogue: 0,0:27:21.53,0:27:22.76,yin,,0,0,0,,否则无法进行缩放\\N{\\fs12}Okay? Otherwise you will not zoom.\r\nDialogue: 0,0:27:22.99,0:27:25.30,yin,,0,0,0,,第二项是一个委托方法\\N{\\fs12}The second thing is a delegate method.\r\nDialogue: 0,0:27:25.80,0:27:28.99,yin,,0,0,0,,缩放的滚动视图要有一个委托\\N{\\fs12}So, scroll views that zoom have to have a delegate.\r\nDialogue: 0,0:27:29.31,0:27:32.80,yin,,0,0,0,,委托只是滚动视图的一个属性\\N{\\fs12}Okay? And delegate is just a property, on scroll view,\r\nDialogue: 0,0:27:32.80,0:27:34.19,yin,,0,0,0,,和动画部分类似\\N{\\fs12}just like it was on the animator,\r\nDialogue: 0,0:27:34.31,0:27:36.47,yin,,0,0,0,,你要将委托设为某个对象\\N{\\fs12}you're gonna set that delegate to be some object,\r\nDialogue: 0,0:27:36.54,0:27:37.97,yin,,0,0,0,,通常是你的控制器\\N{\\fs12}usually your controller,\r\nDialogue: 0,0:27:38.32,0:27:40.44,yin,,0,0,0,,控制器会实现所需要的\\N{\\fs12}and your controller's gonna implement whatever methods\r\nDialogue: 0,0:27:40.44,0:27:42.67,yin,,0,0,0,,UIScrollView委托协议中的方法\\N{\\fs12}in the UIScrollView delegate protocol,\r\nDialogue: 0,0:27:42.68,0:27:44.79,yin,,0,0,0,,我们讲过 记得吧\\N{\\fs12}remember we talked about protocols that it wants.\r\nDialogue: 0,0:27:45.11,0:27:47.83,yin,,0,0,0,,UIScrollView委托中的方法都是可选的\\N{\\fs12}All the methods in the UIScrollView protocol are optional,\r\nDialogue: 0,0:27:48.13,0:27:50.51,yin,,0,0,0,,但如果想实现缩放 这个方法是必须的\\N{\\fs12}but this one is not optional if you want zooming,\r\nDialogue: 0,0:27:51.05,0:27:53.75,yin,,0,0,0,,这个方法viewForZoomingInScrollView\\N{\\fs12}and all of this method, viewForZoomingInScrollView\r\nDialogue: 0,0:27:53.76,0:27:57.66,yin,,0,0,0,,会返回在内容区域中\\N{\\fs12}is returning is which view, in the content area,\r\nDialogue: 0,0:27:57.66,0:27:59.04,yin,,0,0,0,,滚动视图的哪个子视图\\N{\\fs12}which subview of the scroll view,\r\nDialogue: 0,0:27:59.19,0:28:02.60,yin,,0,0,0,,会在缩放时改变缩放比例\\N{\\fs12}is going to have it scale changed when it zooms?\r\nDialogue: 0,0:28:03.57,0:28:06.94,yin,,0,0,0,,所以在滚动视图的内容区域内\\N{\\fs12}Okay? So you might have a view at the top level\r\nDialogue: 0,0:28:06.95,0:28:08.46,yin,,0,0,0,,你可能会有一个顶级视图\\N{\\fs12}inside your content area scroll view\r\nDialogue: 0,0:28:08.46,0:28:10.19,yin,,0,0,0,,包含所有要缩放的视图\\N{\\fs12}that contains all your other views and they're zooming in,\r\nDialogue: 0,0:28:10.19,0:28:10.73,yin,,0,0,0,,没问题\\N{\\fs12}that's fine,\r\nDialogue: 0,0:28:10.81,0:28:13.93,yin,,0,0,0,,或者只有一个可以缩放的视图\\N{\\fs12}or there might be just one view that makes sense to zoom,\r\nDialogue: 0,0:28:13.94,0:28:14.95,yin,,0,0,0,,但是需要返回\\N{\\fs12}but you have to return\r\nDialogue: 0,0:28:14.97,0:28:17.64,yin,,0,0,0,,哪个子视图会被按比例缩放\\N{\\fs12}which subview is going to get scaled,\r\nDialogue: 0,0:28:17.76,0:28:20.38,yin,,0,0,0,,变换要应用于哪个视图\\N{\\fs12}which it's gonna have this transform applied to it.\r\nDialogue: 0,0:28:20.74,0:28:23.81,yin,,0,0,0,,还可以编程实现缩放\\N{\\fs12}Okay? You can also zoom programmatically, again,\r\nDialogue: 0,0:28:23.82,0:28:25.62,yin,,0,0,0,,用户通常会通过捏放手势控制缩放\\N{\\fs12}the user is usually pinching to zoom,\r\nDialogue: 0,0:28:25.62,0:28:26.77,yin,,0,0,0,,但也可以用编程实现\\N{\\fs12}but you can do it programmatically\r\nDialogue: 0,0:28:26.77,0:28:28.70,yin,,0,0,0,,只要设置这个属性zoomScale\\N{\\fs12}by just setting this property zoomScale.\r\nDialogue: 0,0:28:28.92,0:28:30.59,yin,,0,0,0,,设置时可能要使用\\N{\\fs12}When you do set it, you probably want to set it\r\nDialogue: 0,0:28:30.59,0:28:32.36,yin,,0,0,0,,setZoomScale animated\\N{\\fs12}with setZoomScale animated,\r\nDialogue: 0,0:28:32.36,0:28:34.72,yin,,0,0,0,,而不是直接设置zoomScale属性\\N{\\fs12}instead of just setting the zoomScale property directly\r\nDialogue: 0,0:28:34.72,0:28:35.89,yin,,0,0,0,,这样就有动画效果了\\N{\\fs12}so that it gets animated.\r\nDialogue: 0,0:28:36.14,0:28:37.71,yin,,0,0,0,,还可以按矩形缩放\\N{\\fs12}And you can also zoom to a rectangle,\r\nDialogue: 0,0:28:37.71,0:28:38.66,yin,,0,0,0,,是这样的\\N{\\fs12}which looks like this,\r\nDialogue: 0,0:28:38.71,0:28:40.66,yin,,0,0,0,,这是缩放比例1.2的显示效果\\N{\\fs12}so here's zoom scale 1.2,\r\nDialogue: 0,0:28:40.66,0:28:41.88,yin,,0,0,0,,将它放大了一点\\N{\\fs12}so I'm zoomed in a little bit.\r\nDialogue: 0,0:28:42.12,0:28:46.17,yin,,0,0,0,,如果将缩放比例设为1 就是实际大小\\N{\\fs12}If I got to zoom scale 1, okay, this actual size,\r\nDialogue: 0,0:28:46.43,0:28:48.73,yin,,0,0,0,,可以再回到缩放比例1.2\\N{\\fs12}I can go back to zoom scale 1.2.\r\nDialogue: 0,0:28:49.08,0:28:50.85,yin,,0,0,0,,还可以按矩形缩放\\N{\\fs12}I can also zoom to a rectangle,\r\nDialogue: 0,0:28:50.85,0:28:52.56,yin,,0,0,0,,比如说 这里有个小矩形\\N{\\fs12}let's say I have this little rectangle right here,\r\nDialogue: 0,0:28:52.56,0:28:55.05,yin,,0,0,0,,这个兽像的鼻子\\N{\\fs12}this nose of this beast,\r\nDialogue: 0,0:28:55.23,0:28:58.68,yin,,0,0,0,,如果对它进行放大 会尽可能放大\\N{\\fs12}and if I zoom, it will make it as big as possible, okay?\r\nDialogue: 0,0:28:59.33,0:29:00.72,yin,,0,0,0,,还能放下 所以就放大了\\N{\\fs12}It still fits, so it zooms in.\r\nDialogue: 0,0:29:01.03,0:29:03.27,yin,,0,0,0,,如果这个矩形\\N{\\fs12}Or, if I had a square that was bigger\r\nDialogue: 0,0:29:03.27,0:29:04.28,yin,,0,0,0,,大于当前显示范围\\N{\\fs12}than what was currently showing\r\nDialogue: 0,0:29:04.29,0:29:06.60,yin,,0,0,0,,这时再用zoomToRect 它就会缩小\\N{\\fs12}and I said zoomToRect, it'll zoom it down.\r\nDialogue: 0,0:29:07.54,0:29:09.23,yin,,0,0,0,,所以你可以直接用矩形\\N{\\fs12}Okay? So you can basically just take a rectangle\r\nDialogue: 0,0:29:09.23,0:29:12.98,yin,,0,0,0,,让它缩放到合适大小\\N{\\fs12}to make it fit as best it can. Alright.\r\nDialogue: 0,0:29:13.34,0:29:15.36,yin,,0,0,0,,滚动视图有很多委托方法\\N{\\fs12}So scroll view has lots and lots of delegate methods\r\nDialogue: 0,0:29:15.37,0:29:17.59,yin,,0,0,0,,不只是有viewForZoomingInScrollView\\N{\\fs12}besides that viewForZoomingInScrollView thing.\r\nDialogue: 0,0:29:17.80,0:29:21.59,yin,,0,0,0,,例如 如果捏合放大\\N{\\fs12}For example, if you zoomed in, you pinched to zoom\r\nDialogue: 0,0:29:21.59,0:29:23.25,yin,,0,0,0,,将一个视图放大很多\\N{\\fs12}and you zoomed way in on a view,\r\nDialogue: 0,0:29:23.35,0:29:24.87,yin,,0,0,0,,会变得很像素化\\N{\\fs12}it's gonna be really pixelated\r\nDialogue: 0,0:29:24.88,0:29:27.86,yin,,0,0,0,,因为是按比例变换大小\\N{\\fs12}because it's gonna be doing a transformed-based scale, right?\r\nDialogue: 0,0:29:27.86,0:29:30.49,yin,,0,0,0,,将比特位按比例放大 可能会变得很大\\N{\\fs12}Scaling the bits up, bits might look huge,\r\nDialogue: 0,0:29:31.26,0:29:32.54,yin,,0,0,0,,但是有一个委托方法\\N{\\fs12}but you get a delegate method,\r\nDialogue: 0,0:29:32.55,0:29:35.33,yin,,0,0,0,,scrollViewDidEndZooming withView atScale\\N{\\fs12}scrollViewDidEndZooming withView atScale,\r\nDialogue: 0,0:29:35.51,0:29:37.71,yin,,0,0,0,,滚动视图会告诉你\\N{\\fs12}that will tell you, the scroll view will tell you,\r\nDialogue: 0,0:29:37.73,0:29:39.01,yin,,0,0,0,,我完成它的缩放操作了\\N{\\fs12}I just finished zooming this thing\r\nDialogue: 0,0:29:39.01,0:29:40.21,yin,,0,0,0,,它现在是预设缩放比例\\N{\\fs12}and now it's at this scale.\r\nDialogue: 0,0:29:40.29,0:29:43.77,yin,,0,0,0,,这时你就可以重绘视图 让它不再像素化\\N{\\fs12}And now you could redraw your view to not be pixelated.\r\nDialogue: 0,0:29:44.45,0:29:45.93,yin,,0,0,0,,这是个好方法\\N{\\fs12}Okay? So this would be a good way\r\nDialogue: 0,0:29:45.94,0:29:48.22,yin,,0,0,0,,用户可以随意缩放\\N{\\fs12}to kind of let them zoom in and out,\r\nDialogue: 0,0:29:48.24,0:29:50.51,yin,,0,0,0,,性能很高 略有像素化\\N{\\fs12}really high performance, a little pixelated,\r\nDialogue: 0,0:29:50.51,0:29:52.26,yin,,0,0,0,,但用户的手指还在上面\\N{\\fs12}but their fingers are in the way anyway,\r\nDialogue: 0,0:29:52.26,0:29:53.89,yin,,0,0,0,,所以他们可能不太察觉\\N{\\fs12}so they can't probably can't tell that much.\r\nDialogue: 0,0:29:54.15,0:29:56.40,yin,,0,0,0,,当用户移开手指时 你就可以重绘了\\N{\\fs12}And then when they let go, you can do it.\r\nDialogue: 0,0:29:56.40,0:29:58.44,yin,,0,0,0,,实际上 在执行时你会得到通知\\N{\\fs12}And in fact, you even get notification while it's doing it,\r\nDialogue: 0,0:29:58.44,0:29:59.80,yin,,0,0,0,,所以可以在执行时进行重绘\\N{\\fs12}so you could even do it while it's doing it,\r\nDialogue: 0,0:29:59.80,0:30:01.37,yin,,0,0,0,,最好用性能较高的绘制操作\\N{\\fs12}it better be a high-performance drawing\r\nDialogue: 0,0:30:01.37,0:30:02.48,yin,,0,0,0,,因为同时还要处理捏合操作\\N{\\fs12}because they're pinching in and out.\r\nDialogue: 0,0:30:02.48,0:30:03.39,yin,,0,0,0,,但是这样做是可以的\\N{\\fs12}But, you could do it.\r\nDialogue: 0,0:30:03.39,0:30:05.15,yin,,0,0,0,,我只想演示一个委托方法\\N{\\fs12}But I just wanted to show you an example of a delegate method.\r\nDialogue: 0,0:30:05.15,0:30:08.56,yin,,0,0,0,,可能还有十几个滚动视图委托方法\\N{\\fs12}There's probably a dozen more scroll view delegate methods,\r\nDialogue: 0,0:30:08.56,0:30:10.74,yin,,0,0,0,,大家可以查看UIScrollView委托文档\\N{\\fs12}you could go look at the UIScrollView delegate documentation\r\nDialogue: 0,0:30:10.75,0:30:12.40,yin,,0,0,0,,查看这些方法\\N{\\fs12}to find out what they are all.\r\nDialogue: 0,0:30:13.07,0:30:13.49,yin,,0,0,0,,明白了吗\\N{\\fs12}Okay?\r\nDialogue: 0,0:30:13.74,0:30:15.27,yin,,0,0,0,,我们来做个演示\\N{\\fs12}So, we'll do a demo.\r\nDialogue: 0,0:30:15.27,0:30:16.75,yin,,0,0,0,,演示包含很多内容\\N{\\fs12}It's a pretty comprehensive demo.\r\nDialogue: 0,0:30:16.75,0:30:19.14,yin,,0,0,0,,我要演示滚动视图的操作\\N{\\fs12}I'm gonna be doing, showing you scroll view,\r\nDialogue: 0,0:30:19.39,0:30:21.70,yin,,0,0,0,,以及URL下载\\N{\\fs12}and that URL downloading thing,\r\nDialogue: 0,0:30:21.86,0:30:23.64,yin,,0,0,0,,还要演示\\N{\\fs12}and I'm also going to show you,\r\nDialogue: 0,0:30:24.02,0:30:26.63,yin,,0,0,0,,再做一个导航控制器\\N{\\fs12}we'll do another navigation controller,\r\nDialogue: 0,0:30:26.63,0:30:28.48,yin,,0,0,0,,再在课堂上演示一遍\\N{\\fs12}just to show it again in class.\r\nDialogue: 0,0:30:28.77,0:30:33.04,yin,,0,0,0,,最后我要演示一点动画的内容\\N{\\fs12}And at the end, I'm gonna show you a little animation thing,\r\nDialogue: 0,0:30:33.04,0:30:34.71,yin,,0,0,0,,是一个转轮\\N{\\fs12}a spinner that can spin\r\nDialogue: 0,0:30:34.74,0:30:36.57,yin,,0,0,0,,会在其他线程执行操作时旋转\\N{\\fs12}while things are happening in other threads,\r\nDialogue: 0,0:30:36.61,0:30:38.18,yin,,0,0,0,,主线程显示这个小转轮\\N{\\fs12}so the main thread can show his little spinner\r\nDialogue: 0,0:30:38.19,0:30:39.40,yin,,0,0,0,,用户就能知道是怎么回事了\\N{\\fs12}so people can see what's going on.\r\nDialogue: 0,0:30:39.40,0:30:43.31,yin,,0,0,0,,争取在下课前都演示完\\N{\\fs12}So, we'll try to get all of that to fit into our time.\r\nDialogue: 0,0:30:43.31,0:30:46.17,yin,,0,0,0,,这里新建一个项目\\N{\\fs12}So we're gonna make a new project here.\r\nDialogue: 0,0:30:46.17,0:30:47.66,yin,,0,0,0,,选择新建项目\\N{\\fs12}So I'm just gonna create new project.\r\nDialogue: 0,0:30:48.18,0:30:51.82,yin,,0,0,0,,我要叫这个项目Imaginarium\\N{\\fs12}And I'm gonna call this project Imaginarium.\r\nDialogue: 0,0:30:53.28,0:30:58.16,yin,,0,0,0,,将Imaginarium保存在根目录Developer下\\N{\\fs12}Okay? Imaginarium, we'll put it in my home directory developer,\r\nDialogue: 0,0:30:58.16,0:30:59.63,yin,,0,0,0,,强烈推荐这样\\N{\\fs12}which I highly recommend.\r\nDialogue: 0,0:31:00.03,0:31:01.27,yin,,0,0,0,,出来了\\N{\\fs12}Here it is.\r\nDialogue: 0,0:31:01.80,0:31:04.15,yin,,0,0,0,,我要将AppDelegate拖入Supporting Files文件夹中\\N{\\fs12}Okay, I'm dragging AppDelegate to supporting files.\r\nDialogue: 0,0:31:04.36,0:31:05.83,yin,,0,0,0,,下下周\\N{\\fs12}Probably the week after next\r\nDialogue: 0,0:31:05.84,0:31:08.03,yin,,0,0,0,,我们可能会讲这个应用委托\\N{\\fs12}we'll start talking about this app delegate.\r\nDialogue: 0,0:31:08.23,0:31:10.14,yin,,0,0,0,,讲到iOS的多任务处理时\\N{\\fs12}Really the app delegate mostly comes in\r\nDialogue: 0,0:31:10.15,0:31:12.30,yin,,0,0,0,,通常会涉及应用委托\\N{\\fs12}when we talk about multitasking in iOS,\r\nDialogue: 0,0:31:12.80,0:31:14.37,yin,,0,0,0,,多任务处理部分\\N{\\fs12}and we will start talking about multitasking\r\nDialogue: 0,0:31:14.76,0:31:17.07,yin,,0,0,0,,会在下下周讲到 今天不会涉及\\N{\\fs12}the week after next, but not today.\r\nDialogue: 0,0:31:17.70,0:31:20.48,yin,,0,0,0,,我们就用这个基本的视图控制器\\N{\\fs12}So here we go with this basic view controller, right here,\r\nDialogue: 0,0:31:20.48,0:31:21.63,yin,,0,0,0,,这个空的视图控制器\\N{\\fs12}this blank view controller.\r\nDialogue: 0,0:31:21.84,0:31:25.21,yin,,0,0,0,,我只要新建一个MVC\\N{\\fs12}And I'm gonna start off right off the bat by making a new MVC,\r\nDialogue: 0,0:31:25.22,0:31:27.78,yin,,0,0,0,,一个新的视图控制器 它的作用是\\N{\\fs12}a new view controller, and what this view controller does is\r\nDialogue: 0,0:31:27.79,0:31:30.21,yin,,0,0,0,,获取一个URL 然后显示出来\\N{\\fs12}it takes a URL, and displays,\r\nDialogue: 0,0:31:30.28,0:31:34.06,yin,,0,0,0,,URL对应的是网络上某幅图像 某个jpeg文件\\N{\\fs12}that is a URL that's for an image on the internet, some jpeg file,\r\nDialogue: 0,0:31:34.12,0:31:34.86,yin,,0,0,0,,把它显示出来\\N{\\fs12}and it displays it.\r\nDialogue: 0,0:31:35.53,0:31:36.87,yin,,0,0,0,,这就是要做的操作\\N{\\fs12}Okay? So that's what this,\r\nDialogue: 0,0:31:36.93,0:31:37.93,yin,,0,0,0,,先要创建它\\N{\\fs12}this first thing I'm going to create is.\r\nDialogue: 0,0:31:37.93,0:31:40.44,yin,,0,0,0,,直接选择新建文件\\N{\\fs12}So let's just go straight to that, new file,\r\nDialogue: 0,0:31:40.45,0:31:41.73,yin,,0,0,0,,新建一个类\\N{\\fs12}I'm gonna create a new class,\r\nDialogue: 0,0:31:42.00,0:31:44.67,yin,,0,0,0,,是一个UIViewController\\N{\\fs12}it's gonna be a UIViewController, okay,\r\nDialogue: 0,0:31:44.68,0:31:46.22,yin,,0,0,0,,我要叫它ImageViewController\\N{\\fs12}I'm gonna call it ImageViewController.\r\nDialogue: 0,0:31:47.13,0:31:48.08,yin,,0,0,0,,因为这就是它的作用\\N{\\fs12}Okay? Because that's what it does,\r\nDialogue: 0,0:31:48.09,0:31:49.29,yin,,0,0,0,,显示图像的视图控制器\\N{\\fs12}the view controller displays an image.\r\nDialogue: 0,0:31:49.97,0:31:50.86,yin,,0,0,0,,保存在这里\\N{\\fs12}Put it right there.\r\nDialogue: 0,0:31:51.92,0:31:53.73,yin,,0,0,0,,这就是我的ImageViewController\\N{\\fs12}So here's my ImageViewController,\r\nDialogue: 0,0:31:53.73,0:31:55.72,yin,,0,0,0,,从这个公有API入手\\N{\\fs12}I'm going to start right with this public API,\r\nDialogue: 0,0:31:55.73,0:31:57.85,yin,,0,0,0,,要对新类进行操作\\N{\\fs12}as I want to do with new classes,\r\nDialogue: 0,0:31:57.86,0:32:00.17,yin,,0,0,0,,我要增加一个属性\\N{\\fs12}so, I'm going to have a property,\r\nDialogue: 0,0:32:00.41,0:32:04.77,yin,,0,0,0,,是nonatomic strong类型 是一个NSURL\\N{\\fs12}which is nonatomic strong, which is going to be an NSURL,\r\nDialogue: 0,0:32:05.75,0:32:07.42,yin,,0,0,0,,叫做imageURL\\N{\\fs12}which is imageURL, okay?\r\nDialogue: 0,0:32:07.67,0:32:09.17,yin,,0,0,0,,这是公有API\\N{\\fs12}So this is the public API.\r\nDialogue: 0,0:32:09.25,0:32:10.81,yin,,0,0,0,,如果你设置了这个imageURL\\N{\\fs12}If you set this imageURL,\r\nDialogue: 0,0:32:10.98,0:32:13.34,yin,,0,0,0,,这个视图控制器就会显示那幅图像\\N{\\fs12}this view controller will display that image.\r\nDialogue: 0,0:32:13.95,0:32:15.30,yin,,0,0,0,,要怎么做呢\\N{\\fs12}Okay? How's it going to do that?\r\nDialogue: 0,0:32:15.30,0:32:16.28,yin,,0,0,0,,会用到一个类\\N{\\fs12}It's going to use a class,\r\nDialogue: 0,0:32:16.29,0:32:18.82,yin,,0,0,0,,我们几周前讲过 叫做UIImageView\\N{\\fs12}which we talked about a few weeks ago, called UIImageView.\r\nDialogue: 0,0:32:18.83,0:32:21.96,yin,,0,0,0,,就像UILabel是显示文本的一样\\N{\\fs12}UIImageView is kind of like UILabel is to text,\r\nDialogue: 0,0:32:22.10,0:32:23.71,yin,,0,0,0,,UIImageView是显示图像的\\N{\\fs12}UIImageView is to image.\r\nDialogue: 0,0:32:23.71,0:32:26.20,yin,,0,0,0,,它会获取一个UIImage 它有个属性是UIImage\\N{\\fs12}It just takes a UIImage, it has a property which is a UIImage,\r\nDialogue: 0,0:32:26.39,0:32:28.36,yin,,0,0,0,,然后显示它 这就是我们想要的功能\\N{\\fs12}and it displays it, so it's exactly what we want.\r\nDialogue: 0,0:32:28.36,0:32:30.73,yin,,0,0,0,,这个控制器显然要用到它\\N{\\fs12}So this controller is obviously going to use that,\r\nDialogue: 0,0:32:30.99,0:32:34.72,yin,,0,0,0,,删掉这些内容\\N{\\fs12}so let's get rid of all this stuff, and,\r\nDialogue: 0,0:32:34.72,0:32:37.88,yin,,0,0,0,,想要实现这个操作 这里需要什么呢\\N{\\fs12}so what do I need here, to do this?\r\nDialogue: 0,0:32:37.88,0:32:41.46,yin,,0,0,0,,需要一个图像视图\\N{\\fs12}Well, I'm gonna need one of those image views.\r\nDialogue: 0,0:32:41.88,0:32:48.89,yin,,0,0,0,,创建一个UIImageView\\N{\\fs12}So let's create a UIImageView, okay?\r\nDialogue: 0,0:32:50.75,0:32:53.38,yin,,0,0,0,,为什么不对呢\\N{\\fs12}Alright, why is that not doing the right thing already?\r\nDialogue: 0,0:32:55.86,0:32:56.28,yin,,0,0,0,,好吧\\N{\\fs12}Okay.\r\nDialogue: 0,0:32:56.39,0:32:57.32,yin,,0,0,0,,我们看看\\N{\\fs12}Let's see there.\r\nDialogue: 0,0:32:57.68,0:32:58.97,yin,,0,0,0,,可能是因为这个\\N{\\fs12}Oh, maybe because this.\r\nDialogue: 0,0:33:08.65,0:33:09.34,yin,,0,0,0,,不管了\\N{\\fs12}But anyway.\r\nDialogue: 0,0:33:09.56,0:33:11.45,yin,,0,0,0,,我们创建好了这个imageView\\N{\\fs12}Okay, sorry, we have this imageView,\r\nDialogue: 0,0:33:11.46,0:33:13.34,yin,,0,0,0,,它是主要内容\\N{\\fs12}that's gonna be the main thing,\r\nDialogue: 0,0:33:13.35,0:33:15.10,yin,,0,0,0,,对它进行延迟实例化\\N{\\fs12}so I'm going to lazily instantiate that.\r\nDialogue: 0,0:33:15.76,0:33:18.36,yin,,0,0,0,,(UIImageView *)imageView\\N{\\fs12}Image view, imageView,\r\nDialogue: 0,0:33:18.59,0:33:25.46,yin,,0,0,0,,if(!_imageView) _imageView=[[UIImageView alloc] init]\\N{\\fs12}if not imageView then imageView equals UIImageView alloc,\r\nDialogue: 0,0:33:25.46,0:33:27.55,yin,,0,0,0,,这时候我不知道它的框架是什么\\N{\\fs12}and at this time, I don't know its frame,\r\nDialogue: 0,0:33:27.55,0:33:29.17,yin,,0,0,0,,我就将它设为(0,0)了\\N{\\fs12}so I'll just make it be (0,0),\r\nDialogue: 0,0:33:29.18,0:33:32.07,yin,,0,0,0,,但要确保框架被正确设置\\N{\\fs12}but I'll have to make sure its frame gets set properly,\r\nDialogue: 0,0:33:32.52,0:33:33.89,yin,,0,0,0,,在某个时刻 设置图像时\\N{\\fs12}at some point, when I set its image\r\nDialogue: 0,0:33:33.90,0:33:36.11,yin,,0,0,0,,最好确保框架设置正确\\N{\\fs12}I better to make sure its frame is set properly.\r\nDialogue: 0,0:33:36.95,0:33:39.99,yin,,0,0,0,,就是这样了\\N{\\fs12}And, so we have that,\r\nDialogue: 0,0:33:40.16,0:33:42.27,yin,,0,0,0,,这里我要再做一个有趣的操作\\N{\\fs12}now I'm gonna do another interesting thing while we're here,\r\nDialogue: 0,0:33:42.27,0:33:43.76,yin,,0,0,0,,演示一下是如何实现的\\N{\\fs12}just to show you how this is done.\r\nDialogue: 0,0:33:43.91,0:33:45.30,yin,,0,0,0,,我要再添加一个属性\\N{\\fs12}I'm gonna have another property,\r\nDialogue: 0,0:33:45.79,0:33:49.56,yin,,0,0,0,,是一个UIImage\\N{\\fs12}which is going to be a UIImage.\r\nDialogue: 0,0:33:49.78,0:33:52.05,yin,,0,0,0,,它就是我们要显示的图像\\N{\\fs12}And this is going to be the image we're displaying,\r\nDialogue: 0,0:33:52.45,0:33:54.23,yin,,0,0,0,,关于这个属性有趣的一点是\\N{\\fs12}but what's interesting about this property,\r\nDialogue: 0,0:33:54.35,0:33:56.78,yin,,0,0,0,,我不会用一个实例变量来储存它\\N{\\fs12}is I'm not gonna use an instance variable to store it.\r\nDialogue: 0,0:33:57.73,0:34:00.10,yin,,0,0,0,,我会实现setter和getter\\N{\\fs12}Okay? I'm going to implement the setter and the getter,\r\nDialogue: 0,0:34:00.43,0:34:02.23,yin,,0,0,0,,但不会用实例变量\\N{\\fs12}and I'm not going to use an instance variable.\r\nDialogue: 0,0:34:02.99,0:34:04.57,yin,,0,0,0,,怎样实现呢\\N{\\fs12}Okay? So how does that work?\r\nDialogue: 0,0:34:04.72,0:34:06.64,yin,,0,0,0,,我们来实现getter\\N{\\fs12}Well, let's do the getter.\r\nDialogue: 0,0:34:08.53,0:34:09.91,yin,,0,0,0,,是image\\N{\\fs12}Oops. Image.\r\nDialogue: 0,0:34:10.71,0:34:11.75,yin,,0,0,0,,这样做时\\N{\\fs12}And when I do this,\r\nDialogue: 0,0:34:11.76,0:34:15.22,yin,,0,0,0,,只要返回imageView的视图\\N{\\fs12}I'm just gonna return my imageView's view,\r\nDialogue: 0,0:34:15.46,0:34:17.65,yin,,0,0,0,,imageView的image\\N{\\fs12}image, rather, my imageView's image.\r\nDialogue: 0,0:34:19.04,0:34:21.57,yin,,0,0,0,,有对象想要这个属性时\\N{\\fs12}Okay? So when someone wants this property,\r\nDialogue: 0,0:34:21.57,0:34:22.54,yin,,0,0,0,,它是个私有属性\\N{\\fs12}it's a private property,\r\nDialogue: 0,0:34:22.56,0:34:24.69,yin,,0,0,0,,我在代码中想要这个属性时\\N{\\fs12}but whenever I want this property in my code,\r\nDialogue: 0,0:34:24.95,0:34:27.08,yin,,0,0,0,,只要返回imageView的image\\N{\\fs12}I'm just going to return the imageView's one,\r\nDialogue: 0,0:34:27.18,0:34:31.39,yin,,0,0,0,,设置image也类似\\N{\\fs12}and, similarly, when I set this image, okay,\r\nDialogue: 0,0:34:31.84,0:34:36.66,yin,,0,0,0,,看看能不能让它\\N{\\fs12}let's see if we can make this do the right thing\r\nDialogue: 0,0:34:37.06,0:34:39.87,yin,,0,0,0,,显示正确的代码颜色\\N{\\fs12}in terms of code coloring,\r\nDialogue: 0,0:34:39.88,0:34:42.49,yin,,0,0,0,,我也不确定是怎么回事\\N{\\fs12}I'm not sure what's going on here.\r\nDialogue: 0,0:34:43.37,0:34:44.82,yin,,0,0,0,,再打开一遍试试\\N{\\fs12}Let's try this again.\r\nDialogue: 0,0:34:46.50,0:34:48.93,yin,,0,0,0,,我也不知道\\N{\\fs12}Okay, I'm not exactly sure.\r\nDialogue: 0,0:34:48.93,0:34:49.65,yin,,0,0,0,,好了\\N{\\fs12}Oh, there we go.\r\nDialogue: 0,0:34:50.44,0:34:53.04,yin,,0,0,0,,我想让这些代码颜色显示出来\\N{\\fs12}Okay, I want to get this colors going here.\r\nDialogue: 0,0:34:53.18,0:34:56.60,yin,,0,0,0,,好了 我们来设置UIImage\\N{\\fs12}Alright, so, let's set our UIImage.\r\nDialogue: 0,0:34:57.30,0:35:02.22,yin,,0,0,0,,这里也是一样的 只要用\\N{\\fs12}And same thing here, I'm going to just\r\nDialogue: 0,0:35:02.54,0:35:06.33,yin,,0,0,0,,self.imageView.image=image\\N{\\fs12}self dot imageView, dot image, equals the image.\r\nDialogue: 0,0:35:06.60,0:35:09.97,yin,,0,0,0,,为什么要定义这个image属性呢\\N{\\fs12}But here's why I'm defining this little image,\r\nDialogue: 0,0:35:09.97,0:35:12.92,yin,,0,0,0,,因为每次设置imageView的image时\\N{\\fs12}because whenever I set the image in the imageView,\r\nDialogue: 0,0:35:13.18,0:35:14.50,yin,,0,0,0,,都需要做另外一个操作\\N{\\fs12}I need to do one other thing,\r\nDialogue: 0,0:35:14.50,0:35:17.28,yin,,0,0,0,,self.imageView sizeToFit\\N{\\fs12}which is self dot imageView sizeToFit.\r\nDialogue: 0,0:35:18.41,0:35:19.54,yin,,0,0,0,,我想让imageView\\N{\\fs12}Okay? I want the imageView\r\nDialogue: 0,0:35:19.54,0:35:21.94,yin,,0,0,0,,调整自身框架 以适应图像显示\\N{\\fs12}to adjust its frame to fit that image.\r\nDialogue: 0,0:35:22.29,0:35:24.23,yin,,0,0,0,,因为每次设置imageView的image时\\N{\\fs12}So, since I always want to do that\r\nDialogue: 0,0:35:24.24,0:35:25.81,yin,,0,0,0,,都要这样做\\N{\\fs12}whenever I set the imageView's image,\r\nDialogue: 0,0:35:25.87,0:35:27.67,yin,,0,0,0,,我只要准备一个自己的属性\\N{\\fs12}I'm just preparing my own little property,\r\nDialogue: 0,0:35:27.67,0:35:29.43,yin,,0,0,0,,具有合理的语义\\N{\\fs12}which has sensible semantics,\r\nDialogue: 0,0:35:29.74,0:35:31.64,yin,,0,0,0,,通过它来做这个sizeToFit\\N{\\fs12}that does this little sizeToFit.\r\nDialogue: 0,0:35:31.77,0:35:33.16,yin,,0,0,0,,设置图像时要做的其他操作\\N{\\fs12}There are some other things we're going to want to do\r\nDialogue: 0,0:35:33.16,0:35:35.41,yin,,0,0,0,,可以都放到这里\\N{\\fs12}when we set an image, and we can put them all in here,\r\nDialogue: 0,0:35:35.67,0:35:38.05,yin,,0,0,0,,我们这里就先这样了\\N{\\fs12}but we'll start with just these. Okay?\r\nDialogue: 0,0:35:40.01,0:35:42.73,yin,,0,0,0,,下面要做的是在viewDidLoad中...\\N{\\fs12}The next thing I need to do is, in viewDidLoad...\r\nDialogue: 0,0:35:46.16,0:35:46.61,yin,,0,0,0,,像这样\\N{\\fs12}Like this.\r\nDialogue: 0,0:35:46.71,0:35:50.07,yin,,0,0,0,,将这个imageView加到self.view中\\N{\\fs12}Let's go and add this imageView to self dot view.\r\nDialogue: 0,0:35:50.24,0:35:54.28,yin,,0,0,0,,super viewDidLoad 然后是\\N{\\fs12}So let's do super, viewDidLoad, and then I'm going\r\nDialogue: 0,0:35:54.28,0:35:58.27,yin,,0,0,0,,self.view addSubview:self.imageView\\N{\\fs12}to say self dot view, addSubview, self dot imageView.\r\nDialogue: 0,0:35:58.86,0:36:01.94,yin,,0,0,0,,这样让它显示在屏幕上\\N{\\fs12}Okay? So that way I make sure I get it on screen.\r\nDialogue: 0,0:36:01.94,0:36:02.38,yin,,0,0,0,,有问题吗\\N{\\fs12}Question?\r\nDialogue: 0,0:36:02.82,0:36:05.19,yin,,0,0,0,,[学生提问]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,0:36:05.21,0:36:06.48,yin,,0,0,0,,非常棒的问题\\N{\\fs12}Yeah. Great, great question.\r\nDialogue: 0,0:36:06.80,0:36:10.23,yin,,0,0,0,,这里没有@synthesize\\N{\\fs12}So, there's no at sign synthesize for UI...\r\nDialogue: 0,0:36:10.37,0:36:11.60,yin,,0,0,0,,UIImage这里没有 对吗\\N{\\fs12}this UIImage thing, right?\r\nDialogue: 0,0:36:12.09,0:36:14.07,yin,,0,0,0,,编译器也没有提示错误\\N{\\fs12}And compilers not complaining either.\r\nDialogue: 0,0:36:14.45,0:36:15.52,yin,,0,0,0,,怎么回事\\N{\\fs12}What is going on?\r\nDialogue: 0,0:36:15.82,0:36:17.71,yin,,0,0,0,,为什么不需要@synthesize呢\\N{\\fs12}Why don't I need an at sign synthesize?\r\nDialogue: 0,0:36:17.71,0:36:19.14,yin,,0,0,0,,有人想猜一把吗\\N{\\fs12}Anyone want to hazard a guess?\r\nDialogue: 0,0:36:21.57,0:36:23.39,yin,,0,0,0,,[学生回答]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,0:36:23.55,0:36:24.27,yin,,0,0,0,,没错\\N{\\fs12}Correct.\r\nDialogue: 0,0:36:24.38,0:36:26.84,yin,,0,0,0,,答案就是因为我不用实例变量\\N{\\fs12}The answer is because I never use the instance variable.\r\nDialogue: 0,0:36:27.30,0:36:29.70,yin,,0,0,0,,因为image完全是按照另一个对象\\N{\\fs12}Okay? Since image is totally defined\r\nDialogue: 0,0:36:29.71,0:36:31.39,yin,,0,0,0,,来定义的\\N{\\fs12}in terms of another object,\r\nDialogue: 0,0:36:31.40,0:36:33.47,yin,,0,0,0,,我绝不会用_image\\N{\\fs12}I'm never using underbar image,\r\nDialogue: 0,0:36:33.69,0:36:35.80,yin,,0,0,0,,所以我不用合成那个实例变量\\N{\\fs12}and therefore I don't need to synthesize that instance variable,\r\nDialogue: 0,0:36:35.82,0:36:37.58,yin,,0,0,0,,@synthesize就是这个功能\\N{\\fs12}that's what at sign synthesize does.\r\nDialogue: 0,0:36:37.88,0:36:40.47,yin,,0,0,0,,它用来创建实例变量 而我不需要\\N{\\fs12}It creates that instance variable, and I don't need it.\r\nDialogue: 0,0:36:40.56,0:36:42.14,yin,,0,0,0,,编译器没有报错\\N{\\fs12}So, the compiler's not complaining\r\nDialogue: 0,0:36:42.14,0:36:43.82,yin,,0,0,0,,是因为我没有用它 所以不需要\\N{\\fs12}because I'm not using it, so I don't even need it.\r\nDialogue: 0,0:36:44.55,0:36:46.81,yin,,0,0,0,,这就是为什么我用了这个属性\\N{\\fs12}Everyone, that's kind of why I did this property,\r\nDialogue: 0,0:36:46.83,0:36:47.86,yin,,0,0,0,,给大家演示一下\\N{\\fs12}so that you would see that.\r\nDialogue: 0,0:36:48.45,0:36:49.53,yin,,0,0,0,,大家都明白了吗\\N{\\fs12}Okay? Everybody got that?\r\nDialogue: 0,0:36:50.61,0:36:52.70,yin,,0,0,0,,现在有了这个很棒的视图\\N{\\fs12}Okay, so now I have this wonderful view.\r\nDialogue: 0,0:36:52.89,0:36:55.04,yin,,0,0,0,,这里要做的最后一件事是\\N{\\fs12}The last thing I want to do here is\r\nDialogue: 0,0:36:55.28,0:36:59.91,yin,,0,0,0,,当有人设置我的公有API 设置imageURL时\\N{\\fs12}when someone sets my public API, set imageURL,\r\nDialogue: 0,0:37:00.80,0:37:04.92,yin,,0,0,0,,显然我要将imageView的image设成它\\N{\\fs12}obviously, I want to set that imageView's image to be that,\r\nDialogue: 0,0:37:05.18,0:37:09.79,yin,,0,0,0,,在这里存储imageURL\\N{\\fs12}so let's store our imageURL here,\r\nDialogue: 0,0:37:09.95,0:37:14.02,yin,,0,0,0,,然后是 self.image=\\N{\\fs12}and then I'm just gonna say self dot image equals NS...\r\nDialogue: 0,0:37:15.46,0:37:20.59,yin,,0,0,0,,[UIImage imageWithData:[NSData\\N{\\fs12}sorry, UIImage, imageWithData, NSData,\r\nDialogue: 0,0:37:20.65,0:37:27.21,yin,,0,0,0,,dataWithContentsOfURL self.imageURL]]\\N{\\fs12}dataWithContentsOfURL, self dot imageURL.\r\nDialogue: 0,0:37:28.55,0:37:31.72,yin,,0,0,0,,扩大点显示空间\\N{\\fs12}Okay? Let's make some more space. Okay?\r\nDialogue: 0,0:37:32.22,0:37:36.04,yin,,0,0,0,,这里做的就是调用这个self.image\\N{\\fs12}So, all I'm doing here is I'm calling this self dot image,\r\nDialogue: 0,0:37:36.04,0:37:38.86,yin,,0,0,0,,它会调用下面的这个setImage方法\\N{\\fs12}which is going to call this down here, this setImage.\r\nDialogue: 0,0:37:39.40,0:37:43.35,yin,,0,0,0,,使用获取的数据新建UIImage\\N{\\fs12}And, I'm creating a new UIImage using the data\r\nDialogue: 0,0:37:43.55,0:37:47.13,yin,,0,0,0,,数据就是URL的内容\\N{\\fs12}that I get by getting the contents of that URL.\r\nDialogue: 0,0:37:47.31,0:37:49.52,yin,,0,0,0,,这会阻塞线程\\N{\\fs12}This is going to block,\r\nDialogue: 0,0:37:50.24,0:37:52.93,yin,,0,0,0,,因为这个URL是互联网上的\\N{\\fs12}because that URL is gonna be out on the internet.\r\nDialogue: 0,0:37:53.12,0:37:56.15,yin,,0,0,0,,如果这个URL是网上的 这里就会阻塞\\N{\\fs12}If that, if this URL is on the internet, this will block.\r\nDialogue: 0,0:37:56.29,0:37:58.47,yin,,0,0,0,,如果是文件URL就不会 会直接获取数据\\N{\\fs12}If it's a file URL it won't, it'll just get the data.\r\nDialogue: 0,0:37:59.05,0:38:01.32,yin,,0,0,0,,但理解这部分很重要\\N{\\fs12}Okay? But this is very important to understand.\r\nDialogue: 0,0:38:01.32,0:38:04.06,yin,,0,0,0,,这里可能会阻塞主队列\\N{\\fs12}This is where we might be blocking the main queue.\r\nDialogue: 0,0:38:04.66,0:38:05.93,yin,,0,0,0,,那样就不好了\\N{\\fs12}Okay? And that's gonna be bad.\r\nDialogue: 0,0:38:06.14,0:38:07.84,yin,,0,0,0,,我们会阻塞主队列\\N{\\fs12}We're going to block the main queue\r\nDialogue: 0,0:38:07.84,0:38:09.69,yin,,0,0,0,,然后我们会再开启它\\N{\\fs12}and then we're going unblock it, okay?\r\nDialogue: 0,0:38:09.70,0:38:11.10,yin,,0,0,0,,但开始会阻塞它 这很不好\\N{\\fs12}But we're gonna start out blocking out, which is bad,\r\nDialogue: 0,0:38:11.10,0:38:13.20,yin,,0,0,0,,这行代码会带来麻烦\\N{\\fs12}but this is the line of code, the offender,\r\nDialogue: 0,0:38:13.21,0:38:16.19,yin,,0,0,0,,因为dataWithContentsOfURL会涉及网络\\N{\\fs12}because dataWithContentsOfURL will go out on the network\r\nDialogue: 0,0:38:16.54,0:38:19.68,yin,,0,0,0,,如果这个URL是http开头的话\\N{\\fs12}if that URL is an http something. Okay?\r\nDialogue: 0,0:38:21.06,0:38:24.50,yin,,0,0,0,,我们要显示什么图像呢\\N{\\fs12}Okay, so, now what image are we going to display?\r\nDialogue: 0,0:38:24.50,0:38:28.04,yin,,0,0,0,,我们写好了这个好用的通用图像显示器\\N{\\fs12}Right? We have this nice, generic image displayer,\r\nDialogue: 0,0:38:28.34,0:38:33.17,yin,,0,0,0,,我们要显示什么呢\\N{\\fs12}what are we going to display?\r\nDialogue: 0,0:38:33.97,0:38:36.46,yin,,0,0,0,,上一下网\\N{\\fs12}And, now let's go in the internet.\r\nDialogue: 0,0:38:36.67,0:38:40.31,yin,,0,0,0,,这些图像是苹果公司网站上的\\N{\\fs12}So, I've got these images right here, that actually Apple has,\r\nDialogue: 0,0:38:40.31,0:38:43.61,yin,,0,0,0,,苹果公司在网站上放了一些示例图片\\N{\\fs12}they put up a few images that were kind of example images\r\nDialogue: 0,0:38:43.61,0:38:47.51,yin,,0,0,0,,iPhone的拍摄样张 我猜是iPhone5s\\N{\\fs12}that were taken by an iPhone, iPhone5s, I guess,\r\nDialogue: 0,0:38:47.87,0:38:50.03,yin,,0,0,0,,可以看到 这幅图叫photo_1\\N{\\fs12}and you can see there's this one, photo one,\r\nDialogue: 0,0:38:50.03,0:38:53.27,yin,,0,0,0,,是朵花 再看一下photo_2\\N{\\fs12}which is this flower and then there's photo two,\r\nDialogue: 0,0:38:53.31,0:38:55.91,yin,,0,0,0,,应该是小辣椒\\N{\\fs12}which is these peppers, I guess those are,\r\nDialogue: 0,0:38:56.23,0:38:59.32,yin,,0,0,0,,photo_3是水母\\N{\\fs12}and three, which is this jellyfish, okay?\r\nDialogue: 0,0:38:59.56,0:39:03.24,yin,,0,0,0,,我想让我的应用能够显示这些图像\\N{\\fs12}So I want to have my app be able to display these images.\r\nDialogue: 0,0:39:03.77,0:39:05.51,yin,,0,0,0,,我要让应用\\N{\\fs12}Okay? So I'm going to make it\r\nDialogue: 0,0:39:05.52,0:39:07.93,yin,,0,0,0,,能够显示这三幅图中任意一幅\\N{\\fs12}so it can display any of these three images.\r\nDialogue: 0,0:39:08.16,0:39:09.14,yin,,0,0,0,,要怎么实现呢\\N{\\fs12}So how am I going to do that?\r\nDialogue: 0,0:39:09.29,0:39:12.02,yin,,0,0,0,,回到storyboard中\\N{\\fs12}Alright, I'm gonna go to my storyboard,\r\nDialogue: 0,0:39:12.26,0:39:15.09,yin,,0,0,0,,首先拖出一个视图控制器\\N{\\fs12}and first I'm gonna drag out a view controller\r\nDialogue: 0,0:39:15.09,0:39:16.62,yin,,0,0,0,,作为我的图像视图控制器\\N{\\fs12}to be my image view controller,\r\nDialogue: 0,0:39:16.62,0:39:17.80,yin,,0,0,0,,将它拖出来\\N{\\fs12}so let's drag that out,\r\nDialogue: 0,0:39:18.03,0:39:20.27,yin,,0,0,0,,大家都知道 需要将它的类\\N{\\fs12}and we know that we need to set its class\r\nDialogue: 0,0:39:20.30,0:39:21.39,yin,,0,0,0,,设为ImageViewController\\N{\\fs12}to be ImageViewController,\r\nDialogue: 0,0:39:21.39,0:39:24.18,yin,,0,0,0,,现在就有了这个图像视图控制器\\N{\\fs12}so now I have this nice image view controller\r\nDialogue: 0,0:39:24.29,0:39:25.73,yin,,0,0,0,,用来显示图像\\N{\\fs12}that can display an image.\r\nDialogue: 0,0:39:26.31,0:39:29.86,yin,,0,0,0,,现在我要在这个视图控制器中加些按钮\\N{\\fs12}And, now I'm gonna put some buttons in this view controller,\r\nDialogue: 0,0:39:29.86,0:39:31.51,yin,,0,0,0,,这是创建应用时\\N{\\fs12}this is this default view controller\r\nDialogue: 0,0:39:31.54,0:39:33.51,yin,,0,0,0,,自动创建的默认视图控制器\\N{\\fs12}that got created when I created the app,\r\nDialogue: 0,0:39:33.52,0:39:34.51,yin,,0,0,0,,在这里添加一个按钮\\N{\\fs12}so I'm going to create one here.\r\nDialogue: 0,0:39:34.87,0:39:37.37,yin,,0,0,0,,一个按钮用来显示小辣椒\\N{\\fs12}We'll create one for the peppers,\r\nDialogue: 0,0:39:37.95,0:39:40.51,yin,,0,0,0,,或者是其他东西\\N{\\fs12}and... or whatever those things are,\r\nDialogue: 0,0:39:40.70,0:39:43.56,yin,,0,0,0,,再添加一个按钮\\N{\\fs12}and then let's create one for the...\r\nDialogue: 0,0:39:43.57,0:39:46.54,yin,,0,0,0,,显示第一幅图的花 然后\\N{\\fs12}what was the first one, a flower, and then,\r\nDialogue: 0,0:39:46.54,0:39:50.14,yin,,0,0,0,,最后一个是水母\\N{\\fs12}what was the other thing, it was a jellyfish.\r\nDialogue: 0,0:39:50.80,0:39:52.23,yin,,0,0,0,,添加好这些按钮后 我希望...\\N{\\fs12}Okay, so I got these buttons and I want to...\r\nDialogue: 0,0:39:52.25,0:39:53.45,yin,,0,0,0,,当我点击这些按钮时\\N{\\fs12}when I click on these buttons,\r\nDialogue: 0,0:39:53.46,0:39:55.76,yin,,0,0,0,,对应的图像会显示在这边\\N{\\fs12}I want it to show up here, okay?\r\nDialogue: 0,0:39:56.33,0:39:59.28,yin,,0,0,0,,我要通过导航控制器来实现\\N{\\fs12}So, I'm gonna use that by doing a navigation controller\r\nDialogue: 0,0:39:59.28,0:40:00.70,yin,,0,0,0,,让它进行segue\\N{\\fs12}and have it segue, okay?\r\nDialogue: 0,0:40:00.71,0:40:02.67,yin,,0,0,0,,这样我们可以再复习一遍segue\\N{\\fs12}Just so we can review the segues.\r\nDialogue: 0,0:40:02.85,0:40:04.95,yin,,0,0,0,,这三个按钮还要一起调整一下\\N{\\fs12}One thing I want to do all of these is,\r\nDialogue: 0,0:40:04.95,0:40:07.92,yin,,0,0,0,,让它们对齐\\N{\\fs12}let's give them some nice things here.\r\nDialogue: 0,0:40:07.92,0:40:11.13,yin,,0,0,0,,让它们水平居中\\N{\\fs12}Let's have them, horizontally center that way,\r\nDialogue: 0,0:40:11.45,0:40:14.41,yin,,0,0,0,,让它居中\\N{\\fs12}let's have this guy horizontally centered...\r\nDialogue: 0,0:40:14.57,0:40:16.42,yin,,0,0,0,,这样垂直居中\\N{\\fs12}vertically centered this way.\r\nDialogue: 0,0:40:17.45,0:40:20.25,yin,,0,0,0,,从第二个control拖拽到第一个按钮\\N{\\fs12}Let's control, drag from this guy up this\r\nDialogue: 0,0:40:20.25,0:40:21.99,yin,,0,0,0,,让它们保持垂直间距\\N{\\fs12}and keep the vertical spacing,\r\nDialogue: 0,0:40:22.17,0:40:24.19,yin,,0,0,0,,control拖拽到第三个按钮 设置保持垂直距离\\N{\\fs12}control, drag this into that vertical space,\r\nDialogue: 0,0:40:24.20,0:40:24.85,yin,,0,0,0,,都做完之后\\N{\\fs12}so I do all that,\r\nDialogue: 0,0:40:24.86,0:40:26.46,yin,,0,0,0,,可以看到出现了黄线\\N{\\fs12}you can see I have some yellow here,\r\nDialogue: 0,0:40:26.63,0:40:28.61,yin,,0,0,0,,黄色的约束线 我们把它改好\\N{\\fs12}some yellow constraints, let's go fix those.\r\nDialogue: 0,0:40:28.85,0:40:30.96,yin,,0,0,0,,转到左边 点击黄色三角形\\N{\\fs12}We'll go over here, do this,\r\nDialogue: 0,0:40:31.09,0:40:33.00,yin,,0,0,0,,点击修复错位按钮\\N{\\fs12}we'll fix the misplacement there.\r\nDialogue: 0,0:40:33.09,0:40:35.74,yin,,0,0,0,,改好这里 以及这里\\N{\\fs12}And fix that one, and we'll fix that one.\r\nDialogue: 0,0:40:35.96,0:40:36.86,yin,,0,0,0,,这样就好了\\N{\\fs12}So now they're doing it.\r\nDialogue: 0,0:40:37.06,0:40:39.81,yin,,0,0,0,,这里正好可以转到右上 选择这项\\N{\\fs12}This might be a nice chance to go here and select on this\r\nDialogue: 0,0:40:40.15,0:40:42.21,yin,,0,0,0,,切换到横屏模式\\N{\\fs12}and go switch over to landscape.\r\nDialogue: 0,0:40:42.48,0:40:44.29,yin,,0,0,0,,看起来效果不错\\N{\\fs12}It looks like it's doing something sensible,\r\nDialogue: 0,0:40:44.31,0:40:44.98,yin,,0,0,0,,很好\\N{\\fs12}so that's good.\r\nDialogue: 0,0:40:45.66,0:40:46.99,yin,,0,0,0,,大家明白了吗\\N{\\fs12}Okay? Everybody got that?\r\nDialogue: 0,0:40:46.99,0:40:48.96,yin,,0,0,0,,复习一下自动布局的内容\\N{\\fs12}Just a little review of autolayout there.\r\nDialogue: 0,0:40:49.87,0:40:51.97,yin,,0,0,0,,我们将它\\N{\\fs12}Alright, so, let's put this inside\r\nDialogue: 0,0:40:52.05,0:40:53.65,yin,,0,0,0,,放入导航控制器中\\N{\\fs12}of a navigation controller,\r\nDialogue: 0,0:40:53.66,0:40:55.81,yin,,0,0,0,,选择嵌入导航控制器\\N{\\fs12}so I'm gonna embed in navigation controller,\r\nDialogue: 0,0:40:56.09,0:40:57.18,yin,,0,0,0,,将它放在了这里\\N{\\fs12}so that puts that here.\r\nDialogue: 0,0:40:57.26,0:40:58.02,yin,,0,0,0,,很好\\N{\\fs12}That's good.\r\nDialogue: 0,0:40:58.35,0:40:59.56,yin,,0,0,0,,我们在这里加一个标题\\N{\\fs12}Let's go ahead and put a title in here,\r\nDialogue: 0,0:40:59.56,0:41:01.70,yin,,0,0,0,,我们叫它Imaginarium\\N{\\fs12}we'll call this Imaginarium.\r\nDialogue: 0,0:41:02.89,0:41:04.58,yin,,0,0,0,,还要进行segue跳转\\N{\\fs12}Now I want to segue,\r\nDialogue: 0,0:41:04.59,0:41:06.55,yin,,0,0,0,,按下按钮后 跳转到右边这里\\N{\\fs12}when any of these buttons is pressed to do this,\r\nDialogue: 0,0:41:06.57,0:41:07.97,yin,,0,0,0,,只要control拖拽就行了\\N{\\fs12}so I'm just going to control, drag,\r\nDialogue: 0,0:41:07.98,0:41:10.28,yin,,0,0,0,,对这个按钮进行control拖拽 选择push\\N{\\fs12}so let's control, drag this one. Push.\r\nDialogue: 0,0:41:10.69,0:41:12.70,yin,,0,0,0,,对这个按钮进行control拖拽 选择push\\N{\\fs12}Control, drag this one. Push.\r\nDialogue: 0,0:41:13.00,0:41:15.20,yin,,0,0,0,,对这个按钮进行control拖拽 选择push\\N{\\fs12}And control, dray this one. Push.\r\nDialogue: 0,0:41:15.41,0:41:18.72,yin,,0,0,0,,可以看到这三个segue\\N{\\fs12}Now, you see I've got these three segues in here,\r\nDialogue: 0,0:41:18.92,0:41:21.63,yin,,0,0,0,,点击一个 它就会告诉我\\N{\\fs12}if I click on one, it'll tell me what sent...\r\nDialogue: 0,0:41:21.64,0:41:23.97,yin,,0,0,0,,什么引发了这个segue跳转\\N{\\fs12}what, what is causing that segue to happen,\r\nDialogue: 0,0:41:24.12,0:41:25.29,yin,,0,0,0,,很不错的功能\\N{\\fs12}which is kind of a nice feature.\r\nDialogue: 0,0:41:25.94,0:41:28.09,yin,,0,0,0,,这里的标识符要用什么呢\\N{\\fs12}Now what am I going to use for my identifier for here?\r\nDialogue: 0,0:41:28.10,0:41:30.15,yin,,0,0,0,,实际上 这里要用点技巧了\\N{\\fs12}Well actually, I'm gonna be a little bit tricky here,\r\nDialogue: 0,0:41:30.32,0:41:35.21,yin,,0,0,0,,我要用图片名作为标识符\\N{\\fs12}I'm gonna use the name of the photo as the identifier,\r\nDialogue: 0,0:41:35.21,0:41:39.22,yin,,0,0,0,,然后在prepareForSegue中用它来选取\\N{\\fs12}and then in my prepareForSegue, I will use that to pick\r\nDialogue: 0,0:41:39.63,0:41:42.34,yin,,0,0,0,,要展示哪幅图片\\N{\\fs12}which of the three photos I'm gonna show.\r\nDialogue: 0,0:41:42.44,0:41:43.43,yin,,0,0,0,,这是个示例演示\\N{\\fs12}So, you know, it's a demo,\r\nDialogue: 0,0:41:43.44,0:41:45.59,yin,,0,0,0,,尽量少用代码\\N{\\fs12}so I'm trying to make this as little code as possible,\r\nDialogue: 0,0:41:45.61,0:41:47.92,yin,,0,0,0,,这就是我的三个segue\\N{\\fs12}so here's my three things,\r\nDialogue: 0,0:41:47.92,0:41:49.50,yin,,0,0,0,,对应的标识符是这三个图片名\\N{\\fs12}they're going to have these three identifiers,\r\nDialogue: 0,0:41:49.73,0:41:53.02,yin,,0,0,0,,我需要在这里添加prepareForSegue\\N{\\fs12}and I need to do prepareForSegue in this guy,\r\nDialogue: 0,0:41:53.18,0:41:54.51,yin,,0,0,0,,我们来做一下\\N{\\fs12}right, so let's go do that.\r\nDialogue: 0,0:41:55.64,0:41:56.63,yin,,0,0,0,,这样做\\N{\\fs12}Let's do it this way,\r\nDialogue: 0,0:41:56.64,0:41:58.57,yin,,0,0,0,,转到左边的ViewController\\N{\\fs12}let's go over here to our ViewController.\r\nDialogue: 0,0:41:59.01,0:41:59.73,yin,,0,0,0,,这些都不需要\\N{\\fs12}We don't need any of this,\r\nDialogue: 0,0:41:59.73,0:42:02.06,yin,,0,0,0,,这是我们的通用视图控制器\\N{\\fs12}this is our generic view controller, on the side there.\r\nDialogue: 0,0:42:02.29,0:42:04.83,yin,,0,0,0,,所以只需要实现prepareForSegue\\N{\\fs12}So I only need to implement prepareForSegue,\r\nDialogue: 0,0:42:05.42,0:42:09.74,yin,,0,0,0,,需要用刚才创建的ImageViewController\\N{\\fs12}and I'm gonna use the ImageViewController that I just created,\r\nDialogue: 0,0:42:10.29,0:42:13.01,yin,,0,0,0,,因为它是要segue跳转去的对象\\N{\\fs12}because this is the thing I'm going to segue to, alright?\r\nDialogue: 0,0:42:14.07,0:42:15.09,yin,,0,0,0,,所以只需要写\\N{\\fs12}So all I'm going to do is I'm going to say\r\nDialogue: 0,0:42:15.09,0:42:17.83,yin,,0,0,0,,if(segue.destinationViewController\\N{\\fs12}if the segue's destinationViewController\r\nDialogue: 0,0:42:17.84,0:42:22.16,yin,,0,0,0,,isKindOfClass:[ImageViewController class])\\N{\\fs12}is kind of class in ImageViewController, okay,\r\nDialogue: 0,0:42:22.37,0:42:25.30,yin,,0,0,0,,然后我就知道如何进行segue跳转了\\N{\\fs12}then I know how to segue to that.\r\nDialogue: 0,0:42:26.51,0:42:29.24,yin,,0,0,0,,还差一个方括号\\N{\\fs12}So, I, oops, one more square bracket there.\r\nDialogue: 0,0:42:29.92,0:42:31.78,yin,,0,0,0,,只要在这里创建一个局部变量\\N{\\fs12}So I'm just gonna create a local variable here,\r\nDialogue: 0,0:42:31.78,0:42:35.69,yin,,0,0,0,,ImageViewController *ivc=(ImageViewController *)\\N{\\fs12}ImageViewController ivc equals ImageViewController\r\nDialogue: 0,0:42:36.01,0:42:37.23,yin,,0,0,0,,segue.destinationViewController\\N{\\fs12}segue dot destinationViewController,\r\nDialogue: 0,0:42:37.24,0:42:38.18,yin,,0,0,0,,我知道没问题\\N{\\fs12}which I know is okay\r\nDialogue: 0,0:42:38.18,0:42:39.87,yin,,0,0,0,,因为我在这里做了内省\\N{\\fs12}because I did this introspection right here,\r\nDialogue: 0,0:42:39.88,0:42:42.72,yin,,0,0,0,,所以我知道这行代码不会出问题\\N{\\fs12}so I know this line is not gonna cause a problem,\r\nDialogue: 0,0:42:42.95,0:42:46.76,yin,,0,0,0,,然后是ivc.imageURL\\N{\\fs12}and then I'm just gonna say ivc dot imageURL, okay,\r\nDialogue: 0,0:42:46.77,0:42:50.79,yin,,0,0,0,,还记得吗 它是ImageViewController的公有API\\N{\\fs12}remember this is the public API of our ImageViewController,\r\nDialogue: 0,0:42:51.33,0:42:53.27,yin,,0,0,0,,这就是prepareForSegue中要做的操作\\N{\\fs12}okay, and that's what we do when prepare for segues,\r\nDialogue: 0,0:42:53.28,0:42:56.58,yin,,0,0,0,,调用目标视图控制器的公有API\\N{\\fs12}we call public API on the destination view controller.\r\nDialogue: 0,0:42:56.95,0:43:02.58,yin,,0,0,0,,将它设为NSURL URLWithString\\N{\\fs12}So I'm gonna set that to be NSURL, URLWithString,\r\nDialogue: 0,0:43:02.77,0:43:06.72,yin,,0,0,0,,我要加一个带格式字符串\\N{\\fs12}and I'm gonna make a string with a format,\r\nDialogue: 0,0:43:07.17,0:43:08.21,yin,,0,0,0,,我要做的是\\N{\\fs12}and what I'm gonna do is\r\nDialogue: 0,0:43:08.23,0:43:12.47,yin,,0,0,0,,复制粘贴这里的地址\\N{\\fs12}I'm gonna copy and paste this thing right here,\r\nDialogue: 0,0:43:12.98,0:43:14.40,yin,,0,0,0,,刚才打开过的苹果网站路径\\N{\\fs12}that I went to, this Apple thing,\r\nDialogue: 0,0:43:14.41,0:43:15.48,yin,,0,0,0,,我们复制一下\\N{\\fs12}so let's copy that.\r\nDialogue: 0,0:43:16.36,0:43:18.48,yin,,0,0,0,,粘贴到这里\\N{\\fs12}And paste it in here. Paste.\r\nDialogue: 0,0:43:19.23,0:43:22.52,yin,,0,0,0,,这里不用photo_1\\N{\\fs12}But instead of just doing photo one here,\r\nDialogue: 0,0:43:22.52,0:43:26.28,yin,,0,0,0,,而要用segue的标识符\\N{\\fs12}I'm going to use the segue's identifier.\r\nDialogue: 0,0:43:28.52,0:43:30.60,yin,,0,0,0,,为了方便查看效果\\N{\\fs12}Okay? And just so we can see what's going on,\r\nDialogue: 0,0:43:30.61,0:43:34.04,yin,,0,0,0,,我还要将这个视图控制器的标题\\N{\\fs12}I'm also gonna set the title of that view controller\r\nDialogue: 0,0:43:34.04,0:43:35.70,yin,,0,0,0,,设为segue的标识符\\N{\\fs12}to be the segue's identifier, as well,\r\nDialogue: 0,0:43:35.70,0:43:37.47,yin,,0,0,0,,photo_1 photo_2等\\N{\\fs12}that little photo underbar one, or photo two,\r\nDialogue: 0,0:43:37.49,0:43:39.72,yin,,0,0,0,,这样就可以在顶部看到是什么图了\\N{\\fs12}just so we can see at the top what it is.\r\nDialogue: 0,0:43:40.28,0:43:41.27,yin,,0,0,0,,大家都明白在prepareForSegue这里\\N{\\fs12}So everyone understand what I'm doing\r\nDialogue: 0,0:43:41.27,0:43:42.72,yin,,0,0,0,,我做了什么吗\\N{\\fs12}in prepareForSegue here?\r\nDialogue: 0,0:43:43.75,0:43:45.64,yin,,0,0,0,,如何为ImageViewController做准备\\N{\\fs12}How I'm preparing my ImageViewController\r\nDialogue: 0,0:43:45.64,0:43:48.15,yin,,0,0,0,,让它做目标操作\\N{\\fs12}to do what it wants to do? Okay?\r\nDialogue: 0,0:43:48.63,0:43:51.80,yin,,0,0,0,,我们来看看一切是否正常运行\\N{\\fs12}So, let's see if we got everything working here.\r\nDialogue: 0,0:43:51.80,0:43:53.26,yin,,0,0,0,,希望我没有落掉什么步骤\\N{\\fs12}Hopefully I didn't forget anything.\r\nDialogue: 0,0:43:55.91,0:43:58.25,yin,,0,0,0,,试着让应用在设备上运行\\N{\\fs12}Try to get it working on our device here,\r\nDialogue: 0,0:43:58.25,0:43:59.67,yin,,0,0,0,,出来了\\N{\\fs12}oh, here comes something.\r\nDialogue: 0,0:44:01.39,0:44:02.84,yin,,0,0,0,,好的 看\\N{\\fs12}Alright, so, look,\r\nDialogue: 0,0:44:02.92,0:44:05.63,yin,,0,0,0,,初始是横屏模式\\N{\\fs12}it's starting off in the landscape mode,\r\nDialogue: 0,0:44:05.65,0:44:07.69,yin,,0,0,0,,我可以切换到竖屏模式\\N{\\fs12}I can rotate to either one.\r\nDialogue: 0,0:44:08.03,0:44:09.65,yin,,0,0,0,,我们来看一下花的图片\\N{\\fs12}So let's try to take a look at the flower.\r\nDialogue: 0,0:44:09.88,0:44:12.21,yin,,0,0,0,,确实把花的图片显示出来了\\N{\\fs12}Now, it, it did show me the flower,\r\nDialogue: 0,0:44:12.21,0:44:14.51,yin,,0,0,0,,至少左上角显示出来了\\N{\\fs12}at least the upper corner of it,\r\nDialogue: 0,0:44:14.51,0:44:18.21,yin,,0,0,0,,但我不能进行滚动缩放 什么都做不了\\N{\\fs12}but I can't scroll around, I can't zoom, I can't do anything,\r\nDialogue: 0,0:44:18.49,0:44:19.48,yin,,0,0,0,,可以看一下小辣椒图片\\N{\\fs12}I could go look at the peppers.\r\nDialogue: 0,0:44:19.68,0:44:21.81,yin,,0,0,0,,注意 我的UI有点卡\\N{\\fs12}Notice that my UI is kind of stuck.\r\nDialogue: 0,0:44:21.98,0:44:24.21,yin,,0,0,0,,点击水母后 我就不能再动了\\N{\\fs12}When I press jellyfish, ah, now I can't,\r\nDialogue: 0,0:44:24.36,0:44:25.93,yin,,0,0,0,,不能改变主意\\N{\\fs12}like I can't change my mind.\r\nDialogue: 0,0:44:25.93,0:44:29.17,yin,,0,0,0,,选择小辣椒以后 就不能改了\\N{\\fs12}Once I choose peppers, I can't change my mind.\r\nDialogue: 0,0:44:29.69,0:44:32.04,yin,,0,0,0,,这是因为执行这个抓取操作时\\N{\\fs12}And that's because I'm blocking that main queue\r\nDialogue: 0,0:44:32.11,0:44:33.95,yin,,0,0,0,,会阻塞主队列\\N{\\fs12}by doing this fetch. Okay?\r\nDialogue: 0,0:44:33.96,0:44:36.43,yin,,0,0,0,,我们稍后讲一下如何修复这个问题\\N{\\fs12}So we're gonna see how to fix that a little bit later.\r\nDialogue: 0,0:44:36.43,0:44:38.40,yin,,0,0,0,,到目前为止都不错\\N{\\fs12}So, this is good, so far,\r\nDialogue: 0,0:44:38.66,0:44:39.57,yin,,0,0,0,,但如果能看到这朵花\\N{\\fs12}but it'd be a lot nicer\r\nDialogue: 0,0:44:39.57,0:44:41.72,yin,,0,0,0,,就更好了\\N{\\fs12}if I could take a look at this flower,\r\nDialogue: 0,0:44:41.73,0:44:42.76,yin,,0,0,0,,滚动查看\\N{\\fs12}right, scroll around and look at it,\r\nDialogue: 0,0:44:42.79,0:44:44.59,yin,,0,0,0,,下面我们就来实现一下\\N{\\fs12}so let's do that next.\r\nDialogue: 0,0:44:45.95,0:44:48.88,yin,,0,0,0,,实现方法是添加一个滚动视图\\N{\\fs12}And, we're gonna do that by adding a scroll view.\r\nDialogue: 0,0:44:49.07,0:44:51.31,yin,,0,0,0,,转到storyboard\\N{\\fs12}So, I'm just gonna go here to my storyboard,\r\nDialogue: 0,0:44:51.51,0:44:53.94,yin,,0,0,0,,在这里的图像视图控制器中\\N{\\fs12}and here, inside my Image View Controller,\r\nDialogue: 0,0:44:53.94,0:44:55.19,yin,,0,0,0,,这是我的图像视图控制器\\N{\\fs12}this is my Image View Controller,\r\nDialogue: 0,0:44:55.42,0:44:57.75,yin,,0,0,0,,这里我要加一个滚动视图\\N{\\fs12}I'm going to add a scroll view,\r\nDialogue: 0,0:44:57.94,0:45:00.70,yin,,0,0,0,,方法是转到右下角\\N{\\fs12}and we do that just by going down here,\r\nDialogue: 0,0:45:01.09,0:45:02.40,yin,,0,0,0,,添加对象都是从这里\\N{\\fs12}where we add everything from,\r\nDialogue: 0,0:45:02.67,0:45:03.84,yin,,0,0,0,,找到滚动视图\\N{\\fs12}and finding a scroll view\r\nDialogue: 0,0:45:03.85,0:45:06.73,yin,,0,0,0,,在靠近底部的位置 在这\\N{\\fs12}and it's down towards the bottom, oh, there it is.\r\nDialogue: 0,0:45:07.41,0:45:08.17,yin,,0,0,0,,滚动视图\\N{\\fs12}Okay, scroll view.\r\nDialogue: 0,0:45:08.17,0:45:09.08,yin,,0,0,0,,将它拖拽出来\\N{\\fs12}I'm just going to pull it out.\r\nDialogue: 0,0:45:09.39,0:45:12.03,yin,,0,0,0,,让它填满全屏\\N{\\fs12}I'm gonna make it match the whole thing,\r\nDialogue: 0,0:45:12.03,0:45:15.33,yin,,0,0,0,,选择重置为建议约束\\N{\\fs12}I'm gonna actually do reset to suggested constraints,\r\nDialogue: 0,0:45:15.33,0:45:16.12,yin,,0,0,0,,我总是希望检查一下\\N{\\fs12}I always like to see\r\nDialogue: 0,0:45:16.12,0:45:18.15,yin,,0,0,0,,它是否真的选择了较好的约束\\N{\\fs12}if it actually picked good constraints,\r\nDialogue: 0,0:45:18.37,0:45:19.61,yin,,0,0,0,,这里是的\\N{\\fs12}which it did, okay?\r\nDialogue: 0,0:45:19.61,0:45:21.81,yin,,0,0,0,,滚动视图会紧贴边缘\\N{\\fs12}It's gonna have that scroll view stick to the edges,\r\nDialogue: 0,0:45:21.81,0:45:23.05,yin,,0,0,0,,当旋转\\N{\\fs12}so as we rotate\r\nDialogue: 0,0:45:23.07,0:45:25.89,yin,,0,0,0,,或者在不同大小的视图中查看时\\N{\\fs12}or if we were in a different size viewer, or whatever,\r\nDialogue: 0,0:45:25.91,0:45:28.03,yin,,0,0,0,,它都会紧贴边缘 我很喜欢\\N{\\fs12}it would stick to those edges, I really like that,\r\nDialogue: 0,0:45:29.14,0:45:33.89,yin,,0,0,0,,再添加一个连接它的输出口\\N{\\fs12}let's also wire up a outlet for that, an outlet for that.\r\nDialogue: 0,0:45:34.20,0:45:36.63,yin,,0,0,0,,叫它scrollView\\N{\\fs12}We'll call it scrollView. Alright?\r\nDialogue: 0,0:45:36.78,0:45:38.96,yin,,0,0,0,,有了它以后就能向滚动视图通信了\\N{\\fs12}So we have that, so now we can talk to the scroll view,\r\nDialogue: 0,0:45:39.91,0:45:42.26,yin,,0,0,0,,而想要实现它\\N{\\fs12}and all I really need to do to make this work is\r\nDialogue: 0,0:45:42.27,0:45:46.51,yin,,0,0,0,,不用将imageView添加为视图的子视图\\N{\\fs12}instead of adding the imageView as a subview of the view,\r\nDialogue: 0,0:45:46.73,0:45:49.62,yin,,0,0,0,,而是将它添加为滚动视图的子视图\\N{\\fs12}I'm gonna add it as a subview of the scroll view.\r\nDialogue: 0,0:45:50.20,0:45:51.80,yin,,0,0,0,,当然了 这样不能正常运行\\N{\\fs12}But, of course, this will not work.\r\nDialogue: 0,0:45:51.80,0:45:54.06,yin,,0,0,0,,我来证明一下它不能正常运行\\N{\\fs12}I'll go ahead and prove to you this will not work.\r\nDialogue: 0,0:45:56.89,0:45:58.15,yin,,0,0,0,,我是故意这样做的\\N{\\fs12}And I'm doing this intentionally,\r\nDialogue: 0,0:45:58.17,0:45:58.82,yin,,0,0,0,,我花时间这样做\\N{\\fs12}and I'm taking time to do this\r\nDialogue: 0,0:45:58.82,0:46:00.26,yin,,0,0,0,,是因为大家也会犯这个错误\\N{\\fs12}because you'll make this mistake, as well,\r\nDialogue: 0,0:46:00.26,0:46:02.25,yin,,0,0,0,,这是个常见错误\\N{\\fs12}a very common mistake.\r\nDialogue: 0,0:46:02.53,0:46:04.69,yin,,0,0,0,,看看花朵图片 出来了\\N{\\fs12}Just looked at the flower, here's the flower.\r\nDialogue: 0,0:46:04.69,0:46:06.19,yin,,0,0,0,,不行啊\\N{\\fs12}Oh! It's not working.\r\nDialogue: 0,0:46:06.42,0:46:07.73,yin,,0,0,0,,它是在滚动视图中\\N{\\fs12}Okay, it's in that scroll view\r\nDialogue: 0,0:46:07.74,0:46:09.22,yin,,0,0,0,,我把它放进滚动视图的\\N{\\fs12}and I know I put it in a scroll view,\r\nDialogue: 0,0:46:09.23,0:46:10.28,yin,,0,0,0,,怎么会不能用呢\\N{\\fs12}how come it's not working?\r\nDialogue: 0,0:46:10.67,0:46:11.83,yin,,0,0,0,,有人想告诉我为什么吗\\N{\\fs12}Anyone want to tell me why?\r\nDialogue: 0,0:46:12.20,0:46:13.29,yin,,0,0,0,,[学生回答]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,0:46:13.29,0:46:15.01,yin,,0,0,0,,contentSize 没错\\N{\\fs12}ContentSize, exactly.\r\nDialogue: 0,0:46:15.01,0:46:16.37,yin,,0,0,0,,我们需要设置contentSize\\N{\\fs12}We have to set the contentSize.\r\nDialogue: 0,0:46:16.37,0:46:17.68,yin,,0,0,0,,现在滚动视图不知道\\N{\\fs12}So right now the scroll view doesn't know\r\nDialogue: 0,0:46:18.03,0:46:19.38,yin,,0,0,0,,在哪里滚动\\N{\\fs12}where to scroll over, and...\r\nDialogue: 0,0:46:19.77,0:46:22.36,yin,,0,0,0,,大家可能会问 为什么这里有图片显示\\N{\\fs12}you might ask why is it even showing anything here,\r\nDialogue: 0,0:46:22.71,0:46:24.49,yin,,0,0,0,,答案是 我认为滚动视图...\\N{\\fs12}and the answer is I think scroll view,\r\nDialogue: 0,0:46:24.71,0:46:26.33,yin,,0,0,0,,将它添加到storyboard中时\\N{\\fs12}when you add it in a storyboard,\r\nDialogue: 0,0:46:26.34,0:46:29.15,yin,,0,0,0,,它可能将contentSize设为了其bounds\\N{\\fs12}it might set its contentSize to be its bounds\r\nDialogue: 0,0:46:29.16,0:46:30.01,yin,,0,0,0,,或者类似的东西\\N{\\fs12}or something like that,\r\nDialogue: 0,0:46:30.01,0:46:31.76,yin,,0,0,0,,所以这只是默认设置\\N{\\fs12}so it's just some defaulting that's even make it\r\nDialogue: 0,0:46:31.76,0:46:32.79,yin,,0,0,0,,让我们可以看到里面的内容\\N{\\fs12}so we see anything there.\r\nDialogue: 0,0:46:33.73,0:46:35.53,yin,,0,0,0,,我们回到这里 解决这个问题\\N{\\fs12}Okay, so let's go back here and fix that.\r\nDialogue: 0,0:46:35.53,0:46:38.26,yin,,0,0,0,,那我们要在哪里设置contentSize呢\\N{\\fs12}So where do we want to set the contentSize then?\r\nDialogue: 0,0:46:38.94,0:46:42.30,yin,,0,0,0,,扩大点空间 方便大家看到全部代码\\N{\\fs12}And, let's make it so we can see all this code. All right?\r\nDialogue: 0,0:46:43.24,0:46:45.77,yin,,0,0,0,,要设置contentSize\\N{\\fs12}The contentSize, for sure we want to set,\r\nDialogue: 0,0:46:45.77,0:46:49.22,yin,,0,0,0,,只要修改了image 我们就要设置contentSize\\N{\\fs12}anytime we change the image, we want to set the contentSize,\r\nDialogue: 0,0:46:49.22,0:46:51.26,yin,,0,0,0,,这毫无疑问 我们来做一下\\N{\\fs12}there's no doubt about that, so let's do this,\r\nDialogue: 0,0:46:51.26,0:46:54.88,yin,,0,0,0,,self.scrollView.contentSize\\N{\\fs12}self dot scrollView dot contentSize,\r\nDialogue: 0,0:46:55.46,0:46:56.25,yin,,0,0,0,,打错了 是contentSize\\N{\\fs12}oops, size,\r\nDialogue: 0,0:46:57.03,0:47:00.87,yin,,0,0,0,,=self.image.size\\N{\\fs12}equals self dot image dot size.\r\nDialogue: 0,0:47:01.36,0:47:04.83,yin,,0,0,0,,这行代码可能会出问题\\N{\\fs12}Okay? Now, this line of code could cause trouble\r\nDialogue: 0,0:47:05.14,0:47:07.84,yin,,0,0,0,,如果self.image为nil的话\\N{\\fs12}if self dot image is nil,\r\nDialogue: 0,0:47:08.69,0:47:11.32,yin,,0,0,0,,因为我说过 如果你有一个方法\\N{\\fs12}because I told you that if you have a method,\r\nDialogue: 0,0:47:11.45,0:47:13.52,yin,,0,0,0,,这只是image的getter\\N{\\fs12}this is just a getter of the image,\r\nDialogue: 0,0:47:13.97,0:47:17.18,yin,,0,0,0,,返回一个结构体 你将它发给nil\\N{\\fs12}that returns a struct, and you send it to nil,\r\nDialogue: 0,0:47:17.18,0:47:18.60,yin,,0,0,0,,就会得到未定义的结果\\N{\\fs12}you'll get undefined results.\r\nDialogue: 0,0:47:18.79,0:47:19.65,yin,,0,0,0,,这很不好\\N{\\fs12}So this is bad.\r\nDialogue: 0,0:47:19.94,0:47:21.41,yin,,0,0,0,,我们来避免这种情况发生\\N{\\fs12}So let's protect against that,\r\nDialogue: 0,0:47:21.42,0:47:24.47,yin,,0,0,0,,self.image ?\\N{\\fs12}self dot image, question mark,\r\nDialogue: 0,0:47:24.55,0:47:25.80,yin,,0,0,0,,然后用size\\N{\\fs12}then we'll use the size,\r\nDialogue: 0,0:47:25.96,0:47:29.77,yin,,0,0,0,,否则 我们用CGSizeZero 即(0,0)\\N{\\fs12}otherwise, we'll use CGSizeZero, which is 0 by 0.\r\nDialogue: 0,0:47:30.40,0:47:32.85,yin,,0,0,0,,这样可以正常运行\\N{\\fs12}Okay? Now, this will work,\r\nDialogue: 0,0:47:33.02,0:47:34.64,yin,,0,0,0,,但实际上 还有一个地方\\N{\\fs12}but there's actually one other place\r\nDialogue: 0,0:47:34.65,0:47:35.78,yin,,0,0,0,,需要这行代码\\N{\\fs12}that we need to put this.\r\nDialogue: 0,0:47:36.31,0:47:41.13,yin,,0,0,0,,大家可能会觉得惊讶 就是在setScrollView中\\N{\\fs12}And that, maybe surprisingly, is in setScrollView.\r\nDialogue: 0,0:47:41.36,0:47:45.42,yin,,0,0,0,,也就是这个输出口的setter\\N{\\fs12}In other words, in the setter for this outlet,\r\nDialogue: 0,0:47:45.72,0:47:47.22,yin,,0,0,0,,这里的这个scrollView输出口\\N{\\fs12}this scrollView outlet right here,\r\nDialogue: 0,0:47:47.23,0:47:48.41,yin,,0,0,0,,它只是个输出口\\N{\\fs12}it's just an outlet.\r\nDialogue: 0,0:47:49.19,0:47:51.39,yin,,0,0,0,,_scrollView=scrollView\\N{\\fs12}We want... equals, scrollView,\r\nDialogue: 0,0:47:51.40,0:47:55.01,yin,,0,0,0,,要确保两行代码一致\\N{\\fs12}we want to make sure that we do this exact same line of code,\r\nDialogue: 0,0:47:55.02,0:47:56.10,yin,,0,0,0,,为什么呢\\N{\\fs12}and why is that?\r\nDialogue: 0,0:47:56.18,0:48:00.92,yin,,0,0,0,,因为这个scrollView属性\\N{\\fs12}Well, the reason for that is this scrollView property\r\nDialogue: 0,0:48:00.98,0:48:04.79,yin,,0,0,0,,可能会在这个方法执行后被设置\\N{\\fs12}might get set after this happens.\r\nDialogue: 0,0:48:05.58,0:48:08.35,yin,,0,0,0,,特别是prepareForSegue\\N{\\fs12}Specifically, prepareForSegue, right,\r\nDialogue: 0,0:48:08.36,0:48:11.02,yin,,0,0,0,,prepareForSegue是在输出口未设好前执行的\\N{\\fs12}prepareForSegu happens before your outlets get set,\r\nDialogue: 0,0:48:12.11,0:48:13.01,yin,,0,0,0,,明白吗\\N{\\fs12}make sense?\r\nDialogue: 0,0:48:13.60,0:48:18.30,yin,,0,0,0,,setImage会因为setImageURL而执行\\N{\\fs12}So this setImage is gonna be happening because of this setImageURL\r\nDialogue: 0,0:48:18.32,0:48:21.33,yin,,0,0,0,,而setImageURL是在prepareForSegue被执行的\\N{\\fs12}which happens in the prepareForSegue\r\nDialogue: 0,0:48:21.47,0:48:23.80,yin,,0,0,0,,滚动视图这时还没建好\\N{\\fs12}and so the scroll view is not even set up at that time,\r\nDialogue: 0,0:48:23.80,0:48:27.83,yin,,0,0,0,,所以在这里执行时 它还是nil\\N{\\fs12}so this is gonna be nil, at the time that is executed.\r\nDialogue: 0,0:48:28.81,0:48:29.91,yin,,0,0,0,,大家明白吗\\N{\\fs12}Okay? Everyone understand that?\r\nDialogue: 0,0:48:31.06,0:48:33.54,yin,,0,0,0,,不明白吗 明白就点头\\N{\\fs12}No? Nod your head if you understand.\r\nDialogue: 0,0:48:34.96,0:48:36.04,yin,,0,0,0,,人数不多\\N{\\fs12}Not too many of you.\r\nDialogue: 0,0:48:36.56,0:48:37.49,yin,,0,0,0,,也许大家需要\\N{\\fs12}Okay, well you might have to think\r\nDialogue: 0,0:48:37.49,0:48:39.37,yin,,0,0,0,,再思考一下\\N{\\fs12}about that one a little bit, okay?\r\nDialogue: 0,0:48:39.84,0:48:43.50,yin,,0,0,0,,只要理解 当prepareForSegue为你做准备时\\N{\\fs12}Just understand that your outlets are not send... are not set\r\nDialogue: 0,0:48:43.70,0:48:47.19,yin,,0,0,0,,你的输出口还没有建好\\N{\\fs12}when prepareForSegue is preparing you, okay?\r\nDialogue: 0,0:48:47.42,0:48:50.24,yin,,0,0,0,,prepareForSegue中会设置这个imageURL\\N{\\fs12}So prepareForSegue is setting this imageURL,\r\nDialogue: 0,0:48:50.68,0:48:51.92,yin,,0,0,0,,因而执行这个方法\\N{\\fs12}which is happening this,\r\nDialogue: 0,0:48:52.10,0:48:53.24,yin,,0,0,0,,执行这行代码\\N{\\fs12}which is causing this,\r\nDialogue: 0,0:48:53.59,0:48:55.06,yin,,0,0,0,,然后会转到下面这里来\\N{\\fs12}which is going down to here,\r\nDialogue: 0,0:48:55.18,0:48:58.06,yin,,0,0,0,,试图执行这一行 但它是nil\\N{\\fs12}which is trying to do this, but this is nil,\r\nDialogue: 0,0:48:59.09,0:49:00.21,yin,,0,0,0,,所以这行什么都不会执行\\N{\\fs12}so this line will do nothing.\r\nDialogue: 0,0:49:00.98,0:49:02.65,yin,,0,0,0,,因为这里是向nil发送消息\\N{\\fs12}Because we're sending a message to nil here,\r\nDialogue: 0,0:49:02.70,0:49:03.61,yin,,0,0,0,,所以它什么都不会做\\N{\\fs12}so it just does nothing.\r\nDialogue: 0,0:49:04.27,0:49:06.91,yin,,0,0,0,,稍后当这个输出口建好之后\\N{\\fs12}So later when this outlet comes along and get set,\r\nDialogue: 0,0:49:07.21,0:49:08.85,yin,,0,0,0,,这时如果我们有一幅图像\\N{\\fs12}then if we have an image,\r\nDialogue: 0,0:49:08.92,0:49:11.23,yin,,0,0,0,,要确保设置了contentSize\\N{\\fs12}we want to make sure that we set our contentSize, okay?\r\nDialogue: 0,0:49:12.52,0:49:14.38,yin,,0,0,0,,大家可以再思考一下\\N{\\fs12}Alright, so, you can cogitate on that.\r\nDialogue: 0,0:49:15.55,0:49:18.99,yin,,0,0,0,,与此同时 我们运行一下\\N{\\fs12}Meanwhile, let's run this,\r\nDialogue: 0,0:49:19.66,0:49:20.91,yin,,0,0,0,,希望现在可以正常运行了\\N{\\fs12}and hopefully now it'll work.\r\nDialogue: 0,0:49:22.21,0:49:23.29,yin,,0,0,0,,查看花朵图像\\N{\\fs12}So we'll look at the flower.\r\nDialogue: 0,0:49:24.33,0:49:25.55,yin,,0,0,0,,起作用了\\N{\\fs12}And oh it's working!\r\nDialogue: 0,0:49:25.55,0:49:26.96,yin,,0,0,0,,花朵出来了\\N{\\fs12}Okay. So there's our flower,\r\nDialogue: 0,0:49:27.00,0:49:29.45,yin,,0,0,0,,但是不太容易看清 因为不能缩放\\N{\\fs12}it's a little hard to see because we can't zoom in.\r\nDialogue: 0,0:49:29.64,0:49:32.41,yin,,0,0,0,,如果能缩小就好了\\N{\\fs12}Alright? It'd be nice to be able to zoom in on this,\r\nDialogue: 0,0:49:32.51,0:49:35.25,yin,,0,0,0,,小辣椒图片也是一样 它好看一点\\N{\\fs12}same with the peppers, the peppers, a little nicer to look at,\r\nDialogue: 0,0:49:35.26,0:49:37.33,yin,,0,0,0,,也不太好看\\N{\\fs12}this, that's not so nice to look at, but,\r\nDialogue: 0,0:49:38.07,0:49:39.55,yin,,0,0,0,,可以看到小辣椒在这里\\N{\\fs12}there you can look at the peppers over here.\r\nDialogue: 0,0:49:39.79,0:49:42.12,yin,,0,0,0,,这些图都太大了 显然我们需要缩小\\N{\\fs12}Okay, so these are too big, obviously we want to zoom in,\r\nDialogue: 0,0:49:42.46,0:49:43.71,yin,,0,0,0,,如何缩小呢\\N{\\fs12}so how are we going to zoom in?\r\nDialogue: 0,0:49:44.30,0:49:45.39,yin,,0,0,0,,我们来做一下\\N{\\fs12}Let's do that.\r\nDialogue: 0,0:49:45.65,0:49:47.82,yin,,0,0,0,,实现缩小操作非常简单\\N{\\fs12}Zooming in, really simple,\r\nDialogue: 0,0:49:47.83,0:49:50.37,yin,,0,0,0,,还记得我说过只要两步吗\\N{\\fs12}remember I said you only need to do two things, okay?\r\nDialogue: 0,0:49:50.55,0:49:51.78,yin,,0,0,0,,首先是需要设置\\N{\\fs12}One is you got to set\r\nDialogue: 0,0:49:51.78,0:49:55.16,yin,,0,0,0,,滚动视图的最大最小缩放比例\\N{\\fs12}the scroll view's minimum and maximum zoom scale,\r\nDialogue: 0,0:49:55.17,0:49:56.56,yin,,0,0,0,,我们让它缩小到...\\N{\\fs12}so we'll let it zoom into...\r\nDialogue: 0,0:49:56.56,0:50:01.32,yin,,0,0,0,,图像实际大小的20%\\N{\\fs12}let's say 20 percent, of the size of this image, or zoom out.\r\nDialogue: 0,0:50:01.33,0:50:05.51,yin,,0,0,0,,最大缩放比例设为两倍\\N{\\fs12}And then, we'll have the maximum zoom scale be two times.\r\nDialogue: 0,0:50:05.71,0:50:09.88,yin,,0,0,0,,图像不允许放大超过两倍\\N{\\fs12}Okay? So, we won't allow the image to get any bigger\r\nDialogue: 0,0:50:09.88,0:50:12.64,yin,,0,0,0,,最多可以缩小到20%\\N{\\fs12}than twice as big and we'll zoom down to 20 percent.\r\nDialogue: 0,0:50:12.98,0:50:15.60,yin,,0,0,0,,除此之外 另一个操作是需要\\N{\\fs12}And the other thing we need to do besides setting those is\r\nDialogue: 0,0:50:15.60,0:50:17.82,yin,,0,0,0,,设置滚动视图的委托\\N{\\fs12}to set the scroll view's delegate\r\nDialogue: 0,0:50:17.82,0:50:19.18,yin,,0,0,0,,实现另一个方法\\N{\\fs12}and implement that other method.\r\nDialogue: 0,0:50:19.37,0:50:21.99,yin,,0,0,0,,我要将滚动视图的delegat设为它自己\\N{\\fs12}So I'm gonna set the scroll view's delegate to self.\r\nDialogue: 0,0:50:22.45,0:50:22.85,yin,,0,0,0,,看到了吗\\N{\\fs12}Okay?\r\nDialogue: 0,0:50:23.47,0:50:24.69,yin,,0,0,0,,这触发了一个警告\\N{\\fs12}This causes a warning.\r\nDialogue: 0,0:50:25.23,0:50:26.98,yin,,0,0,0,,看到那个黄色小三角形了吗\\N{\\fs12}You see that yellow triangle?\r\nDialogue: 0,0:50:27.57,0:50:28.88,yin,,0,0,0,,在我点击它之前\\N{\\fs12}Why do you think there's a warning here\r\nDialogue: 0,0:50:28.89,0:50:30.05,yin,,0,0,0,,有谁能说说为什么这里会出现一个警告\\N{\\fs12}before I clicked on it, anyone?\r\nDialogue: 0,0:50:30.56,0:50:30.87,yin,,0,0,0,,请说\\N{\\fs12}Yeah?\r\nDialogue: 0,0:50:31.12,0:50:36.02,yin,,0,0,0,,[学生回答]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,0:50:36.04,0:50:38.97,yin,,0,0,0,,没错 但是有一个间接的步骤\\N{\\fs12}Yes. So the, that's, yes, but there's an indirect step,\r\nDialogue: 0,0:50:38.97,0:50:41.43,yin,,0,0,0,,这个警告的意思略有不同\\N{\\fs12}and this warning is actually telling me something slightly different,\r\nDialogue: 0,0:50:42.30,0:50:44.64,yin,,0,0,0,,是过程中的消息\\N{\\fs12}but it, it's telling me something on the way\r\nDialogue: 0,0:50:44.64,0:50:45.40,yin,,0,0,0,,还没到你说的那一步\\N{\\fs12}to exactly what you're saying,\r\nDialogue: 0,0:50:45.41,0:50:47.48,yin,,0,0,0,,我们是要实现viewDidZoom方法\\N{\\fs12}which is we got to implement that viewDidZoom thing.\r\nDialogue: 0,0:50:47.60,0:50:49.53,yin,,0,0,0,,但这个警告并不是这个意思\\N{\\fs12}But that's not what this warning is warning us about.\r\nDialogue: 0,0:50:49.79,0:50:51.41,yin,,0,0,0,,这个警告是说\\N{\\fs12}This warning is saying that\r\nDialogue: 0,0:50:51.42,0:50:54.30,yin,,0,0,0,,你将委托赋给了一个对象\\N{\\fs12}you are assigning this delegate to an object\r\nDialogue: 0,0:50:54.36,0:50:58.00,yin,,0,0,0,,但它没有实现滚动视图委托协议\\N{\\fs12}that does not implement the scroll view delegate protocol, okay?\r\nDialogue: 0,0:50:58.30,0:51:00.82,yin,,0,0,0,,不是实现方法\\N{\\fs12}Now that's not implementing the methods,\r\nDialogue: 0,0:51:01.05,0:51:04.12,yin,,0,0,0,,是声明自己实现了这些方法\\N{\\fs12}that's declaring that it does it.\r\nDialogue: 0,0:51:04.54,0:51:05.67,yin,,0,0,0,,就是上面这里\\N{\\fs12}That's this up here.\r\nDialogue: 0,0:51:06.19,0:51:09.35,yin,,0,0,0,,这就是警告的内容\\N{\\fs12}Okay? This is what it's complaining about,\r\nDialogue: 0,0:51:09.46,0:51:12.02,yin,,0,0,0,,你没有声明你自己\\N{\\fs12}is that you don't declare self,\r\nDialogue: 0,0:51:12.05,0:51:13.36,yin,,0,0,0,,也就是这个ImageViewController\\N{\\fs12}which is this image controller,\r\nDialogue: 0,0:51:13.71,0:51:16.36,yin,,0,0,0,,实现委托协议\\N{\\fs12}to implement the delegate protocol, okay?\r\nDialogue: 0,0:51:16.66,0:51:18.39,yin,,0,0,0,,还记得委托协议吗 有两个步骤\\N{\\fs12}So remember the delegate protocol, there's two things.\r\nDialogue: 0,0:51:18.39,0:51:20.13,yin,,0,0,0,,首先 声明你实现了\\N{\\fs12}One, they're saying that you do it\r\nDialogue: 0,0:51:20.26,0:51:21.90,yin,,0,0,0,,然后实现它\\N{\\fs12}and then number two, doing it.\r\nDialogue: 0,0:51:22.11,0:51:24.34,yin,,0,0,0,,声明的部分\\N{\\fs12}Okay? So it's the saying that you do it\r\nDialogue: 0,0:51:24.34,0:51:25.44,yin,,0,0,0,,就是警告缺少的内容\\N{\\fs12}that it's complaining about,\r\nDialogue: 0,0:51:25.44,0:51:26.44,yin,,0,0,0,,现在没有警告了\\N{\\fs12}and now it's not complaining.\r\nDialogue: 0,0:51:26.62,0:51:29.19,yin,,0,0,0,,即便我并没有真正实现任何一个方法\\N{\\fs12}Even though I don't actually implement any of those methods.\r\nDialogue: 0,0:51:29.43,0:51:31.33,yin,,0,0,0,,为什么没有警告呢\\N{\\fs12}Okay? Why is that not complaining?\r\nDialogue: 0,0:51:31.49,0:51:32.65,yin,,0,0,0,,因为那些方法都是可选的\\N{\\fs12}Because they're all optional.\r\nDialogue: 0,0:51:32.95,0:51:34.77,yin,,0,0,0,,如果其中某个方法是必需的\\N{\\fs12}If any of those methods would required,\r\nDialogue: 0,0:51:35.24,0:51:36.84,yin,,0,0,0,,这里就会出现警告\\N{\\fs12}then it would be complaining here,\r\nDialogue: 0,0:51:36.84,0:51:39.01,yin,,0,0,0,,会提示 你没有实现这个必需方法\\N{\\fs12}it would be saying you don't implement this required method.\r\nDialogue: 0,0:51:39.40,0:51:41.99,yin,,0,0,0,,但因为都是可选的 所以这里没有警告\\N{\\fs12}Okay? But since they're all optional, it doesn't do it.\r\nDialogue: 0,0:51:41.99,0:51:45.09,yin,,0,0,0,,但并不是真的不需要 因为我们想要实现缩放\\N{\\fs12}But, it's not really optional for us because we want zooming,\r\nDialogue: 0,0:51:45.09,0:51:47.02,yin,,0,0,0,,但缩放方法本身是可选的\\N{\\fs12}it's only optional because zooming is optional,\r\nDialogue: 0,0:51:47.28,0:51:51.77,yin,,0,0,0,,我们需要在这里声明滚动视图中要缩放的视图\\N{\\fs12}but we have to specify here the view for zooming in scroll view.\r\nDialogue: 0,0:51:52.32,0:51:57.17,yin,,0,0,0,,我们需要返回要缩放的目标子视图\\N{\\fs12}Okay? We have to return which of the subviews we want to zoom,\r\nDialogue: 0,0:51:57.18,0:51:59.53,yin,,0,0,0,,这里只有一个 就是imageView\\N{\\fs12}and we only have one, which is in our imageView.\r\nDialogue: 0,0:52:00.19,0:52:01.08,yin,,0,0,0,,我们返回它\\N{\\fs12}So we're going to return that\r\nDialogue: 0,0:52:01.10,0:52:02.73,yin,,0,0,0,,这样当滚动视图中发生缩放时\\N{\\fs12}and it's gonna cause the imageView to be zoomed\r\nDialogue: 0,0:52:02.73,0:52:04.29,yin,,0,0,0,,imageView就会被缩放\\N{\\fs12}when zooming happens in the scroll view.\r\nDialogue: 0,0:52:04.57,0:52:06.08,yin,,0,0,0,,如果这里返回nil\\N{\\fs12}If we returned nil here,\r\nDialogue: 0,0:52:06.30,0:52:08.30,yin,,0,0,0,,那么控制缩放的捏合手势\\N{\\fs12}then that pan, the zooming rather, pinching,\r\nDialogue: 0,0:52:08.31,0:52:09.67,yin,,0,0,0,,在滚动视图中不会有任何效果\\N{\\fs12}would do nothing in the scroll view.\r\nDialogue: 0,0:52:10.22,0:52:14.32,yin,,0,0,0,,缩放效果 即修改transform值\\N{\\fs12}Okay? It's only going to zoom, I.E. Change the transform,\r\nDialogue: 0,0:52:14.46,0:52:18.03,yin,,0,0,0,,只针对这里指定的返回子视图\\N{\\fs12}of whatever subview you specify by returning here, okay?\r\nDialogue: 0,0:52:18.39,0:52:19.24,yin,,0,0,0,,我们来运行试试\\N{\\fs12}So let's try this.\r\nDialogue: 0,0:52:21.57,0:52:22.77,yin,,0,0,0,,看看能否缩小\\N{\\fs12}See if we can zoom in.\r\nDialogue: 0,0:52:28.14,0:52:29.21,yin,,0,0,0,,打开花朵图片\\N{\\fs12}Alright, so we go to the flower.\r\nDialogue: 0,0:52:30.42,0:52:32.69,yin,,0,0,0,,花朵出来了 试试缩小 可以了\\N{\\fs12}There's our flower, let's try zooming in, indeed we can.\r\nDialogue: 0,0:52:33.10,0:52:34.76,yin,,0,0,0,,也可以放大\\N{\\fs12}Okay, and zoom out.\r\nDialogue: 0,0:52:36.01,0:52:38.97,yin,,0,0,0,,我没有设置 所以它不能缩小到\\N{\\fs12}Now, I haven't set it so that it zooms small enough\r\nDialogue: 0,0:52:39.51,0:52:41.39,yin,,0,0,0,,小于滚动视图的大小\\N{\\fs12}to be smaller than the scroll view,\r\nDialogue: 0,0:52:41.56,0:52:42.79,yin,,0,0,0,,现在是因为我按住它了\\N{\\fs12}but, because I'm holding it right here,\r\nDialogue: 0,0:52:42.80,0:52:44.24,yin,,0,0,0,,如果我松手 它就会放大\\N{\\fs12}if I let it go, it zooms out,\r\nDialogue: 0,0:52:44.33,0:52:46.89,yin,,0,0,0,,如果允许这样缩小\\N{\\fs12}but if I allowed that, then what would happen is\r\nDialogue: 0,0:52:46.91,0:52:48.54,yin,,0,0,0,,底部就会出现这样的白色边框\\N{\\fs12}you'd have this white border at the bottom.\r\nDialogue: 0,0:52:48.94,0:52:49.49,yin,,0,0,0,,看到了吗\\N{\\fs12}You see that?\r\nDialogue: 0,0:52:49.80,0:52:50.71,yin,,0,0,0,,白色边框\\N{\\fs12}That white border?\r\nDialogue: 0,0:52:50.71,0:52:53.68,yin,,0,0,0,,这是滚动视图的背景色透出来了\\N{\\fs12}That's the background color of the scroll view showing through.\r\nDialogue: 0,0:52:54.28,0:52:57.79,yin,,0,0,0,,我还可以放大 可以放到很大\\N{\\fs12}Okay? And I can zoom in, I can zoom even in so far\r\nDialogue: 0,0:52:57.79,0:52:59.21,yin,,0,0,0,,甚至显示得有点像素化了\\N{\\fs12}that it starts to get a little pixelated,\r\nDialogue: 0,0:52:59.23,0:53:00.37,yin,,0,0,0,,因为我放得太大\\N{\\fs12}because I'm zooming in\r\nDialogue: 0,0:53:00.39,0:53:03.35,yin,,0,0,0,,超过了图片能够显示的像素\\N{\\fs12}more than the picture even has pixels to show me.\r\nDialogue: 0,0:53:03.35,0:53:04.37,yin,,0,0,0,,所以可以看到中间这里\\N{\\fs12}So right in the middle there,\r\nDialogue: 0,0:53:04.37,0:53:05.52,yin,,0,0,0,,出现了阶梯状图像\\N{\\fs12}you can see the little stair step.\r\nDialogue: 0,0:53:06.39,0:53:08.34,yin,,0,0,0,,明白吗\\N{\\fs12}Okay? Make sense?\r\nDialogue: 0,0:53:08.34,0:53:09.86,yin,,0,0,0,,可以看看另一幅图 小辣椒图\\N{\\fs12}We can look at another one, the peppers.\r\nDialogue: 0,0:53:11.37,0:53:14.80,yin,,0,0,0,,小辣椒出来了 缩小\\N{\\fs12}Okay, there's the peppers, let's zoom down. Okay?\r\nDialogue: 0,0:53:16.37,0:53:16.66,yin,,0,0,0,,明白了吗\\N{\\fs12}Make sense?\r\nDialogue: 0,0:53:16.67,0:53:18.41,yin,,0,0,0,,进展真不错\\N{\\fs12}So, we're making really good progress here.\r\nDialogue: 0,0:53:18.59,0:53:20.97,yin,,0,0,0,,还有个问题是 如果点击花朵\\N{\\fs12}One problem though is if I say flowers,\r\nDialogue: 0,0:53:20.98,0:53:24.80,yin,,0,0,0,,UI又被卡住了 怎么回事\\N{\\fs12}and then oh, again, my UI is blocked, what's going on?\r\nDialogue: 0,0:53:24.80,0:53:26.14,yin,,0,0,0,,真的要解决这个问题\\N{\\fs12}I really got to fix that.\r\nDialogue: 0,0:53:26.14,0:53:29.38,yin,,0,0,0,,我们不希望选中一个时 UI被卡住\\N{\\fs12}Okay? We don't want our UI to be blocked when we pick one.\r\nDialogue: 0,0:53:29.38,0:53:31.38,yin,,0,0,0,,比如说 我选择了水母\\N{\\fs12}For example, if I pick jellyfish, I might,\r\nDialogue: 0,0:53:31.56,0:53:32.83,yin,,0,0,0,,如果很长时间都不出来\\N{\\fs12}if it's taking a long time,\r\nDialogue: 0,0:53:32.93,0:53:35.06,yin,,0,0,0,,我可能就改变主意了 想选花朵\\N{\\fs12}I might want to change my mind and then go pick flower.\r\nDialogue: 0,0:53:35.39,0:53:38.15,yin,,0,0,0,,我希望可以在UI中进行任意操作\\N{\\fs12}Okay? So I want to be able to do stuff in my UI\r\nDialogue: 0,0:53:38.94,0:53:41.18,yin,,0,0,0,,不因为网络调用而被卡住\\N{\\fs12}without it being blocked by this network call.\r\nDialogue: 0,0:53:41.83,0:53:44.12,yin,,0,0,0,,我们来修改一下\\N{\\fs12}Okay? So, let's fix that.\r\nDialogue: 0,0:53:44.47,0:53:47.67,yin,,0,0,0,,方法就是让这里的URL抓取操作\\N{\\fs12}And the way we're gonna do that is by doing that URL fetch,\r\nDialogue: 0,0:53:47.67,0:53:50.93,yin,,0,0,0,,在另一个线程执行\\N{\\fs12}this one right here, in another thread,\r\nDialogue: 0,0:53:51.01,0:53:52.46,yin,,0,0,0,,在另一个队列中\\N{\\fs12}okay, on a different queue.\r\nDialogue: 0,0:53:53.14,0:53:55.91,yin,,0,0,0,,我们要怎么做呢\\N{\\fs12}And, so how are we going to do that?\r\nDialogue: 0,0:53:56.18,0:53:57.08,yin,,0,0,0,,非常简单\\N{\\fs12}Really, really simply.\r\nDialogue: 0,0:53:57.08,0:53:58.94,yin,,0,0,0,,只要删掉这行代码\\N{\\fs12}I'm just gonna get rid of this line of code,\r\nDialogue: 0,0:53:59.32,0:54:00.78,yin,,0,0,0,,把它注释掉\\N{\\fs12}comment it out actually,\r\nDialogue: 0,0:54:00.95,0:54:05.20,yin,,0,0,0,,写上self startDownloadingImage\\N{\\fs12}and I'm gonna say self startDownloadingImage.\r\nDialogue: 0,0:54:05.75,0:54:08.13,yin,,0,0,0,,然后实现这个方法\\N{\\fs12}Okay? And then we're gonna implement this method,\r\nDialogue: 0,0:54:08.96,0:54:11.47,yin,,0,0,0,,startDownloadingImage\\N{\\fs12}startDownloadingImage.\r\nDialogue: 0,0:54:11.93,0:54:13.84,yin,,0,0,0,,这个方法只需要\\N{\\fs12}Okay? And all this thing needs to do\r\nDialogue: 0,0:54:13.98,0:54:16.09,yin,,0,0,0,,开始下载\\N{\\fs12}is start the download happening,\r\nDialogue: 0,0:54:16.10,0:54:17.55,yin,,0,0,0,,会在另一个线程中执行\\N{\\fs12}it's going to happen in another thread,\r\nDialogue: 0,0:54:17.56,0:54:19.74,yin,,0,0,0,,它会通过完成处理程序进行回调\\N{\\fs12}it's gonna call us back with that completion handler\r\nDialogue: 0,0:54:19.75,0:54:20.59,yin,,0,0,0,,回调之后\\N{\\fs12}and when it does,\r\nDialogue: 0,0:54:20.68,0:54:24.32,yin,,0,0,0,,就要执行这行代码\\N{\\fs12}I'm gonna execute this line of code, basically, okay,\r\nDialogue: 0,0:54:24.38,0:54:29.88,yin,,0,0,0,,这部分会使用URL下载任务\\N{\\fs12}but this part I'm gonna do using the URL download task\r\nDialogue: 0,0:54:29.88,0:54:31.52,yin,,0,0,0,,幻灯片中见过的\\N{\\fs12}that we saw in the slides. Okay?\r\nDialogue: 0,0:54:31.89,0:54:34.78,yin,,0,0,0,,我们来讲一下这个startDownloadingImage\\N{\\fs12}So let's, let's talk about this startDownloadingImage\r\nDialogue: 0,0:54:34.86,0:54:36.61,yin,,0,0,0,,以及这个方法是怎样的\\N{\\fs12}and what this method needs to look like.\r\nDialogue: 0,0:54:37.01,0:54:40.79,yin,,0,0,0,,首先 我要将image设为nil\\N{\\fs12}The first thing is I'm gonna set image to nil, okay?\r\nDialogue: 0,0:54:41.62,0:54:44.01,yin,,0,0,0,,要求我下载一幅新图像\\N{\\fs12}I've been asked to start downloading a new image,\r\nDialogue: 0,0:54:44.13,0:54:45.15,yin,,0,0,0,,在下载时\\N{\\fs12}while it's downloading,\r\nDialogue: 0,0:54:45.16,0:54:48.77,yin,,0,0,0,,我要清除当前图像视图中的内容\\N{\\fs12}I'm gonna clear whatever's in my image view currently.\r\nDialogue: 0,0:54:49.37,0:54:51.30,yin,,0,0,0,,所以只要将它清空\\N{\\fs12}Okay? So I'm just gonna blank that out.\r\nDialogue: 0,0:54:51.53,0:54:53.86,yin,,0,0,0,,所以首先要将image设为nil\\N{\\fs12}So I'm gonna set my image to start off to be nil.\r\nDialogue: 0,0:54:54.63,0:54:58.74,yin,,0,0,0,,然后 只要有能够尝试的imageURL\\N{\\fs12}And then, as long as I have an imageURL to go try,\r\nDialogue: 0,0:54:59.27,0:55:01.00,yin,,0,0,0,,我们就会尝试下载\\N{\\fs12}then we'll try doing a download,\r\nDialogue: 0,0:55:01.17,0:55:02.83,yin,,0,0,0,,和幻灯片中讲到的一样\\N{\\fs12}and as we saw in the slides,\r\nDialogue: 0,0:55:03.45,0:55:05.46,yin,,0,0,0,,先把这里扩大一点\\N{\\fs12}let's make a lot of space here, oops.\r\nDialogue: 0,0:55:07.42,0:55:10.03,yin,,0,0,0,,我们要将这个URL做成请求\\N{\\fs12}We need to make this URL request, okay?\r\nDialogue: 0,0:55:10.77,0:55:11.89,yin,,0,0,0,,叫它request\\N{\\fs12}We'll call it request,\r\nDialogue: 0,0:55:12.08,0:55:16.63,yin,,0,0,0,,只要用NSURLRequest requestWithURL\\N{\\fs12}and that's just NSURLRequest, requestWithURL,\r\nDialogue: 0,0:55:16.74,0:55:18.17,yin,,0,0,0,,目标URL是什么呢\\N{\\fs12}and what's the URL we want?\r\nDialogue: 0,0:55:18.23,0:55:20.89,yin,,0,0,0,,self.imageURL\\N{\\fs12}Self dot imageURL. Okay?\r\nDialogue: 0,0:55:20.91,0:55:24.64,yin,,0,0,0,,这样就创建了一个获取该imageURL的请求\\N{\\fs12}So this creates a request to go get that imageURL,\r\nDialogue: 0,0:55:24.64,0:55:26.01,yin,,0,0,0,,现在我们需要创建一个任务\\N{\\fs12}now we have to create a task,\r\nDialogue: 0,0:55:26.02,0:55:28.47,yin,,0,0,0,,一个后台任务来执行这个请求\\N{\\fs12}a background task to go do that request.\r\nDialogue: 0,0:55:28.97,0:55:31.81,yin,,0,0,0,,我们用URLSessionConfiguration\\N{\\fs12}So let's do this URLSessionConfiguration thing,\r\nDialogue: 0,0:55:31.81,0:55:34.27,yin,,0,0,0,,在讲幻灯片时只大概提了一下\\N{\\fs12}which I kind of hand waved in the slides,\r\nDialogue: 0,0:55:34.68,0:55:37.11,yin,,0,0,0,,configuration配置部分\\N{\\fs12}but the configuration, really,\r\nDialogue: 0,0:55:37.12,0:55:40.31,yin,,0,0,0,,有三种配置可用\\N{\\fs12}there's three different kinds of configurations you can have,\r\nDialogue: 0,0:55:40.81,0:55:41.60,yin,,0,0,0,,非常简单\\N{\\fs12}it's pretty simple,\r\nDialogue: 0,0:55:41.65,0:55:43.97,yin,,0,0,0,,一种是ephemeralSessionConfiguration临时会话配置\\N{\\fs12}one is an ephemeralSessionConfiguration,\r\nDialogue: 0,0:55:43.97,0:55:45.43,yin,,0,0,0,,如果要下载什么内容\\N{\\fs12}that's just if you're gonna download something\r\nDialogue: 0,0:55:45.43,0:55:46.21,yin,,0,0,0,,下完就完成了\\N{\\fs12}and you're gonna be done.\r\nDialogue: 0,0:55:46.67,0:55:48.02,yin,,0,0,0,,这就是我们在做的事情\\N{\\fs12}And that's exactly what we're doing.\r\nDialogue: 0,0:55:48.30,0:55:51.16,yin,,0,0,0,,还有一个是defaultSessionConfiguration默认会话配置\\N{\\fs12}There's another one which is defaultSessionConfiguration.\r\nDialogue: 0,0:55:51.16,0:55:54.26,yin,,0,0,0,,它表示你可能在下载多个文件\\N{\\fs12}That means you might be multi, downloading multiple files\r\nDialogue: 0,0:55:54.26,0:55:57.40,yin,,0,0,0,,或者让这个会话保持活动状态\\N{\\fs12}or otherwise you keeping this session active\r\nDialogue: 0,0:55:57.40,0:55:59.83,yin,,0,0,0,,执行多项内容 这是默认值\\N{\\fs12}and doing multiple things, but it's just the default,\r\nDialogue: 0,0:55:59.94,0:56:01.96,yin,,0,0,0,,最后一种非常强大\\N{\\fs12}and the last one, really powerful,\r\nDialogue: 0,0:56:01.96,0:56:04.53,yin,,0,0,0,,但要理解iOS的多任务才能使用\\N{\\fs12}but we need to understand iOS multitasking to do it\r\nDialogue: 0,0:56:04.54,0:56:06.58,yin,,0,0,0,,叫做backgroundSessionConfiguration后台会话配置\\N{\\fs12}is backgroundSessionConfiguration.\r\nDialogue: 0,0:56:06.89,0:56:10.68,yin,,0,0,0,,backgroundSessionConfiguration表示开始下载文件后\\N{\\fs12}A backgroundSessionConfiguration means start downloading this file\r\nDialogue: 0,0:56:10.87,0:56:15.59,yin,,0,0,0,,即使用户切换到其他应用或应用停止\\N{\\fs12}and even if the user switches to another app or my app dies,\r\nDialogue: 0,0:56:15.69,0:56:16.77,yin,,0,0,0,,也会继续下载\\N{\\fs12}keep downloading it,\r\nDialogue: 0,0:56:16.77,0:56:18.71,yin,,0,0,0,,下载完成后 再向我发消息\\N{\\fs12}and when it's done, call me back\r\nDialogue: 0,0:56:18.72,0:56:21.09,yin,,0,0,0,,如果需要的话 启动应用来处理\\N{\\fs12}and launch my app, if necessary, to handle that.\r\nDialogue: 0,0:56:21.73,0:56:23.95,yin,,0,0,0,,它是很强大的会话模式\\N{\\fs12}Okay? So it was a very powerful session.\r\nDialogue: 0,0:56:23.95,0:56:28.16,yin,,0,0,0,,但今天我们只用简单一些的临时会话配置\\N{\\fs12}But today, we're just going to do the simpler ephemeral, okay?\r\nDialogue: 0,0:56:28.39,0:56:31.68,yin,,0,0,0,,现在创建URLSession\\N{\\fs12}And so now we'll just create the session, URLSession.\r\nDialogue: 0,0:56:34.68,0:56:38.10,yin,,0,0,0,,创建NSURLSession时\\N{\\fs12}And I'm gonna create this NSURLSession\r\nDialogue: 0,0:56:38.20,0:56:41.90,yin,,0,0,0,,就使用默认方法\\N{\\fs12}using the default way to do it,\r\nDialogue: 0,0:56:41.92,0:56:44.35,yin,,0,0,0,,只要指定configuration\\N{\\fs12}which is just by specifying the configuration only.\r\nDialogue: 0,0:56:44.35,0:56:46.55,yin,,0,0,0,,不使用委托或委托队列\\N{\\fs12}I'm not doing the delegate or delegate queue.\r\nDialogue: 0,0:56:46.84,0:56:49.92,yin,,0,0,0,,所以回调方法会在另一个队列上\\N{\\fs12}So my callback is going to be on a different queue,\r\nDialogue: 0,0:56:49.99,0:56:51.90,yin,,0,0,0,,不会在主队列上\\N{\\fs12}not on the main queue, alright?\r\nDialogue: 0,0:56:52.33,0:56:58.08,yin,,0,0,0,,现在来创建URLSessionDownloadTask\\N{\\fs12}And so now let's create that URLSessionDownloadTask, okay?\r\nDialogue: 0,0:56:58.08,0:56:59.83,yin,,0,0,0,,这个任务\\N{\\fs12}So this task is going to be the...\r\nDialogue: 0,0:57:00.04,0:57:02.47,yin,,0,0,0,,会为我们执行下载操作\\N{\\fs12}the task that's gonna do the downloading for us,\r\nDialogue: 0,0:57:02.47,0:57:03.78,yin,,0,0,0,,只要请求session\\N{\\fs12}and we just asked the session,\r\nDialogue: 0,0:57:04.01,0:57:06.93,yin,,0,0,0,,请用这个请求为我们创建一个下载任务\\N{\\fs12}please create us a download task with that request,\r\nDialogue: 0,0:57:07.51,0:57:10.04,yin,,0,0,0,,用这个完成处理程序\\N{\\fs12}with this completion handler? Okay?\r\nDialogue: 0,0:57:10.67,0:57:12.77,yin,,0,0,0,,把这段代码另起一行\\N{\\fs12}And let's go ahead and put this on the other line\r\nDialogue: 0,0:57:12.78,0:57:13.45,yin,,0,0,0,,方便大家看清楚\\N{\\fs12}so you can see it.\r\nDialogue: 0,0:57:13.62,0:57:15.65,yin,,0,0,0,,有一个小技巧 如果你的参数\\N{\\fs12}One little trick, if you have an argument\r\nDialogue: 0,0:57:15.67,0:57:17.53,yin,,0,0,0,,是像这样的block\\N{\\fs12}that's a block like this, okay?\r\nDialogue: 0,0:57:17.53,0:57:21.64,yin,,0,0,0,,如果双击它 系统就会自动补全内容\\N{\\fs12}If you double click it, it will put it in there for you.\r\nDialogue: 0,0:57:22.53,0:57:25.00,yin,,0,0,0,,也就是会自动添加这些内容\\N{\\fs12}Okay? In other words, it'll type all this stuff in.\r\nDialogue: 0,0:57:25.76,0:57:27.79,yin,,0,0,0,,我不喜欢location这个名字\\N{\\fs12}I don't like this name, location,\r\nDialogue: 0,0:57:27.81,0:57:29.98,yin,,0,0,0,,换一个更清楚的名字localfile本地文件\\N{\\fs12}just to make it clear, this is local file,\r\nDialogue: 0,0:57:29.98,0:57:32.05,yin,,0,0,0,,这是一个本地文件的URL\\N{\\fs12}this is an URL of the local file\r\nDialogue: 0,0:57:32.05,0:57:34.86,yin,,0,0,0,,应用会将URL内容下载至这个文件中\\N{\\fs12}that is downloading this content to this URL to.\r\nDialogue: 0,0:57:34.86,0:57:37.79,yin,,0,0,0,,所以我要叫它localfile\\N{\\fs12}That's why I like to call that localfile.\r\nDialogue: 0,0:57:38.00,0:57:40.26,yin,,0,0,0,,这就是这部分要做的代码\\N{\\fs12}And then here's the code that we want to do in here.\r\nDialogue: 0,0:57:40.74,0:57:45.34,yin,,0,0,0,,完成时会发生什么\\N{\\fs12}And, what happens when it's done?\r\nDialogue: 0,0:57:45.78,0:57:47.67,yin,,0,0,0,,调用这个完成处理程序时\\N{\\fs12}Okay? When we get this completion handler called.\r\nDialogue: 0,0:57:47.67,0:57:50.67,yin,,0,0,0,,我们要设置self.image 对吧\\N{\\fs12}Well, we want to set self dot image, okay,\r\nDialogue: 0,0:57:51.01,0:57:53.04,yin,,0,0,0,,但这里有一件事需要注意\\N{\\fs12}but the only thing here we have to be careful is\r\nDialogue: 0,0:57:53.05,0:57:54.27,yin,,0,0,0,,那就是 我们不在主队列上\\N{\\fs12}we're not on the main queue,\r\nDialogue: 0,0:57:54.28,0:57:56.99,yin,,0,0,0,,所以要在另一个队列上执行 来做一下\\N{\\fs12}so we have to do that in the other queue, so let's do this.\r\nDialogue: 0,0:57:57.07,0:57:59.29,yin,,0,0,0,,首先判断 如果没有错误\\N{\\fs12}If there's no error, first of all,\r\nDialogue: 0,0:57:59.40,0:58:01.53,yin,,0,0,0,,可以看到 这里有个错误参数error\\N{\\fs12}you can see that there's error argument right here,\r\nDialogue: 0,0:58:01.64,0:58:02.70,yin,,0,0,0,,如果没有错误...\\N{\\fs12}so I'm gonna say if there's no error,\r\nDialogue: 0,0:58:02.71,0:58:03.45,yin,,0,0,0,,如果有错误\\N{\\fs12}if there was an error,\r\nDialogue: 0,0:58:03.47,0:58:05.78,yin,,0,0,0,,你可能要在视图某个位置\\N{\\fs12}you might want to put not found or something\r\nDialogue: 0,0:58:05.81,0:58:07.76,yin,,0,0,0,,显示未找到等等\\N{\\fs12}in your view somewhere,\r\nDialogue: 0,0:58:07.78,0:58:09.75,yin,,0,0,0,,但如果没有错误\\N{\\fs12}but, if there's no error,\r\nDialogue: 0,0:58:09.91,0:58:12.09,yin,,0,0,0,,我要做一件有趣的事情\\N{\\fs12}then I'm gonna do an interesting thing here\r\nDialogue: 0,0:58:12.09,0:58:13.15,yin,,0,0,0,,大家可能会很惊讶\\N{\\fs12}that you might be like, what,\r\nDialogue: 0,0:58:13.45,0:58:14.84,yin,,0,0,0,,我会检查判断\\N{\\fs12}which is I'm going to check to see\r\nDialogue: 0,0:58:14.84,0:58:20.93,yin,,0,0,0,,requestURL和self.imageURL的URL是否相等\\N{\\fs12}if the requestURL's URL is equal to self dot imageURL.\r\nDialogue: 0,0:58:22.12,0:58:24.47,yin,,0,0,0,,我为什么要这样做呢\\N{\\fs12}Okay. Why would I do that?\r\nDialogue: 0,0:58:24.47,0:58:26.23,yin,,0,0,0,,打错了 这里是request.URL\\N{\\fs12}Oops, request dot URL.\r\nDialogue: 0,0:58:26.23,0:58:27.17,yin,,0,0,0,,我为什么要这样做\\N{\\fs12}Why would I do this?\r\nDialogue: 0,0:58:27.17,0:58:31.65,yin,,0,0,0,,这里我们将request设为了self.imageURL\\N{\\fs12}Why would I check to see if this is, which we set to be this,\r\nDialogue: 0,0:58:31.84,0:58:34.90,yin,,0,0,0,,为什么还要检查它俩是否相等呢\\N{\\fs12}why would I check to see if this is equal to self dot imageURL,\r\nDialogue: 0,0:58:35.13,0:58:36.02,yin,,0,0,0,,有人知道吗\\N{\\fs12}anyone have an idea?\r\nDialogue: 0,0:58:39.46,0:58:42.25,yin,,0,0,0,,[学生回答]\\N{\\fs12}Student: [inaudible]\r\nDialogue: 0,0:58:42.58,0:58:43.25,yin,,0,0,0,,没错\\N{\\fs12}Absolutely.\r\nDialogue: 0,0:58:43.36,0:58:46.53,yin,,0,0,0,,防止应用中的某个对象\\N{\\fs12}Okay, in case we, somebody else in the app\r\nDialogue: 0,0:58:46.70,0:58:48.82,yin,,0,0,0,,修改了这个imageURL\\N{\\fs12}changed the imageURL,\r\nDialogue: 0,0:58:48.84,0:58:50.60,yin,,0,0,0,,在网络下载的过程中\\N{\\fs12}asked us to display something different,\r\nDialogue: 0,0:58:50.81,0:58:53.62,yin,,0,0,0,,要求应用显示别的内容\\N{\\fs12}while this was outstanding. Okay?\r\nDialogue: 0,0:58:53.72,0:58:56.73,yin,,0,0,0,,应用去网上抓取URL内容了 比如要花十分钟\\N{\\fs12}This URL is out fetching, let's take, it takes 10 minutes,\r\nDialogue: 0,0:58:56.73,0:58:58.90,yin,,0,0,0,,是一个很慢的网站\\N{\\fs12}okay, it really is a slow website out there,\r\nDialogue: 0,0:58:58.90,0:59:00.94,yin,,0,0,0,,要花十分钟 在这十分钟里\\N{\\fs12}it takes 10 minutes, and in that 10 minutes,\r\nDialogue: 0,0:59:00.95,0:59:02.39,yin,,0,0,0,,用户点击了其他内容\\N{\\fs12}the user clicks on something else\r\nDialogue: 0,0:59:02.46,0:59:04.25,yin,,0,0,0,,想让这个视图显示其他内容\\N{\\fs12}and wants this view to display something else.\r\nDialogue: 0,0:59:04.47,0:59:06.63,yin,,0,0,0,,这个下载任务还要十分钟才能完成\\N{\\fs12}Well, this download task is still gonna\r\nDialogue: 0,0:59:06.65,0:59:09.95,yin,,0,0,0,,但我们想要忽略它了\\N{\\fs12}complete 10 minutes later, but we want to ignore it,\r\nDialogue: 0,0:59:10.32,0:59:11.60,yin,,0,0,0,,这个请求\\N{\\fs12}basically, because it's a request\r\nDialogue: 0,0:59:11.60,0:59:13.10,yin,,0,0,0,,请求的是我们不再需要的内容\\N{\\fs12}for something we're not going to use anymore.\r\nDialogue: 0,0:59:13.47,0:59:14.82,yin,,0,0,0,,这是在理解多任务处理时\\N{\\fs12}So this is something that would be important\r\nDialogue: 0,0:59:14.83,0:59:16.35,yin,,0,0,0,,很重要的一点\\N{\\fs12}to understand about multitasking,\r\nDialogue: 0,0:59:16.36,0:59:18.09,yin,,0,0,0,,那就是 操作花费时间\\N{\\fs12}is that things take time,\r\nDialogue: 0,0:59:18.25,0:59:19.50,yin,,0,0,0,,当操作完成时\\N{\\fs12}and when things are finished,\r\nDialogue: 0,0:59:19.60,0:59:21.48,yin,,0,0,0,,要确保当前状态\\N{\\fs12}you have to make sure the state of the world\r\nDialogue: 0,0:59:21.66,0:59:23.80,yin,,0,0,0,,依旧匹配你所认为的\\N{\\fs12}still matches what you thought it was\r\nDialogue: 0,0:59:23.80,0:59:25.31,yin,,0,0,0,,其开始时的状态\\N{\\fs12}when you asked it to start.\r\nDialogue: 0,0:59:25.82,0:59:28.27,yin,,0,0,0,,多任务编程\\N{\\fs12}Okay? Multitasking programming,\r\nDialogue: 0,0:59:28.49,0:59:31.15,yin,,0,0,0,,多线程编程\\N{\\fs12}multithreaded programming rather, is really,\r\nDialogue: 0,0:59:31.22,0:59:33.28,yin,,0,0,0,,在这方面可能有些令人费解\\N{\\fs12}can be kind of mind-bending in that way,\r\nDialogue: 0,0:59:33.44,0:59:35.21,yin,,0,0,0,,但你自己要清楚地思考\\N{\\fs12}but you really have to have the discipline to think, okay,\r\nDialogue: 0,0:59:35.21,0:59:36.97,yin,,0,0,0,,如果这个操作要花费十分钟\\N{\\fs12}what if this takes 10 minutes,\r\nDialogue: 0,0:59:37.17,0:59:39.04,yin,,0,0,0,,那我要让它做什么\\N{\\fs12}then what, what do I want this to do?\r\nDialogue: 0,0:59:39.72,0:59:41.31,yin,,0,0,0,,这是你需要做的事情\\N{\\fs12}Alright? So that's the kind of thing you have to do.\r\nDialogue: 0,0:59:41.85,0:59:43.97,yin,,0,0,0,,在这里 二者是相同的\\N{\\fs12}So, in this case though, it is the same.\r\nDialogue: 0,0:59:44.17,0:59:47.18,yin,,0,0,0,,我们用返回的URL数据\\N{\\fs12}So let's go ahead and create a UIImage\r\nDialogue: 0,0:59:47.19,0:59:49.41,yin,,0,0,0,,来新建一个UIImage\\N{\\fs12}out of the URL data that came back,\r\nDialogue: 0,0:59:49.41,0:59:51.94,yin,,0,0,0,,所以这里我要创建一个本地UIImage\\N{\\fs12}so I'm gonna create a local UIImage here\r\nDialogue: 0,0:59:52.40,0:59:56.56,yin,,0,0,0,,我要用UIImage imageWithData\\N{\\fs12}and I'm gonna do that doing UIImage, imageWithData,\r\nDialogue: 0,0:59:56.70,0:59:59.13,yin,,0,0,0,,这里可以直接用localfile\\N{\\fs12}and this time I can just say the localfile,\r\nDialogue: 0,0:59:59.25,1:00:06.63,yin,,0,0,0,,抱歉 忘了NSData dataWithContentsOfURL\\N{\\fs12}oops, sorry. Go do NSData dataWithContentsOfURL.\r\nDialogue: 0,1:00:06.97,1:00:12.45,yin,,0,0,0,,但这里的URL就是这个localfile\\N{\\fs12}But now the URL is this localfile. Okay?\r\nDialogue: 0,1:00:13.17,1:00:18.57,yin,,0,0,0,,这段代码执行的是本地操作\\N{\\fs12}So this, this right here, is doing locally,\r\nDialogue: 0,1:00:18.57,1:00:20.60,yin,,0,0,0,,所以不会发生阻塞 而这行代码会\\N{\\fs12}so it's not going to block, like this one did.\r\nDialogue: 0,1:00:21.03,1:00:24.64,yin,,0,0,0,,这里阻塞 因为它可能是一个http网络URL\\N{\\fs12}This one blocked because this could be a network http URL,\r\nDialogue: 0,1:00:24.98,1:00:27.82,yin,,0,0,0,,而它是一个本地文件 所以不会发生阻塞\\N{\\fs12}this one, is a local file so it can't block.\r\nDialogue: 0,1:00:28.65,1:00:31.41,yin,,0,0,0,,注意这里的操作\\N{\\fs12}Okay? Now, notice that I'm doing this.\r\nDialogue: 0,1:00:31.53,1:00:33.31,yin,,0,0,0,,看起来像是个UIKit调用\\N{\\fs12}It looks like a UIKit call.\r\nDialogue: 0,1:00:33.49,1:00:35.10,yin,,0,0,0,,是在主队列上的吗\\N{\\fs12}Am I doing this on the main queue?\r\nDialogue: 0,1:00:37.75,1:00:38.22,yin,,0,0,0,,不是\\N{\\fs12}No.\r\nDialogue: 0,1:00:38.22,1:00:40.39,yin,,0,0,0,,有人点头 有人摇头\\N{\\fs12}I see nodding heads or shaking heads.\r\nDialogue: 0,1:00:40.39,1:00:41.24,yin,,0,0,0,,说对了 不是\\N{\\fs12}You're right, no.\r\nDialogue: 0,1:00:41.24,1:00:43.10,yin,,0,0,0,,这不是在主队列上执行的\\N{\\fs12}This is not happening on the main queue.\r\nDialogue: 0,1:00:43.44,1:00:46.00,yin,,0,0,0,,而且这样是可以的\\N{\\fs12}And it turns out that that's okay.\r\nDialogue: 0,1:00:46.24,1:00:49.57,yin,,0,0,0,,UIImage是UIKit类中少数的\\N{\\fs12}UIImage is one of the few UIKit classes\r\nDialogue: 0,1:00:49.58,1:00:53.38,yin,,0,0,0,,允许不在主队列上执行操作的类之一\\N{\\fs12}that you're allowed to do things to off the main queue.\r\nDialogue: 0,1:00:53.88,1:00:55.14,yin,,0,0,0,,因为实际上\\N{\\fs12}And that's because this is not actually\r\nDialogue: 0,1:00:55.15,1:00:56.53,yin,,0,0,0,,这里并不会做任何屏幕操作\\N{\\fs12}gonna do anything on screen,\r\nDialogue: 0,1:00:56.66,1:00:58.73,yin,,0,0,0,,我只是在这里创建了一个局部变量\\N{\\fs12}I'm just creating a local variable here\r\nDialogue: 0,1:00:59.05,1:01:02.97,yin,,0,0,0,,解析这个URL 查看对应数据\\N{\\fs12}that is parsing this URL, looking at its data,\r\nDialogue: 0,1:01:02.97,1:01:05.12,yin,,0,0,0,,为我创建一幅图像\\N{\\fs12}and creating an image for me. Okay?\r\nDialogue: 0,1:01:05.69,1:01:08.81,yin,,0,0,0,,为了好看清楚一点\\N{\\fs12}Here let's make this a little more readable\r\nDialogue: 0,1:01:08.81,1:01:09.66,yin,,0,0,0,,把这段代码移到前面\\N{\\fs12}by moving this back.\r\nDialogue: 0,1:01:10.51,1:01:13.64,yin,,0,0,0,,这里实际上不会涉及UI操作\\N{\\fs12}Okay? So, this is not gonna actually touch the UI,\r\nDialogue: 0,1:01:13.65,1:01:15.94,yin,,0,0,0,,这时只是创建UIImage对象\\N{\\fs12}I'm just creating the UIImage object at this point,\r\nDialogue: 0,1:01:16.10,1:01:16.80,yin,,0,0,0,,没问题\\N{\\fs12}that's okay.\r\nDialogue: 0,1:01:17.26,1:01:19.08,yin,,0,0,0,,但是下一行代码 我要用\\N{\\fs12}But the next line of code I want to do\r\nDialogue: 0,1:01:19.09,1:01:21.86,yin,,0,0,0,,self.image=image\\N{\\fs12}is self dot image equals image, okay?\r\nDialogue: 0,1:01:21.86,1:01:23.63,yin,,0,0,0,,现在我想要将我的图像设成这幅图\\N{\\fs12}Now I want to set my image to that.\r\nDialogue: 0,1:01:23.96,1:01:26.45,yin,,0,0,0,,这行代码要在主队列上执行\\N{\\fs12}This line of code has to happen on the main thread,\r\nDialogue: 0,1:01:26.79,1:01:29.26,yin,,0,0,0,,看一下在设置图像的方法setImage里\\N{\\fs12}because look at all the UI stuff we're gonna do\r\nDialogue: 0,1:01:29.33,1:01:30.40,yin,,0,0,0,,我们要做的各种操作\\N{\\fs12}when we do set image,\r\nDialogue: 0,1:01:30.41,1:01:32.07,yin,,0,0,0,,我们要向滚动视图发送消息\\N{\\fs12}we're gonna be talking to the scroll view,\r\nDialogue: 0,1:01:32.07,1:01:33.30,yin,,0,0,0,,要适应图像显示大小\\N{\\fs12}we're gonna be doing size fit,\r\nDialogue: 0,1:01:33.30,1:01:34.98,yin,,0,0,0,,要修改contentSize\\N{\\fs12}we're gonna change the contentSize,\r\nDialogue: 0,1:01:34.98,1:01:36.26,yin,,0,0,0,,这里可以做各种操作\\N{\\fs12}this can be doing all kinds of stuff,\r\nDialogue: 0,1:01:36.38,1:01:39.27,yin,,0,0,0,,所以要在主队列上运行\\N{\\fs12}so this has to be on the main thread,\r\nDialogue: 0,1:01:39.28,1:01:43.29,yin,,0,0,0,,具体实现方法就是用dispatch_async\\N{\\fs12}and so I'm gonna do that with dispatch async.\r\nDialogue: 0,1:01:43.97,1:01:51.32,yin,,0,0,0,,dispatch_get_main_queue 然后是一个block\\N{\\fs12}Dispatch underbar queue, get main queue, and a block here,\r\nDialogue: 0,1:01:51.66,1:01:55.94,yin,,0,0,0,,然后把这个调用放到block中\\N{\\fs12}and inside this block, I'm gonna put this call right here.\r\nDialogue: 0,1:01:56.96,1:02:02.43,yin,,0,0,0,,剪切 粘贴\\N{\\fs12}Cut and paste. Right? Okay?\r\nDialogue: 0,1:02:02.91,1:02:05.05,yin,,0,0,0,,还有一种方法是\\N{\\fs12}Now another way I could have done this was\r\nDialogue: 0,1:02:05.15,1:02:11.76,yin,,0,0,0,,self performSelectorOnMainThread:@selector(setImage:)\\N{\\fs12}self performSelectorOnMainThread, at sign selector, setImage\r\nDialogue: 0,1:02:12.06,1:02:14.65,yin,,0,0,0,,withObject:image waitUntilDone:NO\\N{\\fs12}withObject, the image, waitUntilDone, NO.\r\nDialogue: 0,1:02:15.34,1:02:16.85,yin,,0,0,0,,这两行代码\\N{\\fs12}Okay, these two lines of code\r\nDialogue: 0,1:02:17.11,1:02:18.46,yin,,0,0,0,,基本上是完全一样的\\N{\\fs12}are pretty much exactly the same thing.\r\nDialogue: 0,1:02:19.88,1:02:22.67,yin,,0,0,0,,大家明白了吗\\N{\\fs12}Okay? Everybody understand that?\r\nDialogue: 0,1:02:24.79,1:02:26.53,yin,,0,0,0,,明白这行代码吗\\N{\\fs12}Okay, everyone understand this line of code?\r\nDialogue: 0,1:02:26.94,1:02:27.31,yin,,0,0,0,,有问题吗\\N{\\fs12}Question?\r\nDialogue: 0,1:02:28.17,1:02:38.37,yin,,0,0,0,,[学生提问]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,1:02:38.37,1:02:41.40,yin,,0,0,0,,问题是 下载这幅图像之前\\N{\\fs12}Yeah, so the question is before I start downloading this image,\r\nDialogue: 0,1:02:41.40,1:02:42.48,yin,,0,0,0,,要不要检查一下\\N{\\fs12}wouldn't I want to check to see\r\nDialogue: 0,1:02:42.49,1:02:44.54,yin,,0,0,0,,是否已经有正在进行的下载任务\\N{\\fs12}if I already have a download going on,\r\nDialogue: 0,1:02:44.56,1:02:46.60,yin,,0,0,0,,答案是 是的 要检查一下\\N{\\fs12}and the answer is yes you would.\r\nDialogue: 0,1:02:47.38,1:02:48.90,yin,,0,0,0,,这只是个示例演示 我们就不做了\\N{\\fs12}You know, this is demo, we're not doing it,\r\nDialogue: 0,1:02:49.04,1:02:49.95,yin,,0,0,0,,但是大家可以这样做\\N{\\fs12}but you would want to do that,\r\nDialogue: 0,1:02:49.97,1:02:51.44,yin,,0,0,0,,你可能要有一个局部变量\\N{\\fs12}you probably want to have a local variable\r\nDialogue: 0,1:02:51.44,1:02:54.26,yin,,0,0,0,,是当前下载的URL\\N{\\fs12}which is the URL that you're currently downloading,\r\nDialogue: 0,1:02:55.26,1:02:56.73,yin,,0,0,0,,甚至要有一个URL数组\\N{\\fs12}maybe even an array of them.\r\nDialogue: 0,1:02:56.95,1:02:59.16,yin,,0,0,0,,因为用户可能会来回点击\\N{\\fs12}Because the person might click back and forth and back and forth,\r\nDialogue: 0,1:02:59.74,1:03:01.51,yin,,0,0,0,,这些URL是正在下载的内容\\N{\\fs12}and so these are all the ones I have outstanding,\r\nDialogue: 0,1:03:01.51,1:03:02.56,yin,,0,0,0,,然后你可能要查找一下\\N{\\fs12}and then you'd want to go and look and see\r\nDialogue: 0,1:03:02.57,1:03:03.51,yin,,0,0,0,,看是否包含目标对象\\N{\\fs12}if it contains that object,\r\nDialogue: 0,1:03:03.52,1:03:05.57,yin,,0,0,0,,如果已经有了 就不要再下载了\\N{\\fs12}and if it does, just don't, don't do this.\r\nDialogue: 0,1:03:05.99,1:03:07.16,yin,,0,0,0,,等它下载完成\\N{\\fs12}Okay? Wait for it to come back.\r\nDialogue: 0,1:03:07.53,1:03:09.16,yin,,0,0,0,,很好的想法\\N{\\fs12}So that's really good, good point.\r\nDialogue: 0,1:03:10.23,1:03:12.70,yin,,0,0,0,,这里有一个警告 抱歉 有问题吗\\N{\\fs12}And then I have this warning right here, oh sorry, question?\r\nDialogue: 0,1:03:13.88,1:03:25.35,yin,,0,0,0,,[学生提问]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,1:03:25.37,1:03:27.21,yin,,0,0,0,,好的 问题是 你是说\\N{\\fs12}Yeah, so, the question, so you mean\r\nDialogue: 0,1:03:27.22,1:03:29.99,yin,,0,0,0,,各种操作对应的队列...\\N{\\fs12}which, where is this queue that all this stuff...\r\nDialogue: 0,1:03:30.48,1:03:31.83,yin,,0,0,0,,何时开始一个新队列呢\\N{\\fs12}When do we start a actually new queue?\r\nDialogue: 0,1:03:31.84,1:03:33.84,yin,,0,0,0,,这个队列\\N{\\fs12}Yeah, so that, that queue,\r\nDialogue: 0,1:03:34.00,1:03:36.93,yin,,0,0,0,,会执行这个完成处理程序\\N{\\fs12}that is going to do this completionHandler, right,\r\nDialogue: 0,1:03:36.93,1:03:38.39,yin,,0,0,0,,这里的这个completionHandler\\N{\\fs12}this completionHandler right here,\r\nDialogue: 0,1:03:38.45,1:03:41.30,yin,,0,0,0,,创建它的队列是由会话任务创建的\\N{\\fs12}the queue to create that is created by the session task,\r\nDialogue: 0,1:03:41.32,1:03:42.92,yin,,0,0,0,,当需要时 它就会创建它\\N{\\fs12}and it creates it when it needs it.\r\nDialogue: 0,1:03:43.15,1:03:44.18,yin,,0,0,0,,可能就是在\\N{\\fs12}Probably it creates it\r\nDialogue: 0,1:03:44.19,1:03:45.94,yin,,0,0,0,,调用这个completionHandler前创建的\\N{\\fs12}right before it calls this completionHandler,\r\nDialogue: 0,1:03:45.95,1:03:46.96,yin,,0,0,0,,但如果你有一个委托\\N{\\fs12}but if you had a delegate\r\nDialogue: 0,1:03:46.96,1:03:48.19,yin,,0,0,0,,它可能会在开始时就创建它\\N{\\fs12}it might create it right at the beginning\r\nDialogue: 0,1:03:48.21,1:03:50.05,yin,,0,0,0,,然后用它来调用委托\\N{\\fs12}and use it to call your delegate, right?\r\nDialogue: 0,1:03:50.49,1:03:52.00,yin,,0,0,0,,在这里 你可能是在需要用它\\N{\\fs12}So in this case, you probably created it\r\nDialogue: 0,1:03:52.01,1:03:53.69,yin,,0,0,0,,触发这段代码之前创建它的\\N{\\fs12}right before you need it and fired this off.\r\nDialogue: 0,1:03:53.94,1:03:55.92,yin,,0,0,0,,因为真正的URL下载操作\\N{\\fs12}Because the actual URL download is happening\r\nDialogue: 0,1:03:55.92,1:03:57.35,yin,,0,0,0,,是在另一个队列中执行的\\N{\\fs12}in yet another queue, right?\r\nDialogue: 0,1:03:57.35,1:03:58.33,yin,,0,0,0,,URL下载队列\\N{\\fs12}The URL downloading queue,\r\nDialogue: 0,1:03:58.34,1:04:00.20,yin,,0,0,0,,实际上 可能是在另一个进程中执行的\\N{\\fs12}and, in fact, it could be another process\r\nDialogue: 0,1:04:00.32,1:04:02.21,yin,,0,0,0,,如果你用了后台会话模式\\N{\\fs12}if you use that background session thing.\r\nDialogue: 0,1:04:03.13,1:04:04.12,yin,,0,0,0,,这是我想到的\\N{\\fs12}So that's all I think,\r\nDialogue: 0,1:04:04.13,1:04:05.22,yin,,0,0,0,,但这个队列应该是在\\N{\\fs12}but this queue is probably created\r\nDialogue: 0,1:04:05.24,1:04:07.07,yin,,0,0,0,,调用这个completionHandler前创建的\\N{\\fs12}right before it calls this handler,\r\nDialogue: 0,1:04:07.18,1:04:08.99,yin,,0,0,0,,是由URLSession创建的\\N{\\fs12}it's created by the session, URLSession,\r\nDialogue: 0,1:04:09.11,1:04:10.49,yin,,0,0,0,,在调用这个completionHandler前创建的\\N{\\fs12}right before it calls this handler.\r\nDialogue: 0,1:04:10.93,1:04:12.37,yin,,0,0,0,,[学生提问]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,1:04:12.48,1:04:12.88,yin,,0,0,0,,不\\N{\\fs12}No.\r\nDialogue: 0,1:04:12.96,1:04:14.22,yin,,0,0,0,,因为这是完全不同的队列\\N{\\fs12}Because this is totally separate queue,\r\nDialogue: 0,1:04:14.37,1:04:15.98,yin,,0,0,0,,毫无关联\\N{\\fs12}totally unrelated to it. Okay?\r\nDialogue: 0,1:04:15.99,1:04:17.87,yin,,0,0,0,,我们只会在这里用到主队列\\N{\\fs12}This is the only time we're touching the main queue,\r\nDialogue: 0,1:04:18.31,1:04:19.24,yin,,0,0,0,,就是这里\\N{\\fs12}right here, is when we...\r\nDialogue: 0,1:04:19.26,1:04:22.80,yin,,0,0,0,,即便在这里 这个block会被放到主队列中\\N{\\fs12}and even here, this block gets put in line on the main queue,\r\nDialogue: 0,1:04:22.81,1:04:25.15,yin,,0,0,0,,而主队列可能在执行别的操作\\N{\\fs12}the main queue might be busy doing other things.\r\nDialogue: 0,1:04:25.19,1:04:27.14,yin,,0,0,0,,从它的队列中调取别的block\\N{\\fs12}Okay? Pulling other blocks off its queue,\r\nDialogue: 0,1:04:27.15,1:04:28.45,yin,,0,0,0,,因为这个block排在队列末尾\\N{\\fs12}because this goes at the end of the line.\r\nDialogue: 0,1:04:28.96,1:04:30.01,yin,,0,0,0,,所以如果有其他block\\N{\\fs12}So if there's other blocks,\r\nDialogue: 0,1:04:30.04,1:04:31.31,yin,,0,0,0,,会先执行它们\\N{\\fs12}those are going to get executed first\r\nDialogue: 0,1:04:31.34,1:04:34.68,yin,,0,0,0,,最后才会执行这个block\\N{\\fs12}and then eventually this block will get executed. Okay?\r\nDialogue: 0,1:04:35.49,1:04:37.31,yin,,0,0,0,,这里有一个警告\\N{\\fs12}So anyway, we have this one warning right here,\r\nDialogue: 0,1:04:37.31,1:04:38.56,yin,,0,0,0,,为什么会有这个警告呢\\N{\\fs12}why do we have this warning?\r\nDialogue: 0,1:04:38.74,1:04:41.35,yin,,0,0,0,,因为我们创建了这个task\\N{\\fs12}That's because this task, we created it,\r\nDialogue: 0,1:04:41.35,1:04:42.99,yin,,0,0,0,,但一直没有向它发送任何消息\\N{\\fs12}but we never sent it a message,\r\nDialogue: 0,1:04:43.22,1:04:45.32,yin,,0,0,0,,看到了吗 这里提示的是未使用变量task\\N{\\fs12}you see, this says unused variable task,\r\nDialogue: 0,1:04:45.50,1:04:48.84,yin,,0,0,0,,很好地提醒了我们 要加上task resume\\N{\\fs12}and that's a good reminder for us to say task resume,\r\nDialogue: 0,1:04:49.05,1:04:50.93,yin,,0,0,0,,如果不加上task resume\\N{\\fs12}because if you don't say task resume,\r\nDialogue: 0,1:04:51.07,1:04:53.15,yin,,0,0,0,,这个task开始时就会挂起\\N{\\fs12}this task starts out suspended\r\nDialogue: 0,1:04:53.16,1:04:54.59,yin,,0,0,0,,不会做任何实际操作\\N{\\fs12}and it will never actually do anything,\r\nDialogue: 0,1:04:54.93,1:04:57.57,yin,,0,0,0,,就待在那等着有人恢复它\\N{\\fs12}just sit there waiting for someone to resume it.\r\nDialogue: 0,1:04:57.78,1:04:58.21,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,1:04:58.84,1:05:03.63,yin,,0,0,0,,[学生提问]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,1:05:03.63,1:05:07.87,yin,,0,0,0,,问题是 是否有方法可以结束任务\\N{\\fs12}Yeah, so the question is, is there ways to abort tasks,\r\nDialogue: 0,1:05:07.99,1:05:09.74,yin,,0,0,0,,我再大体讲一下\\N{\\fs12}I'm gonna talk more generically\r\nDialogue: 0,1:05:09.84,1:05:13.57,yin,,0,0,0,,线程或队列上的block\\N{\\fs12}about blocks on threads, or on queues.\r\nDialogue: 0,1:05:13.68,1:05:15.27,yin,,0,0,0,,如果一个block离开队列\\N{\\fs12}If a block is taken off a queue,\r\nDialogue: 0,1:05:15.66,1:05:17.65,yin,,0,0,0,,开始运行 就不能被终止了\\N{\\fs12}it starts to run, it cannot be stopped.\r\nDialogue: 0,1:05:17.81,1:05:18.99,yin,,0,0,0,,需要它自己停下来\\N{\\fs12}It has to stop itself.\r\nDialogue: 0,1:05:19.20,1:05:21.51,yin,,0,0,0,,它会意识到\\N{\\fs12}It would have to realize, oh, this no longer makes sense\r\nDialogue: 0,1:05:21.51,1:05:23.44,yin,,0,0,0,,不用我再做我做的事情了\\N{\\fs12}for me to be doing what I'm doing, okay?\r\nDialogue: 0,1:05:24.44,1:05:27.89,yin,,0,0,0,,URLSession中有个API是做这个的\\N{\\fs12}There is some API in the URLSession to do things like that,\r\nDialogue: 0,1:05:27.89,1:05:30.51,yin,,0,0,0,,但我想让大家明白 对于队列上的block\\N{\\fs12}but I want you to understand that for blocks on queues,\r\nDialogue: 0,1:05:30.51,1:05:32.18,yin,,0,0,0,,一旦它们开始执行 就不能被终止了\\N{\\fs12}once they start, they cannot be stopped,\r\nDialogue: 0,1:05:32.18,1:05:33.36,yin,,0,0,0,,只能自己停下来\\N{\\fs12}they can only stop themselves.\r\nDialogue: 0,1:05:33.36,1:05:34.70,yin,,0,0,0,,只能自己退出\\N{\\fs12}They can just exit from themselves\r\nDialogue: 0,1:05:34.70,1:05:36.41,yin,,0,0,0,,当它们意识到自己已经不被需要的时候\\N{\\fs12}when they realize they're no longer necessary.\r\nDialogue: 0,1:05:36.98,1:05:39.67,yin,,0,0,0,,我没有时间详细讲URLSession部分了\\N{\\fs12}Okay? I don't have time to get into the URLSession stuff,\r\nDialogue: 0,1:05:39.69,1:05:41.28,yin,,0,0,0,,这就是你的问题的答案\\N{\\fs12}but that's the answer to your question.\r\nDialogue: 0,1:05:43.04,1:05:45.35,yin,,0,0,0,,好了 我们来看看运行效果\\N{\\fs12}Okay, so, let's see if, how this works.\r\nDialogue: 0,1:05:46.38,1:05:47.88,yin,,0,0,0,,希望我没落东西\\N{\\fs12}Hopefully I haven't forgotten anything here.\r\nDialogue: 0,1:05:54.72,1:05:56.08,yin,,0,0,0,,现在 如果我点击花朵\\N{\\fs12}Okay, so now if I picked flower,\r\nDialogue: 0,1:05:56.08,1:05:57.85,yin,,0,0,0,,大家已经能看出不同了吧\\N{\\fs12}you can already see its different, okay?\r\nDialogue: 0,1:05:58.01,1:06:00.02,yin,,0,0,0,,当我点击小辣椒时 立刻就跳转到了这里\\N{\\fs12}When I click peppers, it immediately goes here,\r\nDialogue: 0,1:06:00.02,1:06:01.52,yin,,0,0,0,,即使这时这里是空的\\N{\\fs12}even though it's blank, okay?\r\nDialogue: 0,1:06:01.52,1:06:03.71,yin,,0,0,0,,图片稍后才显示出来\\N{\\fs12}And the photo comes in later, okay?\r\nDialogue: 0,1:06:03.85,1:06:05.66,yin,,0,0,0,,但跳转很快 实际上我还可以返回\\N{\\fs12}But it's immediate and, in fact, I can go back,\r\nDialogue: 0,1:06:05.77,1:06:07.90,yin,,0,0,0,,我不想要花 我想要小辣椒\\N{\\fs12}flower, nah, I don't want flower, I want peppers,\r\nDialogue: 0,1:06:08.14,1:06:09.53,yin,,0,0,0,,不要这个 我想要看水母\\N{\\fs12}nah, I want jellyfish.\r\nDialogue: 0,1:06:09.74,1:06:12.35,yin,,0,0,0,,UI反应迅速\\N{\\fs12}Okay? And, so the UI is taking complete response,\r\nDialogue: 0,1:06:12.35,1:06:15.18,yin,,0,0,0,,即便我将这些图片下载了很多遍\\N{\\fs12}even though I'm downloading these things multiple times,\r\nDialogue: 0,1:06:15.18,1:06:17.39,yin,,0,0,0,,在后台下载 且是不必要的\\N{\\fs12}actually, in the background, unnecessarily, but,\r\nDialogue: 0,1:06:18.34,1:06:21.94,yin,,0,0,0,,我们希望UI响应迅速且灵敏\\N{\\fs12}so this is a way you want your UI to be, very responsive, okay,\r\nDialogue: 0,1:06:22.19,1:06:25.32,yin,,0,0,0,,用户想要什么\\N{\\fs12}and just things happening, you know,\r\nDialogue: 0,1:06:25.34,1:06:28.10,yin,,0,0,0,,立即就执行\\N{\\fs12}the instant the user wants them, okay?\r\nDialogue: 0,1:06:29.07,1:06:31.42,yin,,0,0,0,,但这个UI还有一点不太好\\N{\\fs12}Now, there's one thing that's kind of bad about this UI though\r\nDialogue: 0,1:06:31.42,1:06:32.29,yin,,0,0,0,,点击这里时\\N{\\fs12}is when I click here,\r\nDialogue: 0,1:06:32.39,1:06:34.51,yin,,0,0,0,,这里在做的操作没有反馈\\N{\\fs12}there's no feedback that's doing anything here,\r\nDialogue: 0,1:06:34.52,1:06:37.08,yin,,0,0,0,,看起来就像是 我点击了花朵\\N{\\fs12}this just looks like oh, well, I clicked on flower,\r\nDialogue: 0,1:06:37.09,1:06:38.79,yin,,0,0,0,,但显示没有花\\N{\\fs12}oh, there must not be a flower, right?\r\nDialogue: 0,1:06:39.51,1:06:41.84,yin,,0,0,0,,斯坦福的网速太快了 一下就出来了\\N{\\fs12}Stanford's network is so fast, [inaudible] but..\r\nDialogue: 0,1:06:41.97,1:06:44.03,yin,,0,0,0,,用户可能会觉得没有花 那我换下一幅\\N{\\fs12}he's like oh there's no flower, oh I'll skip it,\r\nDialogue: 0,1:06:44.23,1:06:45.32,yin,,0,0,0,,没有小辣椒 我换\\N{\\fs12}there's no peppers, I'll...\r\nDialogue: 0,1:06:45.33,1:06:47.83,yin,,0,0,0,,因为它在做的操作没有反馈\\N{\\fs12}because there's no feedback that it's doing anything.\r\nDialogue: 0,1:06:48.10,1:06:52.44,yin,,0,0,0,,我们来加一个反馈提示\\N{\\fs12}So let's put some feedback in here that shows something moving\r\nDialogue: 0,1:06:52.44,1:06:54.48,yin,,0,0,0,,移动标志或者小转轮之类的\\N{\\fs12}or something, you know, a little spinning wheel\r\nDialogue: 0,1:06:54.66,1:06:56.73,yin,,0,0,0,,告诉用户 我为你做事呢\\N{\\fs12}that shows the user hey I'm doing something for you,\r\nDialogue: 0,1:06:56.82,1:06:58.22,yin,,0,0,0,,在后台运行着呢 不用担心\\N{\\fs12}in the background, not to worry.\r\nDialogue: 0,1:06:58.69,1:07:03.00,yin,,0,0,0,,iOS中有一个内置的UIView\\N{\\fs12}And there is a UIView that's built into iOS,\r\nDialogue: 0,1:07:03.06,1:07:05.19,yin,,0,0,0,,使用它能够轻松地实现这个功能\\N{\\fs12}that's really easy to use for doing exactly that.\r\nDialogue: 0,1:07:05.65,1:07:07.69,yin,,0,0,0,,回到storyboard这里\\N{\\fs12}So let's go back to our storyboard here.\r\nDialogue: 0,1:07:08.15,1:07:09.28,yin,,0,0,0,,这是我们的storyboard\\N{\\fs12}So we have our storyboard,\r\nDialogue: 0,1:07:09.39,1:07:12.25,yin,,0,0,0,,在右边这个视图中\\N{\\fs12}and what I'm gonna do is into this view right here,\r\nDialogue: 0,1:07:12.25,1:07:18.27,yin,,0,0,0,,我要拖进一个UIActivityIndicator\\N{\\fs12}I'm gonna drag a UIActivityIndicator,\r\nDialogue: 0,1:07:18.45,1:07:19.83,yin,,0,0,0,,在上面\\N{\\fs12}just towards the top here,\r\nDialogue: 0,1:07:20.41,1:07:21.47,yin,,0,0,0,,看起来就是个转轮的样子\\N{\\fs12}it even looks like a spinning wheel,\r\nDialogue: 0,1:07:21.48,1:07:23.92,yin,,0,0,0,,我们要的就是这个小转轮\\N{\\fs12}so this is the little spinning wheel that you're seeing,\r\nDialogue: 0,1:07:24.03,1:07:24.96,yin,,0,0,0,,我将它拖进这里\\N{\\fs12}so I'm going to drag it in here.\r\nDialogue: 0,1:07:24.96,1:07:26.32,yin,,0,0,0,,这里正好可以\\N{\\fs12}Now, this is gonna be a good opportunity\r\nDialogue: 0,1:07:26.33,1:07:27.64,yin,,0,0,0,,讲讲文档大纲\\N{\\fs12}to talk about document outline.\r\nDialogue: 0,1:07:27.77,1:07:29.94,yin,,0,0,0,,当我把它拖进来时 不错\\N{\\fs12}So when I drag this in, okay, that's great,\r\nDialogue: 0,1:07:29.94,1:07:31.46,yin,,0,0,0,,看起来做得很好\\N{\\fs12}it seems like I've done a good thing.\r\nDialogue: 0,1:07:31.51,1:07:32.48,yin,,0,0,0,,我已经把它拖进来了\\N{\\fs12}I've dragged this in here.\r\nDialogue: 0,1:07:32.72,1:07:34.81,yin,,0,0,0,,但实际上 这样做并不是太好\\N{\\fs12}But actually, I didn't do a very good thing here,\r\nDialogue: 0,1:07:35.28,1:07:37.30,yin,,0,0,0,,因为这样将它拖拽进来\\N{\\fs12}because dragging that in\r\nDialogue: 0,1:07:37.41,1:07:39.71,yin,,0,0,0,,实际上让它成为了滚动视图的一个子视图\\N{\\fs12}actually made that a subview of the scroll view.\r\nDialogue: 0,1:07:40.23,1:07:43.97,yin,,0,0,0,,当你拖进一个视图 放在另一个视图上面\\N{\\fs12}Okay? When you drag a view in, on top of another view,\r\nDialogue: 0,1:07:43.97,1:07:45.18,yin,,0,0,0,,它就会成为该视图的子视图\\N{\\fs12}it makes a subview of that.\r\nDialogue: 0,1:07:45.36,1:07:47.51,yin,,0,0,0,,可以在左边的文档大纲中看到\\N{\\fs12}And we can see that over here in the document outline.\r\nDialogue: 0,1:07:47.51,1:07:48.48,yin,,0,0,0,,这是滚动视图\\N{\\fs12}Here's the scroll view.\r\nDialogue: 0,1:07:48.76,1:07:50.48,yin,,0,0,0,,看到它缩进了吗\\N{\\fs12}And see how this is indented a little?\r\nDialogue: 0,1:07:50.72,1:07:51.73,yin,,0,0,0,,代表它是一个子视图\\N{\\fs12}That means it's a subview.\r\nDialogue: 0,1:07:51.73,1:07:53.30,yin,,0,0,0,,我不想让它成为子视图\\N{\\fs12}Now, I don't want it to be a subview,\r\nDialogue: 0,1:07:53.32,1:07:56.94,yin,,0,0,0,,我想让这个转轮显示在滚动视图前面\\N{\\fs12}I want this wheel to sit in front of the scroll view, right,\r\nDialogue: 0,1:07:56.94,1:08:00.12,yin,,0,0,0,,当滚动视图执行操作时 转轮转动\\N{\\fs12}and be spinning whenever the scroll view is doing something\r\nDialogue: 0,1:08:00.12,1:08:02.58,yin,,0,0,0,,停止操作时 转轮隐藏\\N{\\fs12}and go, and to hide itself when it stops,\r\nDialogue: 0,1:08:02.91,1:08:05.50,yin,,0,0,0,,不让它成为子视图 方法是选中它\\N{\\fs12}and so I can make this not be subview by picking it up\r\nDialogue: 0,1:08:06.16,1:08:08.44,yin,,0,0,0,,移动为并列视图\\N{\\fs12}and moving it to be a sibling.\r\nDialogue: 0,1:08:08.90,1:08:11.75,yin,,0,0,0,,现在的问题是我将它放在了后面\\N{\\fs12}Okay? Now, the problem here is I put it in the back,\r\nDialogue: 0,1:08:12.07,1:08:14.16,yin,,0,0,0,,排在上面的子视图显示在后面\\N{\\fs12}things at the top of the view, subview are in the back,\r\nDialogue: 0,1:08:14.33,1:08:16.48,yin,,0,0,0,,所以我可以将它拖到上面这里\\N{\\fs12}so I can just put this up here,\r\nDialogue: 0,1:08:16.81,1:08:18.90,yin,,0,0,0,,现在转轮在前 滚动视图在后\\N{\\fs12}and now I've got this in front and this in back.\r\nDialogue: 0,1:08:19.55,1:08:20.48,yin,,0,0,0,,它们是同级并列的\\N{\\fs12}Okay? And they're siblings.\r\nDialogue: 0,1:08:21.18,1:08:22.55,yin,,0,0,0,,它在前面\\N{\\fs12}So this is in front, okay?\r\nDialogue: 0,1:08:23.45,1:08:24.71,yin,,0,0,0,,这里还要做一件事\\N{\\fs12}Another thing I want to do here\r\nDialogue: 0,1:08:24.73,1:08:26.78,yin,,0,0,0,,就是设置它的约束\\N{\\fs12}is set my constraints on this guy,\r\nDialogue: 0,1:08:26.93,1:08:27.68,yin,,0,0,0,,转到这里\\N{\\fs12}so I'm gonna go here\r\nDialogue: 0,1:08:27.69,1:08:31.17,yin,,0,0,0,,将它设为水平垂直居中\\N{\\fs12}and I'm gonna set it to be horizontal/vertical centered,\r\nDialogue: 0,1:08:31.17,1:08:32.23,yin,,0,0,0,,可以检查一下\\N{\\fs12}and we can just make sure\r\nDialogue: 0,1:08:32.23,1:08:34.40,yin,,0,0,0,,是否设置正确 没问题\\N{\\fs12}that it did the right thing, which it did. Okay?\r\nDialogue: 0,1:08:34.59,1:08:37.32,yin,,0,0,0,,有些黄线 我们把它弄好\\N{\\fs12}We got a little yellow there, so let's fix that.\r\nDialogue: 0,1:08:38.64,1:08:41.57,yin,,0,0,0,,选择修复错位 将它放到正中间\\N{\\fs12}Fix misplacement, put it right in the middle, okay?\r\nDialogue: 0,1:08:41.88,1:08:42.68,yin,,0,0,0,,这样就好了\\N{\\fs12}So we got that.\r\nDialogue: 0,1:08:42.89,1:08:44.45,yin,,0,0,0,,还有一件事要做\\N{\\fs12}The other thing I want to do is,\r\nDialogue: 0,1:08:44.88,1:08:48.84,yin,,0,0,0,,我想让这个小转轮变大\\N{\\fs12}I want this little spinning thing, I want it to be large\r\nDialogue: 0,1:08:49.00,1:08:51.26,yin,,0,0,0,,所以样式这里选择Large White大白样式\\N{\\fs12}so the style I'm gonna use is large white,\r\nDialogue: 0,1:08:52.02,1:08:53.37,yin,,0,0,0,,但我不希望它是白色的\\N{\\fs12}but I don't want it to be white,\r\nDialogue: 0,1:08:53.38,1:08:54.67,yin,,0,0,0,,它是在白色背景上的\\N{\\fs12}because it's on a white background.\r\nDialogue: 0,1:08:54.67,1:08:56.18,yin,,0,0,0,,如果是白色就几乎看不清楚了\\N{\\fs12}So I'm barely gonna be able to see the thing,\r\nDialogue: 0,1:08:56.37,1:08:57.28,yin,,0,0,0,,我们来修改它的颜色\\N{\\fs12}so let's change the color.\r\nDialogue: 0,1:08:57.28,1:08:58.73,yin,,0,0,0,,把它的颜色修改为\\N{\\fs12}So let's make the color be,\r\nDialogue: 0,1:08:58.74,1:09:01.77,yin,,0,0,0,,换成和按钮一样的蓝色\\N{\\fs12}hmm, let's make it be like the blue of the buttons,\r\nDialogue: 0,1:09:02.05,1:09:03.78,yin,,0,0,0,,蓝色转轮挺好的\\N{\\fs12}okay, that's a pretty good color for it to be.\r\nDialogue: 0,1:09:04.31,1:09:06.00,yin,,0,0,0,,还要注意这两个Behavior行为选项\\N{\\fs12}Also, notice these behaviors.\r\nDialogue: 0,1:09:06.21,1:09:09.62,yin,,0,0,0,,Animating动画代表它以动画形式开始\\N{\\fs12}Okay? Animating means this thing starts out animating,\r\nDialogue: 0,1:09:09.70,1:09:12.20,yin,,0,0,0,,我们想要这种效果 因为当这个视图刚出现时\\N{\\fs12}which I want, because when this view first appears,\r\nDialogue: 0,1:09:12.28,1:09:13.33,yin,,0,0,0,,我想让它演示动画\\N{\\fs12}I want it to be animating,\r\nDialogue: 0,1:09:13.33,1:09:14.89,yin,,0,0,0,,因为开始时是在加载页面\\N{\\fs12}because I'm loading from the start.\r\nDialogue: 0,1:09:15.17,1:09:16.93,yin,,0,0,0,,下面的选项是停止时隐藏\\N{\\fs12}And then here's hides when stopped,\r\nDialogue: 0,1:09:16.97,1:09:19.05,yin,,0,0,0,,表示当你在代码中停止它时\\N{\\fs12}that says when you stop it in your code,\r\nDialogue: 0,1:09:19.35,1:09:20.20,yin,,0,0,0,,转轮就会隐藏起来\\N{\\fs12}it's gonna hide it.\r\nDialogue: 0,1:09:20.71,1:09:21.90,yin,,0,0,0,,这样它就不会不停转动\\N{\\fs12}So it's not gonna stop turning\r\nDialogue: 0,1:09:21.90,1:09:24.17,yin,,0,0,0,,始终显示在那里 阻塞滚动视图\\N{\\fs12}and then sit there blocking your scroll view,\r\nDialogue: 0,1:09:24.17,1:09:25.35,yin,,0,0,0,,它自己会隐藏起来\\N{\\fs12}it's going to hide itself.\r\nDialogue: 0,1:09:25.75,1:09:26.91,yin,,0,0,0,,这是个非常棒的功能\\N{\\fs12}Okay? So that's a really cool feature,\r\nDialogue: 0,1:09:26.91,1:09:29.50,yin,,0,0,0,,通常都会选择停止时隐藏\\N{\\fs12}you almost always want hides when stopped on there.\r\nDialogue: 0,1:09:29.77,1:09:31.74,yin,,0,0,0,,可能不需要开始动画\\N{\\fs12}Okay? You may or may not want it to start out animating,\r\nDialogue: 0,1:09:31.74,1:09:34.01,yin,,0,0,0,,但通常要选择停止时隐藏\\N{\\fs12}but you always want to hide when stopped.\r\nDialogue: 0,1:09:34.67,1:09:38.35,yin,,0,0,0,,现在我们回到代码这里\\N{\\fs12}Okay? So, now, let's go back to our code, over here,\r\nDialogue: 0,1:09:38.65,1:09:42.38,yin,,0,0,0,,何时开始和结束它呢\\N{\\fs12}and when do we want to start and stop this thing, okay?\r\nDialogue: 0,1:09:43.04,1:09:44.33,yin,,0,0,0,,什么时候开始结束比较好呢\\N{\\fs12}When's a good time to start and stop?\r\nDialogue: 0,1:09:44.33,1:09:46.87,yin,,0,0,0,,比较好的开始时间是\\N{\\fs12}Well, a good time to start it is\r\nDialogue: 0,1:09:46.89,1:09:48.92,yin,,0,0,0,,开始下载图像时\\N{\\fs12}when we're starting to download an image.\r\nDialogue: 0,1:09:49.13,1:09:51.41,yin,,0,0,0,,我要用... 对了 在此之前\\N{\\fs12}So I'm gonna say, oh, well first of all,\r\nDialogue: 0,1:09:51.45,1:09:53.46,yin,,0,0,0,,我们为什么不做个指向它的输出口呢\\N{\\fs12}why don't we make an outlet to it?\r\nDialogue: 0,1:09:53.91,1:09:55.45,yin,,0,0,0,,回到storyboard\\N{\\fs12}So let's go back to our storyboard,\r\nDialogue: 0,1:09:56.02,1:09:59.95,yin,,0,0,0,,选择系统编辑器 关闭文档大纲栏\\N{\\fs12}let's get our system editor up here, let's close this,\r\nDialogue: 0,1:10:00.99,1:10:03.68,yin,,0,0,0,,我们开着文档大纲栏吧\\N{\\fs12}and let's, actually let's leave that open\r\nDialogue: 0,1:10:03.69,1:10:04.53,yin,,0,0,0,,我要演示一下\\N{\\fs12}because I'll show you,\r\nDialogue: 0,1:10:04.53,1:10:07.39,yin,,0,0,0,,我说过 从文档大纲中\\N{\\fs12}I promised you that control drag\r\nDialogue: 0,1:10:07.40,1:10:09.19,yin,,0,0,0,,进行control拖拽很好用\\N{\\fs12}from the document outline would be good\r\nDialogue: 0,1:10:09.20,1:10:11.70,yin,,0,0,0,,这里就是显示出它好用的地方\\N{\\fs12}and here's an example of when it's really good,\r\nDialogue: 0,1:10:11.88,1:10:15.10,yin,,0,0,0,,想要从这里进行control拖拽有点困难\\N{\\fs12}because trying to control drag from this might be a little dicey,\r\nDialogue: 0,1:10:15.39,1:10:16.97,yin,,0,0,0,,但从这里拖拽是很容易的\\N{\\fs12}but over here, it's really easy.\r\nDialogue: 0,1:10:17.18,1:10:19.05,yin,,0,0,0,,我只要从这里按住control键进行拖拽\\N{\\fs12}So I'm just gonna control, drag from here\r\nDialogue: 0,1:10:19.51,1:10:23.66,yin,,0,0,0,,拖拽到图像视图控制器 没选中\\N{\\fs12}into my image view controller, oops, missed it.\r\nDialogue: 0,1:10:25.88,1:10:26.63,yin,,0,0,0,,这里\\N{\\fs12}Right there.\r\nDialogue: 0,1:10:27.26,1:10:28.78,yin,,0,0,0,,我们叫它spinner\\N{\\fs12}Okay? And we'll call it spinner.\r\nDialogue: 0,1:10:29.42,1:10:32.66,yin,,0,0,0,,可以看到spinner是UIActivityIndicator类型\\N{\\fs12}So there's a spinner, see it's a UIActivityIndicator.\r\nDialogue: 0,1:10:33.37,1:10:36.93,yin,,0,0,0,,现在回到这里 选择视图控制器\\N{\\fs12}Alright so now let's go back to here, and our view controller,\r\nDialogue: 0,1:10:36.93,1:10:38.90,yin,,0,0,0,,尽可能扩大显示宽度\\N{\\fs12}make it as wide as possible.\r\nDialogue: 0,1:10:39.80,1:10:42.76,yin,,0,0,0,,现在有了这个self.spinner 在这里\\N{\\fs12}Okay, so now I have this self dot spinner up here.\r\nDialogue: 0,1:10:43.59,1:10:44.78,yin,,0,0,0,,我要告诉它\\N{\\fs12}And now I'm going to tell it,\r\nDialogue: 0,1:10:45.09,1:10:46.73,yin,,0,0,0,,当我开始下载图像的时候\\N{\\fs12}when I start downloading an image,\r\nDialogue: 0,1:10:47.16,1:10:50.36,yin,,0,0,0,,self.spinner startAnimating\\N{\\fs12}self dot spinner startAnimating.\r\nDialogue: 0,1:10:50.99,1:10:54.04,yin,,0,0,0,,这就是要发送给转轮的方法\\N{\\fs12}Okay? So that's the method that you send to a spinner\r\nDialogue: 0,1:10:54.05,1:10:55.10,yin,,0,0,0,,告诉它开始动画\\N{\\fs12}to tell it to start animating,\r\nDialogue: 0,1:10:55.18,1:10:57.38,yin,,0,0,0,,如果它是隐藏的 设置了动画时不隐藏\\N{\\fs12}and if it's hidden and you have that hides when animated,\r\nDialogue: 0,1:10:57.39,1:10:59.26,yin,,0,0,0,,它就会显示出来 开始转动\\N{\\fs12}it'll unhide itself and start spinning.\r\nDialogue: 0,1:10:59.65,1:11:01.26,yin,,0,0,0,,如果它不是隐藏状态 就会直接开始转动\\N{\\fs12}If it's not hidden, it'll just start spinning.\r\nDialogue: 0,1:11:01.64,1:11:03.95,yin,,0,0,0,,那么何时停止它动画比较好呢\\N{\\fs12}Now when's a good time to stop it from animating?\r\nDialogue: 0,1:11:03.95,1:11:05.81,yin,,0,0,0,,最合适的时间\\N{\\fs12}Well, the best part, time,\r\nDialogue: 0,1:11:05.81,1:11:08.69,yin,,0,0,0,,大概就是当有人设置图像的时候\\N{\\fs12}is probably when someone sets an image.\r\nDialogue: 0,1:11:09.09,1:11:11.40,yin,,0,0,0,,因为如果这里设置了一幅图像\\N{\\fs12}Okay? Because if an image gets set in here,\r\nDialogue: 0,1:11:11.63,1:11:15.28,yin,,0,0,0,,那我们基本可以确定设置好了\\N{\\fs12}then we can pretty much be assured that we're setting,\r\nDialogue: 0,1:11:15.28,1:11:17.49,yin,,0,0,0,,操作完成了 所以就要停止转轮动画了\\N{\\fs12}that we're done, so we'll stop animating then.\r\nDialogue: 0,1:11:18.41,1:11:20.38,yin,,0,0,0,,所以无论这个setImage的发生\\N{\\fs12}Okay? So whether this setImage happens\r\nDialogue: 0,1:11:20.38,1:11:23.22,yin,,0,0,0,,是因为下载操作完成了\\N{\\fs12}because that start downloading thing finally finishes,\r\nDialogue: 0,1:11:23.26,1:11:24.54,yin,,0,0,0,,还是因为有人厌烦了\\N{\\fs12}or because someone gets tired of it\r\nDialogue: 0,1:11:24.55,1:11:26.79,yin,,0,0,0,,将它设为了某个本地图像\\N{\\fs12}and sets it to some image that's a local image,\r\nDialogue: 0,1:11:26.82,1:11:29.02,yin,,0,0,0,,这两种情况 我们都要停止转轮\\N{\\fs12}either way, boom, we're gonna stop doing that spinner.\r\nDialogue: 0,1:11:29.90,1:11:32.17,yin,,0,0,0,,我们来看一下\\N{\\fs12}Okay? So let's take a look at that.\r\nDialogue: 0,1:11:40.48,1:11:41.56,yin,,0,0,0,,选择花朵\\N{\\fs12}Alright, so we do the flower,\r\nDialogue: 0,1:11:41.58,1:11:42.53,yin,,0,0,0,,看到转轮了吗\\N{\\fs12}and see we got the spinner,\r\nDialogue: 0,1:11:42.53,1:11:43.67,yin,,0,0,0,,正在转动 很好\\N{\\fs12}that is spinning, which is nice,\r\nDialogue: 0,1:11:43.68,1:11:45.61,yin,,0,0,0,,告诉我们有操作正在执行\\N{\\fs12}it's telling us that something's happening,\r\nDialogue: 0,1:11:45.63,1:11:48.11,yin,,0,0,0,,我们依旧可以中断它\\N{\\fs12}and we can still interrupt it, go back,\r\nDialogue: 0,1:11:48.12,1:11:50.52,yin,,0,0,0,,转轮的各种操作\\N{\\fs12}it's not blocked, this is not blocking the main thread\r\nDialogue: 0,1:11:50.52,1:11:52.58,yin,,0,0,0,,不会阻塞主线程\\N{\\fs12}in any way to do that spinner, okay?\r\nDialogue: 0,1:11:52.58,1:11:54.39,yin,,0,0,0,,但是它能给用户很好的反馈\\N{\\fs12}But it gives the user some nice feedback\r\nDialogue: 0,1:11:54.69,1:11:56.29,yin,,0,0,0,,告诉用户 我在干活呢\\N{\\fs12}that hey I'm working on something.\r\nDialogue: 0,1:11:57.56,1:11:59.81,yin,,0,0,0,,有问题吗\\N{\\fs12}Okay? Question?\r\nDialogue: 0,1:12:01.15,1:12:02.77,yin,,0,0,0,,[学生提问]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,1:12:02.88,1:12:03.53,yin,,0,0,0,,好问题\\N{\\fs12}Great question.\r\nDialogue: 0,1:12:03.89,1:12:08.08,yin,,0,0,0,,问题是 这个URL的使用有效期是多少\\N{\\fs12}So the question is what is the lifetime of this URL.\r\nDialogue: 0,1:12:08.26,1:12:10.26,yin,,0,0,0,,在这里的completionHandler中\\N{\\fs12}In my completionHandler, right here,\r\nDialogue: 0,1:12:10.52,1:12:11.96,yin,,0,0,0,,这个localfile的使用有效期是多少\\N{\\fs12}what is the lifetime of this localfile?\r\nDialogue: 0,1:12:11.96,1:12:14.70,yin,,0,0,0,,答案是只能用于这个block的有效期范围\\N{\\fs12}And the answer is only for the lifetime of this block.\r\nDialogue: 0,1:12:15.71,1:12:18.39,yin,,0,0,0,,一旦这个block停止执行\\N{\\fs12}Okay? So, as soon as this block stops executing,\r\nDialogue: 0,1:12:18.41,1:12:19.53,yin,,0,0,0,,那个文件就会被删掉\\N{\\fs12}that file will be deleted.\r\nDialogue: 0,1:12:19.93,1:12:21.97,yin,,0,0,0,,所以如果你想保存它 就得复制一下\\N{\\fs12}So if you want to keep it, you got to copy it.\r\nDialogue: 0,1:12:22.51,1:12:24.72,yin,,0,0,0,,复制文件的方法\\N{\\fs12}Okay? And you copy files, by the way,\r\nDialogue: 0,1:12:24.73,1:12:26.96,yin,,0,0,0,,复制URL要用NSFileManager\\N{\\fs12}copy URLs using NSFileManager.\r\nDialogue: 0,1:12:27.47,1:12:28.53,yin,,0,0,0,,下周讲持久化时\\N{\\fs12}Okay? We'll probably talk\r\nDialogue: 0,1:12:28.53,1:12:30.31,yin,,0,0,0,,我们可能会\\N{\\fs12}about NSFileManager briefly next week\r\nDialogue: 0,1:12:30.32,1:12:31.47,yin,,0,0,0,,快速讲一下NSFileManager\\N{\\fs12}when we talk about persistence,\r\nDialogue: 0,1:12:32.33,1:12:34.21,yin,,0,0,0,,但它就是复制文件的方法 用API\\N{\\fs12}but that's how you copy files, they are API\r\nDialogue: 0,1:12:34.21,1:12:37.59,yin,,0,0,0,,从URL复制到URL 就可以复制了\\N{\\fs12}and they're copy from URL to URL and you can copy it away,\r\nDialogue: 0,1:12:37.91,1:12:38.96,yin,,0,0,0,,很好的想法\\N{\\fs12}but that's a very good point.\r\nDialogue: 0,1:12:38.96,1:12:42.45,yin,,0,0,0,,这是一个临时文件 只用于这个block\\N{\\fs12}This is a temporary file, only here, you know, for this block.\r\nDialogue: 0,1:12:42.63,1:12:44.10,yin,,0,0,0,,这个block没有了 文件也就无法继续使用了\\N{\\fs12}And once this block is gone, you're done.\r\nDialogue: 0,1:12:46.23,1:12:48.85,yin,,0,0,0,,还有一点我要快速讲一下\\N{\\fs12}Okay? The other thing I'm gonna say, really briefly,\r\nDialogue: 0,1:12:48.85,1:12:50.26,yin,,0,0,0,,我也不知道幻灯片中是否能讲到\\N{\\fs12}I don't know if we'll get to this in slides,\r\nDialogue: 0,1:12:50.89,1:12:53.42,yin,,0,0,0,,做多任务处理时 我可能会要求大家\\N{\\fs12}when we do multitasking, I'm probably gonna ask you\r\nDialogue: 0,1:12:53.57,1:12:56.95,yin,,0,0,0,,在这里使用backgroundSessionConfiguration\\N{\\fs12}to use a backgroundSessionConfiguration here\r\nDialogue: 0,1:12:56.96,1:13:00.07,yin,,0,0,0,,而不是临时会话配置 在这个配置模式下\\N{\\fs12}instead of ephemeral, which is this one where...\r\nDialogue: 0,1:13:00.32,1:13:01.80,yin,,0,0,0,,即便应用未运行\\N{\\fs12}even if your app's not running,\r\nDialogue: 0,1:13:01.81,1:13:03.59,yin,,0,0,0,,它也会继续下载目标内容\\N{\\fs12}it will keep downloading that thing,\r\nDialogue: 0,1:13:03.60,1:13:06.89,yin,,0,0,0,,完成后再调回你的应用\\N{\\fs12}and then eventually call your app back,\r\nDialogue: 0,1:13:06.90,1:13:09.47,yin,,0,0,0,,想要理解它 需要知道多任务执行的工作原理\\N{\\fs12}but to know that you have to know how the multitasking works.\r\nDialogue: 0,1:13:10.22,1:13:13.30,yin,,0,0,0,,当这样做时 你需要...\\N{\\fs12}When you do that, you will have to have,\r\nDialogue: 0,1:13:14.10,1:13:16.38,yin,,0,0,0,,当使用sessionWithConfiguration时\\N{\\fs12}when you do the sessionWithConfiguration,\r\nDialogue: 0,1:13:16.82,1:13:18.21,yin,,0,0,0,,抱歉 这里补上\\N{\\fs12}sorry, let's do something here.\r\nDialogue: 0,1:13:21.22,1:13:22.85,yin,,0,0,0,,你需要使用带有委托delegate的\\N{\\fs12}You will have to use the version of this\r\nDialogue: 0,1:13:22.85,1:13:24.48,yin,,0,0,0,,sessionWithConfiguration方法\\N{\\fs12}that has a delegate, okay?\r\nDialogue: 0,1:13:24.48,1:13:25.86,yin,,0,0,0,,因为后台会话配置模式\\N{\\fs12}Because the background session one,\r\nDialogue: 0,1:13:25.86,1:13:26.78,yin,,0,0,0,,需要使用委托\\N{\\fs12}you got to use the delegate,\r\nDialogue: 0,1:13:26.78,1:13:28.40,yin,,0,0,0,,不能用完成处理程序\\N{\\fs12}you can't use the completion handler.\r\nDialogue: 0,1:13:29.08,1:13:31.16,yin,,0,0,0,,加上委托就可以了\\N{\\fs12}Okay? Just putting that out there.\r\nDialogue: 0,1:13:31.33,1:13:33.18,yin,,0,0,0,,我们再讲到这时 我会提醒大家\\N{\\fs12}I'll remind you when we get back to that, but,\r\nDialogue: 0,1:13:34.70,1:13:35.86,yin,,0,0,0,,但要知道后台模式要使用委托\\N{\\fs12}got to use the delegate for that.\r\nDialogue: 0,1:13:36.30,1:13:38.53,yin,,0,0,0,,但临时会话配置模式可以使用这个完成处理程序\\N{\\fs12}But for ephemeral, we can use this nice handler.\r\nDialogue: 0,1:13:39.61,1:13:44.85,yin,,0,0,0,,我们就不讲表视图了\\N{\\fs12}Okay. So, we are not going to start on table view\r\nDialogue: 0,1:13:45.25,1:13:51.01,yin,,0,0,0,,下次课再讲 我们来看看最后一张幻灯片\\N{\\fs12}until next time, but let me, this last slide here.\r\nDialogue: 0,1:13:52.13,1:13:53.30,yin,,0,0,0,,说说后面要讲的内容\\N{\\fs12}Talk about what's coming up.\r\nDialogue: 0,1:13:54.23,1:13:56.21,yin,,0,0,0,,周三的时候 这里写的是更多表视图内容\\N{\\fs12}So on Wednesday it says more table view,\r\nDialogue: 0,1:13:56.23,1:13:57.94,yin,,0,0,0,,我们会从头开始讲\\N{\\fs12}but we'll, we'll do all the table view.\r\nDialogue: 0,1:13:58.15,1:13:59.33,yin,,0,0,0,,我还会讲iPad\\N{\\fs12}I'm also gonna do iPad.\r\nDialogue: 0,1:13:59.64,1:14:02.48,yin,,0,0,0,,专门用于iPad的UI内容\\N{\\fs12}Okay? Talk about the special UI idioms that are on the iPad.\r\nDialogue: 0,1:14:03.09,1:14:04.32,yin,,0,0,0,,作业呢 我说了\\N{\\fs12}Your homework, as I said,\r\nDialogue: 0,1:14:04.32,1:14:05.61,yin,,0,0,0,,今天不留作业\\N{\\fs12}there's no homework assigned today,\r\nDialogue: 0,1:14:05.62,1:14:07.88,yin,,0,0,0,,所以大家两天不用做作业了 太好了\\N{\\fs12}so you get two days off on homework, good job,\r\nDialogue: 0,1:14:08.13,1:14:10.07,yin,,0,0,0,,周三会布置一个新作业\\N{\\fs12}and then Wednesday you'll have a whole new assignment\r\nDialogue: 0,1:14:10.08,1:14:11.31,yin,,0,0,0,,完成期限一星期\\N{\\fs12}that will be due a week later,\r\nDialogue: 0,1:14:11.47,1:14:14.03,yin,,0,0,0,,周五有课外辅导\\N{\\fs12}and Friday, we do have section,\r\nDialogue: 0,1:14:14.39,1:14:16.47,yin,,0,0,0,,会开始的早一点\\N{\\fs12}it's actually gonna be a little bit early,\r\nDialogue: 0,1:14:16.58,1:14:17.64,yin,,0,0,0,,时间长一些\\N{\\fs12}and last a little longer,\r\nDialogue: 0,1:14:17.64,1:14:20.73,yin,,0,0,0,,90分钟的课外辅导 而不是50分钟了\\N{\\fs12}it's like a 90 minutes instead of a 50-minute section,\r\nDialogue: 0,1:14:20.91,1:14:23.44,yin,,0,0,0,,斯坦福的同学记得查看Piazza的通知\\N{\\fs12}so watch Piazza for that Stanford people.\r\nDialogue: 0,1:14:23.62,1:14:25.45,yin,,0,0,0,,iTunes U上没有\\N{\\fs12}It won't be on iTunes U.\r\nDialogue: 0,1:14:25.68,1:14:27.92,yin,,0,0,0,,下周我们会讲Core Data\\N{\\fs12}And then next week we're gonna talk about core data\r\nDialogue: 0,1:14:28.37,1:14:29.97,yin,,0,0,0,,大体讲一下持久性\\N{\\fs12}and persistence in general,\r\nDialogue: 0,1:14:29.98,1:14:32.47,yin,,0,0,0,,如何让内容留在手机上\\N{\\fs12}how do we make things stay on the phone,\r\nDialogue: 0,1:14:32.48,1:14:34.11,yin,,0,0,0,,将它们转为数据库\\N{\\fs12}and how do we turn them into a database\r\nDialogue: 0,1:14:34.14,1:14:35.98,yin,,0,0,0,,进行检索等操作\\N{\\fs12}so we can search for things and stuff like that?\r\nDialogue: 0,1:14:36.37,1:14:37.89,yin,,0,0,0,,这就是下面要讲的内容\\N{\\fs12}Okay? So that's what's coming up.\r\nDialogue: 0,1:14:38.51,1:14:40.74,yin,,0,0,0,,谢谢大家 有问题就过来找我吧\\N{\\fs12}Thank you all and I'll be here if you have questions.\r\nDialogue: 0,1:14:43.32,1:14:46.87,yin,,0,0,0,,更多内容 请访问斯坦福网站\\N{\\fs12}For more, please visit us at stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/11. Table View and iPad.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.2.0\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage]\r\nActive Line: 1\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:04.91,0:00:08.39,yin,,0,0,0,,斯坦福大学\\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:08.39,0:00:11.28,yin,,0,0,0,,欢迎来到CS193P的第11讲\\N{\\fs12}So, welcome to Lecture 11 of CS193P.\r\nDialogue: 0,0:00:11.28,0:00:16.44,yin,,0,0,0,,这是2013-2014学年秋季课程\\N{\\fs12}This is the fall quarter of academic year 2013/2014.\r\nDialogue: 0,0:00:16.44,0:00:19.04,yin,,0,0,0,,今天我们将谈到两大主题\\N{\\fs12}And today we're going to talk about two major topics.\r\nDialogue: 0,0:00:19.04,0:00:22.59,yin,,0,0,0,,一是UITableView(UI表格视图) 这是一个很重要的类\\N{\\fs12}One is UI TableView, which a very important class.\r\nDialogue: 0,0:00:22.59,0:00:24.97,yin,,0,0,0,,我们还将谈到iPad\\N{\\fs12}And also we're going to talk about an iPad now.\r\nDialogue: 0,0:00:24.97,0:00:26.89,yin,,0,0,0,,之前做的一切都只针对iPhone\\N{\\fs12}We've been doing everything so far on the iPhone,\r\nDialogue: 0,0:00:26.89,0:00:31.53,yin,,0,0,0,,现在我们想同时针对iPad iPhone两个平台\\N{\\fs12}but we want to start doing things actually on both platforms now; iPad and iPhone.\r\nDialogue: 0,0:00:31.55,0:00:33.34,yin,,0,0,0,,然后我要做一个演示\\N{\\fs12}And then I'm going to do a demo, which is going\r\nDialogue: 0,0:00:33.34,0:00:35.68,yin,,0,0,0,,将两者结合到一起\\N{\\fs12}to of course incorporate these two things.\r\nDialogue: 0,0:00:35.68,0:00:38.15,yin,,0,0,0,,首先看TableView\\N{\\fs12}So let's dive right into TableView.\r\nDialogue: 0,0:00:38.15,0:00:41.54,yin,,0,0,0,,这是一个很重要的类 因为很多时候\\N{\\fs12}This is a very important class, because a lot of times the data\r\nDialogue: 0,0:00:41.54,0:00:46.68,yin,,0,0,0,,应用程序中所要展示的数据 都是以列表的形式出现的\\N{\\fs12}that you need to display in your applications comes in the form of a list.\r\nDialogue: 0,0:00:46.68,0:00:48.97,yin,,0,0,0,,TableView基本上也就是一个列表视图\\N{\\fs12}And TableView is basically a list view.\r\nDialogue: 0,0:00:48.97,0:00:51.37,yin,,0,0,0,,它是一系列项目的列表\\N{\\fs12}It's a list of items.\r\nDialogue: 0,0:00:51.37,0:00:54.10,yin,,0,0,0,,它是一维的\\N{\\fs12}It's one-dimensional in that, you know, it's just --\r\nDialogue: 0,0:00:54.10,0:00:57.30,yin,,0,0,0,,而不是矩阵或是电子表格那些东西\\N{\\fs12}it's not like a matrix or a spreadsheet or something like that.\r\nDialogue: 0,0:00:57.30,0:00:59.70,yin,,0,0,0,,它是一维的 不过可以分为多段\\N{\\fs12}It's one, although it can be divided into sections\r\nDialogue: 0,0:00:59.70,0:01:02.57,yin,,0,0,0,,这就让它能有更多维度\\N{\\fs12}which gives it a little more dimension.\r\nDialogue: 0,0:01:02.57,0:01:06.35,yin,,0,0,0,,当我们要展示多维数据时 例如电子表格的情况\\N{\\fs12}When we want to display multiple dimension things like a spreadsheet would be,\r\nDialogue: 0,0:01:06.35,0:01:10.29,yin,,0,0,0,,我们可以将多个TableView放入到导航控制器中\\N{\\fs12}then we just put multiple TableViews into navigation controllers.\r\nDialogue: 0,0:01:10.29,0:01:15.81,yin,,0,0,0,,用户触碰各行 我们滑动到下一行\\N{\\fs12}And so users touch rows and we slide in the next row basically\r\nDialogue: 0,0:01:15.81,0:01:19.79,yin,,0,0,0,,或者说下一列 考虑电子表格这类情况就是如此\\N{\\fs12}or next column, if you want to think of it in spreadsheet-type terms.\r\nDialogue: 0,0:01:19.79,0:01:20.73,yin,,0,0,0,,这就是我们的做法\\N{\\fs12}So that's how we do it.\r\nDialogue: 0,0:01:20.73,0:01:25.64,yin,,0,0,0,,TableView本身并不能处理多维数据\\N{\\fs12}The TableView itself doesn't manage multidimensional data.\r\nDialogue: 0,0:01:25.64,0:01:29.99,yin,,0,0,0,,TableView还有很多配置选项和自定义\\N{\\fs12}And there's a lot of different configuration and customizations for TableViews.\r\nDialogue: 0,0:01:29.99,0:01:33.92,yin,,0,0,0,,我将有一些幻灯片来展示这些TableView是怎样的\\N{\\fs12}And so I have some slides here to show you some pictures of what TableViews look like.\r\nDialogue: 0,0:01:33.92,0:01:37.88,yin,,0,0,0,,这里有一些不同类型的TableView\\N{\\fs12}So here's a couple of different types of TableViews --\r\nDialogue: 0,0:01:37.88,0:01:41.55,yin,,0,0,0,,这是两种主要类型 左边是普通样式\\N{\\fs12}the two main types -- which is the plain style, that's the one on the left.\r\nDialogue: 0,0:01:41.55,0:01:44.23,yin,,0,0,0,,右边则是分组样式\\N{\\fs12}And then the group style which is the one on the right.\r\nDialogue: 0,0:01:44.23,0:01:49.09,yin,,0,0,0,,普通样式这个同时也是动态TableView\\N{\\fs12}The plain style one that I've shown there is also a dynamic TableView.\r\nDialogue: 0,0:01:49.09,0:01:53.87,yin,,0,0,0,,也就是说 所有内容都是填充自某处的数据库\\N{\\fs12}Meaning that all of its contents are being filled up from some database somewhere.\r\nDialogue: 0,0:01:53.87,0:01:58.45,yin,,0,0,0,,例如这里 我有一些联系人\\N{\\fs12}So you can see here I've got some contacts there.\r\nDialogue: 0,0:01:58.45,0:02:01.64,yin,,0,0,0,,你们有些人估计能够猜出他们是做什么的\\N{\\fs12}Some of you might be able to guess what all those people are.\r\nDialogue: 0,0:02:01.64,0:02:03.97,yin,,0,0,0,,无论如何 这里只是来自某数据库的一份列表\\N{\\fs12}But anyways, it's just a list from some database --\r\nDialogue: 0,0:02:03.97,0:02:05.43,yin,,0,0,0,,团队数据库这之类\\N{\\fs12}a team database or something.\r\nDialogue: 0,0:02:05.43,0:02:07.24,yin,,0,0,0,,而右边这个\\N{\\fs12}And then on the right.\r\nDialogue: 0,0:02:07.24,0:02:09.09,yin,,0,0,0,,是一个分组表格\\N{\\fs12}We have a grouped table.\r\nDialogue: 0,0:02:09.09,0:02:12.03,yin,,0,0,0,,可以看到 数据都分好了组\\N{\\fs12}You can see the kind of -- the things are grouped, right?\r\nDialogue: 0,0:02:12.04,0:02:13.86,yin,,0,0,0,,有距离分组\\N{\\fs12}The little distances section.\r\nDialogue: 0,0:02:13.86,0:02:17.55,yin,,0,0,0,,地图标签分组 这里有更多的分组\\N{\\fs12}The map label section they're kind of grouped together more instead\r\nDialogue: 0,0:02:17.55,0:02:20.87,yin,,0,0,0,,不像左边 只有题名\\N{\\fs12}of just having section titles on the left.\r\nDialogue: 0,0:02:20.87,0:02:24.19,yin,,0,0,0,,而且 右边这个是静态的\\N{\\fs12}And also, that one on the right is static.\r\nDialogue: 0,0:02:24.19,0:02:25.80,yin,,0,0,0,,换言之 其中的项目\\N{\\fs12}In other words, the things that are\r\nDialogue: 0,0:02:25.80,0:02:28.32,yin,,0,0,0,,并不来自于某个数据库\\N{\\fs12}in that aren't coming out of a database.\r\nDialogue: 0,0:02:28.32,0:02:29.70,yin,,0,0,0,,它们只是设定在这里\\N{\\fs12}They're just kind of fixed in there.\r\nDialogue: 0,0:02:29.70,0:02:32.19,yin,,0,0,0,,总是\"以英里计\"和\"以公里计\"\\N{\\fs12}It always says in miles. It always says in kilometers.\r\nDialogue: 0,0:02:32.19,0:02:33.37,yin,,0,0,0,,总是\"英文\"\\N{\\fs12}It always says all this in English.\r\nDialogue: 0,0:02:33.37,0:02:34.44,yin,,0,0,0,,这是固定不变的\\N{\\fs12}It's just fixed.\r\nDialogue: 0,0:02:34.44,0:02:36.28,yin,,0,0,0,,所以说表格是静态的\\N{\\fs12}So it's a static table.\r\nDialogue: 0,0:02:36.28,0:02:40.71,yin,,0,0,0,,这两种类型涵盖了我们可以考虑的所有样式\\N{\\fs12}So these two kind of encompass all the different styles that we can do.\r\nDialogue: 0,0:02:40.71,0:02:45.32,yin,,0,0,0,,我们再来看下TableView的各个部分\\N{\\fs12}So let's talk about some of the particular parts of a TableView.\r\nDialogue: 0,0:02:45.32,0:02:47.75,yin,,0,0,0,,我会告诉你们它们都叫什么 便于讨论\\N{\\fs12}I'm just going to give them some names so we can talk about them.\r\nDialogue: 0,0:02:47.75,0:02:49.82,yin,,0,0,0,,在TableView顶部有一个视图\\N{\\fs12}So at the top of the TableView, there's a view.\r\nDialogue: 0,0:02:49.82,0:02:52.18,yin,,0,0,0,,它处于所有行之上\\N{\\fs12}That comes before all the rows,\r\nDialogue: 0,0:02:52.18,0:02:54.01,yin,,0,0,0,,这是header 表头\\N{\\fs12}which is the header -- the table header.\r\nDialogue: 0,0:02:54.01,0:02:55.78,yin,,0,0,0,,最下面有一行代码\\N{\\fs12}There's a little bit of code at the bottom.\r\nDialogue: 0,0:02:55.78,0:02:57.16,yin,,0,0,0,,便于以后参考\\N{\\fs12}That's more for your reference later.\r\nDialogue: 0,0:02:57.16,0:03:00.80,yin,,0,0,0,,这是TableView中用于设定属性的\\N{\\fs12}That's basically the properties you use to set that thing in the TableView.\r\nDialogue: 0,0:03:00.80,0:03:03.13,yin,,0,0,0,,当然 这里还有一个footer\\N{\\fs12}And of course there's the footer as well.\r\nDialogue: 0,0:03:03.13,0:03:05.55,yin,,0,0,0,,之前是页头 这里是页尾\\N{\\fs12}So the table header and a table footer.\r\nDialogue: 0,0:03:05.55,0:03:07.86,yin,,0,0,0,,中间是所有这些行\\N{\\fs12}In between is where all the rows are.\r\nDialogue: 0,0:03:07.86,0:03:11.35,yin,,0,0,0,,这些行会被分为多段(section)\\N{\\fs12}And the rows are divided into sections.\r\nDialogue: 0,0:03:11.35,0:03:16.50,yin,,0,0,0,,每一段包括多行 也可以是一行\\N{\\fs12}And each section includes some rows -- some number of rows could be one row.\r\nDialogue: 0,0:03:16.50,0:03:19.39,yin,,0,0,0,,也可以是一百行 一千行等等\\N{\\fs12}Or it could be 100 rows. Or a 1,000 rows, whatever.\r\nDialogue: 0,0:03:19.39,0:03:21.05,yin,,0,0,0,,它们也有header和footer\\N{\\fs12}And also a header and a footer.\r\nDialogue: 0,0:03:21.05,0:03:25.33,yin,,0,0,0,,每一段有段头 这两段有header 0和header 1\\N{\\fs12}So each section has headers, so you can see header 0, header 1 for these two sections.\r\nDialogue: 0,0:03:25.33,0:03:29.40,yin,,0,0,0,,这个TableView中有两段 每一个也都有段尾\\N{\\fs12}We have two sections in this TableView, and each one also has footers.\r\nDialogue: 0,0:03:29.40,0:03:31.18,yin,,0,0,0,,段尾其实用得不多\\N{\\fs12}We don't really use the footers that much.\r\nDialogue: 0,0:03:31.18,0:03:34.66,yin,,0,0,0,,不过TableView中有分段时 段头会用得很多\\N{\\fs12}We use the headers quite a bit when we have sections in our TableView.\r\nDialogue: 0,0:03:34.66,0:03:37.84,yin,,0,0,0,,然后很重要的是 这里还有表格单元格(cell)\\N{\\fs12}And then very importantly, there's the table cells.\r\nDialogue: 0,0:03:37.84,0:03:40.36,yin,,0,0,0,,这是来自数据库的实际数据\\N{\\fs12}And this is where the actual data that's coming\r\nDialogue: 0,0:03:40.36,0:03:43.89,yin,,0,0,0,,或是我们在TableView中显示的别的东西\\N{\\fs12}out of our database, or whatever, that we're displaying in our TableView\r\nDialogue: 0,0:03:43.89,0:03:47.24,yin,,0,0,0,,我们将它们放到这些表格单元格中\\N{\\fs12}are coming out of and putting into these table cells,\r\nDialogue: 0,0:03:47.24,0:03:48.83,yin,,0,0,0,,它们实际上是UIView\\N{\\fs12}which are actually UI views.\r\nDialogue: 0,0:03:48.83,0:03:50.80,yin,,0,0,0,,UIView的自定义子类\\N{\\fs12}A custom subclass of UI View.\r\nDialogue: 0,0:03:50.80,0:03:52.98,yin,,0,0,0,,这是这里各部分的名称\\N{\\fs12}So that's what we call all of these various parts.\r\nDialogue: 0,0:03:52.98,0:03:55.68,yin,,0,0,0,,这是普通样式中的情况\\N{\\fs12}This is what it looks like in the plain style.\r\nDialogue: 0,0:03:55.68,0:03:58.24,yin,,0,0,0,,这是分组样式中的情况\\N{\\fs12}And this is the same things in the group style.\r\nDialogue: 0,0:03:58.24,0:04:00.78,yin,,0,0,0,,分组样式中背景更灰一些\\N{\\fs12}So the group style you see kind of this little more grey background and kind\r\nDialogue: 0,0:04:00.78,0:04:04.09,yin,,0,0,0,,将各段组合到一起也更多一些\\N{\\fs12}of groups the sections together a little more.\r\nDialogue: 0,0:04:05.66,0:04:08.41,yin,,0,0,0,,我来讲一下这些段\\N{\\fs12}Let me talk a little bit about the sections,\r\nDialogue: 0,0:04:08.41,0:04:10.38,yin,,0,0,0,,因为这有时会让人困惑\\N{\\fs12}because sometimes that confuses people.\r\nDialogue: 0,0:04:10.38,0:04:13.02,yin,,0,0,0,,段只是将行组织起来的一种方式\\N{\\fs12}A section is just a way to group the rows.\r\nDialogue: 0,0:04:13.02,0:04:15.99,yin,,0,0,0,,左边的信息是没有分段的\\N{\\fs12}So here I've got some information with no sections.\r\nDialogue: 0,0:04:15.99,0:04:17.65,yin,,0,0,0,,这是一系列城市\\N{\\fs12}It's just a bunch of cities.\r\nDialogue: 0,0:04:17.65,0:04:19.72,yin,,0,0,0,,赫尔辛基 巴黎 柏林\\N{\\fs12}Right? Helsinki and Paris and Berlin.\r\nDialogue: 0,0:04:19.72,0:04:21.88,yin,,0,0,0,,而右边还是一份城市列表\\N{\\fs12}And on the right I've also got a list of cities,\r\nDialogue: 0,0:04:21.88,0:04:24.42,yin,,0,0,0,,不过我按国家将它们分到了不同的段中\\N{\\fs12}but they're grouped into sections by the country.\r\nDialogue: 0,0:04:24.42,0:04:25.38,yin,,0,0,0,,这里有日本\\N{\\fs12}You can see Japan.\r\nDialogue: 0,0:04:25.38,0:04:29.61,yin,,0,0,0,,其中有东京 京都 然后是墨西哥\\N{\\fs12}It's got Tokyo and Kyoto and the Mexico.\r\nDialogue: 0,0:04:29.61,0:04:33.17,yin,,0,0,0,,这里有旧金山 还有荷兰\\N{\\fs12}It's got San Francisco, something or other there, and Netherlands.\r\nDialogue: 0,0:04:33.17,0:04:35.31,yin,,0,0,0,,它有阿姆斯特丹\\N{\\fs12}It has Amsterdam.\r\nDialogue: 0,0:04:35.31,0:04:40.18,yin,,0,0,0,,这里按国家分了组 不过仍然是一份城市列表\\N{\\fs12}So they're grouped by country, but it's still just a list of cities.\r\nDialogue: 0,0:04:40.18,0:04:41.33,yin,,0,0,0,,这就是段\\N{\\fs12}So that's the sections.\r\nDialogue: 0,0:04:41.33,0:04:43.57,yin,,0,0,0,,你们在作业中就需要\\N{\\fs12}They're not -- now in your homework you're actually going\r\nDialogue: 0,0:04:43.57,0:04:45.64,yin,,0,0,0,,做和这里一样的事\\N{\\fs12}to have to do, in fact this exact thing.\r\nDialogue: 0,0:04:45.64,0:04:48.86,yin,,0,0,0,,也就是按国家对地名进行分组\\N{\\fs12}Where you're going to be grouping places by the country they're in.\r\nDialogue: 0,0:04:48.86,0:04:51.61,yin,,0,0,0,,你们在作业中需要用到section\\N{\\fs12}And so you will be using sections in your homework.\r\nDialogue: 0,0:04:51.61,0:04:53.95,yin,,0,0,0,,在今天的演示中 我将不会用到section\\N{\\fs12}In the demo today I'm not going to do sections.\r\nDialogue: 0,0:04:53.95,0:04:57.40,yin,,0,0,0,,你们需要自己在作业中搞清楚\\N{\\fs12}I have to leave you something to figure out on your homework.\r\nDialogue: 0,0:04:57.40,0:04:59.65,yin,,0,0,0,,单元格类型\\N{\\fs12}The type of cell.\r\nDialogue: 0,0:04:59.65,0:05:03.42,yin,,0,0,0,,每个单元格 每一行 可以有特定类型\\N{\\fs12}So each cell -- each row -- can have a certain types.\r\nDialogue: 0,0:05:03.42,0:05:06.41,yin,,0,0,0,,有一个副标题类型 有标题和副标题\\N{\\fs12}There's the subtitle type that has like a title and a subtitle there.\r\nDialogue: 0,0:05:06.41,0:05:08.43,yin,,0,0,0,,可以看到城市和国家\\N{\\fs12}You see the city and then the country --\r\nDialogue: 0,0:05:08.43,0:05:11.34,yin,,0,0,0,,地区和国家作为副标题给出\\N{\\fs12}or the region and the country there is the subtitle.\r\nDialogue: 0,0:05:11.34,0:05:13.45,yin,,0,0,0,,基本类型则没有副标题\\N{\\fs12}And then basic has no subtitle.\r\nDialogue: 0,0:05:13.45,0:05:15.75,yin,,0,0,0,,然后还有右侧细节和左侧细节两种\\N{\\fs12}There's the right detail and the left detail.\r\nDialogue: 0,0:05:15.75,0:05:17.99,yin,,0,0,0,,将副标题信息推到边上\\N{\\fs12}That puts that subtitle information kind of off\r\nDialogue: 0,0:05:17.99,0:05:19.89,yin,,0,0,0,,然后用点颜色字体来修饰\\N{\\fs12}to the side with a little bit of color or whatever.\r\nDialogue: 0,0:05:19.89,0:05:23.07,yin,,0,0,0,,这些是单元格的四种不同类型\\N{\\fs12}So these are the four different types of cells.\r\nDialogue: 0,0:05:23.07,0:05:24.29,yin,,0,0,0,,你还可以自定义单元格\\N{\\fs12}And you can also have custom cells.\r\nDialogue: 0,0:05:24.29,0:05:27.65,yin,,0,0,0,,完全自己进行布局\\N{\\fs12}Where you lay out what's in there completely on your own.\r\nDialogue: 0,0:05:27.65,0:05:32.49,yin,,0,0,0,,如何使用TableView呢\\N{\\fs12}So how do you use a TableView?\r\nDialogue: 0,0:05:32.49,0:05:36.64,yin,,0,0,0,,99%的时候 我们都会和TableView控制器一起用\\N{\\fs12}Well 99% of the time we use it with a TableView Controller.\r\nDialogue: 0,0:05:36.64,0:05:39.36,yin,,0,0,0,,TableView控制器可以直接拖出来\\N{\\fs12}So TableView Controller you can just drag it right out.\r\nDialogue: 0,0:05:39.36,0:05:40.92,yin,,0,0,0,,这里我们有Xcode\\N{\\fs12}So here we have X-code.\r\nDialogue: 0,0:05:40.92,0:05:44.01,yin,,0,0,0,,这里有TableView控制器应用程序示例\\N{\\fs12}I've got this TableView Controller example application\r\nDialogue: 0,0:05:44.01,0:05:49.26,yin,,0,0,0,,我只需要从对象面板中拖出一个TableView控制器\\N{\\fs12}here, and I'm just dragging a TableView Controller out of the object pallet\r\nDialogue: 0,0:05:49.27,0:05:53.26,yin,,0,0,0,,放到故事板中 这就得到了一整个场景\\N{\\fs12}and into my storyboard and it puts a whole scene there.\r\nDialogue: 0,0:05:53.26,0:05:57.32,yin,,0,0,0,,这个场景的控制器是一个UITableView控制器\\N{\\fs12}Now that scene's controller is a UITableView Controller.\r\nDialogue: 0,0:05:57.32,0:05:59.71,yin,,0,0,0,,这是iOS中的一个类 UITableViewController\\N{\\fs12}That's a class in IOS. UI TableView Controller.\r\nDialogue: 0,0:05:59.71,0:06:03.19,yin,,0,0,0,,这个UITableViewController场景的视图是\\N{\\fs12}The view of that UI TableView Controller scene is a\r\nDialogue: 0,0:06:03.19,0:06:04.45,yin,,0,0,0,,一个UITableView\\N{\\fs12}UI TableView.\r\nDialogue: 0,0:06:04.45,0:06:08.12,yin,,0,0,0,,使用UITableViewController时 几乎总有\\N{\\fs12}When we use UI TableView Controller almost always the\r\nDialogue: 0,0:06:08.12,0:06:11.09,yin,,0,0,0,,整个视图是一个UITableView\\N{\\fs12}entire view is a UI TableView.\r\nDialogue: 0,0:06:11.09,0:06:15.23,yin,,0,0,0,,视图的复杂性来自于单元格 我们将什么放到单元格中\\N{\\fs12}The complexity in that view comes in the cells -- what we put in the cells.\r\nDialogue: 0,0:06:15.23,0:06:16.97,yin,,0,0,0,,这是信息和数据所在的地方\\N{\\fs12}That's where the information and the data is.\r\nDialogue: 0,0:06:16.97,0:06:19.08,yin,,0,0,0,,我们一般不会放一个TableView\\N{\\fs12}We don't usually put a TableView\r\nDialogue: 0,0:06:19.08,0:06:20.92,yin,,0,0,0,,然后再在它周围放些别的什么\\N{\\fs12}and then some other things around it.\r\nDialogue: 0,0:06:20.92,0:06:22.04,yin,,0,0,0,,虽然你可以这样做\\N{\\fs12}Although you can do that,\r\nDialogue: 0,0:06:22.04,0:06:25.41,yin,,0,0,0,,但一般而言 你不会这样使用UITableViewController\\N{\\fs12}you just usually wouldn't use UI TableView Controller in that case.\r\nDialogue: 0,0:06:25.41,0:06:26.04,yin,,0,0,0,,你只需要\\N{\\fs12}You're going to do kind\r\nDialogue: 0,0:06:26.04,0:06:29.16,yin,,0,0,0,,手动去做UITableViewController为你准备的所有事情\\N{\\fs12}of all the things UI TableView Controller does for you, manually --\r\nDialogue: 0,0:06:29.18,0:06:31.79,yin,,0,0,0,,等下我会具体提到都有些什么\\N{\\fs12}which I'll mention what some of those things are.\r\nDialogue: 0,0:06:31.79,0:06:34.69,yin,,0,0,0,,好 我们把这个拖出来\\N{\\fs12}Alright? So we just drag this thing out.\r\nDialogue: 0,0:06:34.69,0:06:38.73,yin,,0,0,0,,这里我们显然希望它是UITableViewController的子类\\N{\\fs12}We are obviously going to want to subclass UI TableView Controller\r\nDialogue: 0,0:06:38.73,0:06:42.15,yin,,0,0,0,,这样我们就能实现我们自己的控制器行为\\N{\\fs12}so that we can implement our own controller behavior for one thing.\r\nDialogue: 0,0:06:42.15,0:06:44.03,yin,,0,0,0,,viewDidLoad等等\\N{\\fs12}View did load and all those things.\r\nDialogue: 0,0:06:44.03,0:06:46.19,yin,,0,0,0,,此外 我们还要实现\\N{\\fs12}But also we're going to want to implement\r\nDialogue: 0,0:06:46.19,0:06:49.52,yin,,0,0,0,,TableView的委托和数据源\\N{\\fs12}the TableView's delegate and data source.\r\nDialogue: 0,0:06:49.52,0:06:53.05,yin,,0,0,0,,也就是一些属性 它们具有协议 后面我会讲到\\N{\\fs12}Which are a couple of properties that have a protocol, which we're going to talk about.\r\nDialogue: 0,0:06:53.05,0:06:54.80,yin,,0,0,0,,这就是数据载入表格的方式\\N{\\fs12}And that's how the data gets loaded in the table.\r\nDialogue: 0,0:06:54.80,0:06:58.43,yin,,0,0,0,,所有这些东西都将在UITableViewController的子类中完成\\N{\\fs12}So we're going to do all that stuff in a subclass of UI TableView Controller.\r\nDialogue: 0,0:06:58.43,0:07:02.14,yin,,0,0,0,,可以看到 我正在创建一个新文件\\N{\\fs12}So you can see that I did new file, and now I'm creating it,\r\nDialogue: 0,0:07:02.14,0:07:05.33,yin,,0,0,0,,它是UITableViewController的子类\\N{\\fs12}and you can see that it's a subclass of UI TableView Controller and I'm calling it\r\nDialogue: 0,0:07:05.33,0:07:08.61,yin,,0,0,0,,名字用\"MyTableViewController\"(我的表格视图控制器)\\N{\\fs12}my -- actually probably \"My TableView Controller\" is what I should\r\nDialogue: 0,0:07:08.61,0:07:11.21,yin,,0,0,0,,下面这里应该是它 没错\\N{\\fs12}call it -- might have called it that on the next one yeah I did.\r\nDialogue: 0,0:07:11.22,0:07:14.58,yin,,0,0,0,,然后和很多场景一样\\N{\\fs12}And then of course, just like any other scene, you're going\r\nDialogue: 0,0:07:14.58,0:07:18.68,yin,,0,0,0,,你需要点击控制器 并到标识符检查器中设置类\\N{\\fs12}to click on the controller and go over to the identity inspector and set the class.\r\nDialogue: 0,0:07:18.68,0:07:21.47,yin,,0,0,0,,这同其它控制器的做法没有两样\\N{\\fs12}That's exactly the same as you've done for all your controllers, right?\r\nDialogue: 0,0:07:21.47,0:07:25.06,yin,,0,0,0,,你需要设置类 这里我将它设置到MyTableViewController\\N{\\fs12}You have to set the class, so here I'm setting it to My TableView Controller.\r\nDialogue: 0,0:07:25.06,0:07:27.35,yin,,0,0,0,,这两张幻灯片有点不同步\\N{\\fs12}A little out of sync between those two slides.\r\nDialogue: 0,0:07:27.35,0:07:29.74,yin,,0,0,0,,不管它 这里取名叫MyTableViewController\\N{\\fs12}Anyway, My TableView Controller we'll call it.\r\nDialogue: 0,0:07:29.74,0:07:33.49,yin,,0,0,0,,如果我右键点击这个控制器\\N{\\fs12}And if I right-click on that controller.\r\nDialogue: 0,0:07:33.49,0:07:35.13,yin,,0,0,0,,看看这里有什么连接\\N{\\fs12}And see what its connections are,\r\nDialogue: 0,0:07:35.13,0:07:39.34,yin,,0,0,0,,在黑框底部的是引用输出口\\N{\\fs12}you'll see that at the bottom of that black window there's referencing outlets.\r\nDialogue: 0,0:07:39.34,0:07:42.01,yin,,0,0,0,,这里是两个属性 数据源和委托\\N{\\fs12}Those are two properties -- datasource and delegate --\r\nDialogue: 0,0:07:42.01,0:07:45.89,yin,,0,0,0,,这些是ID 尖括号 UITableViewDataSource\\N{\\fs12}those are ID angle bracket. UI TableView Datasource,\r\nDialogue: 0,0:07:45.89,0:07:49.57,yin,,0,0,0,,或ID 尖括号 UITableViewDelegate\\N{\\fs12}or ID angle bracket, UI TableView Delegate.\r\nDialogue: 0,0:07:49.57,0:07:52.04,yin,,0,0,0,,TableViewController拖出来后\\N{\\fs12}And the TableView controller, when we drag it out,\r\nDialogue: 0,0:07:52.04,0:07:55.45,yin,,0,0,0,,就会自动成为这两个东西\\N{\\fs12}automatically sets itself to be those two things.\r\nDialogue: 0,0:07:55.45,0:07:59.24,yin,,0,0,0,,这两个协议中的所有方法都会\\N{\\fs12}So all the methods in those two protocols are going to be implemented\r\nDialogue: 0,0:07:59.24,0:08:02.28,yin,,0,0,0,,被我们这里的TableViewController实现\\N{\\fs12}by our TableView Controller subclass right there.\r\nDialogue: 0,0:08:02.28,0:08:05.74,yin,,0,0,0,,当然 我们会从UITableViewController中继承一些\\N{\\fs12}And of course we're actually going to inherit some of them from UI TableView Controller\r\nDialogue: 0,0:08:05.74,0:08:10.20,yin,,0,0,0,,这些都是处理TableView时 iOS为我们提供的现成东西\\N{\\fs12}which is this nice package that IOS provides to kind of get you going with TableView's.\r\nDialogue: 0,0:08:10.20,0:08:13.10,yin,,0,0,0,,我们等下会谈到数据源和委托\\N{\\fs12}And we're going to talk about the datasource and the delegate and what they --\r\nDialogue: 0,0:08:13.10,0:08:14.97,yin,,0,0,0,,这里有哪些方法\\N{\\fs12}what methods are in there and what we have\r\nDialogue: 0,0:08:14.97,0:08:17.56,yin,,0,0,0,,以及如何让这些发挥作用\\N{\\fs12}to do to make this all work in just a moment.\r\nDialogue: 0,0:08:17.56,0:08:21.35,yin,,0,0,0,,不过首先 看看如何配置TableView\\N{\\fs12}But first, let's look a little bit of how we can configure the TableView\r\nDialogue: 0,0:08:21.35,0:08:23.00,yin,,0,0,0,,让它看起来有所不同\\N{\\fs12}and make it look different ways.\r\nDialogue: 0,0:08:23.02,0:08:26.40,yin,,0,0,0,,TableView默认是普通样式\\N{\\fs12}This TableView comes out and it's in plain style by default,\r\nDialogue: 0,0:08:26.40,0:08:29.57,yin,,0,0,0,,我打算换成分组样式 看看会是怎样\\N{\\fs12}but I'm going to switch it to grouped so we can see what that looks like.\r\nDialogue: 0,0:08:29.57,0:08:30.66,yin,,0,0,0,,似乎很类似\\N{\\fs12}It looks kind of similar.\r\nDialogue: 0,0:08:30.66,0:08:34.61,yin,,0,0,0,,只是周边有一个灰色区域\\N{\\fs12}Again, more of a grey around it -- more grey area because the cell --\r\nDialogue: 0,0:08:34.61,0:08:36.96,yin,,0,0,0,,这样各行就分组得更好一些\\N{\\fs12}the rows are kind of grouped together more.\r\nDialogue: 0,0:08:36.96,0:08:40.99,yin,,0,0,0,,这些单元格现在是动态的\\N{\\fs12}These are dynamic cells right now.\r\nDialogue: 0,0:08:40.99,0:08:43.71,yin,,0,0,0,,也就是说 数据是从外部加载的\\N{\\fs12}In other words, they would be loaded by some external data,\r\nDialogue: 0,0:08:43.71,0:08:45.89,yin,,0,0,0,,使用我们的数据源协议\\N{\\fs12}using our datasource protocol.\r\nDialogue: 0,0:08:45.89,0:08:48.53,yin,,0,0,0,,不过我要把这些转换成静态单元格\\N{\\fs12}But I'm going to switch this to static cells.\r\nDialogue: 0,0:08:48.53,0:08:50.76,yin,,0,0,0,,转换成静态单元格后\\N{\\fs12}And when you switch to static cells,\r\nDialogue: 0,0:08:50.76,0:08:53.28,yin,,0,0,0,,它会给我三行 而不是一行 这很棒\\N{\\fs12}first of all it gave me three instead of one, which was nice.\r\nDialogue: 0,0:08:53.28,0:08:54.71,yin,,0,0,0,,现在 这些单元格成了静态的\\N{\\fs12}Now these cells are static.\r\nDialogue: 0,0:08:54.71,0:08:57.15,yin,,0,0,0,,也就是说 无论我在故事板中怎么编辑它们\\N{\\fs12}Meaning however I edit them in the storyboard,\r\nDialogue: 0,0:08:57.15,0:08:59.03,yin,,0,0,0,,这就会成为它们在程序中的样子\\N{\\fs12}that's what they're going to look like in the program.\r\nDialogue: 0,0:08:59.03,0:09:01.53,yin,,0,0,0,,它们不是从外部数据源加载的\\N{\\fs12}They're not getting loaded up from any external datasource,\r\nDialogue: 0,0:09:01.53,0:09:02.81,yin,,0,0,0,,只是我在这里编辑的\\N{\\fs12}I'm just editing them right here.\r\nDialogue: 0,0:09:02.81,0:09:05.55,yin,,0,0,0,,几乎就像是三个矩形的视图\\N{\\fs12}It's almost like it's just three rectangular views.\r\nDialogue: 0,0:09:05.55,0:09:08.21,yin,,0,0,0,,你可以把按钮或是标签拖到这里\\N{\\fs12}And you can drag buttons in here. You can drag labels.\r\nDialogue: 0,0:09:08.21,0:09:09.89,yin,,0,0,0,,也可以接通输出口\\N{\\fs12}You can wire up outlets.\r\nDialogue: 0,0:09:09.89,0:09:13.07,yin,,0,0,0,,你可以在静态TableView中做任何你想做的事\\N{\\fs12}You can do anything you want in this static TableView.\r\nDialogue: 0,0:09:13.07,0:09:16.37,yin,,0,0,0,,静态TableView是为设置这些所设计的\\N{\\fs12}Really the static TableView is for things like settings and things like that.\r\nDialogue: 0,0:09:16.37,0:09:19.26,yin,,0,0,0,,它们的UI是固定的\\N{\\fs12}Things that, you know, are -- the UI of them is fixed.\r\nDialogue: 0,0:09:19.26,0:09:21.73,yin,,0,0,0,,并不适用于联系人这些\\N{\\fs12}It's not for, you know, contacts and things\r\nDialogue: 0,0:09:21.73,0:09:23.88,yin,,0,0,0,,否则就需要数据库加载 这里只是静态\\N{\\fs12}where you're loading it out of a database. So you can have static.\r\nDialogue: 0,0:09:23.88,0:09:27.28,yin,,0,0,0,,不过现在 我打算转换回动态\\N{\\fs12}But I'm going to switch back to dynamic here.\r\nDialogue: 0,0:09:27.28,0:09:29.44,yin,,0,0,0,,转换回动态单元格\\N{\\fs12}Back to the dynamic cells.\r\nDialogue: 0,0:09:29.44,0:09:30.97,yin,,0,0,0,,转换回动态单元格后\\N{\\fs12}So -- and notice that when I switch\r\nDialogue: 0,0:09:30.97,0:09:34.28,yin,,0,0,0,,注意它在顶部说 原型单元格\\N{\\fs12}to dynamic cells it says along the top, prototype cells.\r\nDialogue: 0,0:09:34.28,0:09:36.66,yin,,0,0,0,,因为这些单元格将成为原型\\N{\\fs12}Because these cells are actually going to be prototypes --\r\nDialogue: 0,0:09:36.66,0:09:39.09,yin,,0,0,0,,无论我们在故事板中怎么做\\N{\\fs12}whatever we do here in the storyboard --\r\nDialogue: 0,0:09:39.09,0:09:41.07,yin,,0,0,0,,这些都会被复制到\\N{\\fs12}that are going to be replicated over and over\r\nDialogue: 0,0:09:41.07,0:09:43.54,yin,,0,0,0,,数据库中加载的一切数据上\\N{\\fs12}for everything that comes out of our database.\r\nDialogue: 0,0:09:43.54,0:09:46.07,yin,,0,0,0,,动态模式中 我们从数据库中获得数据\\N{\\fs12}So in dynamic mode we're getting all the data out of the database\r\nDialogue: 0,0:09:46.07,0:09:49.17,yin,,0,0,0,,并复制这些原型\\N{\\fs12}and we're replicating these prototypes.\r\nDialogue: 0,0:09:49.17,0:09:51.43,yin,,0,0,0,,而且 这还是在分组模式中\\N{\\fs12}Also, this is still in grouped mode.\r\nDialogue: 0,0:09:51.43,0:09:53.68,yin,,0,0,0,,我打算切换回普通模式\\N{\\fs12}So I'm going to switch back to plain mode.\r\nDialogue: 0,0:09:53.68,0:09:55.41,yin,,0,0,0,,上面还是说原型单元格\\N{\\fs12}It still says prototype cells to the top,\r\nDialogue: 0,0:09:55.41,0:09:57.32,yin,,0,0,0,,不过这里我回到了普通模式\\N{\\fs12}but now I'm getting more of the plain mode\r\nDialogue: 0,0:09:57.32,0:10:01.17,yin,,0,0,0,,没有灰色区域和分组这些\\N{\\fs12}where there's not the grey around the group so much.\r\nDialogue: 0,0:10:01.17,0:10:03.19,yin,,0,0,0,,这里还三行\\N{\\fs12}Also you can see I have three of them there.\r\nDialogue: 0,0:10:03.19,0:10:07.13,yin,,0,0,0,,三个原型单元格很不寻常\\N{\\fs12}It's pretty unusual to have three different prototype cells\r\nDialogue: 0,0:10:07.13,0:10:08.80,yin,,0,0,0,,从数据库中加载数据时\\N{\\fs12}when you're loading the stuff out of the database.\r\nDialogue: 0,0:10:08.80,0:10:11.20,yin,,0,0,0,,只有加载的是完全不同的东西时\\N{\\fs12}It would only be if you're loading kind of different things\r\nDialogue: 0,0:10:11.20,0:10:14.08,yin,,0,0,0,,你才需要使用不同显示方式和不同的原型\\N{\\fs12}out of the database and you display them differently you might have different prototypes.\r\nDialogue: 0,0:10:14.09,0:10:15.92,yin,,0,0,0,,不过大多数时候 原型只有一种\\N{\\fs12}But most of the time we only have one.\r\nDialogue: 0,0:10:15.92,0:10:18.48,yin,,0,0,0,,因此 这里我将切换回一个原型单元格\\N{\\fs12}So I'm going to change back to one prototype cell.\r\nDialogue: 0,0:10:18.48,0:10:20.46,yin,,0,0,0,,这里只有一个原型单元格\\N{\\fs12}So I have this one prototype cell.\r\nDialogue: 0,0:10:20.46,0:10:25.11,yin,,0,0,0,,它会被复制到数据库中加载的每一行数据\\N{\\fs12}It's going to be copied for every single thing that I load out of my database; every row.\r\nDialogue: 0,0:10:25.13,0:10:27.51,yin,,0,0,0,,明白什么是原型了吗\\N{\\fs12}Does everybody understand what I'm saying by it's a prototype?\r\nDialogue: 0,0:10:27.51,0:10:29.32,yin,,0,0,0,,可以说是一个被复制的模板\\N{\\fs12}It's like a template that's going to be copied.\r\nDialogue: 0,0:10:29.32,0:10:32.49,yin,,0,0,0,,在故事板中所进行的任何设置\\N{\\fs12}So whatever we do here in the storyboard to set this thing up,\r\nDialogue: 0,0:10:32.49,0:10:33.64,yin,,0,0,0,,都会沿用下去\\N{\\fs12}it's going to look the same.\r\nDialogue: 0,0:10:33.64,0:10:35.46,yin,,0,0,0,,只有数据会发生变化\\N{\\fs12}Except the data will be different because it's going\r\nDialogue: 0,0:10:35.46,0:10:38.76,yin,,0,0,0,,数据是从数据库中加载的 但布局什么的会不变\\N{\\fs12}to be loaded from a database, but the layout of it is going to look the same.\r\nDialogue: 0,0:10:38.76,0:10:40.68,yin,,0,0,0,,我们能做些什么呢\\N{\\fs12}So what kind of things can we do?\r\nDialogue: 0,0:10:40.68,0:10:44.82,yin,,0,0,0,,下面让这些单元格具有副标题\\N{\\fs12}Well, let's change this cell to have that subtitle look\r\nDialogue: 0,0:10:44.82,0:10:47.91,yin,,0,0,0,,得到副标题类型的单元格\\N{\\fs12}like a subtitle thing that we -- cell type okay?\r\nDialogue: 0,0:10:47.91,0:10:50.07,yin,,0,0,0,,这时有标题和副标题\\N{\\fs12}And so now we get a title and a subtitle.\r\nDialogue: 0,0:10:50.07,0:10:52.40,yin,,0,0,0,,从数据库中获取每一行的数据时\\N{\\fs12}So when we pull data out of our database, we're going to want\r\nDialogue: 0,0:10:52.40,0:10:54.14,yin,,0,0,0,,我们既希望获取标题\\N{\\fs12}to pull some data that's the title\r\nDialogue: 0,0:10:54.14,0:10:56.55,yin,,0,0,0,,也希望获取副标题信息\\N{\\fs12}and pull some data that's the subtitle for each row.\r\nDialogue: 0,0:10:56.55,0:11:00.44,yin,,0,0,0,,我们还可以在行右侧附加一点信息\\N{\\fs12}We can also add a little accessory on the right-hand side of the row.\r\nDialogue: 0,0:11:00.44,0:11:03.31,yin,,0,0,0,,这里我打算加一点特殊的 所谓细节披露\\N{\\fs12}So I'm going to put a special one in here, a detailed disclosure.\r\nDialogue: 0,0:11:03.31,0:11:06.28,yin,,0,0,0,,看到这里有个信息圈吧\\N{\\fs12}You see it looks like that little information circle, right?\r\nDialogue: 0,0:11:06.28,0:11:08.19,yin,,0,0,0,,圆圈中有一个i\\N{\\fs12}An \"I\" inside of a circle.\r\nDialogue: 0,0:11:08.19,0:11:10.25,yin,,0,0,0,,这其实是一个很特殊的东西\\N{\\fs12}And that's actually a special thing --\r\nDialogue: 0,0:11:10.25,0:11:13.26,yin,,0,0,0,,以后我还会讲到 不过这里还有其它东西\\N{\\fs12}which I'm going to talk a little bit about later -- but there's other ones there.\r\nDialogue: 0,0:11:13.26,0:11:14.65,yin,,0,0,0,,比如可以是勾勾\\N{\\fs12}You can put like check marks\r\nDialogue: 0,0:11:14.65,0:11:16.98,yin,,0,0,0,,或是披露指示器这些\\N{\\fs12}and just disclosure indicators and things like that.\r\nDialogue: 0,0:11:17.49,0:11:21.64,yin,,0,0,0,,单元格中你可以做哪些事 我不打算全部讲到\\N{\\fs12}And I'm not going to go through all the things you can do to set up the cell you want.\r\nDialogue: 0,0:11:21.64,0:11:24.10,yin,,0,0,0,,你还可以将图片拖进来 等等\\N{\\fs12}You can drag images in there and all that stuff, but\r\nDialogue: 0,0:11:24.10,0:11:25.15,yin,,0,0,0,,这里我只想说\\N{\\fs12}suffice it to say,\r\nDialogue: 0,0:11:25.15,0:11:28.26,yin,,0,0,0,,你可以在这里用检查器 按照你想要的方式设置单元格\\N{\\fs12}you can use the inspector there and set your cell up the way you want.\r\nDialogue: 0,0:11:28.26,0:11:34.08,yin,,0,0,0,,这个单元格将在动态TableView中复制给每一行\\N{\\fs12}So this cell is going to be duplicated for every row now in my dynamic table view.\r\nDialogue: 0,0:11:34.08,0:11:38.33,yin,,0,0,0,,对于TableView单元格来说 属性检查器中\\N{\\fs12}The most important attribute though to set in the attributes inspector\r\nDialogue: 0,0:11:38.33,0:11:41.77,yin,,0,0,0,,最重要的是设置这个标识符\\N{\\fs12}for a TableView cell is this identifier.\r\nDialogue: 0,0:11:41.77,0:11:42.88,yin,,0,0,0,,这里我在\\N{\\fs12}You see where I've typed\r\nDialogue: 0,0:11:42.88,0:11:45.88,yin,,0,0,0,,标识符下键入Flickr Photo Cell(Flickr照片单元格)\\N{\\fs12}in Flickr Photo Cell right there under identifier?\r\nDialogue: 0,0:11:45.88,0:11:49.73,yin,,0,0,0,,这段字符串我们将用于代码中\\N{\\fs12}This is the string that we're going to use in our code\r\nDialogue: 0,0:11:49.73,0:11:53.86,yin,,0,0,0,,让代码知道复制哪个单元格\\N{\\fs12}so that our code knows the cell to replicate.\r\nDialogue: 0,0:11:53.86,0:11:56.94,yin,,0,0,0,,就像我们在segue中做的一样\\N{\\fs12}So you know, just like when we did a segue\r\nDialogue: 0,0:11:56.94,0:12:01.14,yin,,0,0,0,,我们会键入segue的名称 例如显示照片或是别的什么\\N{\\fs12}and we would type in the name of a segue like display photo or something like that?\r\nDialogue: 0,0:12:01.14,0:12:04.32,yin,,0,0,0,,这些然后会被用于代码 根据名称\\N{\\fs12}And that -- and then we used it in our code by name?\r\nDialogue: 0,0:12:04.32,0:12:08.79,yin,,0,0,0,,Xcode使用名称在代码和故事板之间进行同步\\N{\\fs12}Xcode uses names to sync up between your code and what's in the storyboard.\r\nDialogue: 0,0:12:08.79,0:12:12.05,yin,,0,0,0,,因为你需要复制粘贴整个整个的场景\\N{\\fs12}Because you want to be able to copy and paste entire scenes\r\nDialogue: 0,0:12:12.05,0:12:14.99,yin,,0,0,0,,例如从一个故事板到另一个故事板 你希望它们\\N{\\fs12}from one storyboard to another, for example, and you want them\r\nDialogue: 0,0:12:14.99,0:12:17.19,yin,,0,0,0,,到新地方时能和原来的地方关联起来\\N{\\fs12}to hook back up when they get to the new place.\r\nDialogue: 0,0:12:17.19,0:12:19.09,yin,,0,0,0,,这些都是通过名称来的\\N{\\fs12}And they do that because by names.\r\nDialogue: 0,0:12:19.09,0:12:20.33,yin,,0,0,0,,只要名称匹配\\N{\\fs12}As long as the names match.\r\nDialogue: 0,0:12:20.33,0:12:21.56,yin,,0,0,0,,类名\\N{\\fs12}Names of classes.\r\nDialogue: 0,0:12:21.56,0:12:24.20,yin,,0,0,0,,标识符名 这时就能关联起来\\N{\\fs12}Names of identifiers, then it will be hooked back up.\r\nDialogue: 0,0:12:24.20,0:12:26.80,yin,,0,0,0,,演示中 我就会复制粘贴整个的场景\\N{\\fs12}And we're going to see that in the demo. I'm going to copy and paste an entire scene\r\nDialogue: 0,0:12:26.80,0:12:30.58,yin,,0,0,0,,从另一个应用程序复制到我的演示程序\\N{\\fs12}from a completely different application that we wrote into my demo application\r\nDialogue: 0,0:12:30.58,0:12:33.35,yin,,0,0,0,,这些都会关联起来 这非常酷\\N{\\fs12}and it's all going to stay hooked up. Which is really kind of cool.\r\nDialogue: 0,0:12:33.35,0:12:36.60,yin,,0,0,0,,有些人可能会觉得这些字符串太笨拙了\\N{\\fs12}So some people think this is kind of unwieldy to have these strings.\r\nDialogue: 0,0:12:36.60,0:12:38.00,yin,,0,0,0,,你需要在代码中匹配起来\\N{\\fs12}And you have to match them up in your code,\r\nDialogue: 0,0:12:38.00,0:12:40.64,yin,,0,0,0,,不小心输错了一个字符 你就无法匹配\\N{\\fs12}and if you mistype a character, now they don't match up anymore.\r\nDialogue: 0,0:12:40.64,0:12:43.99,yin,,0,0,0,,反正 这里不过是用命名来关联这些东西\\N{\\fs12}But it's really just using naming to hook these things up.\r\nDialogue: 0,0:12:43.99,0:12:46.72,yin,,0,0,0,,这很重要 这个标识符\\N{\\fs12}So that's very important, that identifier, and we're going\r\nDialogue: 0,0:12:46.72,0:12:49.37,yin,,0,0,0,,等下代码中我们就会看到它\\N{\\fs12}to see that in the code in just a moment.\r\nDialogue: 0,0:12:49.37,0:12:52.29,yin,,0,0,0,,好 我们再看看这两种重要的协议\\N{\\fs12}Okay. So let's talk about these two really important protocols.\r\nDialogue: 0,0:12:52.29,0:12:54.48,yin,,0,0,0,,数据源协议和委托协议\\N{\\fs12}The datasource protocol. And the delegate protocol.\r\nDialogue: 0,0:12:54.48,0:12:56.73,yin,,0,0,0,,数据源协议\\N{\\fs12}The datasource protocol --\r\nDialogue: 0,0:12:56.73,0:12:59.38,yin,,0,0,0,,也就是 ID 尖括号 TableViewDataSource\\N{\\fs12}which is ID angle bracket TableView datasource --\r\nDialogue: 0,0:12:59.38,0:13:02.19,yin,,0,0,0,,这是TableView的内容\\N{\\fs12}that is the contents of the TableView.\r\nDialogue: 0,0:13:02.19,0:13:04.96,yin,,0,0,0,,这是从数据库出来 进入表格的数据\\N{\\fs12}That's the data that's coming out of our database that's going into the table.\r\nDialogue: 0,0:13:04.96,0:13:07.66,yin,,0,0,0,,换言之 这是关于显示的是什么\\N{\\fs12}In other words it's the what that is being displayed.\r\nDialogue: 0,0:13:07.66,0:13:10.49,yin,,0,0,0,,也就是显示我们的模型\\N{\\fs12}It's basically displaying our model.\r\nDialogue: 0,0:13:10.49,0:13:12.42,yin,,0,0,0,,记得我们的模型是什么吗\\N{\\fs12}And remember our model is what?\r\nDialogue: 0,0:13:12.44,0:13:15.04,yin,,0,0,0,,数据源将模型引入到表格中\\N{\\fs12}The datasource brings the model into the table.\r\nDialogue: 0,0:13:15.04,0:13:18.96,yin,,0,0,0,,数据源是一种协议 由控制器实现\\N{\\fs12}The controller uses -- the datasource is a protocol implemented by the controller\r\nDialogue: 0,0:13:18.96,0:13:22.16,yin,,0,0,0,,将模型的数据给到视图 TableView\\N{\\fs12}to bring the model's data into the view -- the TableView.\r\nDialogue: 0,0:13:22.16,0:13:26.55,yin,,0,0,0,,另一方面 委托是关于表格如何显示的\\N{\\fs12}The delegate on the other hand, is for how the table is displayed.\r\nDialogue: 0,0:13:26.55,0:13:27.88,yin,,0,0,0,,如何排列事物\\N{\\fs12}How we arrange things.\r\nDialogue: 0,0:13:27.88,0:13:31.66,yin,,0,0,0,,用什么视图显示这些header和footer 诸如此类\\N{\\fs12}What views we use to show those headers and footers; those kinds of things.\r\nDialogue: 0,0:13:31.66,0:13:33.40,yin,,0,0,0,,如果用户触碰一行会怎样\\N{\\fs12}What if someone touches a row?\r\nDialogue: 0,0:13:33.40,0:13:34.48,yin,,0,0,0,,我们希望作出响应\\N{\\fs12}And we want to react to that.\r\nDialogue: 0,0:13:34.48,0:13:35.69,yin,,0,0,0,,这都是委托\\N{\\fs12}That's all the delegate.\r\nDialogue: 0,0:13:35.69,0:13:37.37,yin,,0,0,0,,无关显示的数据\\N{\\fs12}It's not about the data that's being displayed,\r\nDialogue: 0,0:13:37.37,0:13:39.45,yin,,0,0,0,,而是如何显示这张表格\\N{\\fs12}it's more like how are we displaying this table\r\nDialogue: 0,0:13:39.45,0:13:41.90,yin,,0,0,0,,如何对触碰作出响应 诸如此类\\N{\\fs12}and how is it reacting to touches and things like that.\r\nDialogue: 0,0:13:41.90,0:13:47.10,yin,,0,0,0,,这两种我都会讲到 数据源和委托\\N{\\fs12}So we're going to talk about both of these delegates -- the datasource and the delegate.\r\nDialogue: 0,0:13:47.10,0:13:51.06,yin,,0,0,0,,UITableViewController 我讲清楚一些\\N{\\fs12}The UI TableView Controller, just to be clear --\r\nDialogue: 0,0:13:51.06,0:13:52.54,yin,,0,0,0,,前几张幻灯片中我讲过\\N{\\fs12}I showed this a couple slides ago --\r\nDialogue: 0,0:13:52.54,0:13:55.91,yin,,0,0,0,,它会自动关联到数据源和委托\\N{\\fs12}it automatically wires itself up as the datasource and delegate.\r\nDialogue: 0,0:13:55.91,0:13:59.30,yin,,0,0,0,,如果你要使用一个通用视图控制器\\N{\\fs12}If you were going to bring out a generic view controller and drag\r\nDialogue: 0,0:13:59.30,0:14:01.65,yin,,0,0,0,,并将TableView拖到它里面\\N{\\fs12}out a TableView into it -- which you can do.\r\nDialogue: 0,0:14:01.65,0:14:04.73,yin,,0,0,0,,这时你就需要自己动手将数据源和委托\\N{\\fs12}You would have to control drag the datasource and the delegate\r\nDialogue: 0,0:14:04.73,0:14:07.49,yin,,0,0,0,,Control拖动拖到你的试图控制器并关联起来\\N{\\fs12}to your view controller yourself. You'd have to hook them up.\r\nDialogue: 0,0:14:07.49,0:14:10.39,yin,,0,0,0,,或者在代码中关联 反正是要关联起来\\N{\\fs12}Or in code you could hook them up too. But you have to connect them up.\r\nDialogue: 0,0:14:10.39,0:14:13.50,yin,,0,0,0,,而UITableViewController会自动关联起来\\N{\\fs12}But UI TableView controller automatically hooks it up.\r\nDialogue: 0,0:14:13.50,0:14:16.95,yin,,0,0,0,,数据源和委托几乎总是你的控制器\\N{\\fs12}The datasource and delegate are almost always going to be your controller.\r\nDialogue: 0,0:14:16.95,0:14:20.13,yin,,0,0,0,,这很显然 应为控制器的工作就是\\N{\\fs12}That just makes sense because the controller's job is\r\nDialogue: 0,0:14:20.13,0:14:22.53,yin,,0,0,0,,为视图解释模型的信息\\N{\\fs12}to interpret the information of the model for the view.\r\nDialogue: 0,0:14:22.53,0:14:25.71,yin,,0,0,0,,很显然 控制器希望是委托\\N{\\fs12}So obviously the controller wants to be the delegate.\r\nDialogue: 0,0:14:25.71,0:14:29.05,yin,,0,0,0,,回到我们第一天讲的MVC\\N{\\fs12}And again, back to the MVC thing that we did the very first day,\r\nDialogue: 0,0:14:29.05,0:14:34.21,yin,,0,0,0,,这是视图和控制器之间一种盲的 结构化的通信\\N{\\fs12}this is that blind, structured communication between the view and the controller.\r\nDialogue: 0,0:14:34.21,0:14:37.95,yin,,0,0,0,,UITableViewController还有一个属性\\N{\\fs12}The UI TableView Controller also has a property\r\nDialogue: 0,0:14:37.95,0:14:41.88,yin,,0,0,0,,叫tableView 让你能够得到控制器中的TableView\\N{\\fs12}called TableView which lets you get the TableView that's in your controller.\r\nDialogue: 0,0:14:41.88,0:14:44.12,yin,,0,0,0,,这很好 这样你就能对它进行配置\\N{\\fs12}So that's nice to be able to do that so you can configure it\r\nDialogue: 0,0:14:44.12,0:14:45.61,yin,,0,0,0,,同它通信等等\\N{\\fs12}and talk to it and things like that.\r\nDialogue: 0,0:14:45.61,0:14:47.15,yin,,0,0,0,,这很棒\\N{\\fs12}So that's a nice one.\r\nDialogue: 0,0:14:47.15,0:14:49.28,yin,,0,0,0,,它其实是self.view\\N{\\fs12}It actually happens to be self.view\r\nDialogue: 0,0:14:49.28,0:14:51.81,yin,,0,0,0,,在TableViewController中 这有些奇特\\N{\\fs12}in a TableView controller which is a little weird.\r\nDialogue: 0,0:14:51.81,0:14:56.49,yin,,0,0,0,,我认为这是苹果方面的奇怪设计 总之 它就是这样了\\N{\\fs12}That was a strange design choice I think on Apple's part, but it is what it is.\r\nDialogue: 0,0:14:56.49,0:15:00.24,yin,,0,0,0,,好 数据源协议中有哪些重要的方法呢\\N{\\fs12}Okay. So what are the important methods in this datasource protocol?\r\nDialogue: 0,0:15:00.24,0:15:02.24,yin,,0,0,0,,重要的有三个\\N{\\fs12}Well, there's really three important ones.\r\nDialogue: 0,0:15:02.24,0:15:05.16,yin,,0,0,0,,一是 表格中有多少个section\\N{\\fs12}One is, how many sections are in this table?\r\nDialogue: 0,0:15:05.16,0:15:07.10,yin,,0,0,0,,每一个section中有多少行\\N{\\fs12}How many rows are in each section?\r\nDialogue: 0,0:15:07.10,0:15:10.38,yin,,0,0,0,,然后给我一个视图 一个UITableViewCell\\N{\\fs12}And then give me a view -- a UI TableView cell --\r\nDialogue: 0,0:15:10.38,0:15:13.52,yin,,0,0,0,,给我一个视图 让我能够画出这一行\\N{\\fs12}give me a view that I can use to draw this row.\r\nDialogue: 0,0:15:13.52,0:15:16.29,yin,,0,0,0,,很显然 就这三个方法\\N{\\fs12}Obvious, right? These are the three things.\r\nDialogue: 0,0:15:16.29,0:15:18.57,yin,,0,0,0,,知道有多少数据 然后\\N{\\fs12}Know how much data there is, and then it just asks --\r\nDialogue: 0,0:15:18.57,0:15:21.19,yin,,0,0,0,,持续通过这些来请求数据\\N{\\fs12}constantly asks you for the data by asking for these --\r\nDialogue: 0,0:15:21.19,0:15:21.89,yin,,0,0,0,,这个视图\\N{\\fs12}this view.\r\nDialogue: 0,0:15:21.89,0:15:24.08,yin,,0,0,0,,这个UITableViewCell 不断往复\\N{\\fs12}This UI TableView cell over and over.\r\nDialogue: 0,0:15:24.08,0:15:26.42,yin,,0,0,0,,我们先讲最后一个 因为这个最重要\\N{\\fs12}So let's cover the last one first, because that's the most important.\r\nDialogue: 0,0:15:26.42,0:15:29.44,yin,,0,0,0,,section数和行数很简单 只是请求一个数字\\N{\\fs12}It's really easy; the sections and rows, it's just asking you for a number.\r\nDialogue: 0,0:15:29.44,0:15:33.22,yin,,0,0,0,,但为每一行获得单元格就难一些了\\N{\\fs12}But the -- getting the cell for each row is a little more complicated,\r\nDialogue: 0,0:15:33.22,0:15:34.37,yin,,0,0,0,,我们先来看这个\\N{\\fs12}so let's talk about that one first.\r\nDialogue: 0,0:15:34.37,0:15:38.91,yin,,0,0,0,,这是数据源协议中的第三个方法\\N{\\fs12}So this is the third method in the datasource protocol.\r\nDialogue: 0,0:15:38.91,0:15:44.28,yin,,0,0,0,,方法名叫 TableView cellForRowAtIndexPath\\N{\\fs12}And it's called, \"TableView Cell for Row and Index Path\".\r\nDialogue: 0,0:15:44.28,0:15:47.56,yin,,0,0,0,,你应该能预计到它会叫这个\\N{\\fs12}It's kind of exactly what you'd expect it to be called,\r\nDialogue: 0,0:15:47.56,0:15:51.14,yin,,0,0,0,,可以理解 indexPath(索引路径)是一个对象\\N{\\fs12}in the sense, once you understand that index path is just an object\r\nDialogue: 0,0:15:51.14,0:15:54.50,yin,,0,0,0,,描述section和section中的行\\N{\\fs12}that describes the section and row within that section.\r\nDialogue: 0,0:15:54.50,0:15:55.70,yin,,0,0,0,,indexPath是一个对象\\N{\\fs12}So index path is an object.\r\nDialogue: 0,0:15:55.70,0:15:58.28,yin,,0,0,0,,它有两个属性 row和section\\N{\\fs12}It has two properties; row and section.\r\nDialogue: 0,0:15:58.28,0:16:01.86,yin,,0,0,0,,这个参数相当于是将行和section封装到了\\N{\\fs12}So that argument is basically just encapsulating the\r\nDialogue: 0,0:16:01.86,0:16:03.97,yin,,0,0,0,,一个对象之中\\N{\\fs12}row and section into one object.\r\nDialogue: 0,0:16:04.76,0:16:08.05,yin,,0,0,0,,我们被要求提供一个单元格\\N{\\fs12}So that -- so we're being asked here to provide a cell --\r\nDialogue: 0,0:16:08.05,0:16:09.20,yin,,0,0,0,,一个UITableViewCell\\N{\\fs12}a UI TableView cell,\r\nDialogue: 0,0:16:09.20,0:16:13.39,yin,,0,0,0,,这是一个将那一行画到那个section中的UIView\\N{\\fs12}which is a UI view to draw that row in that section.\r\nDialogue: 0,0:16:13.39,0:16:16.71,yin,,0,0,0,,我们只对动态表格这样做\\N{\\fs12}And we only do this for dynamic tables.\r\nDialogue: 0,0:16:16.71,0:16:18.81,yin,,0,0,0,,因为对于静态表格\\N{\\fs12}Because for a static table we set all this\r\nDialogue: 0,0:16:18.81,0:16:20.89,yin,,0,0,0,,所有这些都在故事板中设置\\N{\\fs12}up in the storyboard, so we don't need --\r\nDialogue: 0,0:16:20.89,0:16:23.69,yin,,0,0,0,,TableView不需要问我们要这个视图\\N{\\fs12}you know, there's no need for the TableView to be asking us\r\nDialogue: 0,0:16:23.69,0:16:25.70,yin,,0,0,0,,因为故事板中已经设定好了\\N{\\fs12}for this view, because it's already set up in the storyboard.\r\nDialogue: 0,0:16:25.70,0:16:28.38,yin,,0,0,0,,只有动态表格中才有这些\\N{\\fs12}This is only for dynamic ones that we have this.\r\nDialogue: 0,0:16:28.38,0:16:32.03,yin,,0,0,0,,这里我们需要做哪两件事呢\\N{\\fs12}And what are the two things that we need to do in here?\r\nDialogue: 0,0:16:32.03,0:16:34.32,yin,,0,0,0,,一是 我们需要创建一个单元格\\N{\\fs12}One is, we need to create a cell.\r\nDialogue: 0,0:16:34.32,0:16:36.49,yin,,0,0,0,,然后 我们需要对单元格进行配置\\N{\\fs12}And then we need to configure that cell.\r\nDialogue: 0,0:16:36.49,0:16:38.62,yin,,0,0,0,,我们将单独谈到这两点\\N{\\fs12}So we're going to talk about those two things separately.\r\nDialogue: 0,0:16:38.62,0:16:41.28,yin,,0,0,0,,首先 如何创建一个我们要返回的单元格呢\\N{\\fs12}First of all, how do we create a cell that we're going to return?\r\nDialogue: 0,0:16:41.28,0:16:43.99,yin,,0,0,0,,因为我们需要返回一个单元格 UITableViewCell\\N{\\fs12}Because we have to return a cell here -- UI TableView cell.\r\nDialogue: 0,0:16:43.99,0:16:47.42,yin,,0,0,0,,这里需要用到一个很特别的函数\\N{\\fs12}And we do that using this kind of funky method called,\r\nDialogue: 0,0:16:47.42,0:16:52.14,yin,,0,0,0,,dequeueReusableCellWithIdentifier: forIndexPath:\\N{\\fs12}\"dequeue Reusable Cell with Identifier for Index Path\".\r\nDialogue: 0,0:16:52.14,0:16:57.47,yin,,0,0,0,,它的作用是回到故事板\\N{\\fs12}Okay now, what this does is it essentially goes and looks in the storyboard.\r\nDialogue: 0,0:16:57.47,0:16:59.93,yin,,0,0,0,,找到标识符 Flickr Photo Cell\\N{\\fs12}Finds that identifier -- Flickr Photo Cell --\r\nDialogue: 0,0:16:59.93,0:17:03.04,yin,,0,0,0,,我说过 这在故事板中很重要 记得吧\\N{\\fs12}remember I told you that was an important thing to type in, in the storyboard.\r\nDialogue: 0,0:17:03.04,0:17:07.85,yin,,0,0,0,,它会复制一份原型\\N{\\fs12}And it copies that prototype -- makes a copy of that prototype.\r\nDialogue: 0,0:17:07.85,0:17:10.03,yin,,0,0,0,,并返回它\\N{\\fs12}And returns it.\r\nDialogue: 0,0:17:10.03,0:17:13.27,yin,,0,0,0,,不过 它的作用要比这更复杂一些\\N{\\fs12}However, it's a little more sophisticated than that,\r\nDialogue: 0,0:17:13.27,0:17:20.09,yin,,0,0,0,,dequeueReusableCell(出列可再用单元格)是说 它只创建\\N{\\fs12}and the reason it's called dequeue Reusable Cell, is that it only creates those things\r\nDialogue: 0,0:17:20.09,0:17:23.16,yin,,0,0,0,,行在屏幕上的那些\\N{\\fs12}for the rows that are on-screen.\r\nDialogue: 0,0:17:23.16,0:17:26.58,yin,,0,0,0,,TableView中可能有一千行\\N{\\fs12}I might have a thousand rows in my TableView\r\nDialogue: 0,0:17:26.58,0:17:29.27,yin,,0,0,0,,但我不希望创建一千个视图\\N{\\fs12}and I don't want to make a thousand views.\r\nDialogue: 0,0:17:29.27,0:17:30.87,yin,,0,0,0,,否则会非常低效\\N{\\fs12}That would be incredibly inefficient.\r\nDialogue: 0,0:17:30.87,0:17:33.33,yin,,0,0,0,,我将只创建9个视图\\N{\\fs12}So I only make nine views.\r\nDialogue: 0,0:17:33.33,0:17:35.10,yin,,0,0,0,,因为屏幕上只能容纳9行\\N{\\fs12}Because only nine rows can fit at --\r\nDialogue: 0,0:17:35.10,0:17:38.10,yin,,0,0,0,,这里假设是9行 也可能是15 7 4或别的多少\\N{\\fs12}let's say 9, it could be 15, 7, 4, whatever.\r\nDialogue: 0,0:17:38.10,0:17:39.18,yin,,0,0,0,,屏幕上能放多少\\N{\\fs12}However many will fit on-screen,\r\nDialogue: 0,0:17:39.18,0:17:40.41,yin,,0,0,0,,这里就创建这么多\\N{\\fs12}I'm just going to make that many.\r\nDialogue: 0,0:17:40.41,0:17:42.82,yin,,0,0,0,,沿TableView往下滚动时\\N{\\fs12}And as I scroll through my TableView,\r\nDialogue: 0,0:17:42.82,0:17:45.90,yin,,0,0,0,,一些行会从屏幕上方离开\\N{\\fs12}as rows go off the top of the screen, I'm going to grab\r\nDialogue: 0,0:17:45.90,0:17:48.94,yin,,0,0,0,,我会把其视图放到再利用池中\\N{\\fs12}that view and put it into a little reuse pool.\r\nDialogue: 0,0:17:48.94,0:17:50.67,yin,,0,0,0,,有新的从底下过来时\\N{\\fs12}And then when a new one comes on the bottom,\r\nDialogue: 0,0:17:50.67,0:17:52.23,yin,,0,0,0,,我就会再用它\\N{\\fs12}I'm going to reuse it.\r\nDialogue: 0,0:17:52.23,0:17:55.77,yin,,0,0,0,,这里我只使用屏幕上的这些\\N{\\fs12}So I'm basically going to just, you know, only using the ones on screen.\r\nDialogue: 0,0:17:55.77,0:17:56.67,yin,,0,0,0,,离开屏幕时\\N{\\fs12}And when they go off screen,\r\nDialogue: 0,0:17:56.67,0:17:59.00,yin,,0,0,0,,我会将其用于新出现在屏幕上的\\N{\\fs12}I reuse it for a new one that's coming on-screen.\r\nDialogue: 0,0:17:59.00,0:17:59.83,yin,,0,0,0,,能理解吗\\N{\\fs12}Does that make sense?\r\nDialogue: 0,0:17:59.83,0:18:01.85,yin,,0,0,0,,我是在不断再利用这些东西\\N{\\fs12}So I'm just constantly re-using these things.\r\nDialogue: 0,0:18:01.85,0:18:04.30,yin,,0,0,0,,所以叫作dequeueReusableCell\\N{\\fs12}So that's why it's called dequeueReusableCell.\r\nDialogue: 0,0:18:04.30,0:18:09.01,yin,,0,0,0,,但是 如果没有可以再利用的 它就会复制原型\\N{\\fs12}But if I don't have one, if there's not one to reuse, it copies that prototype that's\r\nDialogue: 0,0:18:09.01,0:18:11.90,yin,,0,0,0,,从故事板中 使用这个名称\\N{\\fs12}in the storyboard, using this name.\r\nDialogue: 0,0:18:12.52,0:18:14.41,yin,,0,0,0,,这方面有问题吗 请讲\\N{\\fs12}Questions about that? Yeah?\r\nDialogue: 0,0:18:14.41,0:18:15.88,yin,,0,0,0,,学生：请明确一下\\N{\\fs12}> Just a quick clarification.\r\nDialogue: 0,0:18:15.88,0:18:19.66,yin,,0,0,0,,你说访问TableView实际上是self.view\\N{\\fs12}You said that to access the TableView it was actually self.view?\r\nDialogue: 0,0:18:19.66,0:18:22.49,yin,,0,0,0,,但我们进入TableView时 情况会不会有所不同\\N{\\fs12}But when we get into TableView are we looking at something different?\r\nDialogue: 0,0:18:22.49,0:18:26.80,yin,,0,0,0,,教授：我说self.tableView等价于self.view\\N{\\fs12}> Okay. When I said that self.tableview is the same as self.view,\r\nDialogue: 0,0:18:26.81,0:18:29.12,yin,,0,0,0,,这仅限于UITableViewController之中\\N{\\fs12}that's only in UI TableView Controller.\r\nDialogue: 0,0:18:29.12,0:18:30.86,yin,,0,0,0,,这是一个实现细节\\N{\\fs12}That's an implementation detail\r\nDialogue: 0,0:18:30.86,0:18:33.43,yin,,0,0,0,,我讲这个是为了避免你们被它绊倒\\N{\\fs12}that I say because it might trip you up.\r\nDialogue: 0,0:18:33.43,0:18:35.51,yin,,0,0,0,,不过我们将总是使用self.tableView\\N{\\fs12}But we always would use self.tableview.\r\nDialogue: 0,0:18:35.51,0:18:37.58,yin,,0,0,0,,我们永远不会用self.view 我们不能\\N{\\fs12}We would never use self.view; we couldn't.\r\nDialogue: 0,0:18:37.58,0:18:39.97,yin,,0,0,0,,实际上 调用dequeueReusableCellWithIdentifier\\N{\\fs12}In fact, we tried to call deque Reasonable Cell with identifier\r\nDialogue: 0,0:18:39.97,0:18:42.55,yin,,0,0,0,,在self.view下编译器会报错\\N{\\fs12}with self.view, the compiler would complain.\r\nDialogue: 0,0:18:42.55,0:18:44.09,yin,,0,0,0,,因为self.view是UIView\\N{\\fs12}Because self.view is a UI view.\r\nDialogue: 0,0:18:44.09,0:18:45.71,yin,,0,0,0,,它不实现这个方法\\N{\\fs12}It doesn't implement that method.\r\nDialogue: 0,0:18:45.71,0:18:47.54,yin,,0,0,0,,self.tableView则是UITableView\\N{\\fs12}Self.tableview is a UI TableView.\r\nDialogue: 0,0:18:47.54,0:18:49.02,yin,,0,0,0,,它才实现\\N{\\fs12}It does.\r\nDialogue: 0,0:18:49.02,0:18:50.58,yin,,0,0,0,,问得很好\\N{\\fs12}Good question though.\r\nDialogue: 0,0:18:50.58,0:18:52.80,yin,,0,0,0,,好 就这样 我得到了一个单元格\\N{\\fs12}Alright. So anyway, this is how I get a cell.\r\nDialogue: 0,0:18:52.80,0:18:56.15,yin,,0,0,0,,我得到了一个UITableViewCell  这是UIView的子类\\N{\\fs12}So I'm getting UI TableView Cell -- remember that's a subclass of UI View.\r\nDialogue: 0,0:18:56.15,0:18:59.23,yin,,0,0,0,,下面我需要加载其中内容\\N{\\fs12}And now I need to load it up basically.\r\nDialogue: 0,0:18:59.23,0:19:02.35,yin,,0,0,0,,需要加载内容时 我可以查阅\\N{\\fs12}And the way I load it up is I just go look\r\nDialogue: 0,0:19:02.35,0:19:05.61,yin,,0,0,0,,UITableViewCell的说明文档 看我能用它做什么\\N{\\fs12}at the documentation for UI TableView Cell and I see what I can do in there.\r\nDialogue: 0,0:19:05.61,0:19:07.97,yin,,0,0,0,,其中一点是 它有一个属性叫\\N{\\fs12}And one thing, for example, is it has a property called,\r\nDialogue: 0,0:19:07.97,0:19:10.03,yin,,0,0,0,,textLabel 这是一个UILabel\\N{\\fs12}\"Text Label\", which is a UI label.\r\nDialogue: 0,0:19:10.03,0:19:13.84,yin,,0,0,0,,在带副标题的单元格中绘制\"Title\"这个词的正是它\\N{\\fs12}That happens to be the thing that draws the word \"Title\" in those subtitled cells.\r\nDialogue: 0,0:19:13.84,0:19:16.72,yin,,0,0,0,,记得那些单元格吗 其中写有Title和Subtitle\\N{\\fs12}Remember we saw the cells there that said title and subtitles?\r\nDialogue: 0,0:19:16.72,0:19:20.52,yin,,0,0,0,,这是绘制\"Title\"的 这里我有cell.textLabel\\N{\\fs12}That's the thing that draws the title, so I just get that cell.textlabel.\r\nDialogue: 0,0:19:20.52,0:19:24.28,yin,,0,0,0,,我将它的文本设置为来自数据库的某些文本\\N{\\fs12}I set its text to be some text that's coming out of my database\r\nDialogue: 0,0:19:24.28,0:19:26.43,yin,,0,0,0,,在这个行和section处\\N{\\fs12}at that row and section.\r\nDialogue: 0,0:19:26.43,0:19:28.61,yin,,0,0,0,,我可以调用任何我要的东西\\N{\\fs12}And I can call it anything I want here.\r\nDialogue: 0,0:19:28.61,0:19:31.81,yin,,0,0,0,,还有cell.detailTextLabel.text\\N{\\fs12}There's also cell.detailtextlabel.text.\r\nDialogue: 0,0:19:31.81,0:19:34.02,yin,,0,0,0,,这将设置副标题\\N{\\fs12}That allows me to set that little subtitle.\r\nDialogue: 0,0:19:34.02,0:19:36.90,yin,,0,0,0,,我还可以设置图像 我可以做各种事情\\N{\\fs12}I can set the image. There's all kinds of things I could do.\r\nDialogue: 0,0:19:36.90,0:19:39.51,yin,,0,0,0,,我还可以创建UITableViewCell的子类\\N{\\fs12}I could even subclass UI TableView Cell,\r\nDialogue: 0,0:19:39.51,0:19:42.22,yin,,0,0,0,,将我自己的视图放到那里 创建到它们的输出口\\N{\\fs12}and put my own views in there and create outlets to them\r\nDialogue: 0,0:19:42.22,0:19:45.83,yin,,0,0,0,,疯狂使用TableViewCell每一行中的内容\\N{\\fs12}and go crazy with what's in each row of the TableView cell.\r\nDialogue: 0,0:19:45.83,0:19:47.96,yin,,0,0,0,,这是可以无限扩展的\\N{\\fs12}So it's infinitely expandable.\r\nDialogue: 0,0:19:47.96,0:19:51.73,yin,,0,0,0,,一般 我们只是这样设置UITableViewCell\\N{\\fs12}Well basically we just set this UI TableView Cell to look like we want,\r\nDialogue: 0,0:19:51.75,0:19:56.11,yin,,0,0,0,,基于来自数据库的信息 匹配行和section\\N{\\fs12}based on what information's coming out of the database that matches that row and section.\r\nDialogue: 0,0:19:56.11,0:19:58.64,yin,,0,0,0,,就这些了 然后我们返回单元格\\N{\\fs12}And that's it. And then we return the cell.\r\nDialogue: 0,0:19:58.64,0:20:01.65,yin,,0,0,0,,TableView会用它来绘制这一行\\N{\\fs12}And the TableView uses it to draw that row.\r\nDialogue: 0,0:20:02.39,0:20:05.56,yin,,0,0,0,,好 这方面有问题吗\\N{\\fs12}Okay. Any questions about that?\r\nDialogue: 0,0:20:05.56,0:20:07.28,yin,,0,0,0,,好 这是这个\\N{\\fs12}Okay so that's it.\r\nDialogue: 0,0:20:07.28,0:20:10.75,yin,,0,0,0,,另外两点是有多少section 有多少行\\N{\\fs12}So now the only other two ones are how many sections and how many rows.\r\nDialogue: 0,0:20:10.75,0:20:12.37,yin,,0,0,0,,也就是这两个方法\\N{\\fs12}And that's just these two methods.\r\nDialogue: 0,0:20:12.37,0:20:14.55,yin,,0,0,0,,TableView中section的数目\\N{\\fs12}Number of sections in TableView.\r\nDialogue: 0,0:20:14.55,0:20:16.81,yin,,0,0,0,,如果你不实现numberOfSectionsInTableView\\N{\\fs12}If you don't implement number of sections in TableView,\r\nDialogue: 0,0:20:16.81,0:20:19.21,yin,,0,0,0,,它会是默认值1\\N{\\fs12}it actually has a default, which is one.\r\nDialogue: 0,0:20:19.21,0:20:23.57,yin,,0,0,0,,不实现numberOfSectionsInTableView时 它就是一大段\\N{\\fs12}So if you don't implement number of sections in TableView, it's all one big section.\r\nDialogue: 0,0:20:23.57,0:20:26.37,yin,,0,0,0,,这是默认设置\\N{\\fs12}That's kind of the default.\r\nDialogue: 0,0:20:26.37,0:20:28.93,yin,,0,0,0,,另一点 是每个section中有多少行\\N{\\fs12}The other one, how many rows are in each section?\r\nDialogue: 0,0:20:28.93,0:20:31.02,yin,,0,0,0,,每个section它都会重复问你\\N{\\fs12}It's going to ask you that repeatedly for every section.\r\nDialogue: 0,0:20:31.02,0:20:33.78,yin,,0,0,0,,这里没有默认值 你必须明确\\N{\\fs12}There's no default there, so this one's required. You must say\r\nDialogue: 0,0:20:33.78,0:20:35.67,yin,,0,0,0,,每个section中有多少行\\N{\\fs12}how many rows are in each section.\r\nDialogue: 0,0:20:35.67,0:20:38.05,yin,,0,0,0,,如果只有一个section 你回答这个就行了\\N{\\fs12}If you only had one section, you could obviously just answer that.\r\nDialogue: 0,0:20:38.05,0:20:39.70,yin,,0,0,0,,这就是演示中我们要做的\\N{\\fs12}That's what we're going to do in our demo.\r\nDialogue: 0,0:20:39.70,0:20:41.41,yin,,0,0,0,,不过section也可以不止一个\\N{\\fs12}But you could have multiple sections like you will\r\nDialogue: 0,0:20:41.41,0:20:43.08,yin,,0,0,0,,作业中就是这样 有不同国家\\N{\\fs12}with your homework when you have the countries.\r\nDialogue: 0,0:20:43.08,0:20:46.19,yin,,0,0,0,,有些国家有两个城市 有些则有十二个\\N{\\fs12}Some countries will have two cities in them; some countries will have 12.\r\nDialogue: 0,0:20:46.19,0:20:50.23,yin,,0,0,0,,你需要对每个section正确回答这个问题\\N{\\fs12}And you'll have to answer this question correctly for every section.\r\nDialogue: 0,0:20:51.74,0:20:53.43,yin,,0,0,0,,静态表格呢\\N{\\fs12}What about a static table?\r\nDialogue: 0,0:20:53.43,0:20:55.48,yin,,0,0,0,,静态表格中这些不需要做\\N{\\fs12}You don't have to do any of this for a static table.\r\nDialogue: 0,0:20:55.48,0:20:56.90,yin,,0,0,0,,不需要管cellForRowAtIndexPath\\N{\\fs12}You don't have to do self for row at index path.\r\nDialogue: 0,0:20:56.90,0:20:58.24,yin,,0,0,0,,不需要管numberOfSectionsInTableView\\N{\\fs12}You don't have to do number of sections of table.\r\nDialogue: 0,0:20:58.24,0:20:59.58,yin,,0,0,0,,不需要管numberOfRowsInSection\\N{\\fs12}You don't have to do number of rows and sections.\r\nDialogue: 0,0:20:59.58,0:21:03.57,yin,,0,0,0,,UITableViewController把这一切都跟你打理好了\\N{\\fs12}It's all just taken care for you by UI TableView Controller.\r\nDialogue: 0,0:21:03.57,0:21:06.33,yin,,0,0,0,,静态 只需要在故事板中编辑即可\\N{\\fs12}So static, just edit in storyboard how you want it;\r\nDialogue: 0,0:21:06.33,0:21:09.03,yin,,0,0,0,,这些东西都不需要担心\\N{\\fs12}and don't worry about any of this stuff for that.\r\nDialogue: 0,0:21:10.87,0:21:12.73,yin,,0,0,0,,此外还有一些方法\\N{\\fs12}There's a bunch of other methods\r\nDialogue: 0,0:21:12.73,0:21:15.99,yin,,0,0,0,,在数据源协议中 不过我们不打算讲\\N{\\fs12}in this datasource protocol that we're not going to talk about.\r\nDialogue: 0,0:21:15.99,0:21:19.30,yin,,0,0,0,,主要是获取header和footer的标题\\N{\\fs12}They're mostly about getting the titles of the headers and the footers.\r\nDialogue: 0,0:21:19.30,0:21:22.89,yin,,0,0,0,,你需要用到返回header字符串名的那个\\N{\\fs12}You will need the one that returns the name of the string for a header,\r\nDialogue: 0,0:21:22.89,0:21:24.53,yin,,0,0,0,,因为你会有一个header\\N{\\fs12}because you're going to have a header --\r\nDialogue: 0,0:21:24.53,0:21:25.60,yin,,0,0,0,,一个section header\\N{\\fs12}a section header --\r\nDialogue: 0,0:21:25.60,0:21:28.69,yin,,0,0,0,,作业中 这将是国家名\\N{\\fs12}and it's going to be the name of the country in your homework.\r\nDialogue: 0,0:21:28.69,0:21:31.24,yin,,0,0,0,,另外 这些表格还可以编辑\\N{\\fs12}There's also -- these tables can be edited.\r\nDialogue: 0,0:21:31.24,0:21:32.63,yin,,0,0,0,,行可以删除\\N{\\fs12}Rows can be removed.\r\nDialogue: 0,0:21:32.63,0:21:34.13,yin,,0,0,0,,可以四处移动\\N{\\fs12}They can be moved around.\r\nDialogue: 0,0:21:34.13,0:21:36.78,yin,,0,0,0,,可以调整顺序\\N{\\fs12}Change the order.\r\nDialogue: 0,0:21:36.78,0:21:38.23,yin,,0,0,0,,等等\\N{\\fs12}All that stuff.\r\nDialogue: 0,0:21:38.23,0:21:40.56,yin,,0,0,0,,这需要同模型保持同步\\N{\\fs12}It has to be kept in sync with the model,\r\nDialogue: 0,0:21:40.56,0:21:43.47,yin,,0,0,0,,数据源协议中有一些方法\\N{\\fs12}and so there are methods in the datasource protocol\r\nDialogue: 0,0:21:43.47,0:21:47.05,yin,,0,0,0,,让你知道行移动和删除中事情发生在什么时候\\N{\\fs12}that lets you know when things are happening in the rows moving and deleting,\r\nDialogue: 0,0:21:47.05,0:21:48.90,yin,,0,0,0,,这样就能同模型保持更新\\N{\\fs12}so you can keep it up to date with your model.\r\nDialogue: 0,0:21:48.90,0:21:49.95,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:21:49.95,0:21:51.40,yin,,0,0,0,,学生：行的数目\\N{\\fs12}> Is the number of rows\r\nDialogue: 0,0:21:51.40,0:21:54.51,yin,,0,0,0,,对于每个section都是一样的吗\\N{\\fs12}in the section something that's the same for every section?\r\nDialogue: 0,0:21:54.51,0:21:55.31,yin,,0,0,0,,还是说你需要声明…\\N{\\fs12}Or do you declare --\r\nDialogue: 0,0:21:55.31,0:22:00.01,yin,,0,0,0,,教授：好 问题是 每个section中的行数是否都一样\\N{\\fs12}> Okay, so the question is, is number of rows in section the same for every section?\r\nDialogue: 0,0:22:00.01,0:22:01.67,yin,,0,0,0,,答案是 当然不是\\N{\\fs12}And the answer is absolutely not.\r\nDialogue: 0,0:22:01.67,0:22:05.29,yin,,0,0,0,,因为有些国家只有两个城市 这时只返回2\\N{\\fs12}Because some countries only have two cities, so you'd return two\r\nDialogue: 0,0:22:05.29,0:22:07.00,yin,,0,0,0,,这是询问这个section时的情况\\N{\\fs12}when it asks you about that section.\r\nDialogue: 0,0:22:07.00,0:22:08.02,yin,,0,0,0,,有些国家则有十个城市\\N{\\fs12}Some countries would have ten.\r\nDialogue: 0,0:22:08.02,0:22:09.30,yin,,0,0,0,,这时就会返回10\\N{\\fs12}So you'd return ten.\r\nDialogue: 0,0:22:09.30,0:22:11.42,yin,,0,0,0,,这个问题会一直重复问你\\N{\\fs12}So you're going to be asked that question repeatedly,\r\nDialogue: 0,0:22:11.42,0:22:16.13,yin,,0,0,0,,每个section都要问一次 每个中的行数显然可以不同\\N{\\fs12}once for every section and the answer could be definitely different for each one.\r\nDialogue: 0,0:22:16.13,0:22:18.07,yin,,0,0,0,,好 以上是数据源\\N{\\fs12}Okay. So that's it for the datasource.\r\nDialogue: 0,0:22:19.05,0:22:22.60,yin,,0,0,0,,另一个是UITableViewDelegate\\N{\\fs12}The other one is called the UI TableView Delegate.\r\nDialogue: 0,0:22:22.60,0:22:25.27,yin,,0,0,0,,重复一次 这个更多的是关于\\N{\\fs12}And this one, again, is more how we're going\r\nDialogue: 0,0:22:25.27,0:22:29.14,yin,,0,0,0,,如何显示表格 而不是关于数据内容\\N{\\fs12}to display this table; not what the data is we're displaying.\r\nDialogue: 0,0:22:29.14,0:22:32.83,yin,,0,0,0,,数据源和委托通常可以是相同的对象\\N{\\fs12}And it's common though for the datasource and the delegate to be the same object,\r\nDialogue: 0,0:22:32.84,0:22:34.79,yin,,0,0,0,,也就是你的控制器\\N{\\fs12}namely your controller.\r\nDialogue: 0,0:22:34.79,0:22:37.28,yin,,0,0,0,,因为TableView只是一个视图\\N{\\fs12}Because the TableView is part of the view -- it's just a view.\r\nDialogue: 0,0:22:37.28,0:22:39.11,yin,,0,0,0,,TableView是UIView 它是视图的一部分\\N{\\fs12}TableView is a UI view, it's part of your view.\r\nDialogue: 0,0:22:39.11,0:22:42.47,yin,,0,0,0,,因此 数据源和委托会使用你的控制器\\N{\\fs12}So datasource delegate uses your controller.\r\nDialogue: 0,0:22:42.47,0:22:45.57,yin,,0,0,0,,委托还能让你观察到表格中发生着什么\\N{\\fs12}The delegate lets you observe what's going on in the table too.\r\nDialogue: 0,0:22:45.57,0:22:48.43,yin,,0,0,0,,将要做这个 确实做了那个\\N{\\fs12}Always will do this; did do that.\r\nDialogue: 0,0:22:48.43,0:22:53.38,yin,,0,0,0,,一个很有趣的是 用户确实选择了一行\\N{\\fs12}And one especially interesting one is user did select a row.\r\nDialogue: 0,0:22:53.38,0:22:57.86,yin,,0,0,0,,委托协议可以告诉你 用户什么时候轻击了某一行\\N{\\fs12}So the delegate protocol can tell you when the user tapped on a row.\r\nDialogue: 0,0:22:57.86,0:23:01.85,yin,,0,0,0,,大多数时候 用户轻击时 我们会segue跳转\\N{\\fs12}Now we're going to -- mostly when the user taps in a row we're going to segue --\r\nDialogue: 0,0:23:01.85,0:23:03.64,yin,,0,0,0,,等下我会讲到\\N{\\fs12}which I'm going to talk about in a moment --\r\nDialogue: 0,0:23:03.64,0:23:06.32,yin,,0,0,0,,不过也有可能实现这个方法\\N{\\fs12}but it's also possible to implement this method\r\nDialogue: 0,0:23:06.32,0:23:08.16,yin,,0,0,0,,在UITableViewDelegate中\\N{\\fs12}in the UI TableView delegate\r\nDialogue: 0,0:23:08.16,0:23:12.67,yin,,0,0,0,,叫作tableView: didSelectRowAtIndexPath\\N{\\fs12}protocol called TableView:did selectrowatindexpath.\r\nDialogue: 0,0:23:12.67,0:23:15.26,yin,,0,0,0,,或许正是你所想的 它告诉你索引路径\\N{\\fs12}Exactly what you think. It tells you the index path.\r\nDialogue: 0,0:23:15.26,0:23:19.20,yin,,0,0,0,,也就是发生触碰的section和行 你可以做点什么\\N{\\fs12}In other words the section and row where something was touched, and you can do something.\r\nDialogue: 0,0:23:19.20,0:23:20.99,yin,,0,0,0,,这里你会做什么呢\\N{\\fs12}Now what would you ever do in here?\r\nDialogue: 0,0:23:20.99,0:23:23.42,yin,,0,0,0,,如果是segue跳转 这里你将什么也不做\\N{\\fs12}Well if you're segueing, you wouldn't do anything in here.\r\nDialogue: 0,0:23:23.42,0:23:27.46,yin,,0,0,0,,但如果是在iPad上 触击一个表格时\\N{\\fs12}But if you're on the iPad, when you touch on a table,\r\nDialogue: 0,0:23:27.46,0:23:29.69,yin,,0,0,0,,或许你更新的东西已经在屏幕上了\\N{\\fs12}maybe the thing you're updating is already on screen.\r\nDialogue: 0,0:23:29.69,0:23:31.78,yin,,0,0,0,,你不需要segue跳转 它已经在那里了\\N{\\fs12}You're not going to segue to it, it's already on there.\r\nDialogue: 0,0:23:31.78,0:23:34.49,yin,,0,0,0,,因为iPad很大 它有足够空间这么做\\N{\\fs12}Because the iPad's so big, it's got room to do that.\r\nDialogue: 0,0:23:34.49,0:23:35.91,yin,,0,0,0,,今天的演示中我们会看到\\N{\\fs12}And we'll see that in the demo today.\r\nDialogue: 0,0:23:35.91,0:23:40.02,yin,,0,0,0,,我们有一张图 点击表格行 它会展示一张图\\N{\\fs12}We're going to have an image where we click on a table row and it shows an image.\r\nDialogue: 0,0:23:40.02,0:23:42.37,yin,,0,0,0,,而这张图已经在屏幕上了\\N{\\fs12}And that image viewing thing is already going to be on screen.\r\nDialogue: 0,0:23:42.37,0:23:44.31,yin,,0,0,0,,我们不需要segue跳转 它已经在那\\N{\\fs12}So we don't want to segue to it, it's already there.\r\nDialogue: 0,0:23:44.31,0:23:46.24,yin,,0,0,0,,我们只需要更新\\N{\\fs12}So we just need to update it and now we're going to do\r\nDialogue: 0,0:23:46.24,0:23:49.57,yin,,0,0,0,,我们会在这个方法中做到 你们会看到是怎么做的\\N{\\fs12}that in this method so you can see how that works.\r\nDialogue: 0,0:23:49.57,0:23:53.70,yin,,0,0,0,,记得之前我展示的那个圆圈i吗\\N{\\fs12}Remember that little circled I that I showed you earlier?\r\nDialogue: 0,0:23:53.70,0:23:55.79,yin,,0,0,0,,也就是特殊细节披露\\N{\\fs12}That special detail disclosure thing?\r\nDialogue: 0,0:23:55.79,0:23:59.76,yin,,0,0,0,,点击它时 通常点击行时发生的事件不会发生\\N{\\fs12}When you tap on it, it won't do what the row normally does.\r\nDialogue: 0,0:23:59.76,0:24:02.28,yin,,0,0,0,,如果点行的其它地方 通常事件会发生\\N{\\fs12}If you tap somewhere else in the row, the row will do its normal thing.\r\nDialogue: 0,0:24:02.28,0:24:04.34,yin,,0,0,0,,但如果点的是这个i\\N{\\fs12}But if you tap on the little I, instead,\r\nDialogue: 0,0:24:04.34,0:24:07.55,yin,,0,0,0,,它就会调用UITableViewDelegate协议的这个方法\\N{\\fs12}it will call this method in the UI TableView Delegate Protocol,\r\nDialogue: 0,0:24:07.55,0:24:07.98,yin,,0,0,0,,叫tableView\\N{\\fs12}called TableView\r\nDialogue: 0,0:24:07.98,0:24:10.98,yin,,0,0,0,,accessoryButtonTappedForRowWithIndexPath\\N{\\fs12}Accessory Button Tap For Row with Index Path.\r\nDialogue: 0,0:24:10.98,0:24:14.16,yin,,0,0,0,,它是干什么的很明显\\N{\\fs12}And it does exactly what you might think it tells you,\r\nDialogue: 0,0:24:14.16,0:24:16.29,yin,,0,0,0,,在小圆圈被点击时的索引路径\\N{\\fs12}the index path of the little circle that was pressed.\r\nDialogue: 0,0:24:16.29,0:24:20.34,yin,,0,0,0,,这就是提供一些辅助信息的通常位置\\N{\\fs12}So this is usually where you would provide some ancillary information.\r\nDialogue: 0,0:24:20.34,0:24:22.69,yin,,0,0,0,,这时不会发生点击行时发生的事件\\N{\\fs12}You wouldn't do the main thing that the row does.\r\nDialogue: 0,0:24:22.69,0:24:26.34,yin,,0,0,0,,这时会发生一些同这一行相关的事情 但有所不同\\N{\\fs12}You would go do something related to what's in that row, but different.\r\nDialogue: 0,0:24:26.34,0:24:26.83,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:24:26.83,0:24:30.48,yin,,0,0,0,,学生：你选出行[声音不清]\\N{\\fs12}> So you pick out the row [inaudible]?\r\nDialogue: 0,0:24:30.49,0:24:33.49,yin,,0,0,0,,教授：是 问题是 我是不是能点击行或是那个小i\\N{\\fs12}> Yes. So the question is, can I click on the row or on that little I?\r\nDialogue: 0,0:24:33.49,0:24:34.26,yin,,0,0,0,,答案是肯定的\\N{\\fs12}And the answer is yes.\r\nDialogue: 0,0:24:34.26,0:24:35.92,yin,,0,0,0,,不同的事件会发生\\N{\\fs12}And different things will happen.\r\nDialogue: 0,0:24:37.18,0:24:40.01,yin,,0,0,0,,点击行会segue跳转 或是调用\\N{\\fs12}So clicking on the row would segue, or we'd call\r\nDialogue: 0,0:24:40.01,0:24:42.60,yin,,0,0,0,,前一张幻灯片上的didSelectRowAtIndexPath\\N{\\fs12}that previous slide, did select row at index path,\r\nDialogue: 0,0:24:42.60,0:24:45.63,yin,,0,0,0,,点击i则会调用这个方法\\N{\\fs12}clicking on the I we'd call this method.\r\nDialogue: 0,0:24:45.63,0:24:48.33,yin,,0,0,0,,委托的方法还有很多很多\\N{\\fs12}There's lots and lots and lots of other delegate methods,\r\nDialogue: 0,0:24:48.33,0:24:51.56,yin,,0,0,0,,或许12个 甚至15个\\N{\\fs12}probably over a dozen; maybe 15 of them.\r\nDialogue: 0,0:24:51.56,0:24:55.82,yin,,0,0,0,,它们也是用来处理各行 编辑各行\\N{\\fs12}They also have to do with handling the rows -- editing of the rows\r\nDialogue: 0,0:24:55.82,0:24:59.64,yin,,0,0,0,,考虑到图形和动画这些方面\\N{\\fs12}with a graphical -- how it happens graphically and animation of it.\r\nDialogue: 0,0:24:59.64,0:25:03.68,yin,,0,0,0,,不是关于数据 而是关于屏幕上的显示方式\\N{\\fs12}Not as -- not the data that's involved, but just how it's going on on screen.\r\nDialogue: 0,0:25:03.68,0:25:05.40,yin,,0,0,0,,还有行的复制粘贴\\N{\\fs12}And copying and pasting rows.\r\nDialogue: 0,0:25:05.40,0:25:07.92,yin,,0,0,0,,还有事物移动时的通知\\N{\\fs12}And notifications for when things move.\r\nDialogue: 0,0:25:07.92,0:25:08.61,yin,,0,0,0,,各种东西\\N{\\fs12}All kinds of stuff.\r\nDialogue: 0,0:25:08.61,0:25:10.24,yin,,0,0,0,,你们可以自己去查阅\\N{\\fs12}So I'll leave that to you to go look up.\r\nDialogue: 0,0:25:10.24,0:25:12.69,yin,,0,0,0,,作业中 这些可能用不到\\N{\\fs12}You won't probably need much -- any of that for your homework,\r\nDialogue: 0,0:25:12.69,0:25:15.45,yin,,0,0,0,,不过熟悉协议中的这些中西总是有好处的\\N{\\fs12}but it's good to, you know, familiarize yourself with that protocol.\r\nDialogue: 0,0:25:16.48,0:25:18.55,yin,,0,0,0,,再来讲单元格的segue跳转\\N{\\fs12}So let's talk about segueing from cells.\r\nDialogue: 0,0:25:18.55,0:25:20.02,yin,,0,0,0,,如何设置一个segue\\N{\\fs12}So how do we set up a segue?\r\nDialogue: 0,0:25:20.02,0:25:21.98,yin,,0,0,0,,我们显然可以按Control键拖动\\N{\\fs12}Well, we just control drag of course.\r\nDialogue: 0,0:25:21.98,0:25:24.99,yin,,0,0,0,,这是一个单元格 我可以从这个单元格Control拖动\\N{\\fs12}So here's a cell, and I just control drag from that cell\r\nDialogue: 0,0:25:24.99,0:25:26.57,yin,,0,0,0,,到另外一个视图控制器\\N{\\fs12}to some other view controller.\r\nDialogue: 0,0:25:26.57,0:25:28.85,yin,,0,0,0,,将这设为push segue\\N{\\fs12}And let's say I make it a push segue.\r\nDialogue: 0,0:25:28.85,0:25:32.16,yin,,0,0,0,,我要把这个放到导航控制器中 它是push segue\\N{\\fs12}I'm going to put this stuff in a navigation controller, and it's going to be a push segue.\r\nDialogue: 0,0:25:32.16,0:25:34.20,yin,,0,0,0,,这就创建了一个segue\\N{\\fs12}And it creates a segue.\r\nDialogue: 0,0:25:34.20,0:25:38.46,yin,,0,0,0,,这里有趣的是 这是一个原型单元格\\N{\\fs12}Now what's interesting about this, is that that's a prototype cell.\r\nDialogue: 0,0:25:38.46,0:25:40.48,yin,,0,0,0,,它会被复制很多很多次\\N{\\fs12}It's going to be copied many, many times.\r\nDialogue: 0,0:25:40.48,0:25:42.13,yin,,0,0,0,,那么prepareForSegue时\\N{\\fs12}So in prepare for segue,\r\nDialogue: 0,0:25:42.13,0:25:45.58,yin,,0,0,0,,我们怎么知道自己是从哪个单元格跳转来的呢\\N{\\fs12}how are we going to know which cell we're segueing from?\r\nDialogue: 0,0:25:45.58,0:25:48.06,yin,,0,0,0,,如果我们要准备的是右边那个视图控制器\\N{\\fs12}Because if we're going to prepare that view controller\r\nDialogue: 0,0:25:48.06,0:25:50.31,yin,,0,0,0,,也就是那个大的 空的 白的控制器\\N{\\fs12}on the right -- that big, blank, white view controller --\r\nDialogue: 0,0:25:50.31,0:25:54.23,yin,,0,0,0,,我们就需要知道给它准备什么数据\\N{\\fs12}we've got to know what data to prepare it with, right?\r\nDialogue: 0,0:25:54.23,0:25:57.39,yin,,0,0,0,,这取决于用户点击的是哪一行\\N{\\fs12}Because it depends on which row they clicked on as to how we're going to prepare it.\r\nDialogue: 0,0:25:57.39,0:26:03.00,yin,,0,0,0,,我们在TableView的情况下看看prepareForSegue吧\\N{\\fs12}So let's look at prepare for segue, in the case of a TableView.\r\nDialogue: 0,0:26:03.00,0:26:04.60,yin,,0,0,0,,这是一样的\\N{\\fs12}So it's the same thing.\r\nDialogue: 0,0:26:04.60,0:26:06.32,yin,,0,0,0,,prepareForSegue: sender\\N{\\fs12}Preparefor segue:sender.\r\nDialogue: 0,0:26:06.32,0:26:07.75,yin,,0,0,0,,不过sender参数\\N{\\fs12}But now that sender argument --\r\nDialogue: 0,0:26:07.75,0:26:10.51,yin,,0,0,0,,之前我们一直忽略它 现在它就发挥作用了\\N{\\fs12}which we've been ignoring so far -- matters.\r\nDialogue: 0,0:26:10.51,0:26:14.55,yin,,0,0,0,,sender的参数就是被点击的UITableViewCell\\N{\\fs12}That sender argument is the UI TableView Cell that was clicked on.\r\nDialogue: 0,0:26:14.55,0:26:19.12,yin,,0,0,0,,有时 知道它的索引路径会很好\\N{\\fs12}And sometimes it's really nice to know the index path of that thing.\r\nDialogue: 0,0:26:19.12,0:26:21.28,yin,,0,0,0,,你知道行和section 毕竟你是\\N{\\fs12}You know? The row and section, because usually you're looking\r\nDialogue: 0,0:26:21.28,0:26:23.57,yin,,0,0,0,,根据行和section在模型中查找\\N{\\fs12}up in your model by row and section.\r\nDialogue: 0,0:26:23.57,0:26:25.45,yin,,0,0,0,,这里有一个很重要的方法叫\\N{\\fs12}And so there's this really important method called\r\nDialogue: 0,0:26:25.45,0:26:28.13,yin,,0,0,0,,indexPathForCell 在UITableView中\\N{\\fs12}indexpathpercell in UI TableView,\r\nDialogue: 0,0:26:28.13,0:26:31.39,yin,,0,0,0,,它会告诉你给定单元格的索引路径\\N{\\fs12}and it will tell you the index path for a given cell.\r\nDialogue: 0,0:26:31.39,0:26:34.94,yin,,0,0,0,,因此 在TableView的prepareForSegue: sender中\\N{\\fs12}So we almost always, in the prepare for segue sender of TableViews\r\nDialogue: 0,0:26:34.94,0:26:36.85,yin,,0,0,0,,第一行几乎总是\\N{\\fs12}do -- this first line is almost always\r\nDialogue: 0,0:26:36.86,0:26:39.15,yin,,0,0,0,,indexPath = self.tableView indexPathForCell\\N{\\fs12}indexpath=self.Tableview indexpathforcell.\r\nDialogue: 0,0:26:39.15,0:26:42.06,yin,,0,0,0,,现在我们有了索引路径 我们可以在模型中查找\\N{\\fs12}Now that we have index path, we can look it up in our model.\r\nDialogue: 0,0:26:42.06,0:26:46.06,yin,,0,0,0,,我们可以准备好segue跳转到的东西 这就好了\\N{\\fs12}We can prepare the thing we're segueing to and off we go.\r\nDialogue: 0,0:26:46.06,0:26:48.26,yin,,0,0,0,,这方面有问题吗\\N{\\fs12}Any questions about this?\r\nDialogue: 0,0:26:49.43,0:26:51.42,yin,,0,0,0,,否则就是常规的segue\\N{\\fs12}Otherwise a normal segue.\r\nDialogue: 0,0:26:52.74,0:26:55.63,yin,,0,0,0,,好 转轮\\N{\\fs12}Okay. Spinner.\r\nDialogue: 0,0:26:55.63,0:26:57.72,yin,,0,0,0,,记得在Imaginarium中\\N{\\fs12}So remember in Imaginarium\r\nDialogue: 0,0:26:57.72,0:27:02.05,yin,,0,0,0,,我们在等待URL加载时让转轮在那旋转\\N{\\fs12}we spin when we're waiting for the URL to load or whatever.\r\nDialogue: 0,0:27:02.05,0:27:07.10,yin,,0,0,0,,TableView的内容通常也需要从网络进行加载\\N{\\fs12}TableView often the contents of the TableView are being loaded from the network.\r\nDialogue: 0,0:27:07.10,0:27:09.20,yin,,0,0,0,,这里也需要转动转轮\\N{\\fs12}And we want to spin there too.\r\nDialogue: 0,0:27:09.20,0:27:11.67,yin,,0,0,0,,这样来让用户知道\\N{\\fs12}We want to spin to let the user know\r\nDialogue: 0,0:27:11.67,0:27:14.66,yin,,0,0,0,,在其它线程中 在其它队列中\\N{\\fs12}that in some other thread; on some other queue,\r\nDialogue: 0,0:27:14.66,0:27:17.31,yin,,0,0,0,,我们正下载表格中的数据\\N{\\fs12}we're downloading data to fill up this table.\r\nDialogue: 0,0:27:17.31,0:27:19.88,yin,,0,0,0,,这在TableView中很容易做到\\N{\\fs12}And it's really easy to do in TableView.\r\nDialogue: 0,0:27:19.88,0:27:21.61,yin,,0,0,0,,TableViewController\\N{\\fs12}TableView Controller.\r\nDialogue: 0,0:27:21.61,0:27:23.90,yin,,0,0,0,,在TableViewController中很容易做到\\N{\\fs12}It's easy to do in TableView Controller.\r\nDialogue: 0,0:27:23.90,0:27:26.29,yin,,0,0,0,,这不是TableView的部分 而是TableViewController的部分\\N{\\fs12}It's not part of TableView. It's part of TableView Controller.\r\nDialogue: 0,0:27:26.29,0:27:28.22,yin,,0,0,0,,TableViewController有一个属性叫\\N{\\fs12}TableView Controller has this property called\r\nDialogue: 0,0:27:28.22,0:27:30.80,yin,,0,0,0,,RefreshControl(刷新控制) 这是一个小转轮\\N{\\fs12}\"Refresh Control\", and it's a little spinner.\r\nDialogue: 0,0:27:30.80,0:27:34.55,yin,,0,0,0,,只需要发送beginRefreshing(开始刷新) 旋转就会开始\\N{\\fs12}And you just send, \"Begin refreshing\" to it and it will start spinning.\r\nDialogue: 0,0:27:34.55,0:27:37.31,yin,,0,0,0,,发送endRefreshing(终止刷新) 旋转就会停止\\N{\\fs12}You say, \"End refreshing\" to it and it will stop spinning.\r\nDialogue: 0,0:27:37.31,0:27:41.29,yin,,0,0,0,,实际上 最酷的是 你还可以\\N{\\fs12}And in fact, what's really cool is if you want, you can make it\r\nDialogue: 0,0:27:41.29,0:27:45.56,yin,,0,0,0,,在用户拉下TableView时 让转轮露出来\\N{\\fs12}so the user can pull down on the TableView to reveal that spinner.\r\nDialogue: 0,0:27:45.56,0:27:47.84,yin,,0,0,0,,这将调用目标动作\\N{\\fs12}And that will call a target action thing\r\nDialogue: 0,0:27:47.84,0:27:50.58,yin,,0,0,0,,这就能刷新表格 重新载入\\N{\\fs12}and you can refresh your table; reload it.\r\nDialogue: 0,0:27:50.58,0:27:53.69,yin,,0,0,0,,换言之 你可以让用户控制刷新\\N{\\fs12}So in other words you can let the user control the refreshing.\r\nDialogue: 0,0:27:53.69,0:27:55.29,yin,,0,0,0,,它是这样的\\N{\\fs12}And so it would look like this:\r\nDialogue: 0,0:27:55.29,0:27:58.70,yin,,0,0,0,,这是我的TableViewController\\N{\\fs12}So here's my TableView Controller there.\r\nDialogue: 0,0:27:58.70,0:28:00.47,yin,,0,0,0,,我还没有加入转轮\\N{\\fs12}I haven't added the spinner yet.\r\nDialogue: 0,0:28:00.47,0:28:04.52,yin,,0,0,0,,看右边 在TableViewController的属性检查器中\\N{\\fs12}If you look over on the right, in the attributes inspector for the TableView Controller,\r\nDialogue: 0,0:28:04.52,0:28:07.57,yin,,0,0,0,,中间这里有刷新\\N{\\fs12}down towards the middle there there's refreshing.\r\nDialogue: 0,0:28:07.57,0:28:10.89,yin,,0,0,0,,我将它从禁用调到启用\\N{\\fs12}And I'm switching it now from disabled to enabled.\r\nDialogue: 0,0:28:10.89,0:28:14.84,yin,,0,0,0,,在这里启用刷新\\N{\\fs12}It says \"Refreshing\" is what it says on -- that's kind of covered there.\r\nDialogue: 0,0:28:14.84,0:28:18.13,yin,,0,0,0,,点击启用后 看文档大纲\\N{\\fs12}And when I hit \"Enabled\", watch the document outline\r\nDialogue: 0,0:28:18.13,0:28:21.87,yin,,0,0,0,,文档大纲在左侧 这里会加一个东西\\N{\\fs12}on the left -- okay, the document outline on the left, something's going to be added.\r\nDialogue: 0,0:28:21.87,0:28:25.35,yin,,0,0,0,,这是一个RefreshControl\\N{\\fs12}Which is bloop -- a refresh control.\r\nDialogue: 0,0:28:25.35,0:28:27.36,yin,,0,0,0,,这时 它只出现在文档大纲\\N{\\fs12}Now it only shows up in the document outline\r\nDialogue: 0,0:28:27.36,0:28:30.77,yin,,0,0,0,,因为它还不存在于任何地方 除非是在动画时\\N{\\fs12}because it doesn't really exist anywhere except for when it's animating.\r\nDialogue: 0,0:28:30.77,0:28:32.88,yin,,0,0,0,,只有动画时 你才能看到它\\N{\\fs12}So that's the only place that you can see it.\r\nDialogue: 0,0:28:32.88,0:28:37.98,yin,,0,0,0,,不过你可以从这里Control拖拽到TableViewController中\\N{\\fs12}But you can control drag from it into your TableView Controller, right?\r\nDialogue: 0,0:28:37.98,0:28:42.28,yin,,0,0,0,,使用某种方法来分发一个线程\\N{\\fs12}And put some method there that goes and forks off some thread\r\nDialogue: 0,0:28:42.28,0:28:44.84,yin,,0,0,0,,让另一个队列重载这张表格\\N{\\fs12}on another queue to go reload this table.\r\nDialogue: 0,0:28:44.84,0:28:47.22,yin,,0,0,0,,最开始可以说beginRefreshing\\N{\\fs12}And you just say, \"Begin refreshing\" at the beginning,\r\nDialogue: 0,0:28:47.22,0:28:50.75,yin,,0,0,0,,完成加载后 你回到主队列\\N{\\fs12}and then once it's all finished loading, when you dispatch back\r\nDialogue: 0,0:28:50.75,0:28:54.29,yin,,0,0,0,,这时你可以说endRefreshing\\N{\\fs12}to the main queue, you're going to say, \"End refreshing.\"\r\nDialogue: 0,0:28:54.29,0:28:55.72,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:28:55.72,0:28:58.61,yin,,0,0,0,,学生：endRefreshing后 那个会消失吗\\N{\\fs12}> End refreshing, does that thing disappear?\r\nDialogue: 0,0:28:58.61,0:29:02.29,yin,,0,0,0,,教授：会 endRefreshing后 转轮会被遮起来\\N{\\fs12}> Yes. When you end refreshing, the little spinning thing, bloop, collapses back up.\r\nDialogue: 0,0:29:02.29,0:29:03.76,yin,,0,0,0,,TableView遮住它\\N{\\fs12}So the TableView hides it.\r\nDialogue: 0,0:29:03.78,0:29:06.59,yin,,0,0,0,,beginRefreshing时 它又会重新出现\\N{\\fs12}And then if you begin refreshing, bloop, it will show it again.\r\nDialogue: 0,0:29:06.59,0:29:10.97,yin,,0,0,0,,记住 用户下拉导致了这些信息的发送\\N{\\fs12}And remember, user pulling down on it causes this message to be sent.\r\nDialogue: 0,0:29:10.97,0:29:12.60,yin,,0,0,0,,这里是刷新\\N{\\fs12}Refresh in this case, right?\r\nDialogue: 0,0:29:12.60,0:29:14.23,yin,,0,0,0,,这里不过是目标动作\\N{\\fs12}But it's just target action.\r\nDialogue: 0,0:29:14.23,0:29:15.51,yin,,0,0,0,,你想做什么都行\\N{\\fs12}You can do anything you want.\r\nDialogue: 0,0:29:15.51,0:29:17.84,yin,,0,0,0,,这并不是必须的\\N{\\fs12}You don't have to do it. If you don't wire --\r\nDialogue: 0,0:29:17.84,0:29:23.69,yin,,0,0,0,,如果你不Control拖动 那么下拉就没这个作用\\N{\\fs12}control drag something, then pulling down won't do this.\r\nDialogue: 0,0:29:25.40,0:29:29.20,yin,,0,0,0,,如果TableView下 模型改变了会怎样\\N{\\fs12}What if your model changes out from under your TableView?\r\nDialogue: 0,0:29:29.20,0:29:32.72,yin,,0,0,0,,TableView一直运行得很好 然后\\N{\\fs12}So your TableView is running along fine, and then all\r\nDialogue: 0,0:29:32.72,0:29:36.28,yin,,0,0,0,,突然模型发生了重大变化 甚至完全变化\\N{\\fs12}of a sudden the model changes in some fundamental way. Like it completely changes.\r\nDialogue: 0,0:29:36.28,0:29:39.10,yin,,0,0,0,,模型下载一组全新的信息\\N{\\fs12}The model will download a completely new set of information.\r\nDialogue: 0,0:29:39.10,0:29:41.99,yin,,0,0,0,,你可以调用TableView中的reloadData(重载数据)方法\\N{\\fs12}You can call this method in TableView called, \"Reload data\".\r\nDialogue: 0,0:29:41.99,0:29:45.65,yin,,0,0,0,,调用TableView时 它会调用多个section\\N{\\fs12}And when you call reload data it's going to call number of sections.\r\nDialogue: 0,0:29:45.65,0:29:47.99,yin,,0,0,0,,section中的多个行 来得到表格…\\N{\\fs12}Number of rows in section to get table --\r\nDialogue: 0,0:29:47.99,0:29:50.24,yin,,0,0,0,,cellForRowAtIndexPath\\N{\\fs12}you know, cell for index -- cellforrowatindex path\r\nDialogue: 0,0:29:50.24,0:29:52.62,yin,,0,0,0,,这会不断发生 来重载整张表格\\N{\\fs12}over and over and over again to reload the entire table.\r\nDialogue: 0,0:29:52.62,0:29:54.55,yin,,0,0,0,,这是一个任务繁重的操作\\N{\\fs12}So this is a fairly heavyweight operation.\r\nDialogue: 0,0:29:54.55,0:29:56.95,yin,,0,0,0,,整张表格都需要重做\\N{\\fs12}It's going to completely redo your whole table.\r\nDialogue: 0,0:29:56.95,0:29:59.52,yin,,0,0,0,,不过在整个模型发生变化时\\N{\\fs12}But if your entire model changes,\r\nDialogue: 0,0:29:59.52,0:30:01.36,yin,,0,0,0,,这或许是合适的做法\\N{\\fs12}this might be an appropriate thing to do.\r\nDialogue: 0,0:30:01.36,0:30:05.60,yin,,0,0,0,,这在我们今天的演示中肯定会发生\\N{\\fs12}That's certainly going to happen in our demo that we're going to write today.\r\nDialogue: 0,0:30:05.60,0:30:10.03,yin,,0,0,0,,如果你知道模型中的变化比较细微\\N{\\fs12}You can be -- if you know the changes in your model are finer tuned,\r\nDialogue: 0,0:30:10.03,0:30:13.24,yin,,0,0,0,,你可以调用reloadRowsAtIndexPaths\\N{\\fs12}you can call methods like reloadrows atindexpaths.\r\nDialogue: 0,0:30:13.24,0:30:15.29,yin,,0,0,0,,只改变那些行\\N{\\fs12}And only change those rows.\r\nDialogue: 0,0:30:15.29,0:30:20.37,yin,,0,0,0,,这是模型变化时重载UI的更加精细的做法\\N{\\fs12}So it's kind of more fine-tuned reloading of your UI when your model changes.\r\nDialogue: 0,0:30:20.37,0:30:22.07,yin,,0,0,0,,你知道什么变化了\\N{\\fs12}You know what changed.\r\nDialogue: 0,0:30:22.07,0:30:23.67,yin,,0,0,0,,还有其它一些方法\\N{\\fs12}And there's some other methods too.\r\nDialogue: 0,0:30:23.67,0:30:25.77,yin,,0,0,0,,熟悉一下UITableView\\N{\\fs12}So familiarize yourself with UI TableView\r\nDialogue: 0,0:30:25.77,0:30:28.52,yin,,0,0,0,,你会弄清你都能做些什么\\N{\\fs12}you'll find out the kinds of things you can do.\r\nDialogue: 0,0:30:28.52,0:30:32.24,yin,,0,0,0,,UITableView本身之中也有好多种方法\\N{\\fs12}There's dozens of other methods in UI TableView itself.\r\nDialogue: 0,0:30:32.24,0:30:33.52,yin,,0,0,0,,它是一个ScrollView\\N{\\fs12}It's a ScrollView --\r\nDialogue: 0,0:30:33.52,0:30:35.49,yin,,0,0,0,,UITableView继承自UIScrollView\\N{\\fs12}UI TableView inherits from ScrollView,\r\nDialogue: 0,0:30:35.49,0:30:38.82,yin,,0,0,0,,它有一些很好的方法 能够滚动到特定的行\\N{\\fs12}so it's got some nice methods for scrolling to certain rows.\r\nDialogue: 0,0:30:38.82,0:30:41.20,yin,,0,0,0,,这能以一种很棒的动画方式发生\\N{\\fs12}So it happens in a nice, animated way.\r\nDialogue: 0,0:30:41.20,0:30:44.00,yin,,0,0,0,,你可以设定header和footer\\N{\\fs12}You can set those headers and footers that we talked\r\nDialogue: 0,0:30:44.00,0:30:46.10,yin,,0,0,0,,在最开始我就讲过这些\\N{\\fs12}about at the very beginning; things like that.\r\nDialogue: 0,0:30:46.10,0:30:48.35,yin,,0,0,0,,你也应该熟悉UITableView\\N{\\fs12}So you should familiarize yourself with UI TableView also\r\nDialogue: 0,0:30:48.35,0:30:50.82,yin,,0,0,0,,熟悉如何将它配置成你想要的样子\\N{\\fs12}and all the things you can do to configure it the way you want.\r\nDialogue: 0,0:30:50.82,0:30:55.49,yin,,0,0,0,,你也可以在故事板中配置 在检查器中配置\\N{\\fs12}And you can configure it also in the storyboards in the inspector there.\r\nDialogue: 0,0:30:55.49,0:30:57.54,yin,,0,0,0,,好 这是TableView\\N{\\fs12}Okay. So that's it for TableView.\r\nDialogue: 0,0:30:57.54,0:31:00.99,yin,,0,0,0,,在继续推进之前 关于TableView有问题吗\\N{\\fs12}Any questions on TableView before we go on?\r\nDialogue: 0,0:31:00.99,0:31:03.86,yin,,0,0,0,,好 下面我要讲通用应用\\N{\\fs12}Okay. Now we're going to talk about universal applications.\r\nDialogue: 0,0:31:03.86,0:31:09.24,yin,,0,0,0,,通用应用指的是一个app同时适用于iPhone和iPad\\N{\\fs12}A universal application is a single app that will run on iPhone and iPad.\r\nDialogue: 0,0:31:09.24,0:31:10.17,yin,,0,0,0,,一个app\\N{\\fs12}A single app.\r\nDialogue: 0,0:31:10.17,0:31:11.61,yin,,0,0,0,,如何做到呢\\N{\\fs12}And how do we do that?\r\nDialogue: 0,0:31:11.61,0:31:13.23,yin,,0,0,0,,如何让它适用于两者\\N{\\fs12}How do we make it so it works on both?\r\nDialogue: 0,0:31:13.23,0:31:14.95,yin,,0,0,0,,这是两种完全不同的环境\\N{\\fs12}Because they're kind of different idioms\r\nDialogue: 0,0:31:14.95,0:31:17.05,yin,,0,0,0,,iPad上有更大的屏幕空间\\N{\\fs12}You know, you've got a lot more screen real estate in an iPad,\r\nDialogue: 0,0:31:17.07,0:31:19.52,yin,,0,0,0,,答案是 我们有两种单独的故事板\\N{\\fs12}and the answer is, we have two separate storyboards.\r\nDialogue: 0,0:31:19.52,0:31:22.59,yin,,0,0,0,,通常 我们有相同的视图控制器\\N{\\fs12}So we have the same view controllers, usually,\r\nDialogue: 0,0:31:22.59,0:31:27.54,yin,,0,0,0,,我们将它们以不同方式安排在另一个故事板中\\N{\\fs12}and we just have different -- we arrange them in a different way in another storyboard.\r\nDialogue: 0,0:31:27.54,0:31:29.72,yin,,0,0,0,,我们有两种单独的故事板\\N{\\fs12}So we have two separate storyboards.\r\nDialogue: 0,0:31:29.72,0:31:32.33,yin,,0,0,0,,它们并不共享任何…\\N{\\fs12}And they don't really share anything --\r\nDialogue: 0,0:31:32.33,0:31:34.27,yin,,0,0,0,,虽然之间可以复制粘贴\\N{\\fs12}although you can copy and paste things between them --\r\nDialogue: 0,0:31:34.27,0:31:37.28,yin,,0,0,0,,但没有办法把它们关联起来\\N{\\fs12}you'll see me doing that -- but they don't really -- there's no way to like link them.\r\nDialogue: 0,0:31:37.28,0:31:38.70,yin,,0,0,0,,它们是单独的\\N{\\fs12}They're really separate.\r\nDialogue: 0,0:31:38.70,0:31:42.65,yin,,0,0,0,,这是因为UI一般都会有非常不同的样子\\N{\\fs12}And that's because the UI's want to generally look quite different.\r\nDialogue: 0,0:31:42.65,0:31:44.44,yin,,0,0,0,,功能是一样的\\N{\\fs12}They're going to have the same functionality,\r\nDialogue: 0,0:31:44.44,0:31:49.42,yin,,0,0,0,,MVC相同 但会绘制在屏幕上的不同地方\\N{\\fs12}so the same MVC's, but they're going to be drawn in different places on screen.\r\nDialogue: 0,0:31:49.42,0:31:51.80,yin,,0,0,0,,如何创建一个通用应用呢\\N{\\fs12}How do you create a universal application?\r\nDialogue: 0,0:31:51.80,0:31:55.69,yin,,0,0,0,,在新建项目时 其中一个问题便是\\N{\\fs12}Well, when you say, \"Project New\", one of the questions there is,\r\nDialogue: 0,0:31:55.69,0:31:59.46,yin,,0,0,0,,你想创建到什么平台 iPhone iPad还是通用\\N{\\fs12}what platform do you want to create this for? iPhone? iPad? Or Universal?\r\nDialogue: 0,0:31:59.46,0:32:03.40,yin,,0,0,0,,点选通用 你就会得到两个故事板\\N{\\fs12}And if you hit Universal, you'll get two storyboards and you're on your way.\r\nDialogue: 0,0:32:03.40,0:32:08.11,yin,,0,0,0,,如果你已经有了一个app 只适用于iPhone或iPad\\N{\\fs12}If you have an existing app that's only iPhone or only iPad,\r\nDialogue: 0,0:32:08.11,0:32:10.02,yin,,0,0,0,,那项目设置就必须改变了\\N{\\fs12}then you have to actually change our project settings.\r\nDialogue: 0,0:32:10.02,0:32:12.65,yin,,0,0,0,,这是这门课中我们首次关注项目设置\\N{\\fs12}And this is the first time in this class we've looked at the project settings.\r\nDialogue: 0,0:32:12.65,0:32:15.07,yin,,0,0,0,,做法是点击app名\\N{\\fs12}You get to them by clicking on the name of your app\r\nDialogue: 0,0:32:15.07,0:32:17.81,yin,,0,0,0,,在导航器的左上角\\N{\\fs12}in the upper left-hand corner of the navigator there.\r\nDialogue: 0,0:32:17.81,0:32:19.39,yin,,0,0,0,,这里是Imaginarium\\N{\\fs12}See where it says Imaginarium?\r\nDialogue: 0,0:32:19.39,0:32:21.11,yin,,0,0,0,,可以看到这些属性\\N{\\fs12}And you'll see all these properties.\r\nDialogue: 0,0:32:21.11,0:32:23.14,yin,,0,0,0,,在general选项卡中\\N{\\fs12}Well in the general tab --\r\nDialogue: 0,0:32:23.14,0:32:26.20,yin,,0,0,0,,看到顶部的general用蓝色标出了吧\\N{\\fs12}see where it says general in blue there at the top?\r\nDialogue: 0,0:32:26.20,0:32:28.34,yin,,0,0,0,,这里有一些一般项目设置选项\\N{\\fs12}There is some general project settings.\r\nDialogue: 0,0:32:28.34,0:32:30.10,yin,,0,0,0,,其中第二部分是部署信息\\N{\\fs12}And the second one is deployment info.\r\nDialogue: 0,0:32:30.10,0:32:31.38,yin,,0,0,0,,关于在哪部署这个\\N{\\fs12}Which is where you're going to deploy this.\r\nDialogue: 0,0:32:31.38,0:32:34.80,yin,,0,0,0,,这个app只适用于iPhone 因为在部署信息中它说\\N{\\fs12}So this app is iPhone only because it says under deployment info,\r\nDialogue: 0,0:32:34.80,0:32:37.82,yin,,0,0,0,,部署目标7.0 设备iPhone\\N{\\fs12}deployment target 7.0, devices, iPhone.\r\nDialogue: 0,0:32:37.82,0:32:42.38,yin,,0,0,0,,我要把设备从iPhone改为通用\\N{\\fs12}So I'm going to change that devices iPhone right there to say universal.\r\nDialogue: 0,0:32:42.38,0:32:45.65,yin,,0,0,0,,改为通用后 它会提供选项\\N{\\fs12}And when I change that to universal, it's going to offer\r\nDialogue: 0,0:32:45.65,0:32:50.72,yin,,0,0,0,,让我将已有故事板复制到新故事板\\N{\\fs12}to copy my existing storyboard to the new storyboard.\r\nDialogue: 0,0:32:50.72,0:32:52.84,yin,,0,0,0,,这里是从iPhone复制到iPad\\N{\\fs12}So in this case it's iPhone copy to an iPad.\r\nDialogue: 0,0:32:52.84,0:32:56.57,yin,,0,0,0,,我建议不复制\\N{\\fs12}I recommend against this. I recommend saying, \"Don't copy\" here.\r\nDialogue: 0,0:32:56.57,0:32:58.57,yin,,0,0,0,,选不复制后\\N{\\fs12}And if you say don't copy, then you'll have\r\nDialogue: 0,0:32:58.57,0:33:02.98,yin,,0,0,0,,你就需要自己创建故事板 做法是新文件\\N{\\fs12}to make the storyboard yourself, and the way you do that is with new file.\r\nDialogue: 0,0:33:02.98,0:33:06.14,yin,,0,0,0,,这是Xcode创建一切新东西的方法\\N{\\fs12}That's how we make everything anew in Xcode.\r\nDialogue: 0,0:33:06.14,0:33:08.78,yin,,0,0,0,,点创建新文件后\\N{\\fs12}And when you go to new file, you go --\r\nDialogue: 0,0:33:08.78,0:33:11.05,yin,,0,0,0,,这时不选Objective-C类这些\\N{\\fs12}instead of saying objective C class or something,\r\nDialogue: 0,0:33:11.05,0:33:14.49,yin,,0,0,0,,而是到下面找到用户界面 下面这里第三个\\N{\\fs12}you go down towards this user interface -- it's the third one down right there.\r\nDialogue: 0,0:33:14.49,0:33:17.91,yin,,0,0,0,,看到了吗 然后在这里面 可以创建新视图或新窗口\\N{\\fs12}See? And then inside there you can make a new view or a new window.\r\nDialogue: 0,0:33:17.91,0:33:20.89,yin,,0,0,0,,这里我们创建故事板 点选故事板\\N{\\fs12}You're going to make a storyboard. So you click storyboard.\r\nDialogue: 0,0:33:20.89,0:33:23.13,yin,,0,0,0,,它会问你要怎样的\\N{\\fs12}It's going to say what kind do you want?\r\nDialogue: 0,0:33:23.13,0:33:25.71,yin,,0,0,0,,我要一个iPad故事板\\N{\\fs12}I want an iPad storyboard.\r\nDialogue: 0,0:33:25.71,0:33:29.02,yin,,0,0,0,,将它放到已有故事板的相同位置\\N{\\fs12}Put it in the same place that your existing storyboard is,\r\nDialogue: 0,0:33:29.02,0:33:32.70,yin,,0,0,0,,这很有可能是一个叫作base.lproj的目录\\N{\\fs12}which is probably going to be a directory called base.lproj\r\nDialogue: 0,0:33:32.70,0:33:34.04,yin,,0,0,0,,在主项目[声音不清]中\\N{\\fs12}in the main project [inaudible].\r\nDialogue: 0,0:33:34.04,0:33:37.26,yin,,0,0,0,,总之 找到另一个故事板 放到一起\\N{\\fs12}But just go find your other storyboard and put it in the same place.\r\nDialogue: 0,0:33:37.26,0:33:40.08,yin,,0,0,0,,你可以给它取一个很好的名称\\N{\\fs12}You probably want to give it a good name like,\r\nDialogue: 0,0:33:40.08,0:33:43.59,yin,,0,0,0,,Main_iPad 或iPad 这之类\\N{\\fs12}main underbar iPad or iPad or something like that.\r\nDialogue: 0,0:33:43.59,0:33:45.62,yin,,0,0,0,,然后放到一个好的组中\\N{\\fs12}And then put it in a group -- a good group.\r\nDialogue: 0,0:33:45.62,0:33:47.38,yin,,0,0,0,,这里我放到了Imaginarium组中\\N{\\fs12}You see down there I've put it in the Imaginarium group.\r\nDialogue: 0,0:33:47.38,0:33:50.34,yin,,0,0,0,,最上的组 顶层的组\\N{\\fs12}The top group -- top level group.\r\nDialogue: 0,0:33:50.34,0:33:54.04,yin,,0,0,0,,现在 我有了iPad故事板\\N{\\fs12}And then you -- now I have this iPad storyboard.\r\nDialogue: 0,0:33:54.04,0:33:56.60,yin,,0,0,0,,看到在我的文件导航器顶部\\N{\\fs12}You see it at the top of my file navigator there\r\nDialogue: 0,0:33:56.60,0:33:58.63,yin,,0,0,0,,这里有Main_iPad.storyboard\\N{\\fs12}in the main underbar iPad.storyboard.\r\nDialogue: 0,0:33:58.63,0:34:02.43,yin,,0,0,0,,这时 我需要在项目设置中\\N{\\fs12}So now what I need to do is tell, in my project settings,\r\nDialogue: 0,0:34:02.43,0:34:05.33,yin,,0,0,0,,告诉Xcode这是我要iPad用的故事板\\N{\\fs12}tell Xcode that that's the storyboard I want to use for iPad.\r\nDialogue: 0,0:34:05.33,0:34:09.57,yin,,0,0,0,,做法是点击屏幕中间这里的iPad\\N{\\fs12}And I do that by clicking on where it says iPad there, in about the middle of the screen.\r\nDialogue: 0,0:34:09.57,0:34:12.62,yin,,0,0,0,,现在这里是iPhone 我要点iPad\\N{\\fs12}Right now it's saying iPhone. So I'm going to click on iPad.\r\nDialogue: 0,0:34:12.64,0:34:14.18,yin,,0,0,0,,这就换了过来\\N{\\fs12}It's going to switch over.\r\nDialogue: 0,0:34:14.20,0:34:16.54,yin,,0,0,0,,然后这里是我的界面文件\\N{\\fs12}And then I'm going to say, my interface file --\r\nDialogue: 0,0:34:16.54,0:34:21.17,yin,,0,0,0,,主界面 设为Main_iPad.storyboard\\N{\\fs12}main interface there -- is main iPad.storyboard.\r\nDialogue: 0,0:34:21.17,0:34:26.27,yin,,0,0,0,,这样一来 在iPad上运行时就都会用这个故事板了\\N{\\fs12}Now it's going to use that storyboard whenever it runs on iPad.\r\nDialogue: 0,0:34:26.27,0:34:29.72,yin,,0,0,0,,如果忘了这一步 那么在iPad上运行时\\N{\\fs12}If you forget to do this step, then when you're on an iPad,\r\nDialogue: 0,0:34:29.72,0:34:31.61,yin,,0,0,0,,程序会像一个巨大的iPhone\\N{\\fs12}it's going to look like a gigantic iPhone.\r\nDialogue: 0,0:34:31.61,0:34:33.04,yin,,0,0,0,,界面将是一个\\N{\\fs12}You know, the interface is just going\r\nDialogue: 0,0:34:33.04,0:34:35.08,yin,,0,0,0,,放大的iPhone版本\\N{\\fs12}to be a gigantic version of your iPhone one.\r\nDialogue: 0,0:34:35.08,0:34:37.36,yin,,0,0,0,,你很快就会意识到 哦 我忘了这一步\\N{\\fs12}So you'll quickly realize, oops I forgot this step.\r\nDialogue: 0,0:34:37.36,0:34:39.53,yin,,0,0,0,,我需要回头把这一步补上\\N{\\fs12}I've got to go back and do this.\r\nDialogue: 0,0:34:40.10,0:34:44.55,yin,,0,0,0,,好 我们的app现在有了两个不同的故事板\\N{\\fs12}Alright. So now we've got this app and it's got two different storyboards.\r\nDialogue: 0,0:34:44.55,0:34:47.37,yin,,0,0,0,,故事板为什么会不同呢\\N{\\fs12}Why are storyboards different\r\nDialogue: 0,0:34:47.37,0:34:50.18,yin,,0,0,0,,两者之间又有哪些不同呢\\N{\\fs12}and in what ways are they different between the two?\r\nDialogue: 0,0:34:50.18,0:34:53.85,yin,,0,0,0,,在iPad上 我们还有别的几种视图控制器\\N{\\fs12}Well, on an iPad we have a couple of other view controllers\r\nDialogue: 0,0:34:53.85,0:34:56.15,yin,,0,0,0,,来将MVC显示在屏幕上\\N{\\fs12}that we can use to put MVC's on screen.\r\nDialogue: 0,0:34:56.15,0:34:57.76,yin,,0,0,0,,一个是拆分视图(SplitView)\\N{\\fs12}One is the split view.\r\nDialogue: 0,0:34:57.76,0:35:01.76,yin,,0,0,0,,拆分视图是将屏幕分成两个MVC\\N{\\fs12}So split view is where we're going to split the screen up into two MVC's.\r\nDialogue: 0,0:35:01.76,0:35:05.65,yin,,0,0,0,,较窄的一个在左边 较大的一个在右边 看到了吗\\N{\\fs12}Kind of a narrow one on the left and a bigger one on the right -- see that?\r\nDialogue: 0,0:35:05.65,0:35:06.98,yin,,0,0,0,,此外还有弹窗\\N{\\fs12}And then also popovers.\r\nDialogue: 0,0:35:06.98,0:35:11.24,yin,,0,0,0,,弹窗是将MVC弹出到一个小矩形中\\N{\\fs12}Popovers are where we're going to pop an MVC up in a little rectangle.\r\nDialogue: 0,0:35:11.24,0:35:14.10,yin,,0,0,0,,看到白色区域内的方程式了吗\\N{\\fs12}So that little white area where the equations are there?\r\nDialogue: 0,0:35:14.10,0:35:17.28,yin,,0,0,0,,这就是一个小型TableView弹出到弹窗中\\N{\\fs12}That is a little TableView that's popping up in a popover.\r\nDialogue: 0,0:35:17.28,0:35:20.29,yin,,0,0,0,,我们将讲到拆分视图 弹窗及其工作方式\\N{\\fs12}So we're going to talk about split view and popover and how those work.\r\nDialogue: 0,0:35:20.29,0:35:22.35,yin,,0,0,0,,不过首先 在代码中\\N{\\fs12}But first in your code,\r\nDialogue: 0,0:35:22.35,0:35:24.64,yin,,0,0,0,,如何知道你是在iPad上\\N{\\fs12}how can you tell you're on an iPad\r\nDialogue: 0,0:35:24.64,0:35:26.23,yin,,0,0,0,,然后在代码中做点不同的事\\N{\\fs12}so that you can do something different in your code?\r\nDialogue: 0,0:35:26.23,0:35:27.75,yin,,0,0,0,,代码基础是共用的\\N{\\fs12}Because you have this shared code base.\r\nDialogue: 0,0:35:27.75,0:35:29.75,yin,,0,0,0,,唯一的不同是故事板\\N{\\fs12}The only thing that's different is the storyboards.\r\nDialogue: 0,0:35:29.75,0:35:31.33,yin,,0,0,0,,有时 你需要分辨是不是在iPad上\\N{\\fs12}So sometimes you want to tell if you're on an iPad.\r\nDialogue: 0,0:35:31.33,0:35:33.78,yin,,0,0,0,,这就是做法 好\\N{\\fs12}Well, that's the way to do it, okay.\r\nDialogue: 0,0:35:33.78,0:35:36.76,yin,,0,0,0,,我建议在检查是否在iPad上之前\\N{\\fs12}I kind of recommend thinking about if there are other things\r\nDialogue: 0,0:35:36.76,0:35:39.51,yin,,0,0,0,,先考虑检查一下别的东西\\N{\\fs12}to check first before checking if you're on an iPad.\r\nDialogue: 0,0:35:39.51,0:35:41.94,yin,,0,0,0,,例如 是否处在SplitView控制器中\\N{\\fs12}Like are you in a SplitView controller?\r\nDialogue: 0,0:35:41.94,0:35:44.03,yin,,0,0,0,,当前MVC是否处在SplitView控制器中\\N{\\fs12}Is your current MVC in a SplitView controller\r\nDialogue: 0,0:35:44.03,0:35:45.90,yin,,0,0,0,,我会告诉你们如何检查这个\\N{\\fs12}and I'm going to show you how you can check that.\r\nDialogue: 0,0:35:45.90,0:35:51.08,yin,,0,0,0,,我要通信的MVC 或是我自己 我的MVC\\N{\\fs12}Or is the MVC that I want to talk to, or is myself -- my MVC --\r\nDialogue: 0,0:35:51.08,0:35:52.08,yin,,0,0,0,,现在是否在屏幕上\\N{\\fs12}on screen right now?\r\nDialogue: 0,0:35:52.08,0:35:55.19,yin,,0,0,0,,要知道在iPad上 它可能在屏幕上 因为空间更大\\N{\\fs12}Because on iPad it might be on screen because there's more room\r\nDialogue: 0,0:35:55.19,0:35:57.71,yin,,0,0,0,,更多MVC可以待在屏幕上\\N{\\fs12}for -- and more MVC's to be on screen.\r\nDialogue: 0,0:35:57.71,0:35:59.68,yin,,0,0,0,,在iPhone上时 则可能不在屏幕上\\N{\\fs12}Whereas on iPhone might not be on screen.\r\nDialogue: 0,0:35:59.68,0:36:01.18,yin,,0,0,0,,这里有些东西需要先检查\\N{\\fs12}So there's something to check first\r\nDialogue: 0,0:36:01.18,0:36:04.36,yin,,0,0,0,,在检查是否处在iPad上时 先检查是否在屏幕上\\N{\\fs12}before checking am I on iPad, just check am I on screen?\r\nDialogue: 0,0:36:04.36,0:36:05.98,yin,,0,0,0,,或 我是否处在SplitView控制器中\\N{\\fs12}Or am I in a SplitView controller?\r\nDialogue: 0,0:36:05.98,0:36:07.13,yin,,0,0,0,,或 我是否处在弹窗中\\N{\\fs12}Or am I in a popover?\r\nDialogue: 0,0:36:07.13,0:36:11.88,yin,,0,0,0,,我们等下就会展示如何检查\\N{\\fs12}So we're going to show how to check -- or how to check if you're\r\nDialogue: 0,0:36:11.88,0:36:15.31,yin,,0,0,0,,是否处在SplitView控制器中\\N{\\fs12}in a SplitView controller in a second here.\r\nDialogue: 0,0:36:15.31,0:36:18.26,yin,,0,0,0,,SplitView控制器是这样的\\N{\\fs12}So here's what a SplitView controller looks like.\r\nDialogue: 0,0:36:18.26,0:36:22.11,yin,,0,0,0,,左边的视图有个名称 叫作master(主要)\\N{\\fs12}We have a name for the left view, we call that the master.\r\nDialogue: 0,0:36:22.11,0:36:24.25,yin,,0,0,0,,右边的视图我们称之为detail(明细)\\N{\\fs12}And the right view we call the detail.\r\nDialogue: 0,0:36:24.25,0:36:27.17,yin,,0,0,0,,这是因为两者之间通常有一个主要/明细关系\\N{\\fs12}And that's usually because there's a master/detail relationship between the two.\r\nDialogue: 0,0:36:27.17,0:36:30.60,yin,,0,0,0,,master中发生的情况通常会决定\\N{\\fs12}With changing in the master usually is affecting what's\r\nDialogue: 0,0:36:30.60,0:36:32.64,yin,,0,0,0,,detail中发生的情况\\N{\\fs12}driving; what's happening in the detail.\r\nDialogue: 0,0:36:32.64,0:36:35.37,yin,,0,0,0,,左边是SplitViewController的横屏模式\\N{\\fs12}So here's one in landscape mode and another one\r\nDialogue: 0,0:36:35.37,0:36:37.37,yin,,0,0,0,,右边则是竖屏模式\\N{\\fs12}in portrait mode of the SplitView controller.\r\nDialogue: 0,0:36:37.37,0:36:39.19,yin,,0,0,0,,这是计算器 它有两个MVC\\N{\\fs12}This is a calculator, so it's got two MVC's.\r\nDialogue: 0,0:36:39.19,0:36:42.85,yin,,0,0,0,,一个是计算器键盘MVC\\N{\\fs12}Kind of a calculator keypad MVC and then a calculator graph --\r\nDialogue: 0,0:36:42.85,0:36:45.83,yin,,0,0,0,,另一个是绘图MVC\\N{\\fs12}or graphing MVC that knows how to graph things.\r\nDialogue: 0,0:36:45.83,0:36:48.10,yin,,0,0,0,,这是一个绘图计算器\\N{\\fs12}So it's like a graphing calculator.\r\nDialogue: 0,0:36:48.10,0:36:52.03,yin,,0,0,0,,SplitViewController位于顶级\\N{\\fs12}The SplitView controller is designed to be at the top level.\r\nDialogue: 0,0:36:52.03,0:36:54.42,yin,,0,0,0,,因此 不要把它放到导航控制器\\N{\\fs12}So don't put a SplitView controller inside a navigation\r\nDialogue: 0,0:36:54.42,0:36:57.23,yin,,0,0,0,,或是选项卡栏控制器内 千万不要\\N{\\fs12}controller or inside a Tab Bar controller. Just don't do it.\r\nDialogue: 0,0:36:57.23,0:36:59.02,yin,,0,0,0,,它不是这样工作的\\N{\\fs12}It's not really designed to work that way.\r\nDialogue: 0,0:36:59.02,0:37:02.18,yin,,0,0,0,,你可以把这些放到它里面 哪一侧都行\\N{\\fs12}You can put those things inside it, in either side,\r\nDialogue: 0,0:37:02.18,0:37:05.32,yin,,0,0,0,,但不要把SplitView放到它们里面\\N{\\fs12}but don't put the SplitView inside them.\r\nDialogue: 0,0:37:05.32,0:37:07.68,yin,,0,0,0,,要在故事板中添加一个非常简单\\N{\\fs12}It's very simple to add one to your storyboard.\r\nDialogue: 0,0:37:07.68,0:37:10.50,yin,,0,0,0,,你只需要把它拖出来 然后它会给你\\N{\\fs12}You just drag it out and then it's going to give you a couple\r\nDialogue: 0,0:37:10.50,0:37:12.47,yin,,0,0,0,,一个master和一个detail\\N{\\fs12}of -- it's going to give you a master and a detail,\r\nDialogue: 0,0:37:12.47,0:37:14.10,yin,,0,0,0,,这个你几乎总会删掉\\N{\\fs12}which you're going to delete almost all the time.\r\nDialogue: 0,0:37:14.10,0:37:18.66,yin,,0,0,0,,然后你control拖动到你的master和detail\\N{\\fs12}And then you just control drag to your master and control drag to your detail.\r\nDialogue: 0,0:37:18.66,0:37:22.28,yin,,0,0,0,,就像选项卡栏控制器一样 它会以相同方式关联起来\\N{\\fs12}Just like a Tab Bar controller, it gets hooked up the same, exact way.\r\nDialogue: 0,0:37:24.38,0:37:28.74,yin,,0,0,0,,在代码中 你希望能够访问master和detail\\N{\\fs12}In your code, you want to be able to access the master and the detail.\r\nDialogue: 0,0:37:28.74,0:37:31.34,yin,,0,0,0,,这方面你需要知道两个属性\\N{\\fs12}And there's two properties you need to know about that.\r\nDialogue: 0,0:37:31.34,0:37:36.57,yin,,0,0,0,,一个属性在UIViewController中 叫splitViewController\\N{\\fs12}One is the property in UI View Controller, called SplitView Controller.\r\nDialogue: 0,0:37:36.57,0:37:39.79,yin,,0,0,0,,如果你发送splitViewController getter\\N{\\fs12}So if you send SplitView Controller, getter,\r\nDialogue: 0,0:37:39.79,0:37:41.77,yin,,0,0,0,,给任何UIViewController\\N{\\fs12}to any UI View Controller,\r\nDialogue: 0,0:37:41.77,0:37:45.10,yin,,0,0,0,,它会返回它所处的SplitViewController\\N{\\fs12}it will return what SplitView Controller it's in.\r\nDialogue: 0,0:37:45.10,0:37:47.72,yin,,0,0,0,,如果它处在一个SplitViewController中的话\\N{\\fs12}If it's in one. Anywhere in it.\r\nDialogue: 0,0:37:47.72,0:37:50.93,yin,,0,0,0,,如果不在SplitViewController中 它会返回nil\\N{\\fs12}If it's not in it, it will return nil.\r\nDialogue: 0,0:37:50.93,0:37:53.45,yin,,0,0,0,,这是一个很好的检查标准\\N{\\fs12}So this is a good thing to check if you have conditional code\r\nDialogue: 0,0:37:53.45,0:37:57.29,yin,,0,0,0,,如果你有条件代码 在iPad和iPhone上按不同方式工作\\N{\\fs12}that works one way in an iPad and one way on an iPhone.\r\nDialogue: 0,0:37:57.29,0:37:59.18,yin,,0,0,0,,你可以检查是否处在SplitViewController中\\N{\\fs12}Is whether you're in a SplitView Controller or not.\r\nDialogue: 0,0:37:59.18,0:38:02.91,yin,,0,0,0,,iPad界面是否建立在SplitViewController之上\\N{\\fs12}If your iPad interface is built on a SplitView Controller.\r\nDialogue: 0,0:38:02.91,0:38:05.42,yin,,0,0,0,,知道处在什么SplitViewController中后\\N{\\fs12}Now, once you find out what SplitView Controller you're in,\r\nDialogue: 0,0:38:05.42,0:38:07.21,yin,,0,0,0,,你可以问SplitViewController\\N{\\fs12}you can ask the SplitView Controller,\r\nDialogue: 0,0:38:07.21,0:38:10.29,yin,,0,0,0,,请告诉我master和detail\\N{\\fs12}please tell me the detail -- the master and the detail.\r\nDialogue: 0,0:38:10.29,0:38:12.97,yin,,0,0,0,,做法是通过这个数组\\N{\\fs12}And the way you do that is with this array\r\nDialogue: 0,0:38:12.97,0:38:15.49,yin,,0,0,0,,在UISplitViewController中 叫viewControllers\\N{\\fs12}in UI SplitView Controller called, \"View Controllers\".\r\nDialogue: 0,0:38:15.49,0:38:19.14,yin,,0,0,0,,这个数组总有两个项目在里面 0是master\\N{\\fs12}And that array always has two items in it; 0 is the master.\r\nDialogue: 0,0:38:19.14,0:38:20.47,yin,,0,0,0,,1是detail\\N{\\fs12}1 is the detail.\r\nDialogue: 0,0:38:20.47,0:38:24.09,yin,,0,0,0,,例如 如果我有一个master VC\\N{\\fs12}So for example, if I had a master VC\r\nDialogue: 0,0:38:24.09,0:38:28.36,yin,,0,0,0,,它想弄清在相同的SplitViewController中 detail是什么\\N{\\fs12}and it wanted to find out what the detail was in the same SplitView Controller it's in,\r\nDialogue: 0,0:38:28.37,0:38:32.73,yin,,0,0,0,,它会说 self.splitViewController.viewControllers[1]\\N{\\fs12}it would say, self.splitviewcontroller.viewcontrollersub1.\r\nDialogue: 0,0:38:32.73,0:38:36.31,yin,,0,0,0,,如果不处在SplitViewController中 这会返回nil\\N{\\fs12}And that would return nil if it's not in a SplitView Controller at all.\r\nDialogue: 0,0:38:36.31,0:38:39.32,yin,,0,0,0,,处在SplitViewController中时 它会返回detail\\N{\\fs12}And if it is a SplitView Controller, it would return the detail.\r\nDialogue: 0,0:38:40.88,0:38:42.70,yin,,0,0,0,,能理解吗\\N{\\fs12}Make sense?\r\nDialogue: 0,0:38:42.70,0:38:48.96,yin,,0,0,0,,SplitViewController有一点很有趣\\N{\\fs12}And so one thing that's kind of interesting about SplitView Controller,\r\nDialogue: 0,0:38:48.96,0:38:53.08,yin,,0,0,0,,同TableView数据源类似 也就是\\N{\\fs12}similar to the TableView datasource is it requires its\r\nDialogue: 0,0:38:53.08,0:38:56.36,yin,,0,0,0,,它需要SplitViewControllerDelegate得到设定\\N{\\fs12}SplitView Controller delegate to be set.\r\nDialogue: 0,0:38:56.36,0:38:59.23,yin,,0,0,0,,为什么这个需要设定呢\\N{\\fs12}And why is this that it's required to be set?\r\nDialogue: 0,0:38:59.23,0:39:01.70,yin,,0,0,0,,答案是竖屏模式\\N{\\fs12}The answer is portrait mode.\r\nDialogue: 0,0:39:01.70,0:39:04.62,yin,,0,0,0,,后面我会在幻灯片中展示一些图片\\N{\\fs12}And I'm going to show you this in some pictures in the next couple of slides.\r\nDialogue: 0,0:39:04.62,0:39:05.97,yin,,0,0,0,,为什么需要委托\\N{\\fs12}Why you need the delegate.\r\nDialogue: 0,0:39:05.97,0:39:07.57,yin,,0,0,0,,委托很烦人\\N{\\fs12}The delegate is annoying.\r\nDialogue: 0,0:39:07.57,0:39:10.16,yin,,0,0,0,,这是iOS最烦人的委托\\N{\\fs12}It's the most annoying delegate in all of IOS.\r\nDialogue: 0,0:39:10.16,0:39:12.37,yin,,0,0,0,,首先 它需要很早设定\\N{\\fs12}Firstly it has to be set very early.\r\nDialogue: 0,0:39:12.37,0:39:13.70,yin,,0,0,0,,也就是在awakeFromNib中\\N{\\fs12}Meaning in away from NIB.\r\nDialogue: 0,0:39:13.70,0:39:15.05,yin,,0,0,0,,你不能等到viewDidLoad\\N{\\fs12}You can't wait till view did load\r\nDialogue: 0,0:39:15.05,0:39:18.15,yin,,0,0,0,,来设定SplitViewController的委托\\N{\\fs12}to set your SplitView Controller's delegate.\r\nDialogue: 0,0:39:18.15,0:39:19.57,yin,,0,0,0,,这很烦人\\N{\\fs12}So that's annoying.\r\nDialogue: 0,0:39:19.57,0:39:23.34,yin,,0,0,0,,然后 在viewDidLoad发生之前 它就开始\\N{\\fs12}Second of all, it starts calling the delegate methods\r\nDialogue: 0,0:39:23.34,0:39:26.33,yin,,0,0,0,,从SplitViewController调用委托方法\\N{\\fs12}from the SplitView Controller before view did load happens.\r\nDialogue: 0,0:39:26.33,0:39:29.72,yin,,0,0,0,,调用委托方法时 什么outlet都还没有设定\\N{\\fs12}So none of your outlets are set while its calling its delegate methods.\r\nDialogue: 0,0:39:29.72,0:39:30.69,yin,,0,0,0,,这很烦人\\N{\\fs12}So that's annoying.\r\nDialogue: 0,0:39:30.69,0:39:34.41,yin,,0,0,0,,所以说 SplitViewControllerDelegate很难打交道\\N{\\fs12}So it's very difficult to deal with the SplitView Controller delegate.\r\nDialogue: 0,0:39:34.41,0:39:37.57,yin,,0,0,0,,幸运的是 它只有一个很简单的职责\\N{\\fs12}Fortunately it only has one, simple responsibility.\r\nDialogue: 0,0:39:37.57,0:39:41.76,yin,,0,0,0,,也就是控制master和detail何时出现\\N{\\fs12}Which is to control when the master and the detail appear\r\nDialogue: 0,0:39:41.76,0:39:44.43,yin,,0,0,0,,在横屏模式和竖屏模式中\\N{\\fs12}in the landscape versus portrait modes.\r\nDialogue: 0,0:39:44.44,0:39:47.16,yin,,0,0,0,,实现这个方法\\N{\\fs12}So in -- so you implement this method.\r\nDialogue: 0,0:39:47.16,0:39:50.86,yin,,0,0,0,,这个方法是通往SplitViewControllerDelegate的门路\\N{\\fs12}This is kind of the gateway SplitView Controller delegate\r\nDialogue: 0,0:39:50.86,0:39:53.15,yin,,0,0,0,,叫作splitViewController: shouldHideViewController:\\N{\\fs12}method called SplitViewcontroller shouldhighviewcontroller\r\nDialogue: 0,0:39:53.16,0:39:54.35,yin,,0,0,0,,inOrientation:\\N{\\fs12}inorientation.\r\nDialogue: 0,0:39:54.37,0:39:59.80,yin,,0,0,0,,它会在横屏或竖屏模式中问你 是否应该隐藏master\\N{\\fs12}And it's going to ask you in landscape or in portrait, should I hide the master?\r\nDialogue: 0,0:39:59.80,0:40:02.33,yin,,0,0,0,,如果返回NO 意思是说从不\\N{\\fs12}Now if you return no, that means never.\r\nDialogue: 0,0:40:02.33,0:40:05.83,yin,,0,0,0,,这意味着master和detail将一直在屏幕上\\N{\\fs12}That means the master and the detail will be on screen\r\nDialogue: 0,0:40:05.83,0:40:08.68,yin,,0,0,0,,无论是在横屏模式还是竖屏模式中\\N{\\fs12}in both the landscape mode and the portrait mode.\r\nDialogue: 0,0:40:08.68,0:40:10.67,yin,,0,0,0,,不过这意味着 竖屏模式中\\N{\\fs12}But that does mean that in portrait mode\r\nDialogue: 0,0:40:10.67,0:40:12.43,yin,,0,0,0,,detail会又高又细\\N{\\fs12}the details can be kind of tall and skinny.\r\nDialogue: 0,0:40:12.43,0:40:14.60,yin,,0,0,0,,master总是又高又细的\\N{\\fs12}The master's always tall and skinny.\r\nDialogue: 0,0:40:14.60,0:40:17.47,yin,,0,0,0,,但detail则高细得有些异常\\N{\\fs12}The details can be kind of unusually tall and skinny.\r\nDialogue: 0,0:40:17.47,0:40:20.04,yin,,0,0,0,,不过有时在UI中 这样做也行\\N{\\fs12}But sometimes UI this makes sense.\r\nDialogue: 0,0:40:20.04,0:40:23.95,yin,,0,0,0,,除NO以外 另一种返回方式是说 只在竖屏中\\N{\\fs12}Another thing to return, besides no, is to say only in portrait.\r\nDialogue: 0,0:40:23.95,0:40:26.03,yin,,0,0,0,,只在竖屏中隐藏master\\N{\\fs12}So only hide the master in portrait.\r\nDialogue: 0,0:40:26.03,0:40:28.63,yin,,0,0,0,,这样在横屏中 你就能看到master\\N{\\fs12}So now in landscape you'll see the master in the detail;\r\nDialogue: 0,0:40:28.63,0:40:30.30,yin,,0,0,0,,而竖屏中则看不到\\N{\\fs12}in portrait you won't.\r\nDialogue: 0,0:40:30.30,0:40:33.52,yin,,0,0,0,,这里重要的是 如果我处在竖屏\\N{\\fs12}But the important thing about this is, if I'm in portrait,\r\nDialogue: 0,0:40:33.52,0:40:35.27,yin,,0,0,0,,如何获得master呢\\N{\\fs12}how do I get at the master?\r\nDialogue: 0,0:40:35.27,0:40:38.17,yin,,0,0,0,,答案是 它会给你一个栏按钮\\N{\\fs12}And the answer is, it's going to give you a little bar button.\r\nDialogue: 0,0:40:38.17,0:40:40.53,yin,,0,0,0,,左上角那个蓝色的就是\\N{\\fs12}You see that little blue bar button up in the corner there?\r\nDialogue: 0,0:40:40.53,0:40:44.21,yin,,0,0,0,,有点看不清 我用黄色对话框指向了它\\N{\\fs12}You can barely see it. It's being pointed to by that yellow call out?\r\nDialogue: 0,0:40:44.21,0:40:50.47,yin,,0,0,0,,点击这个按钮 master就会滑出\\N{\\fs12}That button, if I click on it, it's going to slide the master out.\r\nDialogue: 0,0:40:50.47,0:40:52.35,yin,,0,0,0,,看到了吗 master滑出\\N{\\fs12}See? Slides the master out.\r\nDialogue: 0,0:40:52.35,0:40:55.24,yin,,0,0,0,,点击detail中其它地方 它会消失\\N{\\fs12}If I click anywhere else in the detail it goes away.\r\nDialogue: 0,0:40:55.24,0:40:58.30,yin,,0,0,0,,再次点击按钮 master再次滑出\\N{\\fs12}Click on the button again it slides the master out.\r\nDialogue: 0,0:40:58.30,0:41:02.43,yin,,0,0,0,,这就是在竖屏模式中访问master的方式\\N{\\fs12}So that's how I can get at the master even in portrait mode.\r\nDialogue: 0,0:41:02.43,0:41:05.13,yin,,0,0,0,,不过这个按钮需要放到某个地方\\N{\\fs12}But I have to put that button somewhere.\r\nDialogue: 0,0:41:05.13,0:41:07.63,yin,,0,0,0,,很不幸 这是我的职责\\N{\\fs12}That's my responsibility unfortunately.\r\nDialogue: 0,0:41:07.63,0:41:10.57,yin,,0,0,0,,我需要在所有outlet设定之前搞定\\N{\\fs12}And I have to do it before all my outlets are set,\r\nDialogue: 0,0:41:10.57,0:41:12.24,yin,,0,0,0,,这让我有点难办\\N{\\fs12}so that makes it difficult to do.\r\nDialogue: 0,0:41:12.24,0:41:13.57,yin,,0,0,0,,怎么做的呢\\N{\\fs12}But how would that work?\r\nDialogue: 0,0:41:13.57,0:41:16.11,yin,,0,0,0,,把按钮放到这里\\N{\\fs12}Okay, so to put that button there,\r\nDialogue: 0,0:41:16.11,0:41:17.88,yin,,0,0,0,,SplitViewController会发送给你…\\N{\\fs12}the SplitView Controller is going to send you --\r\nDialogue: 0,0:41:17.88,0:41:19.77,yin,,0,0,0,,顺便说下 如果你不实现委托\\N{\\fs12}oh by the way, if you don't implement the delegate,\r\nDialogue: 0,0:41:19.77,0:41:22.07,yin,,0,0,0,,在竖屏模式中\\N{\\fs12}what's going to happen is in portrait mode, there's not going\r\nDialogue: 0,0:41:22.07,0:41:26.15,yin,,0,0,0,,按钮不会存在 用户无法访问master\\N{\\fs12}to be a button there and so the user won't be able to get at the master.\r\nDialogue: 0,0:41:26.15,0:41:28.45,yin,,0,0,0,,用户显然不希望这样\\N{\\fs12}And that's a little frustrating for users.\r\nDialogue: 0,0:41:28.45,0:41:30.30,yin,,0,0,0,,你可以说 换成横屏不就行了\\N{\\fs12}You could just say, well just switch the landscape.\r\nDialogue: 0,0:41:30.30,0:41:31.35,yin,,0,0,0,,那就有master了\\N{\\fs12}You could have the master back.\r\nDialogue: 0,0:41:31.35,0:41:32.73,yin,,0,0,0,,也许这也行\\N{\\fs12}Ehh, well maybe that's okay.\r\nDialogue: 0,0:41:32.73,0:41:33.71,yin,,0,0,0,,我不知道\\N{\\fs12}I don't know.\r\nDialogue: 0,0:41:33.71,0:41:35.82,yin,,0,0,0,,我认为这样不是很好\\N{\\fs12}I don't think it's that great.\r\nDialogue: 0,0:41:35.82,0:41:39.42,yin,,0,0,0,,哪怕是在竖屏模式中 用户也会指望访问master\\N{\\fs12}Users would expect to be able to get at the master, even from portrait mode.\r\nDialogue: 0,0:41:39.42,0:41:42.86,yin,,0,0,0,,如果不实现委托 这里就不会有按钮\\N{\\fs12}So if you don't do the delegate, you won't have a button there.\r\nDialogue: 0,0:41:42.86,0:41:45.82,yin,,0,0,0,,用户无法访问master\\N{\\fs12}People won't be able to get at the master.\r\nDialogue: 0,0:41:45.82,0:41:49.09,yin,,0,0,0,,在这里放上按钮的是另一个SplitView委托方法\\N{\\fs12}So the way you put the button there is, another SplitView delegate method.\r\nDialogue: 0,0:41:49.09,0:41:51.50,yin,,0,0,0,,willHideViewController: withBarButtonItem:\\N{\\fs12}Willhideview controller withbar buttonitem.\r\nDialogue: 0,0:41:51.50,0:41:53.83,yin,,0,0,0,,这里说的是 我要隐藏master\\N{\\fs12}And what's that's saying is, I'm going to hide the master.\r\nDialogue: 0,0:41:53.83,0:41:56.07,yin,,0,0,0,,这里有一个栏按钮要放到屏幕上的某个地方\\N{\\fs12}Here's a bar button to put somewhere on the screen,\r\nDialogue: 0,0:41:56.07,0:41:59.45,yin,,0,0,0,,用户点击它时 master就会滑动出来\\N{\\fs12}that when the user clicks it, it will slide back.\r\nDialogue: 0,0:41:59.45,0:42:01.71,yin,,0,0,0,,这是一种很简单的实现方法\\N{\\fs12}So here's a simple way to implement it.\r\nDialogue: 0,0:42:01.71,0:42:04.53,yin,,0,0,0,,将detail放到导航控制器中\\N{\\fs12}Put your detail in a navigation controller.\r\nDialogue: 0,0:42:05.45,0:42:07.64,yin,,0,0,0,,将detail放到导航控制器中\\N{\\fs12}You put your detail in a navigation controller.\r\nDialogue: 0,0:42:07.64,0:42:11.36,yin,,0,0,0,,然后你可以设定左侧的栏按钮项目为那个栏按钮\\N{\\fs12}Then you can set the left bar button item to be that bar button.\r\nDialogue: 0,0:42:11.36,0:42:13.42,yin,,0,0,0,,这种做法很酷\\N{\\fs12}What's cool about this way is\r\nDialogue: 0,0:42:13.42,0:42:15.48,yin,,0,0,0,,因为左侧栏按钮项目的设定\\N{\\fs12}that you can set the left bar button item by setting it\r\nDialogue: 0,0:42:15.48,0:42:18.55,yin,,0,0,0,,可以通过设定在UI视图控制器的导航项目上得到\\N{\\fs12}on the navigation item of a UI view controller.\r\nDialogue: 0,0:42:18.55,0:42:20.91,yin,,0,0,0,,这意味着 哪怕你还没设置好\\N{\\fs12}Which means even though you're not set up yet;\r\nDialogue: 0,0:42:20.91,0:42:22.10,yin,,0,0,0,,还没有任何outlet\\N{\\fs12}you don't have any outlets,\r\nDialogue: 0,0:42:22.10,0:42:23.63,yin,,0,0,0,,你就可以把栏按钮放到那里\\N{\\fs12}you can just put that bar button in there\r\nDialogue: 0,0:42:23.63,0:42:27.23,yin,,0,0,0,,无论任何时候 只要视图出现在导航控制器中\\N{\\fs12}and when the view appears in a navigation controller at any time,\r\nDialogue: 0,0:42:27.23,0:42:29.28,yin,,0,0,0,,它就会使用这个左侧栏按钮项目\\N{\\fs12}it's going to use that left bar button item.\r\nDialogue: 0,0:42:29.28,0:42:30.71,yin,,0,0,0,,这就是将它放到左上角的方式\\N{\\fs12}So that's how you put it in the left [inaudible].\r\nDialogue: 0,0:42:30.71,0:42:32.95,yin,,0,0,0,,这是一种很巧妙的做法\\N{\\fs12}So this is kind of a tricky way to do it.\r\nDialogue: 0,0:42:32.95,0:42:35.19,yin,,0,0,0,,让这很容易实现\\N{\\fs12}To make this really easy to implement.\r\nDialogue: 0,0:42:35.19,0:42:37.19,yin,,0,0,0,,我推荐它 它是一个很棒的技巧\\N{\\fs12}I kind of recommend it. It's a good trick.\r\nDialogue: 0,0:42:37.19,0:42:38.48,yin,,0,0,0,,没什么不好的\\N{\\fs12}There's nothing bad about it.\r\nDialogue: 0,0:42:38.48,0:42:40.78,yin,,0,0,0,,唯一的问题在于 你不会希望\\N{\\fs12}The only thing that's bad about it is you would never want\r\nDialogue: 0,0:42:40.78,0:42:44.45,yin,,0,0,0,,导航同时在master和detail中进行\\N{\\fs12}to have navigation going on both in your master and your detail.\r\nDialogue: 0,0:42:44.45,0:42:46.80,yin,,0,0,0,,哪怕你的detail处在导航控制器中\\N{\\fs12}So even though your detail's in a navigation controller,\r\nDialogue: 0,0:42:46.80,0:42:48.91,yin,,0,0,0,,你也不要允许任何实际导航发生\\N{\\fs12}don't allow any actual navigation there.\r\nDialogue: 0,0:42:48.91,0:42:51.52,yin,,0,0,0,,你只是希望用它找个地方放这个栏按钮\\N{\\fs12}You're only using it to have a place to put this bar\r\nDialogue: 0,0:42:51.52,0:42:52.72,yin,,0,0,0,,并在上面写一个标题\\N{\\fs12}and get a title at the top.\r\nDialogue: 0,0:42:52.72,0:42:54.41,yin,,0,0,0,,我们会在演示中做这个\\N{\\fs12}We'll do that in the demo.\r\nDialogue: 0,0:42:54.41,0:42:57.92,yin,,0,0,0,,类似地 切换回横屏模式后\\N{\\fs12}And then similarly, when it switches back to landscape,\r\nDialogue: 0,0:42:57.92,0:43:00.74,yin,,0,0,0,,它会说 你现在可以把栏按钮去掉了\\N{\\fs12}then it's going to say, okay you can take that bar button away now.\r\nDialogue: 0,0:43:00.74,0:43:03.88,yin,,0,0,0,,因为master在横屏模式中总是可见的\\N{\\fs12}Because the master is visible always in landscape.\r\nDialogue: 0,0:43:03.88,0:43:05.08,yin,,0,0,0,,这就是这了\\N{\\fs12}So that's it.\r\nDialogue: 0,0:43:05.08,0:43:07.04,yin,,0,0,0,,这是SplitView中的三个方法\\N{\\fs12}Those are the three SplitView ones.\r\nDialogue: 0,0:43:07.04,0:43:08.88,yin,,0,0,0,,这些幻灯片可以供你们复习\\N{\\fs12}These slides are here for you to review.\r\nDialogue: 0,0:43:08.88,0:43:10.83,yin,,0,0,0,,这个委托比较难\\N{\\fs12}This is a difficult delegate,\r\nDialogue: 0,0:43:10.83,0:43:12.58,yin,,0,0,0,,不过要让SplitView正常工作\\N{\\fs12}but to make SplitView really work right,\r\nDialogue: 0,0:43:12.58,0:43:16.35,yin,,0,0,0,,很不幸 你需要实现这三个方法\\N{\\fs12}unfortunately you have to implement these three methods.\r\nDialogue: 0,0:43:16.35,0:43:19.24,yin,,0,0,0,,好 在master变化时 更新detail\\N{\\fs12}Okay. So updating the detail when the master changes.\r\nDialogue: 0,0:43:19.24,0:43:21.62,yin,,0,0,0,,这在SplitView中非常基础\\N{\\fs12}That's a fundamental thing about what happens in SplitView.\r\nDialogue: 0,0:43:21.62,0:43:22.52,yin,,0,0,0,,如何做到呢\\N{\\fs12}How do you do that?\r\nDialogue: 0,0:43:22.52,0:43:25.70,yin,,0,0,0,,detail和mater同时处在屏幕上\\N{\\fs12}Because the detail and the master are both on screen at the same time.\r\nDialogue: 0,0:43:25.70,0:43:30.21,yin,,0,0,0,,当有人在master中点击时 detail如何更新\\N{\\fs12}How are we going to update the detail when someone clicks in the master basically.\r\nDialogue: 0,0:43:30.21,0:43:32.98,yin,,0,0,0,,有两种做法 一是目标动作\\N{\\fs12}And there's two choices. One is target action.\r\nDialogue: 0,0:43:32.98,0:43:37.12,yin,,0,0,0,,让master有一个目标动作方法到它自身\\N{\\fs12}So just have your master have a target action method to itself.\r\nDialogue: 0,0:43:37.12,0:43:39.67,yin,,0,0,0,,它有了这个目标动作后\\N{\\fs12}And when it gets that target action it's going\r\nDialogue: 0,0:43:39.67,0:43:42.60,yin,,0,0,0,,就会去找detail 并进行更新\\N{\\fs12}to go find its detail and update the detail.\r\nDialogue: 0,0:43:42.60,0:43:44.65,yin,,0,0,0,,同prepareForSegue的做法基本一样\\N{\\fs12}Basically do the same thing it would do in preparing for segue.\r\nDialogue: 0,0:43:44.65,0:43:46.69,yin,,0,0,0,,设定detail中必要的东西\\N{\\fs12}Just set whatever's necessary on that detail.\r\nDialogue: 0,0:43:46.69,0:43:49.14,yin,,0,0,0,,我们在演示中会做这个\\N{\\fs12}That's what we're going to do in our demo.\r\nDialogue: 0,0:43:49.14,0:43:51.64,yin,,0,0,0,,当然 如果master中是TableView\\N{\\fs12}Of course if it's a TableView in master,\r\nDialogue: 0,0:43:51.64,0:43:54.45,yin,,0,0,0,,你就需要使用那个didSelectRowAtIndexPath\\N{\\fs12}you have to use that didselectrow atindexpath.\r\nDialogue: 0,0:43:54.45,0:43:56.53,yin,,0,0,0,,这是TableView的目标动作\\N{\\fs12}That's target action for TableView.\r\nDialogue: 0,0:43:56.53,0:43:58.49,yin,,0,0,0,,但是 如果只是mster中的一个按钮\\N{\\fs12}But if it were just a button in your master\r\nDialogue: 0,0:43:58.49,0:44:01.90,yin,,0,0,0,,就像计算器那样 你可以点一个按钮让它显示图像\\N{\\fs12}like that calculator thing, you could just click a button that says show the graph,\r\nDialogue: 0,0:44:01.90,0:44:05.74,yin,,0,0,0,,这就是普通的目标动作 它会做这样的事情\\N{\\fs12}it could just be normal target action and it would do something like this.\r\nDialogue: 0,0:44:05.74,0:44:08.22,yin,,0,0,0,,找detail 然后更新之\\N{\\fs12}Find the detail and go update it.\r\nDialogue: 0,0:44:08.22,0:44:10.13,yin,,0,0,0,,第二种方式是使用segue\\N{\\fs12}The second way is with a segue.\r\nDialogue: 0,0:44:10.13,0:44:11.77,yin,,0,0,0,,这被称作替换segue\\N{\\fs12}It's called a replace segue.\r\nDialogue: 0,0:44:11.77,0:44:15.23,yin,,0,0,0,,这个segue替换了整个detail视图\\N{\\fs12}This segue replaces the entire detail view.\r\nDialogue: 0,0:44:15.23,0:44:17.19,yin,,0,0,0,,完全替换了它\\N{\\fs12}Completely replaces it.\r\nDialogue: 0,0:44:17.19,0:44:19.92,yin,,0,0,0,,这个很讨厌 因为所有那些委托方法\\N{\\fs12}This one's kind of annoying because of all of those delegate methods.\r\nDialogue: 0,0:44:19.92,0:44:22.80,yin,,0,0,0,,因为它会替换掉整个视图 包括\\N{\\fs12}Because it's going to replace the entire view including the\r\nDialogue: 0,0:44:22.80,0:44:25.05,yin,,0,0,0,,导航控制器以及那个小按钮\\N{\\fs12}navigation controller with the little button.\r\nDialogue: 0,0:44:25.79,0:44:28.83,yin,,0,0,0,,segue到一个新的 你需要把按钮弄出来\\N{\\fs12}So you segue to a new one, and now you've got to somehow get\r\nDialogue: 0,0:44:28.83,0:44:30.94,yin,,0,0,0,,并将它放到新的里面\\N{\\fs12}that button out of there and put it back into the new one.\r\nDialogue: 0,0:44:30.94,0:44:32.31,yin,,0,0,0,,这很麻烦\\N{\\fs12}It's quite a pain in the neck.\r\nDialogue: 0,0:44:32.31,0:44:36.38,yin,,0,0,0,,因此SplitViewController中 我们很少使用替换segue\\N{\\fs12}So we don't really use the replace segue that much in the SplitView Controller.\r\nDialogue: 0,0:44:36.38,0:44:39.34,yin,,0,0,0,,在master总可见的情况下 这还很好\\N{\\fs12}It's pretty good in the ones where the master is always visible.\r\nDialogue: 0,0:44:39.34,0:44:41.35,yin,,0,0,0,,但在master隐藏的情况下\\N{\\fs12}But if we're ever doing the one where the master hides\r\nDialogue: 0,0:44:41.35,0:44:44.65,yin,,0,0,0,,上面有个按钮 让按钮维持在上面那里很麻烦\\N{\\fs12}and we put a button up there, it's a pain to keep that button up there when it's\r\nDialogue: 0,0:44:44.65,0:44:47.73,yin,,0,0,0,,替换segue会持续不断地替换掉\\N{\\fs12}constantly replacing the segue on the right side.\r\nDialogue: 0,0:44:47.73,0:44:53.03,yin,,0,0,0,,记得吧 segue总会给出视图控制器的新版本\\N{\\fs12}Remember by the way, segues always give you new versions of view controllers.\r\nDialogue: 0,0:44:53.03,0:44:54.84,yin,,0,0,0,,在做Imaginarium时\\N{\\fs12}So when we were doing Imaginarium,\r\nDialogue: 0,0:44:54.84,0:44:58.99,yin,,0,0,0,,每次我们点击新的花 水母或是别的什么\\N{\\fs12}every time we'd click on a new flower or jellyfish or whatever,\r\nDialogue: 0,0:44:58.99,0:45:01.81,yin,,0,0,0,,它会使用一个全新的视图控制器实例\\N{\\fs12}it would push to a brand new instance of view controller.\r\nDialogue: 0,0:45:01.81,0:45:03.99,yin,,0,0,0,,segue总是新实例\\N{\\fs12}segues are always new instances.\r\nDialogue: 0,0:45:03.99,0:45:07.20,yin,,0,0,0,,它们从不再利用一个视图控制器\\N{\\fs12}They're never reusing, ever a view controller.\r\nDialogue: 0,0:45:07.20,0:45:09.10,yin,,0,0,0,,这对segue是根本的\\N{\\fs12}That's fundamental to a segue.\r\nDialogue: 0,0:45:09.10,0:45:11.76,yin,,0,0,0,,它总会给出新实例\\N{\\fs12}It gives you a new instance all the time.\r\nDialogue: 0,0:45:11.76,0:45:15.14,yin,,0,0,0,,这里这将是一个新实例 它会替换掉detail\\N{\\fs12}So here it would be a new instance and it would replace the detail.\r\nDialogue: 0,0:45:15.14,0:45:16.23,yin,,0,0,0,,这叫替换segue\\N{\\fs12}It's called a replace segue.\r\nDialogue: 0,0:45:16.23,0:45:18.21,yin,,0,0,0,,要做这个 你只需要control拖动\\N{\\fs12}And to do that you just control drag.\r\nDialogue: 0,0:45:18.21,0:45:21.52,yin,,0,0,0,,类型不选push 而选replace\\N{\\fs12}And the kind, it's instead of being push, you pick replace.\r\nDialogue: 0,0:45:21.52,0:45:25.55,yin,,0,0,0,,这只在SplitView中有效\\N{\\fs12}It will only work when you're doing it inside of a SplitView.\r\nDialogue: 0,0:45:27.18,0:45:30.28,yin,,0,0,0,,iPad要讲的最后一点是弹窗\\N{\\fs12}Last thing we're going to talk about on iPad is popovers.\r\nDialogue: 0,0:45:30.28,0:45:32.03,yin,,0,0,0,,弹窗是这样的\\N{\\fs12}So this is what a popover looks like.\r\nDialogue: 0,0:45:32.03,0:45:36.08,yin,,0,0,0,,这是一个TableView 弹窗内有一些方程式\\N{\\fs12}Okay. There's the little TableView with the equations in it inside a popover.\r\nDialogue: 0,0:45:36.08,0:45:41.09,yin,,0,0,0,,弹窗控制器PopoverController类并不是UIViewController\\N{\\fs12}And popover controller, the class, is actually not a UI View Controller.\r\nDialogue: 0,0:45:41.09,0:45:43.63,yin,,0,0,0,,PopoverController是一个NSObject\\N{\\fs12}Popover controller is an NS object.\r\nDialogue: 0,0:45:43.63,0:45:48.88,yin,,0,0,0,,它的作用是控制另一个视图控制器 弹出到屏幕上\\N{\\fs12}But what it does is it controls another view controller popping up on screen.\r\nDialogue: 0,0:45:48.88,0:45:52.03,yin,,0,0,0,,做法是通过这个属性 contentViewController\\N{\\fs12}And it does that with this property content view controller.\r\nDialogue: 0,0:45:52.03,0:45:54.07,yin,,0,0,0,,你在UIPopoverController上设置这个\\N{\\fs12}You set that on the UI popover controller.\r\nDialogue: 0,0:45:54.07,0:45:56.87,yin,,0,0,0,,通常 你control拖动它到故事板\\N{\\fs12}Usually you control drag it into storyboard.\r\nDialogue: 0,0:45:56.87,0:46:01.36,yin,,0,0,0,,因此 这个属性几乎不需要直接设置\\N{\\fs12}So you almost never actually set this property directly.\r\nDialogue: 0,0:46:01.36,0:46:04.89,yin,,0,0,0,,设定这个segue后\\N{\\fs12}And when you set it, that segue.\r\nDialogue: 0,0:46:04.89,0:46:08.65,yin,,0,0,0,,当用户点击触发segue的东西时\\N{\\fs12}When the person clicks on it -- the thing that's going to cause the segue --\r\nDialogue: 0,0:46:08.65,0:46:11.43,yin,,0,0,0,,你会得到prepareForSegue 因为这是一个segue\\N{\\fs12}you're going to get prepare for segue because it's a segue.\r\nDialogue: 0,0:46:11.43,0:46:13.13,yin,,0,0,0,,不过这里有一点很特殊\\N{\\fs12}But there's a special thing there,\r\nDialogue: 0,0:46:13.13,0:46:15.50,yin,,0,0,0,,也就是 你将得到的segue将是\\N{\\fs12}which is that the segue you get is going to be a subclass\r\nDialogue: 0,0:46:15.50,0:46:19.18,yin,,0,0,0,,UIStoryboardPopoverSegue的子类\\N{\\fs12}of UI storyboard popover segue.\r\nDialogue: 0,0:46:19.18,0:46:22.29,yin,,0,0,0,,你可以检查这些类 如果是\\N{\\fs12}And so you can check this kind of class, and if it is,\r\nDialogue: 0,0:46:22.29,0:46:25.46,yin,,0,0,0,,你可以让segue给你弹窗控制器\\N{\\fs12}you can ask the segue, give me the popover controller --\r\nDialogue: 0,0:46:25.46,0:46:26.61,yin,,0,0,0,,UIPopoverController\\N{\\fs12}UI popover controller --\r\nDialogue: 0,0:46:26.61,0:46:28.96,yin,,0,0,0,,控制这个要弹出的窗口\\N{\\fs12}that controls this thing that's going to popover.\r\nDialogue: 0,0:46:28.96,0:46:30.97,yin,,0,0,0,,不过大多数弹窗\\N{\\fs12}But mostly popovers are just a matter\r\nDialogue: 0,0:46:30.97,0:46:33.76,yin,,0,0,0,,只是去找你要弹出的视图控制器\\N{\\fs12}of finding the view controller that you want to pop up.\r\nDialogue: 0,0:46:33.76,0:46:35.52,yin,,0,0,0,,control拖动到其中\\N{\\fs12}Control drag into it.\r\nDialogue: 0,0:46:35.52,0:46:40.74,yin,,0,0,0,,设定弹窗segue的类型 然后释放\\N{\\fs12}Setting the type of segue to be popover, and letting it go.\r\nDialogue: 0,0:46:40.74,0:46:42.95,yin,,0,0,0,,为segue做好准备 然后就好了\\N{\\fs12}And just prepare for segue and off you go.\r\nDialogue: 0,0:46:42.95,0:46:44.25,yin,,0,0,0,,这是很普通的segue\\N{\\fs12}It's a normal segue.\r\nDialogue: 0,0:46:44.25,0:46:46.01,yin,,0,0,0,,重复一次 这是一个segue\\N{\\fs12}And again, it's a segue so the\r\nDialogue: 0,0:46:46.01,0:46:48.78,yin,,0,0,0,,因此要放到弹窗内的视图控制器会实例化\\N{\\fs12}view controller that's going to be put inside the popover is instantiated.\r\nDialogue: 0,0:46:48.78,0:46:52.14,yin,,0,0,0,,全新的一个 使用故事板中的内容\\N{\\fs12}A brand new one; using whatever's in storyboard.\r\nDialogue: 0,0:46:52.14,0:46:54.44,yin,,0,0,0,,弹窗在故事板中很容易\\N{\\fs12}So popovers are actually really easy in the storyboard.\r\nDialogue: 0,0:46:54.44,0:46:56.13,yin,,0,0,0,,只需要control拖动 这就好了\\N{\\fs12}You just control, drag, boom you're done.\r\nDialogue: 0,0:46:56.13,0:46:57.92,yin,,0,0,0,,有时 你都不需要做这些事\\N{\\fs12}And sometimes you don't even need to do this business\r\nDialogue: 0,0:46:57.92,0:47:00.78,yin,,0,0,0,,为segue做准备 因为你不需要同弹窗控制器对话\\N{\\fs12}and prepare for segue because you don't need to talk to the popover controller.\r\nDialogue: 0,0:47:00.78,0:47:03.06,yin,,0,0,0,,你只需要同你要segue到的东西对话\\N{\\fs12}You just need to talk to the thing you're segueing to.\r\nDialogue: 0,0:47:03.06,0:47:05.90,yin,,0,0,0,,设定带有方程的TableView\\N{\\fs12}Set up that TableView with the equations in it --\r\nDialogue: 0,0:47:05.90,0:47:09.00,yin,,0,0,0,,y=x cosx 或是别的什么\\N{\\fs12}y=x cosine x or whatever was in there.\r\nDialogue: 0,0:47:09.00,0:47:11.54,yin,,0,0,0,,你只需要设置这些 你都不需要弹窗控制器\\N{\\fs12}You just need to set that up. So you don't even need the popover controller.\r\nDialogue: 0,0:47:11.54,0:47:16.39,yin,,0,0,0,,你只需要同弹窗内的东西展开对话\\N{\\fs12}You just need to talk directly to the thing inside the popover.\r\nDialogue: 0,0:47:16.39,0:47:18.85,yin,,0,0,0,,用户要取消弹窗\\N{\\fs12}The user dismisses a popover\r\nDialogue: 0,0:47:18.85,0:47:20.73,yin,,0,0,0,,只需要点击外面任何地方\\N{\\fs12}by just touching anywhere outside of it.\r\nDialogue: 0,0:47:20.73,0:47:23.32,yin,,0,0,0,,点击外面任何地方 弹窗就会消失\\N{\\fs12}If they touch outside of it the popover dismisses.\r\nDialogue: 0,0:47:23.32,0:47:27.29,yin,,0,0,0,,这里有一个例外 如果用户点击外面\\N{\\fs12}You can -- there is an exception if they touch outside\r\nDialogue: 0,0:47:27.29,0:47:31.67,yin,,0,0,0,,但点击的是弹窗控制器中这个视图数组中的视图\\N{\\fs12}of it, but they touch on a view that's in this array of views in the popover controller,\r\nDialogue: 0,0:47:31.67,0:47:32.99,yin,,0,0,0,,这就会出现例外\\N{\\fs12}those are like exceptions.\r\nDialogue: 0,0:47:32.99,0:47:35.22,yin,,0,0,0,,这时 弹窗就不会消失\\N{\\fs12}Those won't cause it to dismiss.\r\nDialogue: 0,0:47:35.22,0:47:38.29,yin,,0,0,0,,一个很烦人的情况是工具栏\\N{\\fs12}One thing -- annoying case of this is a toolbar.\r\nDialogue: 0,0:47:38.29,0:47:40.80,yin,,0,0,0,,整个工具栏处在passthroughViews中\\N{\\fs12}The entire toolbar is in the passthroughViews.\r\nDialogue: 0,0:47:40.80,0:47:43.61,yin,,0,0,0,,如果从工具栏上点击按钮弹出一个窗口\\N{\\fs12}So if you bring up a popover from a button in a toolbar,\r\nDialogue: 0,0:47:43.61,0:47:45.73,yin,,0,0,0,,然后用户点击工具栏上别的地方\\N{\\fs12}then if the user clicks anywhere else in the toolbar --\r\nDialogue: 0,0:47:45.73,0:47:49.03,yin,,0,0,0,,例如另一个按钮 这个弹窗不会消失\\N{\\fs12}like on another button -- it won't dismiss that popover.\r\nDialogue: 0,0:47:49.03,0:47:51.20,yin,,0,0,0,,为什么要这样设计 我不知道\\N{\\fs12}Why they decided to do that, I do not know.\r\nDialogue: 0,0:47:51.20,0:47:54.04,yin,,0,0,0,,反正 这个passthroughViews就是这样\\N{\\fs12}But that's what this pass through views thing is.\r\nDialogue: 0,0:47:54.04,0:47:55.43,yin,,0,0,0,,这可能会很烦人\\N{\\fs12}It can be annoying.\r\nDialogue: 0,0:47:55.43,0:47:57.19,yin,,0,0,0,,你也可以自己设置\\N{\\fs12}But you can set it yourself too.\r\nDialogue: 0,0:47:57.19,0:48:01.79,yin,,0,0,0,,你可以说 如果点击这里 我不希望弹窗消失\\N{\\fs12}You can say, well if they click over here, I don't want to dismiss that popover.\r\nDialogue: 0,0:48:01.79,0:48:04.32,yin,,0,0,0,,你也可以在代码中让弹窗消失\\N{\\fs12}You can dismiss popovers from code by just saying,\r\nDialogue: 0,0:48:04.32,0:48:07.16,yin,,0,0,0,,使用dismissPopoverAnimated 在UIPopoverController中\\N{\\fs12}dismisspopover animated, in UI Popover Controller,\r\nDialogue: 0,0:48:07.16,0:48:08.88,yin,,0,0,0,,这样它就会消失\\N{\\fs12}and that will dismiss it.\r\nDialogue: 0,0:48:08.88,0:48:12.54,yin,,0,0,0,,你还可以弄清用户是否让它消失\\N{\\fs12}And you can find out if the user dismissed it using\r\nDialogue: 0,0:48:12.54,0:48:15.72,yin,,0,0,0,,使用popoverControllerDidDismissPopover\\N{\\fs12}popovercontroller diddismiss thispopover.\r\nDialogue: 0,0:48:15.72,0:48:18.20,yin,,0,0,0,,这是一个UIPopoverControllerDelegate方法\\N{\\fs12}This is a UI Popover Controller delegate method.\r\nDialogue: 0,0:48:18.20,0:48:21.30,yin,,0,0,0,,如果UIPopoverController有一个委托 而且你设置了\\N{\\fs12}So if UI Popover Controller has a delegate, and if you set that delegate\r\nDialogue: 0,0:48:21.30,0:48:24.17,yin,,0,0,0,,你就会在用户取消弹窗时获得这个信息\\N{\\fs12}you'll get this message when the user dismisses the popover.\r\nDialogue: 0,0:48:24.17,0:48:28.34,yin,,0,0,0,,通常 你不需要弄清这个 不过有时这个可能会有用\\N{\\fs12}You usually don't need to find this out, but sometimes you want to know.\r\nDialogue: 0,0:48:28.34,0:48:29.48,yin,,0,0,0,,这是弹窗\\N{\\fs12}So that's popovers.\r\nDialogue: 0,0:48:29.48,0:48:32.45,yin,,0,0,0,,这周的作业中我不要求你们使用弹窗\\N{\\fs12}We're not going to -- I'm not going to ask you to do popovers in your homework this week.\r\nDialogue: 0,0:48:32.45,0:48:35.66,yin,,0,0,0,,我会把它布置到下周 它也不在我的演示中\\N{\\fs12}I'll try to fit it into next weeks, and it's not in my demo either.\r\nDialogue: 0,0:48:35.66,0:48:39.49,yin,,0,0,0,,弹窗这个可能会有些模糊\\N{\\fs12}So popovers are going to remain probably a little bit, you know,\r\nDialogue: 0,0:48:39.49,0:48:41.31,yin,,0,0,0,,直到我们进行演示\\N{\\fs12}fuzzy to you until we do a demo.\r\nDialogue: 0,0:48:41.31,0:48:43.47,yin,,0,0,0,,这是演示\\N{\\fs12}So here is the demo.\r\nDialogue: 0,0:48:43.47,0:48:44.99,yin,,0,0,0,,名字叫Shutterbug(摄影迷)\\N{\\fs12}It's called Shutter Bug.\r\nDialogue: 0,0:48:44.99,0:48:49.20,yin,,0,0,0,,我将有一个TableView\\N{\\fs12}And what it's going to be is I'm going to have a TableView full\r\nDialogue: 0,0:48:49.20,0:48:57.05,yin,,0,0,0,,其中有一两百张Flickr上最新发布的照片\\N{\\fs12}of a list of a couple of hundred of the most recently posted photos on Flickr.\r\nDialogue: 0,0:48:58.15,0:49:00.68,yin,,0,0,0,,我会访问Flickr\\N{\\fs12}So I'm going to query Flickr with, you know, URL.\r\nDialogue: 0,0:49:00.68,0:49:02.95,yin,,0,0,0,,并获得这些信息\\N{\\fs12}Go out there and query Flickr and get this information.\r\nDialogue: 0,0:49:02.95,0:49:05.10,yin,,0,0,0,,然后用信息填满TableView\\N{\\fs12}Load up the TableView with it,\r\nDialogue: 0,0:49:05.10,0:49:06.20,yin,,0,0,0,,点击它时\\N{\\fs12}and when you click on it we'll use\r\nDialogue: 0,0:49:06.20,0:49:10.23,yin,,0,0,0,,我们会用Imaginarium的图像视图控制器来显示照片\\N{\\fs12}our image view controller from Imaginarium to display the photo.\r\nDialogue: 0,0:49:10.23,0:49:14.09,yin,,0,0,0,,然后我会在iPhone和iPad上这样做\\N{\\fs12}And then I'm going to do that on the iPhone; and I'm going to do it on iPad as well.\r\nDialogue: 0,0:49:14.09,0:49:16.10,yin,,0,0,0,,演示就是这样了\\N{\\fs12}So that's what the demo's going to be.\r\nDialogue: 0,0:49:16.10,0:49:18.82,yin,,0,0,0,,这里你们会看到很多东西\\N{\\fs12}And you'll see a lot of stuff here.\r\nDialogue: 0,0:49:18.82,0:49:22.33,yin,,0,0,0,,好 把这个挪开\\N{\\fs12}Alright. So let's get this out of the way.\r\nDialogue: 0,0:49:28.77,0:49:31.66,yin,,0,0,0,,这是接下来的一些东西\\N{\\fs12}I'll show you the coming attractions here.\r\nDialogue: 0,0:49:31.66,0:49:34.17,yin,,0,0,0,,作业今天布置 一周后交\\N{\\fs12}Your homework that's going out today is due in a week --\r\nDialogue: 0,0:49:34.17,0:49:37.42,yin,,0,0,0,,下周三 关于所有这些东西\\N{\\fs12}next Wednesday -- it's about all this stuff.\r\nDialogue: 0,0:49:37.42,0:49:39.50,yin,,0,0,0,,周五 我们还是有斯坦福专用课外辅导\\N{\\fs12}Again, Friday we have the Stanford only section.\r\nDialogue: 0,0:49:39.50,0:49:41.81,yin,,0,0,0,,下周 我们还会谈到Core Data\\N{\\fs12}And then next week we'll be covering core data.\r\nDialogue: 0,0:49:41.81,0:49:45.99,yin,,0,0,0,,或许我们还会谈到多任务API\\N{\\fs12}And maybe we'll get to some multitasking API as well.\r\nDialogue: 0,0:49:45.99,0:49:49.36,yin,,0,0,0,,好 关掉这个\\N{\\fs12}Alright. Let's close that.\r\nDialogue: 0,0:49:49.36,0:49:55.66,yin,,0,0,0,,我们要在Xcode中创建一个新项目\\N{\\fs12}We're going to create a new -- oops -- new project here in Xcode.\r\nDialogue: 0,0:49:55.66,0:49:58.69,yin,,0,0,0,,名字叫Shutterbug\\N{\\fs12}I'm going to call it Shutter Bug.\r\nDialogue: 0,0:49:58.69,0:50:01.06,yin,,0,0,0,,它将是通用的\\N{\\fs12}And it's going to be universal.\r\nDialogue: 0,0:50:01.06,0:50:03.70,yin,,0,0,0,,不只用于iPhone 而是通用的\\N{\\fs12}So I'm not making it iPhone only; I'm going to make it universal.\r\nDialogue: 0,0:50:03.70,0:50:07.43,yin,,0,0,0,,我会得到两个故事板 点击这个\\N{\\fs12}So I'm going to get two storyboards out of this when I click this.\r\nDialogue: 0,0:50:07.43,0:50:10.45,yin,,0,0,0,,这些东西还是放到老地方\\N{\\fs12}We'll put it in at the same place we always put everything.\r\nDialogue: 0,0:50:10.45,0:50:12.88,yin,,0,0,0,,这里可以看到 两个故事板\\N{\\fs12}So here it is, and you can see two storyboards.\r\nDialogue: 0,0:50:12.88,0:50:15.34,yin,,0,0,0,,这里有一个iPhone故事板\\N{\\fs12}There's an iPhone storyboard right here.\r\nDialogue: 0,0:50:15.34,0:50:17.48,yin,,0,0,0,,这里有一个iPad故事板\\N{\\fs12}And here's an iPad storyboard.\r\nDialogue: 0,0:50:17.48,0:50:21.57,yin,,0,0,0,,这两个中间我什么都不想要\\N{\\fs12}And so I don't really want anything in either of these,\r\nDialogue: 0,0:50:21.57,0:50:24.50,yin,,0,0,0,,这里有一个巨大的视图 我打算删掉\\N{\\fs12}so I've got this gigantic view here, so I'm just going to delete that.\r\nDialogue: 0,0:50:24.50,0:50:26.88,yin,,0,0,0,,iPhone也是一样 把这个删掉\\N{\\fs12}And same thing iPhone. I've got this one right here, I'm going to delete that.\r\nDialogue: 0,0:50:26.88,0:50:29.90,yin,,0,0,0,,这两个我都打算从完全空白的故事板开始\\N{\\fs12}So I'm going to start with completely blank storyboards in both.\r\nDialogue: 0,0:50:29.90,0:50:31.78,yin,,0,0,0,,首先建立iPhone这个\\N{\\fs12}And we'll build the iPhone one first.\r\nDialogue: 0,0:50:31.78,0:50:35.17,yin,,0,0,0,,然后再转到iPad\\N{\\fs12}Then we'll switch over to the iPad.\r\nDialogue: 0,0:50:35.17,0:50:37.85,yin,,0,0,0,,这是一个基于TableView的app\\N{\\fs12}So this is going to be a TableView-based app.\r\nDialogue: 0,0:50:37.85,0:50:41.62,yin,,0,0,0,,我只需要选一个TableView 然后拖出来\\N{\\fs12}So I'm just going to pick up a TableView out of here and drag it out.\r\nDialogue: 0,0:50:41.62,0:50:43.31,yin,,0,0,0,,这是我的TableView\\N{\\fs12}So here's my TableView.\r\nDialogue: 0,0:50:43.31,0:50:46.49,yin,,0,0,0,,显然 我要把它的类\\N{\\fs12}Of course I'm going to want to set its class\r\nDialogue: 0,0:50:46.49,0:50:49.63,yin,,0,0,0,,设置为UITableViewController的子类\\N{\\fs12}to be some subclass of UI TableView Controller.\r\nDialogue: 0,0:50:49.63,0:50:51.70,yin,,0,0,0,,我们照这样来做\\N{\\fs12}So let's go do that. Let's make that.\r\nDialogue: 0,0:50:53.23,0:50:54.74,yin,,0,0,0,,这是一个类\\N{\\fs12}Alright. It's a class.\r\nDialogue: 0,0:50:54.74,0:50:57.90,yin,,0,0,0,,它是UITableViewController的子类\\N{\\fs12}It's going to be a subclass of UI TableView Controller.\r\nDialogue: 0,0:50:57.90,0:51:02.97,yin,,0,0,0,,这个我打算取名为FlickrPhotosTVC\\N{\\fs12}I'm going to call this thing Flickr Photos TVC --\r\nDialogue: 0,0:51:02.97,0:51:04.91,yin,,0,0,0,,TVC表示表格视图控制器\\N{\\fs12}for TableView Controller. Because that's what it's going to do.\r\nDialogue: 0,0:51:04.91,0:51:07.93,yin,,0,0,0,,这是一个显示Flickr照片的表格视图控制器\\N{\\fs12}It's going to be a TableView Controller that shows Flickr photos.\r\nDialogue: 0,0:51:07.93,0:51:10.28,yin,,0,0,0,,把它放到标准位置\\N{\\fs12}And I'll put it in the normal places.\r\nDialogue: 0,0:51:10.28,0:51:11.26,yin,,0,0,0,,有了\\N{\\fs12}Here we go.\r\nDialogue: 0,0:51:11.26,0:51:16.19,yin,,0,0,0,,到这里 将其设为当前的类\\N{\\fs12}Let's go over here and we'll set that to be our class for now.\r\nDialogue: 0,0:51:16.19,0:51:22.13,yin,,0,0,0,,看这个类 其中有所有这些代码\\N{\\fs12}And so now, if I look at this class, this is going to have all of my code in it.\r\nDialogue: 0,0:51:22.13,0:51:25.16,yin,,0,0,0,,这里有很多东西\\N{\\fs12}Now it comes with a lot of stuff.\r\nDialogue: 0,0:51:25.16,0:51:27.18,yin,,0,0,0,,有视图控制器生命周期的东西\\N{\\fs12}Here's my view controller lifecycle stuff that it has,\r\nDialogue: 0,0:51:27.18,0:51:29.52,yin,,0,0,0,,我要把这些删除掉\\N{\\fs12}I'm going to get rid of that.\r\nDialogue: 0,0:51:29.52,0:51:32.14,yin,,0,0,0,,它有这个表格视图数据源的东西\\N{\\fs12}It comes with this TableView datasource stuff --\r\nDialogue: 0,0:51:32.14,0:51:35.28,yin,,0,0,0,,顺便说下 我喜欢改变这里的pragma\\N{\\fs12}by the way I like to change this pragma\r\nDialogue: 0,0:51:35.28,0:51:36.88,yin,,0,0,0,,让它像这样\\N{\\fs12}to be -- to look like this.\r\nDialogue: 0,0:51:36.88,0:51:38.53,yin,,0,0,0,,这样我更容易看\\N{\\fs12}It's a little easier for me to see.\r\nDialogue: 0,0:51:38.53,0:51:41.63,yin,,0,0,0,,这将是TableViewDatasource方法\\N{\\fs12}And this is the -- going to be the TableView datasource\r\nDialogue: 0,0:51:41.63,0:51:43.04,yin,,0,0,0,,认识这三个吧\\N{\\fs12}method. Do you recognize those three?\r\nDialogue: 0,0:51:43.04,0:51:44.16,yin,,0,0,0,,section数目\\N{\\fs12}Number of sections?\r\nDialogue: 0,0:51:44.16,0:51:44.80,yin,,0,0,0,,行数\\N{\\fs12}Number of rows?\r\nDialogue: 0,0:51:44.80,0:51:46.45,yin,,0,0,0,,我们会实现这些\\N{\\fs12}So we're going to implement those.\r\nDialogue: 0,0:51:46.45,0:51:50.47,yin,,0,0,0,,注释掉的内容 为编辑表格提供了很多东西\\N{\\fs12}Comment it out down here it gives you a lot of stuff for editing the table.\r\nDialogue: 0,0:51:50.47,0:51:52.57,yin,,0,0,0,,四处移动 诸如此类\\N{\\fs12}Moving things around, stuff like that.\r\nDialogue: 0,0:51:52.57,0:51:55.96,yin,,0,0,0,,今天我不打算讲这些 你可以闲暇时看看\\N{\\fs12}We're not going to cover any of that today. You can review at your leisure.\r\nDialogue: 0,0:51:55.96,0:51:58.46,yin,,0,0,0,,然后显然是导航 这是prepareForSegue\\N{\\fs12}And then of course navigation, which is prepare for segue,\r\nDialogue: 0,0:51:58.46,0:52:01.24,yin,,0,0,0,,后面我们会做这个\\N{\\fs12}we are going to do that a little bit later.\r\nDialogue: 0,0:52:01.24,0:52:03.13,yin,,0,0,0,,这里我们有了一个新类\\N{\\fs12}So we have a new class here.\r\nDialogue: 0,0:52:03.13,0:52:05.16,yin,,0,0,0,,我们谈谈它的公共API\\N{\\fs12}Let's talk about its public API.\r\nDialogue: 0,0:52:05.18,0:52:07.70,yin,,0,0,0,,这个的公共API很简单\\N{\\fs12}And this one's going to have easy public API.\r\nDialogue: 0,0:52:07.70,0:52:13.81,yin,,0,0,0,,这是一个strong NSArray 我们称之为photos\\N{\\fs12}Which is a strong NS array, which we'll call photos.\r\nDialogue: 0,0:52:13.81,0:52:17.86,yin,,0,0,0,,这将是Flickr照片NSDictionary中的\\N{\\fs12}And this is going to be of Flickr photo NS dictionaries.\r\nDialogue: 0,0:52:17.86,0:52:20.90,yin,,0,0,0,,这些是我从Flickr下载的字典\\N{\\fs12}So these are going to be dictionaries that I'm going to download from Flickr.\r\nDialogue: 0,0:52:20.90,0:52:24.86,yin,,0,0,0,,在Flickr上 这些字典有关于照片的信息\\N{\\fs12}And these dictionaries have information about photos that are on Flickr.\r\nDialogue: 0,0:52:24.86,0:52:26.17,yin,,0,0,0,,这里不过是这些\\N{\\fs12}So that's all these are.\r\nDialogue: 0,0:52:26.17,0:52:28.80,yin,,0,0,0,,字典 带有一系列关于照片的键和值\\N{\\fs12}Dictionaries with a bunch of keys and values in there about photos.\r\nDialogue: 0,0:52:28.80,0:52:30.30,yin,,0,0,0,,并不是实际的图像数据\\N{\\fs12}Not the actual image data --\r\nDialogue: 0,0:52:30.30,0:52:31.83,yin,,0,0,0,,那些需要单独取用\\N{\\fs12}I'll have to fetch that separately.\r\nDialogue: 0,0:52:31.83,0:52:34.40,yin,,0,0,0,,这里只是关于照片的信息\\N{\\fs12}But just information about it.\r\nDialogue: 0,0:52:34.40,0:52:38.77,yin,,0,0,0,,有一点我要确保自己做了 也就是模型变化时\\N{\\fs12}And one thing I really want to make sure that I do, is that when my model changes --\r\nDialogue: 0,0:52:38.77,0:52:43.75,yin,,0,0,0,,当有人设置照片… 哦…\\N{\\fs12}so someone sets the photos -- oops --\r\nDialogue: 0,0:52:45.36,0:52:47.16,yin,,0,0,0,,重来一次\\N{\\fs12}I do this again -- this is doing this again --\r\nDialogue: 0,0:52:47.16,0:52:52.45,yin,,0,0,0,,如果有人设置了这个照片数组\\N{\\fs12}so if someone sets this array of photos --\r\nDialogue: 0,0:52:54.03,0:52:59.75,yin,,0,0,0,,那么我就要确保我的TableView更新了\\N{\\fs12}then I'm going to make sure that I update my TableView.\r\nDialogue: 0,0:53:02.42,0:53:05.26,yin,,0,0,0,,是叫这个吧 重载[声音不清]时 对\\N{\\fs12}Is that what it's called when you reload [inaudible] yeah.\r\nDialogue: 0,0:53:05.26,0:53:08.41,yin,,0,0,0,,只要模型发生变化 我就需要\\N{\\fs12}And that's just -- any time a model changes, obviously I want\r\nDialogue: 0,0:53:08.41,0:53:10.68,yin,,0,0,0,,重载表格中的数据\\N{\\fs12}to reload my data in my table.\r\nDialogue: 0,0:53:10.68,0:53:11.59,yin,,0,0,0,,这很好理解\\N{\\fs12}That makes sense.\r\nDialogue: 0,0:53:11.59,0:53:13.97,yin,,0,0,0,,我如何设置这个呢\\N{\\fs12}Now how am I going to set this?\r\nDialogue: 0,0:53:13.97,0:53:15.48,yin,,0,0,0,,如何调用setPhotos\\N{\\fs12}How am I going to call set photos?\r\nDialogue: 0,0:53:15.48,0:53:16.99,yin,,0,0,0,,如何获得这些Flickr数据\\N{\\fs12}How am I going to get this Flickr data?\r\nDialogue: 0,0:53:16.99,0:53:18.13,yin,,0,0,0,,代码放到哪\\N{\\fs12}Where am I going to put that code?\r\nDialogue: 0,0:53:18.13,0:53:20.81,yin,,0,0,0,,我不打算把代码放到这个类中\\N{\\fs12}Well I don't actually want to put that in this class.\r\nDialogue: 0,0:53:20.81,0:53:22.57,yin,,0,0,0,,因为我希望这个类是通用的\\N{\\fs12}Because I want this class to be a generic,\r\nDialogue: 0,0:53:22.57,0:53:24.86,yin,,0,0,0,,Flickr照片浏览类\\N{\\fs12}Flickr photo viewing class.\r\nDialogue: 0,0:53:24.86,0:53:28.41,yin,,0,0,0,,我不希望它只能针对特定的一系列照片\\N{\\fs12}I don't want it to be specific to any particular set of photos,\r\nDialogue: 0,0:53:28.41,0:53:30.44,yin,,0,0,0,,我打算为此建立一个具体的子类\\N{\\fs12}so I'm going to make a concrete subclass of this --\r\nDialogue: 0,0:53:30.44,0:53:34.35,yin,,0,0,0,,这不是一个抽象类 因为它能独自工作\\N{\\fs12}okay, so this is not really an abstract class because it kind of works on its own.\r\nDialogue: 0,0:53:34.35,0:53:37.90,yin,,0,0,0,,我打算建立一个具体的子类\\N{\\fs12}But I'm going to make a -- essentially like a concrete subclass of it.\r\nDialogue: 0,0:53:37.90,0:53:41.37,yin,,0,0,0,,它是FlickrPhotosTVC的一个子类\\N{\\fs12}It's a subclass of Flickr photos TVC.\r\nDialogue: 0,0:53:41.37,0:53:49.11,yin,,0,0,0,,起名为JustPostedFlikrPhotosTVC\\N{\\fs12}And I'm going to call it, justposted flikrphotostvc.\r\nDialogue: 0,0:53:49.13,0:53:51.16,yin,,0,0,0,,它是FlickrPhotosTVC的一个子类\\N{\\fs12}So it's going to be a subclass of that and it's going\r\nDialogue: 0,0:53:51.16,0:53:53.42,yin,,0,0,0,,用于显示刚刚发布的那些\\N{\\fs12}to show me the ones that have just been posted.\r\nDialogue: 0,0:53:53.42,0:53:57.02,yin,,0,0,0,,我们创建这个 到这里\\N{\\fs12}So let's create that in here.\r\nDialogue: 0,0:53:57.02,0:53:59.46,yin,,0,0,0,,我们得到了这个新的\\N{\\fs12}So we have this new one here.\r\nDialogue: 0,0:53:59.46,0:54:04.11,yin,,0,0,0,,它只需要调用self.photos\\N{\\fs12}And it's just -- all it's going to do is call self.photos\r\nDialogue: 0,0:54:04.11,0:54:05.96,yin,,0,0,0,,来设置这里的模型\\N{\\fs12}to set this model right here.\r\nDialogue: 0,0:54:05.96,0:54:09.45,yin,,0,0,0,,在故事板中 我们换个类\\N{\\fs12}So in our storyboard, let's change our class here.\r\nDialogue: 0,0:54:09.45,0:54:11.74,yin,,0,0,0,,我们将从FlickrPhotosTVC\\N{\\fs12}Instead of being flickrsphotostvc,\r\nDialogue: 0,0:54:11.74,0:54:17.34,yin,,0,0,0,,切换到JustPostedFlikrPhotosTVC\\N{\\fs12}I'm going to change this to be justpostedflickr photostvc.\r\nDialogue: 0,0:54:17.35,0:54:20.99,yin,,0,0,0,,这就会显示刚刚发布的那些\\N{\\fs12}So now that's going to show my just posted ones.\r\nDialogue: 0,0:54:20.99,0:54:23.63,yin,,0,0,0,,刚刚发布的这些如何实现呢\\N{\\fs12}So what about the implementation of this just posted?\r\nDialogue: 0,0:54:23.63,0:54:24.46,yin,,0,0,0,,很简单\\N{\\fs12}It's really easy.\r\nDialogue: 0,0:54:24.46,0:54:27.97,yin,,0,0,0,,我只需要在viewDidLoad中\\N{\\fs12}I just in my view id load --\r\nDialogue: 0,0:54:27.97,0:54:29.89,yin,,0,0,0,,super viewDidLoad\\N{\\fs12}super viewDidLoad,\r\nDialogue: 0,0:54:29.89,0:54:33.76,yin,,0,0,0,,我要调用self fetchPhotos\\N{\\fs12}I'm just going to call selffetchphotos.\r\nDialogue: 0,0:54:33.76,0:54:38.16,yin,,0,0,0,,然后这里创建fetchPhotos方法\\N{\\fs12}And then we'll make a fetchphotos method here.\r\nDialogue: 0,0:54:38.16,0:54:41.32,yin,,0,0,0,,这里写 self.photos=什么东西\\N{\\fs12}And I'm just going to say self.photos= something.\r\nDialogue: 0,0:54:41.32,0:54:46.11,yin,,0,0,0,,我将在这里取回照片\\N{\\fs12}That's -- I'm going to get my photos here.\r\nDialogue: 0,0:54:46.11,0:54:47.82,yin,,0,0,0,,这里有什么问题\\N{\\fs12}Alright, what's the problem here?\r\nDialogue: 0,0:54:48.71,0:54:51.73,yin,,0,0,0,,根类 这很奇怪\\N{\\fs12}Root class -- hmm that's weird.\r\nDialogue: 0,0:54:51.73,0:54:54.16,yin,,0,0,0,,哦 奇怪了\\N{\\fs12}Oh. Strange.\r\nDialogue: 0,0:54:55.59,0:54:56.96,yin,,0,0,0,,FlickrPhotosTVC\\N{\\fs12}Flickrphotostvc.\r\nDialogue: 0,0:54:56.96,0:55:02.29,yin,,0,0,0,,好 我不知道为什么没有加上这个\\N{\\fs12}Okay. I'm not sure why it didn't add that.\r\nDialogue: 0,0:55:02.29,0:55:07.99,yin,,0,0,0,,好 就是这样了 这很好\\N{\\fs12}Okay. So there we go. Alright so that's good.\r\nDialogue: 0,0:55:07.99,0:55:10.13,yin,,0,0,0,,在这里 我们需要\\N{\\fs12}So that's where -- so in here is where we're going to have to go\r\nDialogue: 0,0:55:10.13,0:55:12.38,yin,,0,0,0,,去取Flickr照片\\N{\\fs12}out to make a fetch to Flickr and do that.\r\nDialogue: 0,0:55:12.38,0:55:13.87,yin,,0,0,0,,我们来写这段代码\\N{\\fs12}So let's go ahead and write that code.\r\nDialogue: 0,0:55:13.87,0:55:15.17,yin,,0,0,0,,很简单\\N{\\fs12}Pretty straight forward.\r\nDialogue: 0,0:55:15.17,0:55:17.11,yin,,0,0,0,,我们需要一点辅助代码\\N{\\fs12}One thing we're going to need though is a little bit\r\nDialogue: 0,0:55:17.11,0:55:19.67,yin,,0,0,0,,帮助我们取用Flickr数据\\N{\\fs12}of helper code to help us with those Flickr fetches.\r\nDialogue: 0,0:55:19.67,0:55:21.97,yin,,0,0,0,,为了作业需要 这个提供给你们\\N{\\fs12}And I've provided this to you for your homework.\r\nDialogue: 0,0:55:21.97,0:55:22.96,yin,,0,0,0,,在这里\\N{\\fs12}Here it is right here.\r\nDialogue: 0,0:55:22.96,0:55:24.43,yin,,0,0,0,,这是Flickr取用代码\\N{\\fs12}This Flickr fetching code.\r\nDialogue: 0,0:55:25.34,0:55:27.13,yin,,0,0,0,,我们到这里来\\N{\\fs12}Let's go over here to this.\r\nDialogue: 0,0:55:27.13,0:55:30.04,yin,,0,0,0,,拖进来 简单看一下\\N{\\fs12}We can drag this in. We'll take a brief look at this.\r\nDialogue: 0,0:55:30.04,0:55:32.30,yin,,0,0,0,,复制进来\\N{\\fs12}I'm going to copy it in.\r\nDialogue: 0,0:55:32.30,0:55:34.08,yin,,0,0,0,,好 看这个Flickr取用器\\N{\\fs12}Alright. So if you look at this Flickr fetcher,\r\nDialogue: 0,0:55:34.08,0:55:39.23,yin,,0,0,0,,它有这个API 提供这些类方法\\N{\\fs12}it has this API right here that provides these class methods\r\nDialogue: 0,0:55:39.23,0:55:43.44,yin,,0,0,0,,这里有一些URL 你能从中取用Flickr信息\\N{\\fs12}with some URLs that you can fetch information from Flickr.\r\nDialogue: 0,0:55:43.44,0:55:47.50,yin,,0,0,0,,例如 我们会考虑最新地理参考的照片\\N{\\fs12}So we're going to do, for example, recent georeferenced photos.\r\nDialogue: 0,0:55:47.50,0:55:49.80,yin,,0,0,0,,作业中 你们需要考虑顶级位置\\N{\\fs12}For your homework you're going to want to do top places.\r\nDialogue: 0,0:55:49.80,0:55:53.00,yin,,0,0,0,,因为作业中 我要求你们从Flickr中展示位置\\N{\\fs12}Because in your homework you're going to be asked to show places from Flickr.\r\nDialogue: 0,0:55:53.00,0:55:55.97,yin,,0,0,0,,而这里我只显示照片\\N{\\fs12}And I'm just going to be showing only photos.\r\nDialogue: 0,0:55:55.97,0:56:01.00,yin,,0,0,0,,我们打算使用这些URL来取回信息\\N{\\fs12}So we're going to use those URLs to do some fetching.\r\nDialogue: 0,0:56:01.00,0:56:05.75,yin,,0,0,0,,我需要import FlickrFetcher.h 像这样\\N{\\fs12}So I better import flickrfetcher.h so I can do that.\r\nDialogue: 0,0:56:05.75,0:56:07.35,yin,,0,0,0,,这个如何工作呢\\N{\\fs12}And how does this work?\r\nDialogue: 0,0:56:07.35,0:56:12.45,yin,,0,0,0,,获得URL 用此来获得刚发布的照片\\N{\\fs12}Well, let's get the URL that we're going to use to get those just posted photos\r\nDialogue: 0,0:56:12.45,0:56:14.66,yin,,0,0,0,,通过这个FlickrFetcher\\N{\\fs12}from this Flickrfetcher thing,\r\nDialogue: 0,0:56:14.66,0:56:15.74,yin,,0,0,0,,URL\\N{\\fs12}URL.\r\nDialogue: 0,0:56:15.74,0:56:18.31,yin,,0,0,0,,我要这个 最近照片\\N{\\fs12}And so I want this one, recent photos.\r\nDialogue: 0,0:56:18.31,0:56:21.62,yin,,0,0,0,,这样我就有了一个URL 我要获取数据\\N{\\fs12}So now I have a URL. I need to get that data.\r\nDialogue: 0,0:56:21.62,0:56:23.30,yin,,0,0,0,,这是NSData\\N{\\fs12}So that's NSdata.\r\nDialogue: 0,0:56:23.30,0:56:28.90,yin,,0,0,0,,从Flickr取回的数据 格式是JSON\\N{\\fs12}Now the data that comes back from Flickr comes back in a format called JSON.\r\nDialogue: 0,0:56:28.90,0:56:30.95,yin,,0,0,0,,知道JSON的请举手\\N{\\fs12}Raise your hand if you know what JSON is.\r\nDialogue: 0,0:56:30.95,0:56:32.80,yin,,0,0,0,,几乎所有人都知道JSON\\N{\\fs12}Okay, so almost everyone knows what JSON is.\r\nDialogue: 0,0:56:32.80,0:56:36.09,yin,,0,0,0,,我不想要JSON格式 但我别无选择\\N{\\fs12}So I don't want it in JSON, but that's my only choice.\r\nDialogue: 0,0:56:36.09,0:56:38.71,yin,,0,0,0,,我要从JSON中获得结果\\N{\\fs12}So I'm going to get those results in JSON\r\nDialogue: 0,0:56:38.71,0:56:43.15,yin,,0,0,0,,我可以说 NSData dataWithContentsOfURL\\N{\\fs12}by saying NSdata -- datawithcontentsofurl.\r\nDialogue: 0,0:56:43.15,0:56:48.46,yin,,0,0,0,,同之前… dataWithContentsOfURL\\N{\\fs12}Same thing we used datawith contentsofurl.\r\nDialogue: 0,0:56:48.46,0:56:50.48,yin,,0,0,0,,同之前的做法一样\\N{\\fs12}Same thing we did before.\r\nDialogue: 0,0:56:50.48,0:56:52.48,yin,,0,0,0,,不过我不想要JSON格式\\N{\\fs12}But I don't want them in JSON format.\r\nDialogue: 0,0:56:52.48,0:56:55.75,yin,,0,0,0,,我希望格式是数组和字典\\N{\\fs12}Really the format that I want them in is arrays and dictionaries.\r\nDialogue: 0,0:56:55.75,0:56:57.98,yin,,0,0,0,,比起JSON 这些显然更好处理\\N{\\fs12}That's a much nicer format for us to deal with than JSON.\r\nDialogue: 0,0:56:57.98,0:57:01.37,yin,,0,0,0,,JSON很像数组和字典 不过并不完全一样\\N{\\fs12}JSON is like arrays in dictionaries but not exactly the same.\r\nDialogue: 0,0:57:01.37,0:57:05.81,yin,,0,0,0,,幸运的是 iOS中有一种方式能够做到\\N{\\fs12}Luckily, there is a way in IOS to do that.\r\nDialogue: 0,0:57:05.81,0:57:09.87,yin,,0,0,0,,我们将把这些转化为propertyListResults\\N{\\fs12}So we'll change that to basically property list results.\r\nDialogue: 0,0:57:09.87,0:57:12.43,yin,,0,0,0,,将JSON格式转化为属性列表\\N{\\fs12}To turn a JSON thing into a property list,\r\nDialogue: 0,0:57:12.43,0:57:16.34,yin,,0,0,0,,这是JSON… 叫什么来着\\N{\\fs12}and that's with the [inaudible] JSON -- what's called again?\r\nDialogue: 0,0:57:16.34,0:57:18.77,yin,,0,0,0,,NSJSONSerialization\\N{\\fs12}NSjsonserialization.\r\nDialogue: 0,0:57:18.78,0:57:21.48,yin,,0,0,0,,方法叫作JsonObjectWithData\\N{\\fs12}And the method is called jsonobjectwithdata.\r\nDialogue: 0,0:57:21.48,0:57:23.28,yin,,0,0,0,,你给它JSON数据\\N{\\fs12}You give it the JSON data.\r\nDialogue: 0,0:57:23.28,0:57:26.23,yin,,0,0,0,,选项 0 这些你可以自己去查\\N{\\fs12}Options. We'll say 0 -- you can look those up if you want.\r\nDialogue: 0,0:57:26.23,0:57:29.07,yin,,0,0,0,,它可以返回NS错误\\N{\\fs12}And it will return an error and that's -- you know, NS error,\r\nDialogue: 0,0:57:29.07,0:57:31.53,yin,,0,0,0,,不过我们不打算检查 便于演示\\N{\\fs12}but we're not going to check for errors because it's a demo.\r\nDialogue: 0,0:57:31.53,0:57:33.94,yin,,0,0,0,,这样 我就有了字典格式\\N{\\fs12}And so now I have this stuff in dictionary format.\r\nDialogue: 0,0:57:33.94,0:57:36.43,yin,,0,0,0,,在继续推进之前 我们先来看看log\\N{\\fs12}So before we go any further, let's just log this.\r\nDialogue: 0,0:57:36.43,0:57:40.73,yin,,0,0,0,,\"Flickr results = %@\", propertyListResults\\N{\\fs12}Flickrresults =%@property listresults.\r\nDialogue: 0,0:57:40.73,0:57:44.91,yin,,0,0,0,,通过log 我们可以看到它是怎样的\\N{\\fs12}So I'm just going to log this so we can take a look and see what this looks like.\r\nDialogue: 0,0:57:44.91,0:57:48.15,yin,,0,0,0,,运行一下 现在在UI中 它还什么都做不了\\N{\\fs12}So let's just run this. It's not going to do anything in our UI yet,\r\nDialogue: 0,0:57:48.15,0:57:54.89,yin,,0,0,0,,不过它会记录这次数据取回的日志\\N{\\fs12}but hopefully it will log this particular fetch of the fetchworks.\r\nDialogue: 0,0:57:54.89,0:57:58.45,yin,,0,0,0,,哦 似乎没能正常工作\\N{\\fs12}So -- oh, well, no that's not working.\r\nDialogue: 0,0:57:58.45,0:58:00.55,yin,,0,0,0,,糟糕 好吧 让我这样\\N{\\fs12}Well, that's not good -- oh that's okay, let's do this.\r\nDialogue: 0,0:58:00.55,0:58:02.68,yin,,0,0,0,,到这里\\N{\\fs12}Alright let's do it here.\r\nDialogue: 0,0:58:02.68,0:58:05.90,yin,,0,0,0,,因为iPad还没有设置 而它想到iPad上运行\\N{\\fs12}Because we haven't done our iPad one, it's trying to run it on an iPad.\r\nDialogue: 0,0:58:05.90,0:58:09.71,yin,,0,0,0,,我们用模拟器来试下\\N{\\fs12}So we're just going to run it on the simulator here.\r\nDialogue: 0,0:58:09.71,0:58:12.64,yin,,0,0,0,,把模拟器弄小点\\N{\\fs12}So much for our little simulator.\r\nDialogue: 0,0:58:12.64,0:58:14.32,yin,,0,0,0,,我们不打算看UI中的情况\\N{\\fs12}Okay we're not actually going to be looking at anything in UI.\r\nDialogue: 0,0:58:14.32,0:58:17.55,yin,,0,0,0,,它不过是在取回数据 信息显示在这里\\N{\\fs12}So it's doing this fetch, and here's the information right here.\r\nDialogue: 0,0:58:17.57,0:58:20.47,yin,,0,0,0,,放大一些 这样你们就能看到\\N{\\fs12}Let's go ahead and make it big so you can see it.\r\nDialogue: 0,0:58:20.47,0:58:22.48,yin,,0,0,0,,可以看到 这是一个字典\\N{\\fs12}And you can see that it's a dictionary.\r\nDialogue: 0,0:58:22.48,0:58:26.78,yin,,0,0,0,,这个格式就是作为字典进行的记录\\N{\\fs12}This is kind of this little format that is used to log in as dictionaries.\r\nDialogue: 0,0:58:26.78,0:58:29.39,yin,,0,0,0,,字典中 立马有一个键\\N{\\fs12}And inside this dictionary there's a key right off the bat\r\nDialogue: 0,0:58:29.39,0:58:31.96,yin,,0,0,0,,叫作photos 这是另一个字典\\N{\\fs12}called, \"Photos\" which is another dictionary.\r\nDialogue: 0,0:58:31.96,0:58:34.99,yin,,0,0,0,,这个字典中 有处在哪一页\\N{\\fs12}And inside that dictionary there's which page this is --\r\nDialogue: 0,0:58:34.99,0:58:37.37,yin,,0,0,0,,总共有98000页\\N{\\fs12}98,000 pages available, okay?\r\nDialogue: 0,0:58:37.37,0:58:39.09,yin,,0,0,0,,每一页有250项\\N{\\fs12}250 items each.\r\nDialogue: 0,0:58:39.09,0:58:41.06,yin,,0,0,0,,Flickr上发生有很多事情\\N{\\fs12}So a lot going on in Flickr.\r\nDialogue: 0,0:58:41.06,0:58:44.50,yin,,0,0,0,,这里有另外一个键 这个键的值是一个数组\\N{\\fs12}And there's another key here, and the value of this key is an array.\r\nDialogue: 0,0:58:44.50,0:58:46.71,yin,,0,0,0,,这是照片的数组\\N{\\fs12}And this is an array of the photos.\r\nDialogue: 0,0:58:46.71,0:58:48.87,yin,,0,0,0,,每一个都是一个字典\\N{\\fs12}Each one of which is a dictionary.\r\nDialogue: 0,0:58:48.87,0:58:50.69,yin,,0,0,0,,可以看到有很多东西\\N{\\fs12}And you can see there's a lot of stuff\r\nDialogue: 0,0:58:50.69,0:58:55.69,yin,,0,0,0,,在这些字典中 包括这里的照片标题\\N{\\fs12}in these dictionaries including the title of the photo right here.\r\nDialogue: 0,0:58:55.69,0:58:57.22,yin,,0,0,0,,然后还有这个\\N{\\fs12}And there's also this one right here.\r\nDialogue: 0,0:58:57.22,0:58:58.59,yin,,0,0,0,,描述\\N{\\fs12}Description.\r\nDialogue: 0,0:58:58.59,0:59:00.78,yin,,0,0,0,,也就是照片的描述\\N{\\fs12}Which is a description of the photo.\r\nDialogue: 0,0:59:00.78,0:59:02.93,yin,,0,0,0,,这个其实是另一个字典\\N{\\fs12}And this one's actually another dictionary.\r\nDialogue: 0,0:59:02.93,0:59:05.40,yin,,0,0,0,,其中有一个键 这是实际的描述\\N{\\fs12}And inside it is a key that's the actual description --\r\nDialogue: 0,0:59:05.40,0:59:07.46,yin,,0,0,0,,这个的描述是空的\\N{\\fs12}this one had a blank description.\r\nDialogue: 0,0:59:07.46,0:59:11.43,yin,,0,0,0,,从这个照片中获得值有些复杂\\N{\\fs12}So this one's going to be a little more tricky to get this value out of this photo.\r\nDialogue: 0,0:59:11.43,0:59:14.54,yin,,0,0,0,,无论如何 我们需要取出这些东西\\N{\\fs12}But anyway, we're going to have to pull this stuff\r\nDialogue: 0,0:59:14.54,0:59:17.17,yin,,0,0,0,,以一种古怪的格式从字典中去取\\N{\\fs12}out of this dictionary in this kind of odd format.\r\nDialogue: 0,0:59:17.17,0:59:18.73,yin,,0,0,0,,我们下面就来做这个\\N{\\fs12}So let's just do that.\r\nDialogue: 0,0:59:18.73,0:59:26.57,yin,,0,0,0,,要从这里获得照片 我们可以这样写代码\\N{\\fs12}So we can get the photos out of there by saying how about this:\r\nDialogue: 0,0:59:26.57,0:59:31.77,yin,,0,0,0,,propertyListResults valueForKeyPath\\N{\\fs12}propertylist resultsvalue forkeypath.\r\nDialogue: 0,0:59:31.77,0:59:34.22,yin,,0,0,0,,然后在FlickrFetcher中\\N{\\fs12}And then in Flickr fetcher,\r\nDialogue: 0,0:59:34.22,0:59:40.14,yin,,0,0,0,,我有一个很棒的#define定义 来获得这些照片\\N{\\fs12}I have a nice little pound sign define here to get those photos --\r\nDialogue: 0,0:59:40.14,0:59:43.87,yin,,0,0,0,,一开始就从照片字典中取出照片数组\\N{\\fs12}that photo array out of the photos dictionary at the beginning.\r\nDialogue: 0,0:59:43.87,0:59:46.14,yin,,0,0,0,,不过这里有一个点 这很有趣\\N{\\fs12}But this has a dot in it which is interesting.\r\nDialogue: 0,0:59:46.14,0:59:50.25,yin,,0,0,0,,点意思是说 这个键\\N{\\fs12}A dot means this key --\r\nDialogue: 0,0:59:50.25,0:59:54.60,yin,,0,0,0,,这个键 在这个键的字典内\\N{\\fs12}this key, inside of this key -- the dictionary for this key.\r\nDialogue: 0,0:59:54.60,0:59:57.66,yin,,0,0,0,,这相当于追随字典中的字典\\N{\\fs12}So it's kind of like following dictionaries inside dictionaries.\r\nDialogue: 0,0:59:57.66,0:59:59.28,yin,,0,0,0,,这个就是这样了\\N{\\fs12}That's what this thing does.\r\nDialogue: 0,0:59:59.28,1:00:02.38,yin,,0,0,0,,我要用到这个 不过要让它工作\\N{\\fs12}So I'm going to use this, but to make it work\r\nDialogue: 0,1:00:02.38,1:00:05.45,yin,,0,0,0,,我们需要使用valueForKeyPath方法\\N{\\fs12}we have to use this value for key path method\r\nDialogue: 0,1:00:05.45,1:00:07.62,yin,,0,0,0,,而不是使用objectForKey\\N{\\fs12}instead of using object for key, right?\r\nDialogue: 0,1:00:07.62,1:00:10.04,yin,,0,0,0,,像常规字典方法中那样\\N{\\fs12}Which would be a normal dictionary method.\r\nDialogue: 0,1:00:10.04,1:00:12.38,yin,,0,0,0,,我打算这样做\\N{\\fs12}So I'm going to do that.\r\nDialogue: 0,1:00:12.38,1:00:16.72,yin,,0,0,0,,我要处理太多方括号的问题\\N{\\fs12}I'm going to deal with the too many square brackets issue.\r\nDialogue: 0,1:00:16.72,1:00:20.44,yin,,0,0,0,,好 这就能从中取出相片\\N{\\fs12}Okay. So that is going to pull those photos out of there.\r\nDialogue: 0,1:00:20.44,1:00:23.55,yin,,0,0,0,,现在 照片以字典数组的形式存在\\N{\\fs12}So now I have the photos as an array of dictionaries.\r\nDialogue: 0,1:00:23.55,1:00:29.15,yin,,0,0,0,,我打算把我的模型设为这个\\N{\\fs12}And I'm just going to set my model to be that.\r\nDialogue: 0,1:00:29.15,1:00:32.07,yin,,0,0,0,,这不会太难\\N{\\fs12}So that wasn't too hard.\r\nDialogue: 0,1:00:32.07,1:00:32.69,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,1:00:35.28,1:00:36.95,yin,,0,0,0,,问null和nil的区别\\N{\\fs12}What's the difference between null and nil?\r\nDialogue: 0,1:00:36.95,1:00:38.35,yin,,0,0,0,,问得很好\\N{\\fs12}Okay that's a good question.\r\nDialogue: 0,1:00:38.35,1:00:42.46,yin,,0,0,0,,nil意思是对象指针是0\\N{\\fs12}Nil means an object pointer is 0.\r\nDialogue: 0,1:00:42.46,1:00:45.82,yin,,0,0,0,,指针什么都没指 这就是nil\\N{\\fs12}A pointer that doesn't point to anything is nil.\r\nDialogue: 0,1:00:45.82,1:00:51.25,yin,,0,0,0,,null是说C指针 什么都没指\\N{\\fs12}Null means a C pointer is -- points to nothing.\r\nDialogue: 0,1:00:51.25,1:00:53.63,yin,,0,0,0,,这时 这会是一个&error\\N{\\fs12}And in that case that was an ampersand error.\r\nDialogue: 0,1:00:53.63,1:00:56.57,yin,,0,0,0,,换言之 根据引用 这是NSError\\N{\\fs12}In other words a by reference NS error.\r\nDialogue: 0,1:00:56.57,1:00:58.94,yin,,0,0,0,,这里不是一个NSError指针\\N{\\fs12}So this is not an NS error pointer.\r\nDialogue: 0,1:00:58.94,1:01:01.96,yin,,0,0,0,,而是一个NSError\\N{\\fs12}It was an NS error star-star\r\nDialogue: 0,1:01:04.32,1:01:07.15,yin,,0,0,0,,能理解吗\\N{\\fs12}Do you understand that?\r\nDialogue: 0,1:01:07.15,1:01:08.35,yin,,0,0,0,,这里这个\\N{\\fs12}This thing right here,\r\nDialogue: 0,1:01:08.35,1:01:12.51,yin,,0,0,0,,如果我要获得错误 我需要说&error\\N{\\fs12}if I wanted to get the error I would have said &error.\r\nDialogue: 0,1:01:12.51,1:01:13.57,yin,,0,0,0,,像这样\\N{\\fs12}Like this.\r\nDialogue: 0,1:01:13.57,1:01:17.90,yin,,0,0,0,,然后是NSError *error\\N{\\fs12}And I would have had NSerror star error.\r\nDialogue: 0,1:01:17.90,1:01:24.04,yin,,0,0,0,,这将=nil\\N{\\fs12}So this is -- and I -- this would be =nil.\r\nDialogue: 0,1:01:24.04,1:01:28.58,yin,,0,0,0,,但&error是指向这个指针的一个指针\\N{\\fs12}But an ampersand error is a pointer to this pointer.\r\nDialogue: 0,1:01:28.58,1:01:33.30,yin,,0,0,0,,那就是null\\N{\\fs12}So that would be null.\r\nDialogue: 0,1:01:36.34,1:01:40.59,yin,,0,0,0,,好 关于这个有一点不好\\N{\\fs12}Okay. So one thing that's bad about this, this guy right here.\r\nDialogue: 0,1:01:40.59,1:01:43.08,yin,,0,0,0,,有什么不好\\N{\\fs12}What's that going to do that's bad?\r\nDialogue: 0,1:01:45.35,1:01:47.01,yin,,0,0,0,,阻塞了主队列\\N{\\fs12}block the main queue.\r\nDialogue: 0,1:01:47.01,1:01:49.72,yin,,0,0,0,,由于时间有限 这个我不打算修正\\N{\\fs12}So we're not going to fix that because we're going to be time constrained here.\r\nDialogue: 0,1:01:49.72,1:01:50.96,yin,,0,0,0,,不过这里我警告一下\\N{\\fs12}But I'm going to put a warning in.\r\nDialogue: 0,1:01:50.96,1:01:53.27,yin,,0,0,0,,这里我加了一个带#号的警告\\N{\\fs12}So there's a nice little pound sound warning thing you can put\r\nDialogue: 0,1:01:53.27,1:01:58.30,yin,,0,0,0,,你可以在这里添加你自己的警告信息\\N{\\fs12}in that lets you add your own warnings.\r\nDialogue: 0,1:01:59.44,1:02:03.49,yin,,0,0,0,,这会阻塞主队列所使用的主线程\\N{\\fs12}It really blocks the main thread that is used by the main queue.\r\nDialogue: 0,1:02:03.49,1:02:06.61,yin,,0,0,0,,这里写一个警告 提醒你以后回头\\N{\\fs12}But this is to basically create a warning and this will remind you to go back\r\nDialogue: 0,1:02:06.61,1:02:08.47,yin,,0,0,0,,在提交之前修正\\N{\\fs12}and fix this before you submit it, for example,\r\nDialogue: 0,1:02:08.47,1:02:11.07,yin,,0,0,0,,成品代码中显然不应该有任何警告\\N{\\fs12}because you don't want to have any warnings in your code.\r\nDialogue: 0,1:02:11.07,1:02:13.15,yin,,0,0,0,,这里我们就不修正了\\N{\\fs12}So we're not going to do this right now\r\nDialogue: 0,1:02:13.15,1:02:15.10,yin,,0,0,0,,因为还有其它东西要讲\\N{\\fs12}because we want to get on to some of the other things.\r\nDialogue: 0,1:02:15.11,1:02:17.06,yin,,0,0,0,,我们时间明显不够了\\N{\\fs12}And we're going to run overtime as it is.\r\nDialogue: 0,1:02:17.06,1:02:20.63,yin,,0,0,0,,最后我会修正这个 然后发布\\N{\\fs12}But I'll do this at the end and then I'll post it.\r\nDialogue: 0,1:02:20.63,1:02:22.16,yin,,0,0,0,,不过好消息是\\N{\\fs12}But the good news is that\r\nDialogue: 0,1:02:22.16,1:02:26.78,yin,,0,0,0,,我们在超类中设定了模型 这里\\N{\\fs12}we have set our model back in our superclass, right here.\r\nDialogue: 0,1:02:26.78,1:02:30.40,yin,,0,0,0,,我们现在有了所有需要的信息 来使用表格\\N{\\fs12}So we have all the information we need now to use our tables --\r\nDialogue: 0,1:02:30.40,1:02:33.46,yin,,0,0,0,,来使用数据源来加载表格\\N{\\fs12}use datasource to load up that table.\r\nDialogue: 0,1:02:33.46,1:02:36.13,yin,,0,0,0,,首先这个TableView中有多少section\\N{\\fs12}So first, how many sections in this TableView?\r\nDialogue: 0,1:02:36.13,1:02:38.93,yin,,0,0,0,,我们将把这些都放到一个大的section中\\N{\\fs12}Well we're going to put it all in one big section.\r\nDialogue: 0,1:02:38.93,1:02:43.31,yin,,0,0,0,,我们不会有国家这些子section\\N{\\fs12}We're not going to have, like countries or anything else -- any subsections.\r\nDialogue: 0,1:02:43.31,1:02:44.66,yin,,0,0,0,,只有一个大的section\\N{\\fs12}So we're all going to have one big section.\r\nDialogue: 0,1:02:44.66,1:02:46.72,yin,,0,0,0,,我们可以把这个警告删掉\\N{\\fs12}So we can get rid of this nice warning actually.\r\nDialogue: 0,1:02:46.72,1:02:48.59,yin,,0,0,0,,当然 如果我删掉了这整个方法\\N{\\fs12}And of course, if I deleted this whole method,\r\nDialogue: 0,1:02:48.59,1:02:51.07,yin,,0,0,0,,情况会是一样 因为默认值就是1\\N{\\fs12}that would be the same because the default is one.\r\nDialogue: 0,1:02:51.07,1:02:55.01,yin,,0,0,0,,而这里 section中的行数 我只有一个大的section\\N{\\fs12}And here, number of rows in section -- well again I only have one section,\r\nDialogue: 0,1:02:55.01,1:02:58.10,yin,,0,0,0,,所以这里可以返回self.photos count\\N{\\fs12}so I can just return self.photoscount --\r\nDialogue: 0,1:02:58.10,1:03:01.05,yin,,0,0,0,,这就是我所拥有的照片的量\\N{\\fs12}that's the number of photos I have.\r\nDialogue: 0,1:03:01.05,1:03:05.13,yin,,0,0,0,,如果section有多个 我就需要返回一个不同的数字\\N{\\fs12}Now if I had multiple sections I would need to find -- return a different number.\r\nDialogue: 0,1:03:05.13,1:03:07.44,yin,,0,0,0,,不过这里 section只有一个 我这样做就行了\\N{\\fs12}But here I only have one section so I can do that.\r\nDialogue: 0,1:03:07.44,1:03:10.72,yin,,0,0,0,,然后这里是tableView: cellForRowAtIndexPath:\\N{\\fs12}And then here is our tableView cellForRowAtIndexPath.\r\nDialogue: 0,1:03:10.72,1:03:13.62,yin,,0,0,0,,这里它问 你在故事板里设了什么\\N{\\fs12}Here it's saying, what did you put in the storyboard\r\nDialogue: 0,1:03:13.62,1:03:15.73,yin,,0,0,0,,用于单元格的标识符\\N{\\fs12}for the identifier for the cell? Well what did we put?\r\nDialogue: 0,1:03:15.73,1:03:17.94,yin,,0,0,0,,我们回到这里看看\\N{\\fs12}Let's go look back here.\r\nDialogue: 0,1:03:17.94,1:03:19.46,yin,,0,0,0,,我们要检查这个单元格\\N{\\fs12}We'll inspect this cell.\r\nDialogue: 0,1:03:19.46,1:03:20.57,yin,,0,0,0,,属性检查器\\N{\\fs12}The attribute inspector.\r\nDialogue: 0,1:03:20.57,1:03:22.57,yin,,0,0,0,,再用标识符 这里什么都没设\\N{\\fs12}Reuse identifier; we didn't put anything.\r\nDialogue: 0,1:03:22.57,1:03:24.90,yin,,0,0,0,,我们试试Flickr Photo Cell\\N{\\fs12}Let's try Flickrphotocell.\r\nDialogue: 0,1:03:24.90,1:03:27.09,yin,,0,0,0,,这会是一个很好的名字\\N{\\fs12}That would be a good name for that.\r\nDialogue: 0,1:03:27.09,1:03:29.17,yin,,0,0,0,,这里 在代码中\\N{\\fs12}And so now here in our code,\r\nDialogue: 0,1:03:29.17,1:03:31.77,yin,,0,0,0,,我们要确保写的是相同的东西\\N{\\fs12}we want to make sure we put the same thing here.\r\nDialogue: 0,1:03:31.77,1:03:33.32,yin,,0,0,0,,这样它就能知道\\N{\\fs12}And that's how it's going to know\r\nDialogue: 0,1:03:33.32,1:03:37.03,yin,,0,0,0,,一遍又一遍地去复制这个原型\\N{\\fs12}to duplicate this particular prototype cell over and over.\r\nDialogue: 0,1:03:37.03,1:03:39.67,yin,,0,0,0,,顺便说下 我们还可以把这设为标题\\N{\\fs12}We could also, by the way, set this to maybe do subtitle.\r\nDialogue: 0,1:03:39.67,1:03:42.55,yin,,0,0,0,,按任何方式把这个单元格设置成我们想要的\\N{\\fs12}Kind of set this thing up the way that we want, this cell.\r\nDialogue: 0,1:03:42.55,1:03:47.02,yin,,0,0,0,,让正确的东西得到复制\\N{\\fs12}So that it gets copied -- the right thing we want gets copied.\r\nDialogue: 0,1:03:47.02,1:03:48.66,yin,,0,0,0,,好 现在我们有了单元格\\N{\\fs12}Okay so we have this cell now, okay,\r\nDialogue: 0,1:03:48.66,1:03:51.30,yin,,0,0,0,,从这里的dequeueReusableCellWithIdentifier\\N{\\fs12}from the Dequeue Reusable Cell with Identifier there.\r\nDialogue: 0,1:03:51.32,1:03:53.15,yin,,0,0,0,,然后我们需要对单元格进行配置\\N{\\fs12}And then we need to configure the cell.\r\nDialogue: 0,1:03:53.15,1:03:56.65,yin,,0,0,0,,配置时 我们需要来自模型的信息\\N{\\fs12}Well to configure the cell, we need the information from our model.\r\nDialogue: 0,1:03:56.65,1:03:58.65,yin,,0,0,0,,我们需要获取字典\\N{\\fs12}So we need to get the dictionary\r\nDialogue: 0,1:03:58.65,1:04:01.53,yin,,0,0,0,,对应于这个索引路径处的照片\\N{\\fs12}for the photo that's at this index path.\r\nDialogue: 0,1:04:01.53,1:04:03.49,yin,,0,0,0,,在这个行和section处\\N{\\fs12}In other words this row and section.\r\nDialogue: 0,1:04:03.49,1:04:06.67,yin,,0,0,0,,我们还是只有一个大的section 因此我们需要的只是\\N{\\fs12}And again, we only have one big section, so we really just need the photo that's\r\nDialogue: 0,1:04:06.67,1:04:08.45,yin,,0,0,0,,数组中特定位置的照片\\N{\\fs12}at that place in the array.\r\nDialogue: 0,1:04:08.45,1:04:13.63,yin,,0,0,0,,这将是photos[indexPath.row]\\N{\\fs12}So that will be photossub indexpath.row.\r\nDialogue: 0,1:04:13.63,1:04:15.65,yin,,0,0,0,,如果这里有多个section\\N{\\fs12}I would use indexpath.\r\nDialogue: 0,1:04:15.65,1:04:18.36,yin,,0,0,0,,我就要用indexPath.section 你们作业中就是如此\\N{\\fs12}section if I had multiple sections like you're going to have.\r\nDialogue: 0,1:04:18.36,1:04:19.24,yin,,0,0,0,,现在我有了照片\\N{\\fs12}So now I have the photo.\r\nDialogue: 0,1:04:19.24,1:04:21.14,yin,,0,0,0,,我有了你们看到的这个字典\\N{\\fs12}I have that dictionary that you saw --\r\nDialogue: 0,1:04:21.14,1:04:22.71,yin,,0,0,0,,这里有一些字典\\N{\\fs12}there were a bunch of dictionaries there.\r\nDialogue: 0,1:04:22.71,1:04:24.69,yin,,0,0,0,,下面来配置单元格\\N{\\fs12}So let's configure the cell.\r\nDialogue: 0,1:04:24.69,1:04:29.68,yin,,0,0,0,,将这个的textLabel设为photo…\\N{\\fs12}Let's set the text label of that one to be, let's say the photo.\r\nDialogue: 0,1:04:29.68,1:04:31.91,yin,,0,0,0,,这里我要使用相同的valueForKeyPath\\N{\\fs12}And I'm going to use this same value for keypath here,\r\nDialogue: 0,1:04:31.91,1:04:37.63,yin,,0,0,0,,避免Flickr的这些东西里面有点\\N{\\fs12}in case any of these things have Flickr have dots in them.\r\nDialogue: 0,1:04:39.19,1:04:43.67,yin,,0,0,0,,我们import FlickrFetcher\\N{\\fs12}Let's import Flickr fetcher.\r\nDialogue: 0,1:04:43.67,1:04:47.31,yin,,0,0,0,,FlickrFetcher也有所有这些东西\\N{\\fs12}Flicker fetcher also has all of these things\r\nDialogue: 0,1:04:47.31,1:04:49.72,yin,,0,0,0,,用于照片内的键\\N{\\fs12}for the keys inside of a photo.\r\nDialogue: 0,1:04:49.72,1:04:52.00,yin,,0,0,0,,位置内的键 你会需要这个\\N{\\fs12}The keys inside of a place -- which you'll need.\r\nDialogue: 0,1:04:52.00,1:04:55.06,yin,,0,0,0,,有些键在各种不同的东西里面\\N{\\fs12}Some keys that are in kind of all different things.\r\nDialogue: 0,1:04:55.06,1:04:57.12,yin,,0,0,0,,我们到这里\\N{\\fs12}And so let's go here.\r\nDialogue: 0,1:04:57.12,1:05:00.29,yin,,0,0,0,,我们需要FLICKR_PHOTO_TITLE\\N{\\fs12}We want Flickr photo title.\r\nDialogue: 0,1:05:02.75,1:05:03.66,yin,,0,0,0,,像这样\\N{\\fs12}Like that.\r\nDialogue: 0,1:05:03.66,1:05:06.55,yin,,0,0,0,,好 然后我们要说detailTextLabel\\N{\\fs12}Alright. And then we'll say the detail text label --\r\nDialogue: 0,1:05:06.55,1:05:10.66,yin,,0,0,0,,这是那个副标题 我们这里用photo valueForKeyPath\\N{\\fs12}that's the little subtitle -- we'll do photo value forkeypath.\r\nDialogue: 0,1:05:10.66,1:05:13.39,yin,,0,0,0,,我们需要那个 因为这个有点\\N{\\fs12}And we need that because this one has dots.\r\nDialogue: 0,1:05:13.39,1:05:15.41,yin,,0,0,0,,也就是描述\\N{\\fs12}And that is the description.\r\nDialogue: 0,1:05:15.41,1:05:20.97,yin,,0,0,0,,描述在这里是description._content\\N{\\fs12}And the description one -- as you'll see here -- is description. underbarcontent.\r\nDialogue: 0,1:05:20.97,1:05:23.34,yin,,0,0,0,,如果你回头去看Flickr\\N{\\fs12}And if you remember -- if you go back and look at the Flickr thing,\r\nDialogue: 0,1:05:23.34,1:05:26.54,yin,,0,0,0,,你就会知道这里为什么是description._content\\N{\\fs12}you'll see why this is description. underbarcontent.\r\nDialogue: 0,1:05:26.54,1:05:28.58,yin,,0,0,0,,我们有了这个\\N{\\fs12}So we got that.\r\nDialogue: 0,1:05:28.58,1:05:31.07,yin,,0,0,0,,我们返回单元格 这就够了\\N{\\fs12}We return to the cell, and that's really all we need to do.\r\nDialogue: 0,1:05:31.07,1:05:32.89,yin,,0,0,0,,我们可以运行这个\\N{\\fs12}So let's go ahead and run this.\r\nDialogue: 0,1:05:35.08,1:05:36.51,yin,,0,0,0,,这里我们得到了那个警告\\N{\\fs12}Okay, we got that warning there.\r\nDialogue: 0,1:05:36.51,1:05:37.35,yin,,0,0,0,,阻塞主线程\\N{\\fs12}Block main thread.\r\nDialogue: 0,1:05:37.35,1:05:41.93,yin,,0,0,0,,在到Flickr取回信息时 这个现在确实阻塞了主线程\\N{\\fs12}And this is blocking the main thread right now as it goes out to Flickr to fetch.\r\nDialogue: 0,1:05:41.93,1:05:43.06,yin,,0,0,0,,不过它还是获得了信息\\N{\\fs12}But it did get it.\r\nDialogue: 0,1:05:43.06,1:05:44.57,yin,,0,0,0,,这里有一系列图片\\N{\\fs12}So here's a whole bunch of photos.\r\nDialogue: 0,1:05:44.57,1:05:47.00,yin,,0,0,0,,有些有副标题 有些没有\\N{\\fs12}Some of them have subtitles; some not.\r\nDialogue: 0,1:05:47.00,1:05:49.11,yin,,0,0,0,,这很酷 我们可以点它们\\N{\\fs12}Okay. That's cool. Cool. We can click on them.\r\nDialogue: 0,1:05:49.11,1:05:52.95,yin,,0,0,0,,不过我们还要确保 点击照片时能够看到照片\\N{\\fs12}But it'd be sure nice if we could see these photos when we click on them.\r\nDialogue: 0,1:05:52.95,1:05:55.72,yin,,0,0,0,,显然 我们需要segue来做到这一点\\N{\\fs12}But of course we need to do a segue to do that.\r\nDialogue: 0,1:05:55.72,1:05:57.33,yin,,0,0,0,,下面我们就来做这个\\N{\\fs12}So let's go ahead and do that.\r\nDialogue: 0,1:05:57.34,1:05:59.12,yin,,0,0,0,,回到这里\\N{\\fs12}So let's go back to here.\r\nDialogue: 0,1:05:59.12,1:06:03.11,yin,,0,0,0,,这个segue很容易做\\N{\\fs12}And you know, this segue is really easy to do.\r\nDialogue: 0,1:06:03.11,1:06:05.45,yin,,0,0,0,,回到我们的iPhone故事板\\N{\\fs12}Let's go back to our iPhone storyboard here.\r\nDialogue: 0,1:06:05.45,1:06:07.70,yin,,0,0,0,,我们需要\\N{\\fs12}What we need though is the --\r\nDialogue: 0,1:06:07.70,1:06:12.76,yin,,0,0,0,,用到Imaginarium中的那个美妙的图像视图控制器\\N{\\fs12}what we want is from Imaginarium, we want that nice, image view controller.\r\nDialogue: 0,1:06:12.76,1:06:14.91,yin,,0,0,0,,好 看看怎么得到这个\\N{\\fs12}Okay, well watch how we can get that.\r\nDialogue: 0,1:06:14.91,1:06:18.90,yin,,0,0,0,,我要回到Imaginarium\\N{\\fs12}I'm going to go back to my Imaginarium.\r\nDialogue: 0,1:06:18.90,1:06:20.86,yin,,0,0,0,,这是Imaginarium\\N{\\fs12}Here's Imaginarium.\r\nDialogue: 0,1:06:20.86,1:06:24.13,yin,,0,0,0,,首先我要把图像视图控制器代码\\N{\\fs12}First of all I'm going to take the image view controller code\r\nDialogue: 0,1:06:24.13,1:06:27.54,yin,,0,0,0,,从一个项目拖动到另一个中\\N{\\fs12}and just drag it from one project to another.\r\nDialogue: 0,1:06:27.54,1:06:30.41,yin,,0,0,0,,这完全是合法的 这里我会复制它\\N{\\fs12}That's perfectly legal. I'm going to copy it in this case.\r\nDialogue: 0,1:06:30.41,1:06:32.97,yin,,0,0,0,,你也可以关联它们 但要小心\\N{\\fs12}You could link them, but be careful if you do that.\r\nDialogue: 0,1:06:32.97,1:06:34.79,yin,,0,0,0,,更有趣的是\\N{\\fs12}But even more amazingly, I'm actually going to go\r\nDialogue: 0,1:06:34.79,1:06:37.75,yin,,0,0,0,,我要到故事板 抓取这个场景\\N{\\fs12}to the storyboard and grab this scene right here --\r\nDialogue: 0,1:06:37.75,1:06:40.55,yin,,0,0,0,,这个拥有滚动视图等各种东西的场景\\N{\\fs12}this scene that has all this scroll view and all this stuff in it.\r\nDialogue: 0,1:06:40.55,1:06:46.44,yin,,0,0,0,,将它复制粘贴到Shutterbug的故事板中\\N{\\fs12}And copy it and go over to this storyboard in Shutter Bug and paste it.\r\nDialogue: 0,1:06:46.77,1:06:49.88,yin,,0,0,0,,它照做了 只是找到它的问题\\N{\\fs12}It did do it. It's just a question of finding it.\r\nDialogue: 0,1:06:50.54,1:06:52.88,yin,,0,0,0,,放到一边 好了\\N{\\fs12}Put it over on the side, there it is.\r\nDialogue: 0,1:06:52.88,1:06:55.80,yin,,0,0,0,,好 现在我有了这个\\N{\\fs12}Okay. So now I have this thing here.\r\nDialogue: 0,1:06:55.80,1:06:59.89,yin,,0,0,0,,由于所有这些关联都是根据名称来的\\N{\\fs12}And all of the links that were in here, since they're all\r\nDialogue: 0,1:06:59.89,1:07:05.41,yin,,0,0,0,,只要我还有这个类 这些就仍然能够工作\\N{\\fs12}by name, all will still work as long as I have this particular class.\r\nDialogue: 0,1:07:05.41,1:07:06.96,yin,,0,0,0,,这里是图像视图控制器\\N{\\fs12}Which is image view controller.\r\nDialogue: 0,1:07:06.96,1:07:10.38,yin,,0,0,0,,它在这里还是将其设置为图像视图控制器\\N{\\fs12}It even still sets the thing here to be an image view controller.\r\nDialogue: 0,1:07:10.38,1:07:14.97,yin,,0,0,0,,看看这些东西 它们还是关联在一起的\\N{\\fs12}And if I go look at this -- all these things, they're linked -- they're still linked up.\r\nDialogue: 0,1:07:15.90,1:07:17.22,yin,,0,0,0,,我对这里的滚动表示抱歉\\N{\\fs12}Sorry for the scrolling here.\r\nDialogue: 0,1:07:17.22,1:07:19.86,yin,,0,0,0,,可以看到这里的活动指示器 它们都关联在一起\\N{\\fs12}But see, you can see the activity indicator, that's all linked up.\r\nDialogue: 0,1:07:19.86,1:07:22.13,yin,,0,0,0,,因为关联都是通过名称来的\\N{\\fs12}Because it's all being done by name.\r\nDialogue: 0,1:07:22.13,1:07:24.50,yin,,0,0,0,,我们有了这个美妙的东西\\N{\\fs12}So we have this nice thing.\r\nDialogue: 0,1:07:24.50,1:07:26.36,yin,,0,0,0,,下面来segue\\N{\\fs12}So we'll -- let's segue to it.\r\nDialogue: 0,1:07:26.36,1:07:29.36,yin,,0,0,0,,我们使用control拖动… 我们有这个单元格 抱歉\\N{\\fs12}We're just going to control drag -- we got this cell right here, sorry.\r\nDialogue: 0,1:07:29.36,1:07:32.80,yin,,0,0,0,,这个单元格 control拖动它 到这里\\N{\\fs12}This cell and we're just going to control drag from it to here.\r\nDialogue: 0,1:07:32.80,1:07:34.91,yin,,0,0,0,,我们要把这放到导航控制器中\\N{\\fs12}Let's do -- we're going to put this in a navigation controller.\r\nDialogue: 0,1:07:34.91,1:07:36.67,yin,,0,0,0,,我们要push\\N{\\fs12}So we'll push.\r\nDialogue: 0,1:07:36.67,1:07:39.65,yin,,0,0,0,,这是我们的东西 我们需要一个很好的名称用于segue\\N{\\fs12}Here's our thing. We need a nice name for our segue here.\r\nDialogue: 0,1:07:39.65,1:07:44.76,yin,,0,0,0,,就叫Display Photo 显示照片\\N{\\fs12}We'll call this display photo. Oops display photo.\r\nDialogue: 0,1:07:44.76,1:07:46.62,yin,,0,0,0,,这里叫什么其实都行\\N{\\fs12}We can call it again, anything we want.\r\nDialogue: 0,1:07:46.62,1:07:50.81,yin,,0,0,0,,把这些都嵌入到导航控制器中\\N{\\fs12}Let's put this stuff all in a navigation controller -- embed in navigation controller.\r\nDialogue: 0,1:07:51.19,1:07:53.61,yin,,0,0,0,,我们有一个很好的UI\\N{\\fs12}So we have an nice UI here.\r\nDialogue: 0,1:07:53.61,1:07:57.03,yin,,0,0,0,,我们几乎什额外工作都不需要做\\N{\\fs12}Really, with almost no work for us to develop.\r\nDialogue: 0,1:07:57.03,1:08:00.51,yin,,0,0,0,,在这里 我们可以直接把这称作Shutterbug\\N{\\fs12}While we're here, let's go ahead and call this one Shutter Bug.\r\nDialogue: 0,1:08:00.51,1:08:05.03,yin,,0,0,0,,这个的标题则依照照片的标题来设定\\N{\\fs12}We will set the title of this one, based on the title of the photo.\r\nDialogue: 0,1:08:05.03,1:08:07.72,yin,,0,0,0,,我们只需要做什么就能让segue开始工作\\N{\\fs12}So all we need to do to make a segue work is what?\r\nDialogue: 0,1:08:07.72,1:08:08.94,yin,,0,0,0,,prepareForSegue\\N{\\fs12}Prepare for segue.\r\nDialogue: 0,1:08:08.94,1:08:10.71,yin,,0,0,0,,我们回到这里 进行prepareForSegue\\N{\\fs12}So let's go back and do prepare for segue.\r\nDialogue: 0,1:08:10.71,1:08:13.03,yin,,0,0,0,,实际上 下面这里它被注释掉了\\N{\\fs12}It's actually commented out down here.\r\nDialogue: 0,1:08:14.80,1:08:16.11,yin,,0,0,0,,取消注释\\N{\\fs12}Plug it back in.\r\nDialogue: 0,1:08:16.11,1:08:19.37,yin,,0,0,0,,这里我们只需要\\N{\\fs12}And all -- the only trick we need to know here is\r\nDialogue: 0,1:08:19.37,1:08:22.34,yin,,0,0,0,,从这个sender获得索引路径\\N{\\fs12}that we need to get the index path from this sender.\r\nDialogue: 0,1:08:22.34,1:08:24.65,yin,,0,0,0,,也就是点击的TableView单元格\\N{\\fs12}Which is the TableView cell that was clicked on.\r\nDialogue: 0,1:08:24.65,1:08:26.26,yin,,0,0,0,,让我们这样做\\N{\\fs12}So let's do that.\r\nDialogue: 0,1:08:26.26,1:08:33.39,yin,,0,0,0,,NSIndexPath *indexPath = [self.tableView…\\N{\\fs12}NSindexpath. indexpath=self .tableview --\r\nDialogue: 0,1:08:33.39,1:08:36.24,yin,,0,0,0,,记住 所有TableView控制器都有这个tableView\\N{\\fs12}remember all TableView controllers have this TableView\r\nDialogue: 0,1:08:36.24,1:08:38.50,yin,,0,0,0,,属性 让你用于获取这个\\N{\\fs12}property that you can use to get this stuff.\r\nDialogue: 0,1:08:38.50,1:08:41.96,yin,,0,0,0,,然后我需要indexPathForCell:sender\\N{\\fs12}And I want indexpath forcellsender.\r\nDialogue: 0,1:08:41.96,1:08:44.03,yin,,0,0,0,,好 这样我就有了这个索引路径\\N{\\fs12}Okay. So now I have this index path.\r\nDialogue: 0,1:08:44.03,1:08:48.57,yin,,0,0,0,,如果我要想保险 我还可以说 if (indexPath)\\N{\\fs12}If I want to be really safe, I could say, ifindexpath.\r\nDialogue: 0,1:08:48.57,1:08:51.76,yin,,0,0,0,,这样一来 如果这个sender…\\N{\\fs12}That way if somehow this sender, you know,\r\nDialogue: 0,1:08:51.76,1:08:53.58,yin,,0,0,0,,我还可以更保险一些\\N{\\fs12}I could even be super safe and say,\r\nDialogue: 0,1:08:53.58,1:08:56.74,yin,,0,0,0,,我可以说  if ([sender isKindOfClass:\\N{\\fs12}ifsender iskindofclass\r\nDialogue: 0,1:08:56.74,1:09:00.25,yin,,0,0,0,,[UITableViewCell class]])\\N{\\fs12}uitableview cell class.\r\nDialogue: 0,1:09:00.99,1:09:03.74,yin,,0,0,0,,有些人想要非常小心\\N{\\fs12}Some people are really -- want to be careful about,\r\nDialogue: 0,1:09:03.74,1:09:06.34,yin,,0,0,0,,使用ID 他们想使用内省\\N{\\fs12}you know, using ID and they want to use introspection.\r\nDialogue: 0,1:09:06.34,1:09:08.36,yin,,0,0,0,,我显然能够明白你为什么要这样做\\N{\\fs12}And I certainly appreciate why you want to do that.\r\nDialogue: 0,1:09:08.36,1:09:10.91,yin,,0,0,0,,有时 让app崩溃其实更好\\N{\\fs12}Sometimes it's better to let your app just crash.\r\nDialogue: 0,1:09:10.91,1:09:13.70,yin,,0,0,0,,这有时能够帮你更快地找到bug\\N{\\fs12}And when you do that you'll find the bugs faster sometimes.\r\nDialogue: 0,1:09:13.70,1:09:17.66,yin,,0,0,0,,或者 在其中一些if中 你可以加入else log\\N{\\fs12}Or in some of these ifs, you want to put elseloga --\r\nDialogue: 0,1:09:17.66,1:09:19.77,yin,,0,0,0,,关于内部错误或是别的什么\\N{\\fs12}you know, an internal error or something like that.\r\nDialogue: 0,1:09:19.77,1:09:21.65,yin,,0,0,0,,无论如何 我们有了这个索引路径\\N{\\fs12}But anyway, we've got this index path.\r\nDialogue: 0,1:09:21.65,1:09:25.10,yin,,0,0,0,,它不是nil 于是我们能找到这个TableView单元格\\N{\\fs12}It's not nil, so we were able to find this TableView cell\r\nDialogue: 0,1:09:25.10,1:09:28.06,yin,,0,0,0,,在这个TableView中 这很好 我们开了个好头\\N{\\fs12}in this TableView so that's good. We're off to a good start.\r\nDialogue: 0,1:09:28.06,1:09:37.89,yin,,0,0,0,,看看这是不是Display Photo那个segue\\N{\\fs12}Let's see if this is the display photo segue.\r\nDialogue: 0,1:09:37.89,1:09:40.18,yin,,0,0,0,,如果是 我们看看\\N{\\fs12}If it is, let's see\r\nDialogue: 0,1:09:40.18,1:09:47.72,yin,,0,0,0,,如果segue.destinationViewController isKindOfClass\\N{\\fs12}if the segue destination view controller is kind of class --\r\nDialogue: 0,1:09:47.72,1:09:50.70,yin,,0,0,0,,是那类图像视图控制器 因为这就是我们要的\\N{\\fs12}that image view controller class, because that's what we need it to be.\r\nDialogue: 0,1:09:50.70,1:09:53.22,yin,,0,0,0,,图像视图控制器\\N{\\fs12}Image view controller.\r\nDialogue: 0,1:09:54.39,1:09:59.59,yin,,0,0,0,,如果它是一个图像视图控制器\\N{\\fs12}So if it is an image view controller class,\r\nDialogue: 0,1:10:01.83,1:10:04.27,yin,,0,0,0,,那就很棒了\\N{\\fs12}then we are good to go.\r\nDialogue: 0,1:10:04.27,1:10:06.04,yin,,0,0,0,,我们要的一切就都有了\\N{\\fs12}Kind of got everything we need at this point.\r\nDialogue: 0,1:10:06.04,1:10:09.14,yin,,0,0,0,,这里我要创建一个小的辅助方法\\N{\\fs12}And I'm actually going to create a little helper method here,\r\nDialogue: 0,1:10:09.14,1:10:13.04,yin,,0,0,0,,也就是prepareImageViewController\\N{\\fs12}which is prepare imageviewcontroller\r\nDialogue: 0,1:10:13.05,1:10:15.55,yin,,0,0,0,,ImageViewController\\N{\\fs12}imageviewcontroller\r\nDialogue: 0,1:10:15.55,1:10:18.55,yin,,0,0,0,,toDisplayPhoto\\N{\\fs12}todisplayphoto\r\nDialogue: 0,1:10:18.56,1:10:23.35,yin,,0,0,0,,NSDictionary photo 这只是一个\\N{\\fs12}NSdictionaryphoto. So this is just going to be something --\r\nDialogue: 0,1:10:23.35,1:10:26.39,yin,,0,0,0,,帮助实际准备的辅助方法\\N{\\fs12}a little helper thing that does the actual preparation.\r\nDialogue: 0,1:10:26.39,1:10:28.29,yin,,0,0,0,,这很简单\\N{\\fs12}And this is really easy.\r\nDialogue: 0,1:10:28.29,1:10:31.62,yin,,0,0,0,,ivc.imageURL 记得Imaginarium中的这个吗\\N{\\fs12}Ivc.imageurl -- remember that from the Imaginarium?\r\nDialogue: 0,1:10:31.62,1:10:35.15,yin,,0,0,0,,这就是图像视图控制器公共API\\N{\\fs12}That's what the image view controller's public API is.\r\nDialogue: 0,1:10:35.15,1:10:38.20,yin,,0,0,0,,我们需要为这张照片获取URL\\N{\\fs12}We need to get the URL for this photo.\r\nDialogue: 0,1:10:38.20,1:10:40.64,yin,,0,0,0,,FlickrFetcher也可以帮我们完成这个\\N{\\fs12}And it turns out Flickr fetcher can help us with that too.\r\nDialogue: 0,1:10:40.64,1:10:42.24,yin,,0,0,0,,FlickrFetcher\\N{\\fs12}Flickr fetcher.\r\nDialogue: 0,1:10:42.24,1:10:46.10,yin,,0,0,0,,这里有个URLforPhoto\\N{\\fs12}There's a thing called URL for photo.\r\nDialogue: 0,1:10:46.10,1:10:48.48,yin,,0,0,0,,给它一个photo字典\\N{\\fs12}And we just give it the photo dictionary\r\nDialogue: 0,1:10:48.48,1:10:51.09,yin,,0,0,0,,它使用字典内的东西来获取URL\\N{\\fs12}and it uses stuff inside the dictionary to get the URL.\r\nDialogue: 0,1:10:51.09,1:10:55.96,yin,,0,0,0,,这里可以选择我们想要的格式 我要选择large格式\\N{\\fs12}And then we can pick what format we want, and I'm going to pick the large format.\r\nDialogue: 0,1:10:55.96,1:10:59.74,yin,,0,0,0,,这里的选项有large original square三种\\N{\\fs12}The choices there are large, original, or square.\r\nDialogue: 0,1:10:59.74,1:11:01.64,yin,,0,0,0,,square就像一个缩略图 非常小\\N{\\fs12}Square is like a thumbnail -- really small --\r\nDialogue: 0,1:11:01.64,1:11:03.26,yin,,0,0,0,,只在需要缩略图时才用这个\\N{\\fs12}so only use that if you need a thumbnail,\r\nDialogue: 0,1:11:03.26,1:11:05.25,yin,,0,0,0,,这次作业中不需要这样\\N{\\fs12}which you don't need for this assignment.\r\nDialogue: 0,1:11:05.25,1:11:06.91,yin,,0,0,0,,original是高清\\N{\\fs12}An original is high res.\r\nDialogue: 0,1:11:06.91,1:11:11.03,yin,,0,0,0,,large则是比较好的大小 例如1024x768这些\\N{\\fs12}And then large, it's kind of a good size, like 1024 x 768 or something like that.\r\nDialogue: 0,1:11:11.03,1:11:14.42,yin,,0,0,0,,我还说 我要把这个的标题\\N{\\fs12}And then I told you also I'm going to set the title of this thing\r\nDialogue: 0,1:11:14.42,1:11:18.98,yin,,0,0,0,,设为photo valueForKeyPath\\N{\\fs12}to be the photovalue forkeypath\r\nDialogue: 0,1:11:18.98,1:11:21.67,yin,,0,0,0,,FLICKR_PHOTO_TITLE\\N{\\fs12}flickrphototitle.\r\nDialogue: 0,1:11:21.67,1:11:25.83,yin,,0,0,0,,这样我就还能得到图像视图控制器的标题\\N{\\fs12}So I'm going to set the title of that image view controller as well.\r\nDialogue: 0,1:11:25.83,1:11:31.56,yin,,0,0,0,,下面调用这个辅助方法 prepareImageViewController\\N{\\fs12}So now let's call this little helper thing prepareimage viewcontroller.\r\nDialogue: 0,1:11:31.56,1:11:34.68,yin,,0,0,0,,图像视图控制器是segue.destinationViewController\\N{\\fs12}The image view controller is segue.destination view controller,\r\nDialogue: 0,1:11:34.68,1:11:36.08,yin,,0,0,0,,toDisplayPhoto\\N{\\fs12}to display photo.\r\nDialogue: 0,1:11:36.08,1:11:42.08,yin,,0,0,0,,照片是self.photosIndexPath.row\\N{\\fs12}The photo is self.photosindex path.row.\r\nDialogue: 0,1:11:42.98,1:11:44.85,yin,,0,0,0,,都理解吗\\N{\\fs12}Everyone understand that?\r\nDialogue: 0,1:11:44.86,1:11:48.59,yin,,0,0,0,,我只是在这个索引路径处访问了模型\\N{\\fs12}Okay. I'm just reaching into my model here at this index path\r\nDialogue: 0,1:11:48.59,1:11:50.70,yin,,0,0,0,,这是sender\\N{\\fs12}that was the sender.\r\nDialogue: 0,1:11:50.70,1:11:52.95,yin,,0,0,0,,看看这能否奏效\\N{\\fs12}Alright? So let's see if this works.\r\nDialogue: 0,1:11:56.35,1:12:00.56,yin,,0,0,0,,这还是阻塞了主线程 我只是懒得管它\\N{\\fs12}Again, this is blocking our main thread here, which is a bummer.\r\nDialogue: 0,1:12:00.56,1:12:02.11,yin,,0,0,0,,你们知道怎么处理它\\N{\\fs12}You'd know how to not do that.\r\nDialogue: 0,1:12:02.11,1:12:05.63,yin,,0,0,0,,现在 我们就到了UI导航控制器中\\N{\\fs12}So here we have now, we're in a UI navigation controller.\r\nDialogue: 0,1:12:05.63,1:12:06.93,yin,,0,0,0,,很酷 我们有这个\\N{\\fs12}That's cool. We got that.\r\nDialogue: 0,1:12:06.93,1:12:08.64,yin,,0,0,0,,让我点击一点东西\\N{\\fs12}Let's go ahead and click on something\r\nDialogue: 0,1:12:08.64,1:12:11.86,yin,,0,0,0,,这里其实有些无伤大雅\\N{\\fs12}that hopefully is innocuous here it is.\r\nDialogue: 0,1:12:11.86,1:12:14.31,yin,,0,0,0,,可以放大和缩小\\N{\\fs12}And we can zoom in and out.\r\nDialogue: 0,1:12:14.31,1:12:17.73,yin,,0,0,0,,很酷 我们可以回头点点别的\\N{\\fs12}That's cool. Alright we can go back and click on something else.\r\nDialogue: 0,1:12:17.73,1:12:20.32,yin,,0,0,0,,另一张罗马照片 这是圆形竞技场\\N{\\fs12}Another Rome picture.That was the Coliseum.\r\nDialogue: 0,1:12:20.32,1:12:23.95,yin,,0,0,0,,但愿这样也能行\\N{\\fs12}Okay. Hopefully things are work here too.\r\nDialogue: 0,1:12:23.95,1:12:24.78,yin,,0,0,0,,非常酷\\N{\\fs12}So that's pretty cool.\r\nDialogue: 0,1:12:24.78,1:12:27.49,yin,,0,0,0,,很轻松就获得了一个很强大的app\\N{\\fs12}That was pretty easy to get a pretty powerful app together.\r\nDialogue: 0,1:12:27.49,1:12:29.63,yin,,0,0,0,,我们只花了20分钟\\N{\\fs12}We did it in about 20 minutes.\r\nDialogue: 0,1:12:29.63,1:12:32.60,yin,,0,0,0,,再在iPad上做这个\\N{\\fs12}So now let's do this on iPad.\r\nDialogue: 0,1:12:32.60,1:12:35.71,yin,,0,0,0,,其实这也很简单\\N{\\fs12}This turns out to be quite easy as well.\r\nDialogue: 0,1:12:35.71,1:12:38.09,yin,,0,0,0,,我们前往iPad故事板\\N{\\fs12}So we're going to go to the iPad storyboard.\r\nDialogue: 0,1:12:38.09,1:12:41.64,yin,,0,0,0,,我把iPad故事板上移到了iPhone故事板附近\\N{\\fs12}I'm actually going to move the iPad storyboard up near the iPhone storyboard.\r\nDialogue: 0,1:12:41.64,1:12:43.54,yin,,0,0,0,,它现在是空白的\\N{\\fs12}So it's blank right now.\r\nDialogue: 0,1:12:43.54,1:12:46.55,yin,,0,0,0,,我要拖出SplitView控制器\\N{\\fs12}And I'm going to drag out a SplitView controller.\r\nDialogue: 0,1:12:46.55,1:12:48.29,yin,,0,0,0,,它在这里\\N{\\fs12}So here it is right here.\r\nDialogue: 0,1:12:48.29,1:12:52.24,yin,,0,0,0,,如果这里不是iPad故事板 它将不会出现在这里\\N{\\fs12}Now this will not be in this list if this is not an iPad storyboard.\r\nDialogue: 0,1:12:52.24,1:12:54.54,yin,,0,0,0,,在处理iPhone的情况时\\N{\\fs12}So sometimes you have your iPhone on,\r\nDialogue: 0,1:12:54.54,1:12:56.49,yin,,0,0,0,,你会发现这里没有SplitView控制器\\N{\\fs12}and there's no SplitView controller, you're like, what?\r\nDialogue: 0,1:12:56.49,1:12:59.31,yin,,0,0,0,,不要惊讶 只有iPad中才有\\N{\\fs12}Where's the SplitView controller? Okay you've got to be -- selected your iPad one.\r\nDialogue: 0,1:12:59.31,1:13:00.74,yin,,0,0,0,,我把这个拖出来\\N{\\fs12}So I'm going to bring this out.\r\nDialogue: 0,1:13:00.74,1:13:01.77,yin,,0,0,0,,这是SplitView控制器\\N{\\fs12}Here's the SplitView controller.\r\nDialogue: 0,1:13:01.77,1:13:03.95,yin,,0,0,0,,注意这些是免费提供给我的\\N{\\fs12}Notice it gave me these for free.\r\nDialogue: 0,1:13:03.95,1:13:07.55,yin,,0,0,0,,我不喜欢免费提供的东西\\N{\\fs12}I got what I paid for, which is I don't want either of these things.\r\nDialogue: 0,1:13:07.55,1:13:15.14,yin,,0,0,0,,我想要iPad中我的master是这个\\N{\\fs12}So I want my master in my iPad one to be this right here.\r\nDialogue: 0,1:13:15.14,1:13:17.16,yin,,0,0,0,,这个Shutterbug列表\\N{\\fs12}This Shutter Bug list.\r\nDialogue: 0,1:13:17.16,1:13:20.14,yin,,0,0,0,,我还希望detail是图像视图\\N{\\fs12}And I want my detail to be that image view, right?\r\nDialogue: 0,1:13:20.14,1:13:22.99,yin,,0,0,0,,我这里只需要全选复制\\N{\\fs12}So I'm just going to select all and copy here.\r\nDialogue: 0,1:13:22.99,1:13:25.46,yin,,0,0,0,,回到iPad故事板 粘贴\\N{\\fs12}And go over to my iPad storyboard and paste.\r\nDialogue: 0,1:13:25.46,1:13:27.30,yin,,0,0,0,,放到这里\\N{\\fs12}Put some in here.\r\nDialogue: 0,1:13:27.30,1:13:29.03,yin,,0,0,0,,看起来有些乱\\N{\\fs12}Kind of makes a bit of a mess of it.\r\nDialogue: 0,1:13:29.03,1:13:31.27,yin,,0,0,0,,把它移动一下\\N{\\fs12}But let's move it around here.\r\nDialogue: 0,1:13:31.27,1:13:33.41,yin,,0,0,0,,这是一样的东西\\N{\\fs12}So here -- this is the same thing.\r\nDialogue: 0,1:13:33.41,1:13:36.99,yin,,0,0,0,,看起来不一样 因为大小有不同 实际上是一样的\\N{\\fs12}Doesn't look the same because the sizes are different, but it's the same thing we had.\r\nDialogue: 0,1:13:37.06,1:13:41.79,yin,,0,0,0,,我要把这两个设置成master\\N{\\fs12}And I'm just going to make this -- these two be the master\r\nDialogue: 0,1:13:41.79,1:13:45.08,yin,,0,0,0,,我只需要从SplitView控制器control拖动到这里\\N{\\fs12}by control dragging from my SplitView controller over here.\r\nDialogue: 0,1:13:45.08,1:13:47.86,yin,,0,0,0,,我可以选master或detail 这里选master\\N{\\fs12}And I can pick master or detail -- I'll take master.\r\nDialogue: 0,1:13:47.86,1:13:51.41,yin,,0,0,0,,然后我要把这个control拖动到这里\\N{\\fs12}And then I'm going to control drag from here over to this guy,\r\nDialogue: 0,1:13:51.41,1:13:53.92,yin,,0,0,0,,将其设置为detail\\N{\\fs12}and make that the detail.\r\nDialogue: 0,1:13:53.92,1:13:56.48,yin,,0,0,0,,这样我就有了master和detail\\N{\\fs12}So now I've got master and detail.\r\nDialogue: 0,1:13:56.48,1:13:57.81,yin,,0,0,0,,这正是我要的\\N{\\fs12}Exactly what I want.\r\nDialogue: 0,1:13:57.83,1:14:00.79,yin,,0,0,0,,我将得到一个SplitView 其左侧很窄\\N{\\fs12}So I'm going to have a SplitView that has a little narrow thing\r\nDialogue: 0,1:14:00.79,1:14:02.43,yin,,0,0,0,,这些是照片的列表\\N{\\fs12}on the left, which is the list of photos.\r\nDialogue: 0,1:14:02.43,1:14:05.67,yin,,0,0,0,,大空间则将是我选择的照片\\N{\\fs12}And the big space is going to be the photo that I chose.\r\nDialogue: 0,1:14:05.67,1:14:07.50,yin,,0,0,0,,不过这里还有一个小问题\\N{\\fs12}I've got one slight problem here though,\r\nDialogue: 0,1:14:07.50,1:14:09.83,yin,,0,0,0,,也就是 这个segue还在这里\\N{\\fs12}which is this little segue still is here.\r\nDialogue: 0,1:14:09.83,1:14:11.94,yin,,0,0,0,,因此点击这里的东西时\\N{\\fs12}So when I click on things here, it's going to try\r\nDialogue: 0,1:14:11.94,1:14:15.72,yin,,0,0,0,,它会尝试把这个视图控制器替换成这个\\N{\\fs12}to replace this little view controller with this.\r\nDialogue: 0,1:14:15.72,1:14:17.03,yin,,0,0,0,,我不希望这样\\N{\\fs12}And I don't want that.\r\nDialogue: 0,1:14:17.03,1:14:20.75,yin,,0,0,0,,我要删掉这个segue\\N{\\fs12}So I'm going to delete this segue.\r\nDialogue: 0,1:14:20.75,1:14:23.50,yin,,0,0,0,,这就得到了我想要的\\N{\\fs12}Now that gives me what I want.\r\nDialogue: 0,1:14:23.50,1:14:27.66,yin,,0,0,0,,不过还有问题 我点这里它就不会更新了\\N{\\fs12}But now the problem is if I click in here, it's not going to update this.\r\nDialogue: 0,1:14:27.66,1:14:29.22,yin,,0,0,0,,怎么办呢\\N{\\fs12}So how do I do that?\r\nDialogue: 0,1:14:29.22,1:14:33.01,yin,,0,0,0,,这就可以用到委托方法didSelectRowAtIndexPath\\N{\\fs12}That's doing what that delegate method did select row at index path.\r\nDialogue: 0,1:14:33.01,1:14:35.48,yin,,0,0,0,,我们可以回到这里\\N{\\fs12}So we're just going to go to back to here.\r\nDialogue: 0,1:14:35.48,1:14:38.65,yin,,0,0,0,,我们将有一个新的pragma\\N{\\fs12}And we're going to have another -- a new pragma here.\r\nDialogue: 0,1:14:38.65,1:14:44.33,yin,,0,0,0,,#pragma mark UITableViewDelegate\\N{\\fs12}#Pragmamark uitableviewdelegate --\r\nDialogue: 0,1:14:44.33,1:14:46.18,yin,,0,0,0,,不是Datasource 而是Delegate\\N{\\fs12}not datasource but delegate --\r\nDialogue: 0,1:14:46.18,1:14:47.66,yin,,0,0,0,,在这里键入时\\N{\\fs12}and we're going to type here\r\nDialogue: 0,1:14:47.66,1:14:53.49,yin,,0,0,0,,可以看到这里有很多UITableViewDelegate\\N{\\fs12}and start typing, and you can see there's a lot of UI TableView delegates.\r\nDialogue: 0,1:14:53.49,1:14:57.09,yin,,0,0,0,,我们需要的是这个 didSelectRowAtIndexPath\\N{\\fs12}So we want the one right here. See it did select row at index path.\r\nDialogue: 0,1:14:57.09,1:14:59.72,yin,,0,0,0,,我们需要这个\\N{\\fs12}We want that one.\r\nDialogue: 0,1:14:59.72,1:15:04.25,yin,,0,0,0,,这里我们需要获得SplitView控制器中的detail\\N{\\fs12}And here what we need to do is get the detail in the SplitView controller.\r\nDialogue: 0,1:15:04.25,1:15:06.04,yin,,0,0,0,,我告诉过你们这是…\\N{\\fs12}And I told you that that is --\r\nDialogue: 0,1:15:06.04,1:15:07.84,yin,,0,0,0,,detail视图控制器是\\N{\\fs12}the detail view controller\r\nDialogue: 0,1:15:07.84,1:15:12.64,yin,,0,0,0,,self.splitViewController.viewControllers[1]\\N{\\fs12}is self.splitviewcontroller. viewcontrollerssub1.\r\nDialogue: 0,1:15:12.66,1:15:15.26,yin,,0,0,0,,还是那句话 如果我们不在SplitView中\\N{\\fs12}And again, if we're not in a SplitView --\r\nDialogue: 0,1:15:15.26,1:15:18.98,yin,,0,0,0,,要知道 这段代码也可以在iPhone上运行\\N{\\fs12}because this code is going to be executed on the iPhone as well.\r\nDialogue: 0,1:15:18.98,1:15:21.53,yin,,0,0,0,,如果我们不在SplitView中 这个会是nil\\N{\\fs12}And if we're not in a SplitView this is going to be nil.\r\nDialogue: 0,1:15:21.53,1:15:23.45,yin,,0,0,0,,这整个也将是nil\\N{\\fs12}So this whole thing is going to be nil.\r\nDialogue: 0,1:15:23.45,1:15:25.86,yin,,0,0,0,,这就什么都做不了 因为这也将是nil\\N{\\fs12}So this is going to do nothing because this is going to be nil.\r\nDialogue: 0,1:15:25.86,1:15:27.54,yin,,0,0,0,,这是一段很棒的代码\\N{\\fs12}So this is great code.\r\nDialogue: 0,1:15:27.54,1:15:29.75,yin,,0,0,0,,我不需要说 if iPad 怎么怎么\\N{\\fs12}I didn't have to say if iPad or anything.\r\nDialogue: 0,1:15:29.75,1:15:33.05,yin,,0,0,0,,只有在SplitView控制器中时 这个才会发生\\N{\\fs12}It's just this is only going to happen if I'm in a SplitView controller.\r\nDialogue: 0,1:15:33.05,1:15:35.89,yin,,0,0,0,,这里我稍微稳妥一点\\N{\\fs12}So I'm going to be a little, you know, worried here,\r\nDialogue: 0,1:15:35.89,1:15:37.80,yin,,0,0,0,,我说 isKindOfClass\\N{\\fs12}and I'm going to say iskindofclass --\r\nDialogue: 0,1:15:37.80,1:15:40.54,yin,,0,0,0,,确保这在图像视图控制器中\\N{\\fs12}and make sure that that's an image view controller.\r\nDialogue: 0,1:15:41.24,1:15:43.05,yin,,0,0,0,,如果它是 我就将\\N{\\fs12}But if it is, then I'm just going\r\nDialogue: 0,1:15:43.05,1:15:46.54,yin,,0,0,0,,调用下面这里的prepareImageViewController\\N{\\fs12}to call my prepare image controller thing down here,\r\nDialogue: 0,1:15:46.54,1:15:48.57,yin,,0,0,0,,这将是detail\\N{\\fs12}and this is going to be the detail.\r\nDialogue: 0,1:15:48.57,1:15:55.04,yin,,0,0,0,,照片将是self.photos[indexPath.row]\\N{\\fs12}And the photo is going to be self.photos indexpath.row.\r\nDialogue: 0,1:15:55.04,1:15:59.59,yin,,0,0,0,,因为它给我的是选中的索引路径\\N{\\fs12}Because it gives me the index path that got selected.\r\nDialogue: 0,1:15:59.59,1:16:01.76,yin,,0,0,0,,这就是这里需要发生的事情\\N{\\fs12}Right? So that's all that needs to happen here.\r\nDialogue: 0,1:16:01.76,1:16:05.20,yin,,0,0,0,,我们运行着试下\\N{\\fs12}So let's just go ahead and run this.\r\nDialogue: 0,1:16:05.20,1:16:07.48,yin,,0,0,0,,哦 我应该在iPad上运行\\N{\\fs12}Oops. Well it's running on an iPad how about that?\r\nDialogue: 0,1:16:07.48,1:16:09.51,yin,,0,0,0,,在真实设备上运行 如何\\N{\\fs12}Well we'll run it on the real device how about.\r\nDialogue: 0,1:16:24.12,1:16:28.36,yin,,0,0,0,,好 还是一样 这里被阻塞了 直到内容被加载完毕\\N{\\fs12}Okay. So again, it blocked until it had loaded that thing,\r\nDialogue: 0,1:16:28.36,1:16:29.49,yin,,0,0,0,,这比较不幸\\N{\\fs12}which is unfortunate.\r\nDialogue: 0,1:16:29.49,1:16:30.61,yin,,0,0,0,,转轮在转\\N{\\fs12}That thing is spinning.\r\nDialogue: 0,1:16:30.61,1:16:33.88,yin,,0,0,0,,我不喜欢这个 因为我还没有选任何照片\\N{\\fs12}I don't really like that because I haven't picked a photo yet.\r\nDialogue: 0,1:16:33.88,1:16:37.89,yin,,0,0,0,,免得忘记了 我现在就回到iPad故事板\\N{\\fs12}So I'm just going to go quickly, before I even forget, go back to my iPad storyboard --\r\nDialogue: 0,1:16:37.89,1:16:41.66,yin,,0,0,0,,而且只处理iPad故事板 另一个则不用\\N{\\fs12}and only in my iPad storyboard, not in the other one.\r\nDialogue: 0,1:16:41.66,1:16:43.17,yin,,0,0,0,,我要选\\N{\\fs12}I'm going to pick\r\nDialogue: 0,1:16:43.17,1:16:46.92,yin,,0,0,0,,那个活动视图控制器 这里\\N{\\fs12}that activity view controller, which is right here.\r\nDialogue: 0,1:16:46.92,1:16:48.58,yin,,0,0,0,,我要检查它\\N{\\fs12}And I'm going to inspect it.\r\nDialogue: 0,1:16:48.58,1:16:50.35,yin,,0,0,0,,让它不要一开始就出现动画\\N{\\fs12}And I'm going to not start it out animating.\r\nDialogue: 0,1:16:50.35,1:16:52.08,yin,,0,0,0,,另一个故事板中仍然会这样做\\N{\\fs12}It's still going to do it in my other one --\r\nDialogue: 0,1:16:52.08,1:16:54.10,yin,,0,0,0,,这没问题 因为那个是在创建一个新的视图控制器\\N{\\fs12}which is okay because that's creating a new view controller\r\nDialogue: 0,1:16:54.10,1:16:57.32,yin,,0,0,0,,每次segue时都是如此 这个则不一样\\N{\\fs12}every time I segue -- but not in this one --\r\nDialogue: 0,1:16:57.32,1:17:01.36,yin,,0,0,0,,不过我希望在点击图片时 例如罗马 它会加载罗马\\N{\\fs12}but hopefully if I click on a picture -- like Rome here -- it loads up Rome.\r\nDialogue: 0,1:17:01.36,1:17:02.25,yin,,0,0,0,,这是罗马\\N{\\fs12}And so here is Rome.\r\nDialogue: 0,1:17:02.25,1:17:03.60,yin,,0,0,0,,我可以放大\\N{\\fs12}I can zoom in.\r\nDialogue: 0,1:17:03.60,1:17:07.64,yin,,0,0,0,,我还可以选另一张图 例如巴克莱中心\\N{\\fs12}If I pick another picture, let's say Barclays Center -- That's --\r\nDialogue: 0,1:17:07.64,1:17:09.94,yin,,0,0,0,,这没问题 我猜\\N{\\fs12}oh well, that looks okay I guess.\r\nDialogue: 0,1:17:09.94,1:17:11.04,yin,,0,0,0,,这个能行\\N{\\fs12}This worked.\r\nDialogue: 0,1:17:11.04,1:17:13.66,yin,,0,0,0,,但有点偏离\\N{\\fs12}It's kind of a little off.\r\nDialogue: 0,1:17:13.66,1:17:15.22,yin,,0,0,0,,可以看到 顶部有白色\\N{\\fs12}You'll see there's the white at the top.\r\nDialogue: 0,1:17:15.22,1:17:16.64,yin,,0,0,0,,这并不很对\\N{\\fs12}That's not really quite right.\r\nDialogue: 0,1:17:16.64,1:17:19.74,yin,,0,0,0,,左侧有白色区域 看到左侧的白色区域了吗\\N{\\fs12}And this white on the left -- you see the white on the left --\r\nDialogue: 0,1:17:19.74,1:17:21.56,yin,,0,0,0,,左侧的白色区域是怎么回事\\N{\\fs12}what's going on with the white on the left?\r\nDialogue: 0,1:17:21.56,1:17:22.51,yin,,0,0,0,,为什么会有这个\\N{\\fs12}Why is this happening?\r\nDialogue: 0,1:17:22.51,1:17:25.84,yin,,0,0,0,,我们的图像视图控制器设计得并没有这么好\\N{\\fs12}Well we didn't design our image view controller that well\r\nDialogue: 0,1:17:25.84,1:17:28.15,yin,,0,0,0,,能像这样再利用\\N{\\fs12}to be reused like this.\r\nDialogue: 0,1:17:28.15,1:17:29.49,yin,,0,0,0,,这个图像视图控制器\\N{\\fs12}This image view controller is staying\r\nDialogue: 0,1:17:29.49,1:17:32.26,yin,,0,0,0,,一直待在屏幕上并被再利用\\N{\\fs12}on screen all the time and being reused.\r\nDialogue: 0,1:17:32.26,1:17:34.45,yin,,0,0,0,,它其中会有一些bug\\N{\\fs12}And it has a couple of bugs in it that are causing\r\nDialogue: 0,1:17:34.45,1:17:38.10,yin,,0,0,0,,如果我放大了 然后换另外一张照片\\N{\\fs12}when I zoom in, and then I replace it with another photo.\r\nDialogue: 0,1:17:38.10,1:17:40.28,yin,,0,0,0,,首先 它不会重置缩放尺度\\N{\\fs12}First of all it's not resetting the zoom scale back\r\nDialogue: 0,1:17:40.28,1:17:41.80,yin,,0,0,0,,为1 这本是应该的\\N{\\fs12}down to one -- which it should --\r\nDialogue: 0,1:17:41.80,1:17:43.60,yin,,0,0,0,,而且在缩放匹配时\\N{\\fs12}but also it's sizing to fit\r\nDialogue: 0,1:17:43.60,1:17:48.08,yin,,0,0,0,,它会不再处在可滚动区域的左上角\\N{\\fs12}and causing it to no longer be in the upper left-hand corner of our scrollable area.\r\nDialogue: 0,1:17:48.08,1:17:49.81,yin,,0,0,0,,我们快速修正一下这个\\N{\\fs12}So let's fix that real quick.\r\nDialogue: 0,1:17:49.81,1:17:51.44,yin,,0,0,0,,到图像视图控制器\\N{\\fs12}Let's go to our image view controller.\r\nDialogue: 0,1:17:51.44,1:17:52.89,yin,,0,0,0,,修正很简单\\N{\\fs12}Those are easy fixes.\r\nDialogue: 0,1:17:52.89,1:17:56.58,yin,,0,0,0,,每次设定图像时 我们都要让scrollView\\N{\\fs12}Every time we set an image, we're going to take our scrollView\r\nDialogue: 0,1:17:56.58,1:18:00.67,yin,,0,0,0,,重置缩放尺度为1\\N{\\fs12}and reset it's zoom scale back to one.\r\nDialogue: 0,1:18:00.67,1:18:03.59,yin,,0,0,0,,这里我们不再仅仅使用sizeToFit\\N{\\fs12}And instead of just doing size to fit right here,\r\nDialogue: 0,1:18:03.59,1:18:08.28,yin,,0,0,0,,我们打算明确将图像视图框\\N{\\fs12}we're going to explicitly set the image views frame\r\nDialogue: 0,1:18:08.28,1:18:12.39,yin,,0,0,0,,设为一个我们要生成的矩形 它处在原点\\N{\\fs12}to a rectangle that we're going to make, which is at the origin.\r\nDialogue: 0,1:18:12.39,1:18:19.05,yin,,0,0,0,,而且宽度是图像的宽度 高度是图像的高度\\N{\\fs12}And is the images size.width and the images size.height.\r\nDialogue: 0,1:18:19.05,1:18:20.82,yin,,0,0,0,,这样bug就修正了\\N{\\fs12}Okay. So that will fix that bug.\r\nDialogue: 0,1:18:20.82,1:18:22.94,yin,,0,0,0,,我们不再使用sizeToFit\\N{\\fs12}We don't want size to fit anymore because we're doing --\r\nDialogue: 0,1:18:22.94,1:18:25.21,yin,,0,0,0,,而是使用图像本身大小\\N{\\fs12}this is sizing it to fit essentially.\r\nDialogue: 0,1:18:25.21,1:18:27.39,yin,,0,0,0,,这个bug被修正了 这很好\\N{\\fs12}So we fixed that bug. That's nice.\r\nDialogue: 0,1:18:27.39,1:18:29.68,yin,,0,0,0,,另外还有一点不是太好\\N{\\fs12}The other thing that's not so great about this\r\nDialogue: 0,1:18:29.68,1:18:31.94,yin,,0,0,0,,要是在顶部有个标题就好了\\N{\\fs12}is it'd be nice to have a title along the top.\r\nDialogue: 0,1:18:31.94,1:18:33.08,yin,,0,0,0,,我们设置了标题\\N{\\fs12}We set the title,\r\nDialogue: 0,1:18:33.08,1:18:36.29,yin,,0,0,0,,但它并没有出现在detail一侧的任何地方\\N{\\fs12}but it doesn't appear anywhere on the detail side.\r\nDialogue: 0,1:18:36.29,1:18:40.58,yin,,0,0,0,,要是能有一个标题就好了 就像这边这样\\N{\\fs12}Right? So it'd be nice if we had a title just like on the -- this side over here.\r\nDialogue: 0,1:18:40.58,1:18:42.56,yin,,0,0,0,,这上面显示说Shutterbug\\N{\\fs12}That says Shutter Bug at the top, it'd be nice\r\nDialogue: 0,1:18:42.56,1:18:46.09,yin,,0,0,0,,右边我们也希望这里有 Jake at the Breakers\\N{\\fs12}if it said Jake at the Breakers over here on the right.\r\nDialogue: 0,1:18:46.09,1:18:47.92,yin,,0,0,0,,怎么做呢\\N{\\fs12}So how are we going to do that?\r\nDialogue: 0,1:18:47.94,1:18:50.22,yin,,0,0,0,,这个技巧其实我原来就讲过\\N{\\fs12}I'm going to do that with that little trick I told you.\r\nDialogue: 0,1:18:50.22,1:18:53.93,yin,,0,0,0,,我要到我的iPad故事板\\N{\\fs12}I'm just going to go here to my iPad storyboard.\r\nDialogue: 0,1:18:53.93,1:18:56.93,yin,,0,0,0,,选取这个detail视图 然后\\N{\\fs12}I'm going to pick this detail view and I'm just going\r\nDialogue: 0,1:18:56.93,1:19:00.53,yin,,0,0,0,,将它嵌入到导航控制器中\\N{\\fs12}to embed it in a navigation controller.\r\nDialogue: 0,1:19:00.53,1:19:02.34,yin,,0,0,0,,这样问题就能修复了\\N{\\fs12}And that's just going to fix that problem.\r\nDialogue: 0,1:19:02.34,1:19:04.69,yin,,0,0,0,,运行着试下 我们修正了三个问题\\N{\\fs12}So let's go ahead and run -- well we've fixed three problems there.\r\nDialogue: 0,1:19:04.69,1:19:07.58,yin,,0,0,0,,下面看看问题有没有真正解决\\N{\\fs12}Let's make sure all these problems actually got fixed.\r\nDialogue: 0,1:19:08.71,1:19:12.42,yin,,0,0,0,,你们会看到 问题是修正了 但又会有新问题产生\\N{\\fs12}And you're going to see that we fixed them, but we introduced a problem as well.\r\nDialogue: 0,1:19:19.48,1:19:21.80,yin,,0,0,0,,现在是这样了 这个会更好\\N{\\fs12}Okay so we have this -- oh this is better.\r\nDialogue: 0,1:19:21.80,1:19:23.74,yin,,0,0,0,,上面这里有预留空间\\N{\\fs12}We've got this space on the top right there.\r\nDialogue: 0,1:19:23.74,1:19:27.45,yin,,0,0,0,,但愿我们在点击罗马或是免费票时\\N{\\fs12}Hopefully when we click on something like Rome or free tickets.\r\nDialogue: 0,1:19:27.45,1:19:29.69,yin,,0,0,0,,我们会得到… 哦 什么都没显示\\N{\\fs12}We'll get -- oh it's not working anymore.\r\nDialogue: 0,1:19:29.69,1:19:31.89,yin,,0,0,0,,为什么右边什么都没显示\\N{\\fs12}Why is it not putting anything on the right?\r\nDialogue: 0,1:19:31.89,1:19:37.60,yin,,0,0,0,,原因在于 detail被改变 它不再是图像视图控制器\\N{\\fs12}And the reason for that is we changed the detail to not be an image view controller.\r\nDialogue: 0,1:19:37.81,1:19:40.75,yin,,0,0,0,,而是一个导航控制器\\N{\\fs12}Instead, it's now a navigation controller.\r\nDialogue: 0,1:19:40.75,1:19:47.75,yin,,0,0,0,,但我们这里更新didSelectRowAtIndexPath的代码\\N{\\fs12}So our code over here, where we update with didselectrow atindexpath.\r\nDialogue: 0,1:19:47.75,1:19:51.87,yin,,0,0,0,,却在检验detail是不是图像视图控制器\\N{\\fs12}It's checking if detail is kind of class image view controller.\r\nDialogue: 0,1:19:51.87,1:19:54.53,yin,,0,0,0,,这注定失败 因为它不是\\N{\\fs12}And that's failing because it's not.\r\nDialogue: 0,1:19:54.53,1:19:56.13,yin,,0,0,0,,不过这个很好修正\\N{\\fs12}But this is an easy fix as well.\r\nDialogue: 0,1:19:56.13,1:19:57.85,yin,,0,0,0,,我们只需要说 if detail\\N{\\fs12}We're just going to say if the detail\r\nDialogue: 0,1:19:57.85,1:19:59.21,yin,,0,0,0,,isKindOfClass\\N{\\fs12}is kind of class,\r\nDialogue: 0,1:19:59.21,1:20:01.45,yin,,0,0,0,,UINavigationController\\N{\\fs12}UI navigation controller.\r\nDialogue: 0,1:20:01.45,1:20:04.11,yin,,0,0,0,,如果detail属于UI导航控制器这一类\\N{\\fs12}So if there's a UI navigation controller in the detail,\r\nDialogue: 0,1:20:04.11,1:20:10.33,yin,,0,0,0,,那么detail实际上就是UINavigationController\\N{\\fs12}then the detail is really the UI navigation controller\r\nDialogue: 0,1:20:10.33,1:20:14.66,yin,,0,0,0,,detail.viewControllers firstObject\\N{\\fs12}detail.viewcontrollers firstobject.\r\nDialogue: 0,1:20:14.66,1:20:17.59,yin,,0,0,0,,也就是导航控制器中的根视图控制器\\N{\\fs12}In other words the root view controller in navigation controller. So I'm just --\r\nDialogue: 0,1:20:17.61,1:20:19.55,yin,,0,0,0,,如果detail是导航控制器\\N{\\fs12}if the detail is in the navigation controller,\r\nDialogue: 0,1:20:19.55,1:20:22.95,yin,,0,0,0,,我就会进去获得它的根视图控制器\\N{\\fs12}I'm just going to look in and get its root view controller instead.\r\nDialogue: 0,1:20:24.20,1:20:28.28,yin,,0,0,0,,这样问题就解决了\\N{\\fs12}So fixes that problem.\r\nDialogue: 0,1:20:29.48,1:20:31.16,yin,,0,0,0,,但愿吧\\N{\\fs12}Hopefully.\r\nDialogue: 0,1:20:35.71,1:20:37.55,yin,,0,0,0,,好 再次试试罗马\\N{\\fs12}Okay. So let's try Rome again --\r\nDialogue: 0,1:20:37.55,1:20:40.49,yin,,0,0,0,,好 现在上面有了罗马的标题\\N{\\fs12}oh now we got the title Rome up there at the top.\r\nDialogue: 0,1:20:40.49,1:20:43.06,yin,,0,0,0,,哪怕是放大以后\\N{\\fs12}Even if we zoom in on this and switch\r\nDialogue: 0,1:20:43.06,1:20:47.02,yin,,0,0,0,,再换到别的照片 缩放尺度还是回到了1\\N{\\fs12}to another one that's different, it went back to zoom scale one,\r\nDialogue: 0,1:20:47.02,1:20:49.96,yin,,0,0,0,,左边也没有任何白色边缘\\N{\\fs12}and we don't have white on the left edge, right?\r\nDialogue: 0,1:20:49.96,1:20:52.20,yin,,0,0,0,,这次 我再把图像缩小一些\\N{\\fs12}So even if -- again, we'll make it really small this time.\r\nDialogue: 0,1:20:52.20,1:20:54.78,yin,,0,0,0,,点击罗得岛纽波特\\N{\\fs12}We'll click to Newport, Rhode Island here.\r\nDialogue: 0,1:20:54.78,1:20:57.39,yin,,0,0,0,,缩放尺度回到了1 而且没有白色边缘\\N{\\fs12}Okay it went back to zoom scale of 1 with no white.\r\nDialogue: 0,1:20:57.39,1:20:59.94,yin,,0,0,0,,所有问题都解决了\\N{\\fs12}So we fixed all of our problems. We didn't have that\r\nDialogue: 0,1:20:59.95,1:21:03.04,yin,,0,0,0,,我们也没有了一开始的转轮动画\\N{\\fs12}the animating thing -- animating at the beginning\r\nDialogue: 0,1:21:03.04,1:21:07.16,yin,,0,0,0,,当然 选择新照片时 动画显然会出现 这很好\\N{\\fs12}although it does animate when we pick a new 1, so that's all good.\r\nDialogue: 0,1:21:07.16,1:21:08.95,yin,,0,0,0,,看起来非常棒\\N{\\fs12}So this is really looking good.\r\nDialogue: 0,1:21:08.95,1:21:12.96,yin,,0,0,0,,我做这个是因为这是典型的循环渐进过程\\N{\\fs12}So this is a typical kind of -- I wanted to do this because it's kind\r\nDialogue: 0,1:21:12.96,1:21:16.90,yin,,0,0,0,,只是有些加速了 毕竟这里只是课堂演示\\N{\\fs12}of a typical iteration process; speeded up of course because we're in a demo here.\r\nDialogue: 0,1:21:16.90,1:21:18.99,yin,,0,0,0,,一开始 你发现出了某种问题\\N{\\fs12}Where you find something that doesn't quite work.\r\nDialogue: 0,1:21:18.99,1:21:19.96,yin,,0,0,0,,怎么回事\\N{\\fs12}Hmm. What's going on?\r\nDialogue: 0,1:21:19.96,1:21:23.65,yin,,0,0,0,,你回到代码 然后修正错误 如此往复\\N{\\fs12}You go back to your code; you have to fix some things, etcetera.\r\nDialogue: 0,1:21:23.65,1:21:28.73,yin,,0,0,0,,最后 我们其实还有一个问题\\N{\\fs12}So the last thing that I want to show -- now we do have another problem here.\r\nDialogue: 0,1:21:28.73,1:21:32.01,yin,,0,0,0,,我一直都是在横屏模式展示 下面来看竖屏\\N{\\fs12}I've been showing this in landscape. Let's look at this thing in portrait.\r\nDialogue: 0,1:21:32.01,1:21:34.19,yin,,0,0,0,,在竖屏中 这很棒\\N{\\fs12}Okay. This is awesome in portrait. This is great.\r\nDialogue: 0,1:21:34.19,1:21:36.21,yin,,0,0,0,,只是我无法访问master\\N{\\fs12}Except for I can't get at the master.\r\nDialogue: 0,1:21:36.21,1:21:40.59,yin,,0,0,0,,我没办法换照片 要换照片只能回到横屏\\N{\\fs12}I can't change my photo. It's -- the only way to change a photo is to go back here.\r\nDialogue: 0,1:21:40.59,1:21:42.11,yin,,0,0,0,,这显然不好\\N{\\fs12}So that's not so nice.\r\nDialogue: 0,1:21:42.11,1:21:45.07,yin,,0,0,0,,我们希望在左上角有一个按钮\\N{\\fs12}It would be nice if we had this button in the upper left\r\nDialogue: 0,1:21:45.07,1:21:46.70,yin,,0,0,0,,能够让我们选择照片\\N{\\fs12}over here, that would bring out that thing.\r\nDialogue: 0,1:21:46.70,1:21:48.15,yin,,0,0,0,,我们快速做一下\\N{\\fs12}So let's do that real quick.\r\nDialogue: 0,1:21:48.15,1:21:52.99,yin,,0,0,0,,这其实很容易搞定 因为这里我们处在导航控制器中\\N{\\fs12}That turns out to be quite easy to do, because we're in a navigation controller there.\r\nDialogue: 0,1:21:53.25,1:21:55.68,yin,,0,0,0,,我们打算在图像控制器中这样做\\N{\\fs12}And we're going to do that in the image controller.\r\nDialogue: 0,1:21:55.68,1:21:59.00,yin,,0,0,0,,原因在于 它处在detail上\\N{\\fs12}The reason I'm going to do it in the image view controller is because it's on the detail.\r\nDialogue: 0,1:21:59.00,1:22:01.04,yin,,0,0,0,,它在这里可见\\N{\\fs12}It's what's visible right here.\r\nDialogue: 0,1:22:01.04,1:22:04.81,yin,,0,0,0,,我要将它弄成SplitView控制器委托\\N{\\fs12}So I'm going to make it be the SplitView controller delegate.\r\nDialogue: 0,1:22:04.81,1:22:06.55,yin,,0,0,0,,到下面这里\\N{\\fs12}So just go down to the bottom here.\r\nDialogue: 0,1:22:06.55,1:22:12.93,yin,,0,0,0,,pragma mark UISplitViewControllerDelegate\\N{\\fs12}Pragmamark UIsplitviewcontroller delegate.\r\nDialogue: 0,1:22:12.93,1:22:15.67,yin,,0,0,0,,我打算使用awakeFromNib\\N{\\fs12}Okay. And I'm going to do this awake from NIB.\r\nDialogue: 0,1:22:15.67,1:22:20.55,yin,,0,0,0,,我这里说 self.splitViewController.delegate = self\\N{\\fs12}I'm going to say self.splitview controller.delegate =self.\r\nDialogue: 0,1:22:20.55,1:22:22.87,yin,,0,0,0,,在awakeFromNib中 我可以这样做\\N{\\fs12}Okay. That's okay to do in awake from NIB\r\nDialogue: 0,1:22:22.87,1:22:25.94,yin,,0,0,0,,因为这到awakeFromNib发生时将会设定\\N{\\fs12}because this will be set by the time awake from NIB happens.\r\nDialogue: 0,1:22:25.94,1:22:27.52,yin,,0,0,0,,虽然这非常非常早\\N{\\fs12}Even though that's really, really early.\r\nDialogue: 0,1:22:27.52,1:22:29.64,yin,,0,0,0,,我得到了一个警告 因为我还需要\\N{\\fs12}I'm getting a warning because I have to say\r\nDialogue: 0,1:22:29.64,1:22:33.81,yin,,0,0,0,,UISplitViewControllerDelegate\\N{\\fs12}UI SplitView controller delegate.\r\nDialogue: 0,1:22:33.81,1:22:37.88,yin,,0,0,0,,好 现在我还要在协议中实现这些方法\\N{\\fs12}Okay. Now I've got to implement the methods in that protocol.\r\nDialogue: 0,1:22:37.88,1:22:40.86,yin,,0,0,0,,它们是这样的 splitView 这里有很多东西\\N{\\fs12}They look like this, SplitView so there's a whole bunch of them here.\r\nDialogue: 0,1:22:40.86,1:22:42.91,yin,,0,0,0,,我要用的是\\N{\\fs12}Actually I'm going to do the one\r\nDialogue: 0,1:22:42.91,1:22:47.25,yin,,0,0,0,,决定master是否隐藏的那个\\N{\\fs12}which says whether to hide the thing first --\r\nDialogue: 0,1:22:47.25,1:22:48.94,yin,,0,0,0,,也就是这个\\N{\\fs12}that's this one.\r\nDialogue: 0,1:22:48.94,1:22:51.71,yin,,0,0,0,,Tab 上面这里留点空间\\N{\\fs12}So tab. Up here I'm going to make some space\r\nDialogue: 0,1:22:51.71,1:22:53.90,yin,,0,0,0,,这样就不会一直滚到底部\\N{\\fs12}so this stops scrolling all the way to the bottom.\r\nDialogue: 0,1:22:53.90,1:22:58.36,yin,,0,0,0,,这个是说 我在特定朝向下是否隐藏master\\N{\\fs12}So this is the one that says should I hide the master in a certain orientation?\r\nDialogue: 0,1:22:58.36,1:23:00.88,yin,,0,0,0,,这里我想说 隐藏master…\\N{\\fs12}And I'm going to say, only hide it --\r\nDialogue: 0,1:23:00.88,1:23:02.80,yin,,0,0,0,,看看我记不记得这个叫什么\\N{\\fs12}let's see if I can remember what this thing is called --\r\nDialogue: 0,1:23:02.80,1:23:10.15,yin,,0,0,0,,仅当UI界面朝向是竖屏的时候\\N{\\fs12}UI interface orientation is portrait.\r\nDialogue: 0,1:23:10.15,1:23:15.29,yin,,0,0,0,,我将只在竖屏模式隐藏master\\N{\\fs12}Okay. So in portrait mode only, I'm going to hide the master.\r\nDialogue: 0,1:23:15.29,1:23:18.54,yin,,0,0,0,,隐藏后 我就需要处理这个splitView…\\N{\\fs12}So now when I hide it, I have to do this SplitView.\r\nDialogue: 0,1:23:18.54,1:23:20.83,yin,,0,0,0,,我要做两件事\\N{\\fs12}I have to do these two things, will hide --\r\nDialogue: 0,1:23:20.83,1:23:22.93,yin,,0,0,0,,willHide和willShow\\N{\\fs12}will hide and will show.\r\nDialogue: 0,1:23:22.93,1:23:25.66,yin,,0,0,0,,willHide在这里\\N{\\fs12}So let's do will hide right there.\r\nDialogue: 0,1:23:25.66,1:23:30.90,yin,,0,0,0,,然后是splitView willShow\\N{\\fs12}And then let's do with SplitView will show.\r\nDialogue: 0,1:23:30.90,1:23:32.16,yin,,0,0,0,,好长\\N{\\fs12}That's a mouthful.\r\nDialogue: 0,1:23:32.16,1:23:34.35,yin,,0,0,0,,好 我们这样做\\N{\\fs12}Okay. So let's do that.\r\nDialogue: 0,1:23:34.35,1:23:36.22,yin,,0,0,0,,由于我处在导航控制器中\\N{\\fs12}And because I'm in a navigation controller,\r\nDialogue: 0,1:23:36.22,1:23:38.70,yin,,0,0,0,,这些都非常非常容易实现\\N{\\fs12}these turn out to be really, really easy to implement.\r\nDialogue: 0,1:23:38.70,1:23:42.60,yin,,0,0,0,,当我隐藏时 它会给我这个栏按钮\\N{\\fs12}Okay. When I hide it gives me this bar button right here.\r\nDialogue: 0,1:23:42.60,1:23:45.95,yin,,0,0,0,,我只需要把这个放入我的导航项目\\N{\\fs12}And I just need to put that in my navigation item\r\nDialogue: 0,1:23:45.95,1:23:53.93,yin,,0,0,0,,这样它就会作为左侧栏按钮项目出现\\N{\\fs12}so that it will appear as the left bar button item.\r\nDialogue: 0,1:23:53.93,1:23:55.85,yin,,0,0,0,,这里还有一个技巧\\N{\\fs12}I'm going to do another little trick here.\r\nDialogue: 0,1:23:55.85,1:23:58.69,yin,,0,0,0,,也就是 我想要我的图像视图控制器\\N{\\fs12}Is that I want my image view controller,\r\nDialogue: 0,1:23:58.69,1:24:02.00,yin,,0,0,0,,我不需要它知道Flickr照片的任何信息\\N{\\fs12}I don't want it to know anything about that Flickr photo thing.\r\nDialogue: 0,1:24:02.00,1:24:09.37,yin,,0,0,0,,因此 我可以将栏按钮项目的标题设为master的标题\\N{\\fs12}So I'm actually going to set this bar button item's title equal to the master title.\r\nDialogue: 0,1:24:09.37,1:24:13.15,yin,,0,0,0,,无论被隐藏的master的标题是什么\\N{\\fs12}So whatever the title of the master that's being hidden,\r\nDialogue: 0,1:24:13.15,1:24:15.68,yin,,0,0,0,,这个按钮都将使用这个标题\\N{\\fs12}that's what I'm going to make that little button say as its title.\r\nDialogue: 0,1:24:15.68,1:24:19.01,yin,,0,0,0,,我需要回到iPad故事板来设置这个\\N{\\fs12}So I better go back to my iPad storyboard and set this,\r\nDialogue: 0,1:24:19.01,1:24:22.89,yin,,0,0,0,,也就是 我要设置它的标题 可以在故事板中设\\N{\\fs12}which is, the thing I better set its title, which I can set in the storyboard.\r\nDialogue: 0,1:24:22.89,1:24:25.57,yin,,0,0,0,,这个我们称之为Shutterbug\\N{\\fs12}We'll call this Shutter Bug.\r\nDialogue: 0,1:24:25.57,1:24:30.78,yin,,0,0,0,,这会让SplitView控制器的这段代码更通用一些\\N{\\fs12}So that's going to make this code for the SplitView controller more generic here.\r\nDialogue: 0,1:24:30.78,1:24:33.72,yin,,0,0,0,,然后 当这个东西消失时\\N{\\fs12}And then when the thing goes away,\r\nDialogue: 0,1:24:33.72,1:24:37.41,yin,,0,0,0,,我要把这个左侧栏按钮项目设置为nil\\N{\\fs12}I'm just going to set this left bar button item equal to nil\r\nDialogue: 0,1:24:37.41,1:24:39.03,yin,,0,0,0,,让那个东西消失\\N{\\fs12}to make that thing go away.\r\nDialogue: 0,1:24:39.03,1:24:40.55,yin,,0,0,0,,这就修正了\\N{\\fs12}Alright? So that fixes that.\r\nDialogue: 0,1:24:40.96,1:24:42.51,yin,,0,0,0,,看看结果怎样\\N{\\fs12}Let's go see what that looks like.\r\nDialogue: 0,1:24:56.13,1:24:59.13,yin,,0,0,0,,好 这里是横屏模式\\N{\\fs12}Okay. So here I have in landscape it shows.\r\nDialogue: 0,1:24:59.13,1:25:01.45,yin,,0,0,0,,进入竖屏 master没了\\N{\\fs12}When I go here to portrait it goes away.\r\nDialogue: 0,1:25:01.45,1:25:03.25,yin,,0,0,0,,不过左上角有了一个按钮\\N{\\fs12}But now I have this button in the upper left.\r\nDialogue: 0,1:25:03.25,1:25:06.06,yin,,0,0,0,,点击 master就会出来\\N{\\fs12}If I click it, it slides that thing out.\r\nDialogue: 0,1:25:06.06,1:25:08.09,yin,,0,0,0,,点别的地方 它就会消失\\N{\\fs12}If I click somewhere else it goes away.\r\nDialogue: 0,1:25:08.09,1:25:11.51,yin,,0,0,0,,我可以点这里 获得某张照片\\N{\\fs12}So I can click here, get some photo.\r\nDialogue: 0,1:25:11.51,1:25:12.59,yin,,0,0,0,,或许罗马会好点\\N{\\fs12}Maybe Rome would be better.\r\nDialogue: 0,1:25:12.59,1:25:14.54,yin,,0,0,0,,我不知道巴克莱中心那个是什么东西\\N{\\fs12}I don't know what the Barclays center's about.\r\nDialogue: 0,1:25:14.54,1:25:16.35,yin,,0,0,0,,罗马更安全一些\\N{\\fs12}Rome seems safe.\r\nDialogue: 0,1:25:16.35,1:25:17.58,yin,,0,0,0,,这是罗马\\N{\\fs12}So here's Rome, right?\r\nDialogue: 0,1:25:17.58,1:25:18.56,yin,,0,0,0,,这很好\\N{\\fs12}And this is nice, we can do this.\r\nDialogue: 0,1:25:18.56,1:25:21.12,yin,,0,0,0,,如果我们想要别的 我把这个弄出来\\N{\\fs12}But if I want something else, I can just slide this thing out.\r\nDialogue: 0,1:25:21.12,1:25:23.82,yin,,0,0,0,,再下面 再找一张不同的罗马照片\\N{\\fs12}Look down; find a different Rome.\r\nDialogue: 0,1:25:23.82,1:25:25.42,yin,,0,0,0,,好理解吧\\N{\\fs12}Makes sense?\r\nDialogue: 0,1:25:25.42,1:25:29.50,yin,,0,0,0,,回到横屏模式 按钮就消失了\\N{\\fs12}If I slide back to landscape, you take that button away. That button is no longer there.\r\nDialogue: 0,1:25:29.50,1:25:31.67,yin,,0,0,0,,这就是那个委托的作用\\N{\\fs12}Okay. So that's what that delegate's doing.\r\nDialogue: 0,1:25:31.67,1:25:33.32,yin,,0,0,0,,这让我们更容易实现\\N{\\fs12}It was easy for us to implement\r\nDialogue: 0,1:25:33.32,1:25:36.46,yin,,0,0,0,,因为我们把detail放入了一个SplitView控制器\\N{\\fs12}because we put the detail into a SplitView controller.\r\nDialogue: 0,1:25:36.46,1:25:40.95,yin,,0,0,0,,总想做到这一点 并没有那么简单\\N{\\fs12}It wouldn't always be so easy to do that.\r\nDialogue: 0,1:25:40.95,1:25:46.13,yin,,0,0,0,,最后我要做一件事 也就是修正\\N{\\fs12}The last thing I'm going to do here is fix that problem\r\nDialogue: 0,1:25:46.13,1:25:48.58,yin,,0,0,0,,主线程阻塞的问题\\N{\\fs12}with the blocking of the main thread.\r\nDialogue: 0,1:25:48.58,1:25:52.68,yin,,0,0,0,,我打算很快地做一下 看好了\\N{\\fs12}I'm going to do this super fast. So hang onto your hats.\r\nDialogue: 0,1:25:52.68,1:25:54.07,yin,,0,0,0,,在这里\\N{\\fs12}I'm going to do that here.\r\nDialogue: 0,1:25:54.07,1:25:57.00,yin,,0,0,0,,我将使用一种不同以往的做法\\N{\\fs12}And I'm going to do it in a different way than we did before.\r\nDialogue: 0,1:25:57.02,1:25:59.99,yin,,0,0,0,,因为我想教给你们另一种做法\\N{\\fs12}Because I want to show you a different way to do this.\r\nDialogue: 0,1:25:59.99,1:26:02.85,yin,,0,0,0,,这里 我打算创建我自己的队列\\N{\\fs12}Which is, I'm going to create my own queue.\r\nDialogue: 0,1:26:02.85,1:26:06.35,yin,,0,0,0,,dispatch_queue_t\\N{\\fs12}So dispatchunderbar queueunderbarT --\r\nDialogue: 0,1:26:06.35,1:26:08.88,yin,,0,0,0,,这里我叫它fetchQ\\N{\\fs12}fetchqueue I'll call it.\r\nDialogue: 0,1:26:08.88,1:26:13.41,yin,,0,0,0,,我要用dispatch_queue_create创建它\\N{\\fs12}I'm going to create it with dispatch create queue create.\r\nDialogue: 0,1:26:13.41,1:26:18.16,yin,,0,0,0,,我将称它为flicker fetcher\\N{\\fs12}I'm going to call it Flickerfetcher -- that's just the name I'm going to call it.\r\nDialogue: 0,1:26:18.16,1:26:19.51,yin,,0,0,0,,它是一个串行队列\\N{\\fs12}And it's a serial queue.\r\nDialogue: 0,1:26:19.51,1:26:21.51,yin,,0,0,0,,这样我就创建了我自己的队列\\N{\\fs12}So I just created my own queue.\r\nDialogue: 0,1:26:21.51,1:26:23.31,yin,,0,0,0,,一个全新的队列\\N{\\fs12}Brand new queue.\r\nDialogue: 0,1:26:23.31,1:26:25.54,yin,,0,0,0,,有了我自己的队列后 我就可以\\N{\\fs12}And now that I have my own queue I'm just going to\r\nDialogue: 0,1:26:25.54,1:26:28.90,yin,,0,0,0,,dispatch_async到这个队列上\\N{\\fs12}dispatch async onto that queue.\r\nDialogue: 0,1:26:29.62,1:26:31.06,yin,,0,0,0,,一段代码\\N{\\fs12}A block.\r\nDialogue: 0,1:26:33.13,1:26:37.96,yin,,0,0,0,,这段代码中间将是这些阻塞的内容\\N{\\fs12}And that block is just going to have this blocking stuff in it.\r\nDialogue: 0,1:26:39.98,1:26:41.75,yin,,0,0,0,,所有这些东西\\N{\\fs12}All this stuff here.\r\nDialogue: 0,1:26:41.75,1:26:43.60,yin,,0,0,0,,不过self.photos\\N{\\fs12}But self.photos -- okay?\r\nDialogue: 0,1:26:43.60,1:26:45.29,yin,,0,0,0,,不需要在这里\\N{\\fs12}Which does need to be in here,\r\nDialogue: 0,1:26:45.29,1:26:49.21,yin,,0,0,0,,很不幸 这会做处在UI中的事情\\N{\\fs12}unfortunately this is going to do stuff on -- that's in the UI so it needs\r\nDialogue: 0,1:26:49.21,1:26:53.51,yin,,0,0,0,,因此需要分派回主线程\\N{\\fs12}to be dispatched back to the main thread.\r\nDialogue: 0,1:26:58.15,1:27:00.13,yin,,0,0,0,,那个放到那里\\N{\\fs12}Alright. Put that there.\r\nDialogue: 0,1:27:00.13,1:27:01.51,yin,,0,0,0,,这个放到这里\\N{\\fs12}Put this here.\r\nDialogue: 0,1:27:02.66,1:27:04.42,yin,,0,0,0,,这样做之后\\N{\\fs12}So that's going to do this.\r\nDialogue: 0,1:27:04.42,1:27:06.52,yin,,0,0,0,,主线程就不会被阻塞了\\N{\\fs12}We're not going to block the main thread anymore.\r\nDialogue: 0,1:27:06.52,1:27:09.46,yin,,0,0,0,,我们通过创建自己的队列完成了这个工作\\N{\\fs12}So this is a way to do it by creating your own queue.\r\nDialogue: 0,1:27:09.46,1:27:11.78,yin,,0,0,0,,这里我们没有使用URLSession\\N{\\fs12}Instead of doing all that stuff we do with the URL session\r\nDialogue: 0,1:27:11.78,1:27:13.61,yin,,0,0,0,,而是像这样做了\\N{\\fs12}and all that stuff we can just do this.\r\nDialogue: 0,1:27:13.61,1:27:15.06,yin,,0,0,0,,那里有问题吗\\N{\\fs12}Is that a question right there?\r\nDialogue: 0,1:27:15.07,1:27:15.49,yin,,0,0,0,,请讲\\N{\\fs12}Yeah.\r\nDialogue: 0,1:27:17.50,1:27:19.78,yin,,0,0,0,,为什么这里我们不需要使用weak self\\N{\\fs12}Why do we not have to do weak self in this thing?\r\nDialogue: 0,1:27:19.78,1:27:23.88,yin,,0,0,0,,因为这段代码没有太强地被我们自身所引用\\N{\\fs12}Because this block is not held on too strongly by ourselves.\r\nDialogue: 0,1:27:23.88,1:27:25.46,yin,,0,0,0,,它很强地引用了我们\\N{\\fs12}We -- it holds us strongly,\r\nDialogue: 0,1:27:25.46,1:27:27.99,yin,,0,0,0,,但我们没有很强地引用它 这就没关系了\\N{\\fs12}but we don't hold it strongly so we're good to go.\r\nDialogue: 0,1:27:28.00,1:27:31.28,yin,,0,0,0,,最后我还要做一件事 这里我将同时来做\\N{\\fs12}And the last thing I'm going to do -- which I'll do at the same time here --\r\nDialogue: 0,1:27:31.28,1:27:35.28,yin,,0,0,0,,也就是刷新那个 因为这很容易做到\\N{\\fs12}is that little refresh thing, because that's really easy to do.\r\nDialogue: 0,1:27:35.28,1:27:38.96,yin,,0,0,0,,先在iPad版上来做 两个版本我们都会考虑\\N{\\fs12}And let's do that here on the iPad version -- we'll have to do it on both versions,\r\nDialogue: 0,1:27:38.96,1:27:41.61,yin,,0,0,0,,这里是我们的TableView\\N{\\fs12}but here's our TableView right here.\r\nDialogue: 0,1:27:41.61,1:27:45.66,yin,,0,0,0,,我们希望有一个刷新转轮在刷新时转动\\N{\\fs12}And we wanted to have a little refresh spinner when all that business is going on.\r\nDialogue: 0,1:27:45.66,1:27:47.67,yin,,0,0,0,,要做到这个 我们可以用检查器\\N{\\fs12}So to do that we just inspect it.\r\nDialogue: 0,1:27:47.67,1:27:50.65,yin,,0,0,0,,下面这里 可以看到它说刷新\\N{\\fs12}And down here you see it says refreshing, right here.\r\nDialogue: 0,1:27:50.65,1:27:52.24,yin,,0,0,0,,这里我们选启用\\N{\\fs12}So we're going to say enabled.\r\nDialogue: 0,1:27:52.24,1:27:54.87,yin,,0,0,0,,这样做之后 在文档大纲中你会看到\\N{\\fs12}And when we did that, in our document outline you'll see\r\nDialogue: 0,1:27:54.87,1:27:57.22,yin,,0,0,0,,我们这里得到了这个刷新控制\\N{\\fs12}that we got this refresh control right here.\r\nDialogue: 0,1:27:57.22,1:28:02.39,yin,,0,0,0,,而且我们还可以很轻松地得到下拉支持\\N{\\fs12}And really, for free we can get it -- the pull down support\r\nDialogue: 0,1:28:02.40,1:28:06.42,yin,,0,0,0,,只要我们在这里把fetchPhotos设为IBAction\\N{\\fs12}if we just make fetch photos here be an IB action.\r\nDialogue: 0,1:28:06.42,1:28:11.73,yin,,0,0,0,,因为 如果这是IBAction 我们就能control拖动到它\\N{\\fs12}Because if that's an IB action, then we can control drag to it.\r\nDialogue: 0,1:28:11.73,1:28:14.21,yin,,0,0,0,,因为我们可以control拖动到任何IBAction\\N{\\fs12}Because we can control drag to any IB action.\r\nDialogue: 0,1:28:14.21,1:28:17.55,yin,,0,0,0,,向下拉会调用这个fetchPhotos\\N{\\fs12}And so now that pull down is going to call this fetch photos.\r\nDialogue: 0,1:28:17.55,1:28:20.68,yin,,0,0,0,,在fetchPhotos中 我们仍然需要说\\N{\\fs12}Now we still are required, inside this fetch photos,\r\nDialogue: 0,1:28:20.68,1:28:24.39,yin,,0,0,0,,self.refreshControl beginRefreshing\\N{\\fs12}to say self.refresh controlbegin refreshing.\r\nDialogue: 0,1:28:24.39,1:28:27.89,yin,,0,0,0,,完成之后 下面这里\\N{\\fs12}And then when we're done, down here.\r\nDialogue: 0,1:28:27.89,1:28:32.63,yin,,0,0,0,,我们需要说 self.refreshControl endRefreshing\\N{\\fs12}We need to say self.refresh controlendrefreshing.\r\nDialogue: 0,1:28:33.73,1:28:35.35,yin,,0,0,0,,都懂了吗\\N{\\fs12}Everyone understand this?\r\nDialogue: 0,1:28:35.35,1:28:38.65,yin,,0,0,0,,这会让转轮开始旋转并刷新\\N{\\fs12}This is going to make things start spinning and make it go down.\r\nDialogue: 0,1:28:38.65,1:28:41.97,yin,,0,0,0,,这个目标动作让我们能够往下拉\\N{\\fs12}But this target action we did makes it so we can pull down on it.\r\nDialogue: 0,1:28:41.97,1:28:43.95,yin,,0,0,0,,我们来看看这个\\N{\\fs12}So let's take a look at that.\r\nDialogue: 0,1:28:53.34,1:28:55.48,yin,,0,0,0,,加载成功 可以看到它在刷新\\N{\\fs12}Okay so it loads up, and you can see it's refreshing.\r\nDialogue: 0,1:28:55.48,1:28:58.06,yin,,0,0,0,,它正在从Flickr取回数据\\N{\\fs12}See it's doing all the Flickr fetch now instead\r\nDialogue: 0,1:28:58.06,1:29:01.67,yin,,0,0,0,,同时又不像原来那样阻塞我们的UI\\N{\\fs12}of doing it all before, you know, and blocking our UI.\r\nDialogue: 0,1:29:01.67,1:29:04.78,yin,,0,0,0,,实际上 如果我下拉它 它又会刷新\\N{\\fs12}And in fact, if I pull down on it, it does it again.\r\nDialogue: 0,1:29:04.78,1:29:07.87,yin,,0,0,0,,但我的UI仍然可用 因为刷新是在另一个队列中\\N{\\fs12}But my UI is still active because it's doing that in a different queue.\r\nDialogue: 0,1:29:07.87,1:29:09.91,yin,,0,0,0,,我还是可以四处滚动\\N{\\fs12}So I can still scroll around, but it's doing\r\nDialogue: 0,1:29:09.91,1:29:12.33,yin,,0,0,0,,同时程序会在后台取回数据进行更新\\N{\\fs12}that fetch in the background and it's going to update this.\r\nDialogue: 0,1:29:12.34,1:29:16.28,yin,,0,0,0,,Flickr上 这些最新发布只是每15分钟左右更新一次\\N{\\fs12}Flickr only updates this most recently posted thing every 15 minutes or so,\r\nDialogue: 0,1:29:16.28,1:29:17.71,yin,,0,0,0,,因此这里列表没变化\\N{\\fs12}so that's why you're not seeing the list change.\r\nDialogue: 0,1:29:17.71,1:29:22.65,yin,,0,0,0,,如果我等十分钟再来刷新 列表肯定会发生变化\\N{\\fs12}But if I waited 10 minutes and did it, then that would happen.\r\nDialogue: 0,1:29:22.65,1:29:25.28,yin,,0,0,0,,就这些了\\N{\\fs12}And so there we go.\r\nDialogue: 0,1:29:25.28,1:29:27.66,yin,,0,0,0,,顺便说下 如果只是部分拉下 它不会刷新\\N{\\fs12}By the way, if you pull this down partially it doesn't do it.\r\nDialogue: 0,1:29:27.66,1:29:31.79,yin,,0,0,0,,需要拉到很下 转轮才会旋转 刷新才会开始\\N{\\fs12}You have to pull it down all the way and start it spinning.\r\nDialogue: 0,1:29:31.81,1:29:33.92,yin,,0,0,0,,这是UI的一部分\\N{\\fs12}This is part of the UI.\r\nDialogue: 0,1:29:33.92,1:29:36.70,yin,,0,0,0,,确保这就是你想要的\\N{\\fs12}To make sure you really wanted that.\r\nDialogue: 0,1:29:36.70,1:29:39.06,yin,,0,0,0,,以上就是我的全部演示了\\N{\\fs12}That's all I wanted to show you.\r\nDialogue: 0,1:29:39.06,1:29:41.64,yin,,0,0,0,,很抱歉今天有些拖堂了\\N{\\fs12}Sorry to have -- run a little over -- a little extra time.\r\nDialogue: 0,1:29:41.64,1:29:44.97,yin,,0,0,0,,有问题的现在可以来提 谢谢\\N{\\fs12}I'm here if you have any questions. Thank you.\r\nDialogue: 0,1:29:44.97,1:29:48.97,yin,,0,0,0,,更多内容 请访问我校官网stanford.edu\\N{\\fs12}> For more, please visit us at stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/12. Documents and Core Data.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.2.0\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage]\r\nActive Line: 2\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.34,0:00:08.80,yin,,0,0,0,,斯坦福大学\\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:08.80,0:00:15.84,yin,,0,0,0,,欢迎来到CS193P课程 2013-14秋季第12讲\\N{\\fs12}Okay, well welcome to CS193p, Lecture 12 of fall 2013 and 14,\r\nDialogue: 0,0:00:15.84,0:00:19.61,yin,,0,0,0,,今天我们只有一个主题 也就是Core Data\\N{\\fs12}and today we have one topic and one topic only, which is core data.\r\nDialogue: 0,0:00:19.61,0:00:25.11,yin,,0,0,0,,之前有人问过 第五次作业周三交\\N{\\fs12}And, as someone was asking earlier, assignment 5 is due on Wednesday\r\nDialogue: 0,0:00:25.11,0:00:29.36,yin,,0,0,0,,而最后一次作业 作业六 到时也会布置 一周后交\\N{\\fs12}and then your last assignment, assignment 6, will go out then and be due a week later.\r\nDialogue: 0,0:00:29.36,0:00:34.42,yin,,0,0,0,,周三 我将讲到期末项目要求\\N{\\fs12}On Wednesday, I'm going to be going over the final project requirements\r\nDialogue: 0,0:00:34.42,0:00:37.15,yin,,0,0,0,,我们还会继续讲一点Core Data\\N{\\fs12}and we're going to continue with core data a little bit,\r\nDialogue: 0,0:00:37.15,0:00:40.75,yin,,0,0,0,,讨论Core Data和UITableView\\N{\\fs12}talk about core data with table, UI table view.\r\nDialogue: 0,0:00:40.75,0:00:42.37,yin,,0,0,0,,然后我要做一个大的演示\\N{\\fs12}And then I'm going to do a big demo.\r\nDialogue: 0,0:00:42.37,0:00:44.99,yin,,0,0,0,,今天的课将都是幻灯片讲解\\N{\\fs12}So today's lecture is going to be all slides.\r\nDialogue: 0,0:00:44.99,0:00:48.55,yin,,0,0,0,,一般我不喜欢这样做 一次讲太多幻灯片并不好\\N{\\fs12}I don't usually like to do that just because it's an awful lot of slides all at once,\r\nDialogue: 0,0:00:48.55,0:00:50.39,yin,,0,0,0,,不过这次我打算这样做\\N{\\fs12}but it makes sense in this case\r\nDialogue: 0,0:00:50.39,0:00:52.78,yin,,0,0,0,,今天内容的演示都将放到周三\\N{\\fs12}and I'll be doing the demo for today's stuff on Wednesday,\r\nDialogue: 0,0:00:52.78,0:00:56.64,yin,,0,0,0,,然后下周 我们会谈到高级segue\\N{\\fs12}and then next week we'll start talking about advanced segueing\r\nDialogue: 0,0:00:56.64,0:00:58.91,yin,,0,0,0,,或许我们还会讨论MapKit 多任务处理\\N{\\fs12}and maybe we'll do some map kit, multitasking,\r\nDialogue: 0,0:00:58.91,0:01:01.03,yin,,0,0,0,,下周会讲什么我不确定\\N{\\fs12}I'm not quite sure what I'm going to cover next week\r\nDialogue: 0,0:01:01.03,0:01:03.44,yin,,0,0,0,,因为这方面 你们将没有作业\\N{\\fs12}because you won't have a homework assignment on that.\r\nDialogue: 0,0:01:03.44,0:01:06.69,yin,,0,0,0,,今天和周三我要讲的Core Data内容\\N{\\fs12}This core data stuff that we're covering today and Wednesday,\r\nDialogue: 0,0:01:06.69,0:01:09.69,yin,,0,0,0,,将是你们最后一次作业的主题\\N{\\fs12}that's going to be the topic of your last homework assignment\r\nDialogue: 0,0:01:09.69,0:01:12.07,yin,,0,0,0,,这次作业将在周三布置\\N{\\fs12}that goes out on Wednesday.\r\nDialogue: 0,0:01:12.07,0:01:15.09,yin,,0,0,0,,Core Data 什么是Core Data\\N{\\fs12}So, core data, what is core data?\r\nDialogue: 0,0:01:15.09,0:01:17.22,yin,,0,0,0,,Core Data是一个面向对象的数据库\\N{\\fs12}Core data is an object-oriented database.\r\nDialogue: 0,0:01:17.22,0:01:18.52,yin,,0,0,0,,我们为什么需要它呢\\N{\\fs12}Why do we need it?\r\nDialogue: 0,0:01:18.52,0:01:21.22,yin,,0,0,0,,原因在于 在大型应用程序中\\N{\\fs12}Because in any kind of significant application\r\nDialogue: 0,0:01:21.22,0:01:23.20,yin,,0,0,0,,我们需要处理很多数据\\N{\\fs12}where we have a lot of data to crunch on,\r\nDialogue: 0,0:01:23.20,0:01:27.50,yin,,0,0,0,,我们不能将其存储于NSUserDefault或是完全不存储\\N{\\fs12}we can't be storing it in NS user defaults or not storing it at all,\r\nDialogue: 0,0:01:27.52,0:01:30.22,yin,,0,0,0,,完全从Flickr上进行下载 对吧\\N{\\fs12}or always fetching it down from Flickr, right?\r\nDialogue: 0,0:01:30.22,0:01:34.08,yin,,0,0,0,,你们当前的作业 以及上周的Shutterbug演示\\N{\\fs12}So your current assignment, or the Shutterbug demo that we did last week,\r\nDialogue: 0,0:01:34.08,0:01:37.30,yin,,0,0,0,,我们一直是在取回整个模型\\N{\\fs12}we're just always fetching our entire model,\r\nDialogue: 0,0:01:37.30,0:01:40.15,yin,,0,0,0,,每次都要从Flickr取回\\N{\\fs12}basically, every time we want it from Flickr,\r\nDialogue: 0,0:01:40.15,0:01:43.54,yin,,0,0,0,,但如果照片数据库很大呢\\N{\\fs12}but what if we had a very large database of photos, thousands\r\nDialogue: 0,0:01:43.54,0:01:46.87,yin,,0,0,0,,包含成千上万的照片信息\\N{\\fs12}or tens of thousands of little pieces of information\r\nDialogue: 0,0:01:46.87,0:01:49.88,yin,,0,0,0,,这时我们就不能每次都从Flickr取回了\\N{\\fs12}about photos, we couldn't be fetching that down every time\r\nDialogue: 0,0:01:49.88,0:01:52.91,yin,,0,0,0,,也不能存到NSUserDefault 我们需要一个数据库\\N{\\fs12}and we couldn't store it in NS user default so we need a real database.\r\nDialogue: 0,0:01:52.91,0:01:56.58,yin,,0,0,0,,而且真正的数据库还让我们能够进行聪明的查询\\N{\\fs12}Plus, a read database allows us to make really smart queries\r\nDialogue: 0,0:01:56.58,0:01:58.75,yin,,0,0,0,,关于现在我们的数据是什么\\N{\\fs12}about what's, our data is right now.\r\nDialogue: 0,0:01:58.75,0:02:01.85,yin,,0,0,0,,如果只是显示在表格中 我们就很难查询了\\N{\\fs12}We can't really query it at all, or almost not at all,\r\nDialogue: 0,0:02:01.85,0:02:03.63,yin,,0,0,0,,如果只是显示在表格中 我们就很难查询了\\N{\\fs12}we're just kind of displaying it all in tables,\r\nDialogue: 0,0:02:03.63,0:02:07.98,yin,,0,0,0,,因此 下面我们需要让app的精密程度上升一个层次\\N{\\fs12}so to take the next level of sophistication in our app, we need to do that.\r\nDialogue: 0,0:02:07.98,0:02:12.18,yin,,0,0,0,,Core Data是iOS7中一个非常强大的框架\\N{\\fs12}So, core data is a very, very powerful framework in iOS7,\r\nDialogue: 0,0:02:12.18,0:02:15.90,yin,,0,0,0,,就它的作用而言 它绝对是最强大的之一\\N{\\fs12}one of the most powerful in terms of what it can do.\r\nDialogue: 0,0:02:15.90,0:02:21.84,yin,,0,0,0,,一堂课多一点的时间 我只能讲到一些皮毛\\N{\\fs12}I can only just barely scratch the surface in a lecture, in a little bit.\r\nDialogue: 0,0:02:21.84,0:02:24.33,yin,,0,0,0,,这周 我打算让你们理解基本知识\\N{\\fs12}This week, I'm just going to try and get you the basics\r\nDialogue: 0,0:02:24.33,0:02:25.73,yin,,0,0,0,,你们之后需要…\\N{\\fs12}and you're going to have to, you know,\r\nDialogue: 0,0:02:25.73,0:02:28.48,yin,,0,0,0,,如果未来你想做一个严谨的数据库app\\N{\\fs12}if you want to do a serious database app in your future,\r\nDialogue: 0,0:02:28.48,0:02:30.67,yin,,0,0,0,,也许是期末项目或是以后的项目\\N{\\fs12}maybe for your final project or beyond,\r\nDialogue: 0,0:02:30.67,0:02:32.96,yin,,0,0,0,,你需要额外去阅读相关内容\\N{\\fs12}you'll need to do a little bit of extra reading up\r\nDialogue: 0,0:02:32.96,0:02:35.37,yin,,0,0,0,,因为Core Data内容太多了\\N{\\fs12}because core data is massive.\r\nDialogue: 0,0:02:35.76,0:02:40.82,yin,,0,0,0,,就基础而言 它是一种创建对象的方式\\N{\\fs12}But fundamentally, it's a base, it's a way of creating objects,\r\nDialogue: 0,0:02:40.82,0:02:43.72,yin,,0,0,0,,创建你要处理的Objective-C对象\\N{\\fs12}objective C objects that you are going to deal with\r\nDialogue: 0,0:02:43.73,0:02:50.98,yin,,0,0,0,,并映射到 连接到SQL或XML数据库\\N{\\fs12}that are mapped, or linked, to SQL, or XML, databases.\r\nDialogue: 0,0:02:50.98,0:02:56.35,yin,,0,0,0,,它是面向对象领域同数据库领域之间的桥梁\\N{\\fs12}So, it's kind of a bridge between object-oriented land and database land,\r\nDialogue: 0,0:02:56.35,0:02:59.36,yin,,0,0,0,,数据库领域主要是SQL这些\\N{\\fs12}and database land is dominated by things like sequel.\r\nDialogue: 0,0:02:59.36,0:03:01.97,yin,,0,0,0,,多少人知道SQL是什么\\N{\\fs12}How many people here know what SQL is?\r\nDialogue: 0,0:03:01.97,0:03:04.39,yin,,0,0,0,,不是如何对其编程 知道它是什么就行了\\N{\\fs12}Not know how to program SQL, but know what it is?\r\nDialogue: 0,0:03:04.39,0:03:05.81,yin,,0,0,0,,几乎所有人都知道\\N{\\fs12}Yeah, so everyone, pretty much.\r\nDialogue: 0,0:03:05.81,0:03:10.38,yin,,0,0,0,,Core Data主要连接的就是SQL后台\\N{\\fs12}So that's mostly what core data is hooked up is, is sequel backend.\r\nDialogue: 0,0:03:10.38,0:03:12.93,yin,,0,0,0,,Core Data是如何工作的呢\\N{\\fs12}So how does core data work?\r\nDialogue: 0,0:03:12.93,0:03:16.64,yin,,0,0,0,,首先 你用Xcode中的工具创建一个可视映射\\N{\\fs12}First, you create a visual map using a tool in Xcode.\r\nDialogue: 0,0:03:16.64,0:03:19.22,yin,,0,0,0,,拖放这类东西\\N{\\fs12}So dragging and dropping and all that stuff,\r\nDialogue: 0,0:03:19.22,0:03:23.59,yin,,0,0,0,,在你的数据的面向对象的视图\\N{\\fs12}so creating a mapping between an object-oriented view of your data\r\nDialogue: 0,0:03:23.59,0:03:29.49,yin,,0,0,0,,同SQL 或是数据的表格和行之间创建映射\\N{\\fs12}and the sequel or tables and rows version of your data.\r\nDialogue: 0,0:03:29.49,0:03:32.87,yin,,0,0,0,,Core Data在创建这个映射之后\\N{\\fs12}And core data allows really\r\nDialogue: 0,0:03:32.87,0:03:35.81,yin,,0,0,0,,能够很好进行无缝结合\\N{\\fs12}that to be pretty seamless once you've created this mapping,\r\nDialogue: 0,0:03:35.81,0:03:37.93,yin,,0,0,0,,以后我会更进一步讲到这个\\N{\\fs12}and we'll talk all about that and how it does that,\r\nDialogue: 0,0:03:37.93,0:03:43.40,yin,,0,0,0,,不过首先 我们来看看如何在Xcode中创建这个可视映射\\N{\\fs12}but let's start by looking how we create this visual map in Xcode.\r\nDialogue: 0,0:03:43.40,0:03:46.77,yin,,0,0,0,,首先 创建映射我们需要选新文件\\N{\\fs12}So, first, we create the map by doing new file,\r\nDialogue: 0,0:03:46.77,0:03:49.34,yin,,0,0,0,,往项目中加新东西\\N{\\fs12}anytime we want to add something new to our project,\r\nDialogue: 0,0:03:49.34,0:03:52.86,yin,,0,0,0,,总需要点新文件 但在新文件中\\N{\\fs12}we're going to do new file, but in new file, instead of doing\r\nDialogue: 0,0:03:52.86,0:03:56.46,yin,,0,0,0,,这里不再是Cocoa Touch或Objective-C类\\N{\\fs12}like Cocoa Touch, objective C class, we're going to go down to\r\nDialogue: 0,0:03:56.46,0:03:58.84,yin,,0,0,0,,而是下面这里的Core Data\\N{\\fs12}where it says core data, see that?\r\nDialogue: 0,0:03:58.84,0:04:01.88,yin,,0,0,0,,选择数据模型 不要错选映射模型\\N{\\fs12}And pick data model, don't accidentally pick mapping model,\r\nDialogue: 0,0:04:01.88,0:04:05.11,yin,,0,0,0,,这里要的是数据模型 数据模型就是\\N{\\fs12}its data model that you want here, okay, the data model is the mapping\r\nDialogue: 0,0:04:05.11,0:04:08.39,yin,,0,0,0,,面向对象的世界同数据库世界之间的映射\\N{\\fs12}between the object-oriented world and the database world.\r\nDialogue: 0,0:04:08.39,0:04:09.40,yin,,0,0,0,,点这个\\N{\\fs12}So you click that,\r\nDialogue: 0,0:04:09.40,0:04:12.49,yin,,0,0,0,,它会问你 叫什么名称 放到哪里\\N{\\fs12}it's going to ask you what you want to call it and where you want to put it.\r\nDialogue: 0,0:04:12.49,0:04:17.22,yin,,0,0,0,,如果只有一个 有些人喜欢把模型文件叫Model\\N{\\fs12}Some people like to call their model file, model, if they only have one.\r\nDialogue: 0,0:04:17.22,0:04:20.37,yin,,0,0,0,,有些人则喜欢用应用程序的名字\\N{\\fs12}Some people like to name it the name of the application.\r\nDialogue: 0,0:04:20.37,0:04:22.54,yin,,0,0,0,,就像上周 如果我们要用Core Data\\N{\\fs12}So like of last week, if we were doing core data we might have\r\nDialogue: 0,0:04:22.54,0:04:24.69,yin,,0,0,0,,我们可以叫它Shutterbug\\N{\\fs12}called Shutterbug, the name.\r\nDialogue: 0,0:04:24.69,0:04:28.99,yin,,0,0,0,,有时 映射会有多个 这完全有可能\\N{\\fs12}Sometimes you might have multiple mappings, and it is totally possible\r\nDialogue: 0,0:04:28.99,0:04:33.35,yin,,0,0,0,,在大程序中 很有可能存在多数据库 多映射\\N{\\fs12}and in a big application you might well have multiple databases, multiple mappings,\r\nDialogue: 0,0:04:33.35,0:04:36.53,yin,,0,0,0,,你将有多个文件 因此 你取名称的时候\\N{\\fs12}and so you would have multiple files, so you want to pick names\r\nDialogue: 0,0:04:36.53,0:04:39.02,yin,,0,0,0,,应该让映射对应于\\N{\\fs12}for your mappings that kind of correspond\r\nDialogue: 0,0:04:39.02,0:04:40.81,yin,,0,0,0,,它们在程序中的用途\\N{\\fs12}to what their purpose is inside your application,\r\nDialogue: 0,0:04:40.81,0:04:43.70,yin,,0,0,0,,这里我们使用默认值 也就是Model\\N{\\fs12}so here we're going to take the default, which is just model,\r\nDialogue: 0,0:04:43.70,0:04:46.05,yin,,0,0,0,,可以看到这里 新文件得以创建\\N{\\fs12}and you can see there, it creates this new file.\r\nDialogue: 0,0:04:46.05,0:04:51.89,yin,,0,0,0,,看导航器中 Model.xcdatamodeld\\N{\\fs12}If you look over in the navigator over there, model dot xc data model d.\r\nDialogue: 0,0:04:51.89,0:04:55.59,yin,,0,0,0,,这是我们的映射 可视映射文件\\N{\\fs12}And this is our mapping, our visual mapping file,\r\nDialogue: 0,0:04:55.59,0:04:59.05,yin,,0,0,0,,可以看到这里 它有一些组成部分\\N{\\fs12}and you can see here that it has some components,\r\nDialogue: 0,0:04:59.06,0:05:01.10,yin,,0,0,0,,大多数我都会讲到\\N{\\fs12}and we're going to talk about most of them.\r\nDialogue: 0,0:05:01.10,0:05:05.87,yin,,0,0,0,,分别是实体 属性 关系和取回属性\\N{\\fs12}The components are entities, attributes, relationships, and fetch properties.\r\nDialogue: 0,0:05:06.47,0:05:10.60,yin,,0,0,0,,实体就像是对象 它们会映射到我们的对象\\N{\\fs12}So entities are kind of like objects, they're going to map to our objects.\r\nDialogue: 0,0:05:10.60,0:05:14.18,yin,,0,0,0,,在数据库世界中 它们是表格\\N{\\fs12}In the database world, they are tables.\r\nDialogue: 0,0:05:14.18,0:05:18.05,yin,,0,0,0,,属性就像是数据库中的列\\N{\\fs12}Attributes are kind of like the columns in a table in database.\r\nDialogue: 0,0:05:18.05,0:05:21.99,yin,,0,0,0,,在面向对象的世界中 它们相当于对象的属性\\N{\\fs12}In our object-oriented world, they're going to be properties on objects.\r\nDialogue: 0,0:05:21.99,0:05:24.92,yin,,0,0,0,,关系也是对象上的属性\\N{\\fs12}Relationships are also properties on objects,\r\nDialogue: 0,0:05:24.92,0:05:28.17,yin,,0,0,0,,但它们是指针 指向数据库中的其它对象\\N{\\fs12}but they are pointers to other objects in the database, okay,\r\nDialogue: 0,0:05:28.17,0:05:30.98,yin,,0,0,0,,或是指向一些别的对象\\N{\\fs12}or pointers to a bunch of other objects, okay,\r\nDialogue: 0,0:05:30.98,0:05:36.26,yin,,0,0,0,,在数据库意义上 这就像是将不同表格连在一起\\N{\\fs12}so this would be kind of like joins between tables in the database sense.\r\nDialogue: 0,0:05:36.26,0:05:37.95,yin,,0,0,0,,取回属性是一种\\N{\\fs12}Fetch properties are kind of a\r\nDialogue: 0,0:05:37.95,0:05:41.71,yin,,0,0,0,,精密筹划的方式 得到一个指针指向其它属性\\N{\\fs12}calculated way to have a pointer to some other properties.\r\nDialogue: 0,0:05:41.73,0:05:45.69,yin,,0,0,0,,这里出于时间考虑 我就不详细讲解取回属性了\\N{\\fs12}I just have to cut something for time, so we're not going to talk about fetch properties,\r\nDialogue: 0,0:05:45.70,0:05:48.76,yin,,0,0,0,,理解了取回的工作方式后 它们就会很好理解\\N{\\fs12}they're really not that complicated once you understand how fetching works,\r\nDialogue: 0,0:05:48.76,0:05:53.04,yin,,0,0,0,,这堂课比较靠后的时候我会讲到 到时候你们就懂了\\N{\\fs12}much later in this lecture then you'll kind of get the idea.\r\nDialogue: 0,0:05:53.04,0:05:55.17,yin,,0,0,0,,你们会知道取回属性是怎么回事\\N{\\fs12}Oh, I can see how maybe fetch properties would work\r\nDialogue: 0,0:05:55.17,0:05:56.87,yin,,0,0,0,,你们也可以去读说明文档\\N{\\fs12}and then you can read the documentation and figure it out.\r\nDialogue: 0,0:05:56.87,0:06:01.30,yin,,0,0,0,,数据模型就包含这些 实体 属性 关系\\N{\\fs12}So, that's what the data model consists of, entities, attributes, relationships.\r\nDialogue: 0,0:06:01.30,0:06:03.13,yin,,0,0,0,,这就是我们要讲的\\N{\\fs12}That's what we're going to talk about.\r\nDialogue: 0,0:06:03.13,0:06:05.77,yin,,0,0,0,,就今天的例子而言\\N{\\fs12}Let's, for our example today,\r\nDialogue: 0,0:06:05.77,0:06:09.51,yin,,0,0,0,,假设我们有一个类似于Shutterbug的程序\\N{\\fs12}let's say we had a Shutterbug-like application\r\nDialogue: 0,0:06:09.51,0:06:13.02,yin,,0,0,0,,它有照片和拍照者\\N{\\fs12}that had photos and photographers.\r\nDialogue: 0,0:06:13.02,0:06:16.72,yin,,0,0,0,,你们的作业是地点和照片\\N{\\fs12}So your homework is going to be more places and photos.\r\nDialogue: 0,0:06:16.72,0:06:20.09,yin,,0,0,0,,而我周三的演示和这里的幻灯片\\N{\\fs12}Our demo here, and the demo I do on Wednesday, and the slides,\r\nDialogue: 0,0:06:20.09,0:06:21.87,yin,,0,0,0,,则是照片和拍照者\\N{\\fs12}are going to be photos and photographers.\r\nDialogue: 0,0:06:21.87,0:06:23.78,yin,,0,0,0,,这就是数据库中的两个东西\\N{\\fs12}So those are the two things that are going to be in our database,\r\nDialogue: 0,0:06:23.78,0:06:25.17,yin,,0,0,0,,照片和拍照者\\N{\\fs12}photos and photographers.\r\nDialogue: 0,0:06:25.17,0:06:28.59,yin,,0,0,0,,让我们为照片创建一个实体\\N{\\fs12}So, let's create an entity for the photos.\r\nDialogue: 0,0:06:28.59,0:06:31.84,yin,,0,0,0,,点下面的添加实体 我们得到实体\\N{\\fs12}So we click add entity down there at the bottom and we get this entity.\r\nDialogue: 0,0:06:31.84,0:06:34.83,yin,,0,0,0,,名称从Entity换成Photo\\N{\\fs12}I'm going to change the name from entity to photo,\r\nDialogue: 0,0:06:34.83,0:06:38.04,yin,,0,0,0,,这将是数据库中我的照片对象\\N{\\fs12}so this is going to be my photo object in the database.\r\nDialogue: 0,0:06:38.04,0:06:42.09,yin,,0,0,0,,然后我可以添加属性到照片对象\\N{\\fs12}And then I can add attributes to my photo object by clicking\r\nDialogue: 0,0:06:42.09,0:06:45.28,yin,,0,0,0,,点击属性下方的+号就行了\\N{\\fs12}on that little plus underneath where it says attributes there.\r\nDialogue: 0,0:06:45.28,0:06:47.41,yin,,0,0,0,,添加了一个 默认叫attribute\\N{\\fs12}And when I add one, it adds one called attribute,\r\nDialogue: 0,0:06:47.41,0:06:49.75,yin,,0,0,0,,我要把这个名称改成title\\N{\\fs12}I'm going to change the name of that to title,\r\nDialogue: 0,0:06:49.75,0:06:52.70,yin,,0,0,0,,照片都有标题 因此这里用title\\N{\\fs12}so photos have a title, so I'm going to put a title in there.\r\nDialogue: 0,0:06:52.70,0:06:57.80,yin,,0,0,0,,注意到 这时右上方出现了红色的错误警告\\N{\\fs12}And you notice as I do this, I get an error, a little red error warning up there.\r\nDialogue: 0,0:06:57.80,0:06:58.57,yin,,0,0,0,,为什么会这样\\N{\\fs12}Why is that?\r\nDialogue: 0,0:06:58.57,0:07:02.62,yin,,0,0,0,,这是因为 title的类型没有定义\\N{\\fs12}That's because the type of my title is undefined.\r\nDialogue: 0,0:07:02.62,0:07:06.14,yin,,0,0,0,,可以看到title旁边 它说类型未定义\\N{\\fs12}You see where it says type, undefined next to title there?\r\nDialogue: 0,0:07:06.14,0:07:07.25,yin,,0,0,0,,这是不允许的\\N{\\fs12}So that's not allowed.\r\nDialogue: 0,0:07:07.25,0:07:10.41,yin,,0,0,0,,你必须指定数据库中所有属性的类型\\N{\\fs12}You have to specify the type of all the properties\r\nDialogue: 0,0:07:10.41,0:07:13.82,yin,,0,0,0,,你可以点击这个未定义\\N{\\fs12}in your database, and so you just click on that undefined,\r\nDialogue: 0,0:07:13.82,0:07:17.28,yin,,0,0,0,,我选String 标题显然是字符串\\N{\\fs12}I'm going to set this one to be a string, the title, obviously, is a string.\r\nDialogue: 0,0:07:17.28,0:07:21.70,yin,,0,0,0,,看看除了字符串还可以是什么\\N{\\fs12}Now, what can some of these things be, besides strings?\r\nDialogue: 0,0:07:21.70,0:07:25.19,yin,,0,0,0,,还有数字 整数或是浮点数\\N{\\fs12}Well they can be numbers, either integers or floating point numbers,\r\nDialogue: 0,0:07:25.19,0:07:27.86,yin,,0,0,0,,这些都将数据库表示为…\\N{\\fs12}those are all representing the database as,\r\nDialogue: 0,0:07:27.86,0:07:30.54,yin,,0,0,0,,或者说在对象世界中 作为NSNumber\\N{\\fs12}in your object world rather, as NS numbers.\r\nDialogue: 0,0:07:30.54,0:07:35.42,yin,,0,0,0,,实际上 数据库中的所有属性\\N{\\fs12}All your properties, in fact, all the attributes in your objects in the database,\r\nDialogue: 0,0:07:35.42,0:07:38.04,yin,,0,0,0,,都是某种形式的对象\\N{\\fs12}all their properties are going to be objects of some sort.\r\nDialogue: 0,0:07:38.04,0:07:40.98,yin,,0,0,0,,如果是字符串 那就是NSString对象\\N{\\fs12}So NS string objects if their strings.\r\nDialogue: 0,0:07:40.98,0:07:43.72,yin,,0,0,0,,如果是整数 浮点数 双精度数字 布尔型数字\\N{\\fs12}NS numbers if they're integers, floats, or double,\r\nDialogue: 0,0:07:43.72,0:07:45.10,yin,,0,0,0,,那就是NSNumber\\N{\\fs12}or Booleans.\r\nDialogue: 0,0:07:45.10,0:07:47.42,yin,,0,0,0,,如果是日期 那就是NSDate\\N{\\fs12}NS date if they're dates.\r\nDialogue: 0,0:07:47.42,0:07:49.92,yin,,0,0,0,,如果是二进制数据 那就是NSData\\N{\\fs12}NS datas if they're binary data,\r\nDialogue: 0,0:07:49.92,0:07:51.24,yin,,0,0,0,,这是倒数第二个\\N{\\fs12}that's the second to the bottom.\r\nDialogue: 0,0:07:51.24,0:07:55.35,yin,,0,0,0,,Transformable这个很有趣 这些是NSData对象\\N{\\fs12}And then transformable is kind of an interesting one, those will be NS data objects,\r\nDialogue: 0,0:07:55.35,0:07:58.10,yin,,0,0,0,,它能提供一种可转换的对象\\N{\\fs12}which will provide a little transformable object\r\nDialogue: 0,0:07:58.10,0:08:00.34,yin,,0,0,0,,能将其转化为别的类型\\N{\\fs12}that will convert them to some other type,\r\nDialogue: 0,0:08:00.34,0:08:02.46,yin,,0,0,0,,甚至是struct这些\\N{\\fs12}like even a struct, or something like that,\r\nDialogue: 0,0:08:02.46,0:08:04.55,yin,,0,0,0,,我们不打算深究Transformable\\N{\\fs12}and we're not going to talk about transformables,\r\nDialogue: 0,0:08:04.55,0:08:07.96,yin,,0,0,0,,总之 可以在数据库中存储任何数据类型\\N{\\fs12}but it is possible to store really any data type in the database\r\nDialogue: 0,0:08:07.96,0:08:10.64,yin,,0,0,0,,只要提供的是Transformable对象\\N{\\fs12}as long as you provide a transformation object\r\nDialogue: 0,0:08:10.64,0:08:13.89,yin,,0,0,0,,它就能在NSData之间来回转换\\N{\\fs12}that will convert them back and forth between NS data.\r\nDialogue: 0,0:08:13.89,0:08:17.13,yin,,0,0,0,,这里title很简单 它是一个字符串\\N{\\fs12}So here, title is a simple one, it's a string,\r\nDialogue: 0,0:08:17.13,0:08:19.12,yin,,0,0,0,,这里我还要加其它一些属性\\N{\\fs12}I'm going to add a whole bunch of other attributes here\r\nDialogue: 0,0:08:19.12,0:08:21.94,yin,,0,0,0,,可以看到 现在这里没报错了\\N{\\fs12}that you kind of look, no more error there right now,\r\nDialogue: 0,0:08:21.94,0:08:23.82,yin,,0,0,0,,设成字符串后就没错误了\\N{\\fs12}that I set it as string there's no more error.\r\nDialogue: 0,0:08:23.82,0:08:25.27,yin,,0,0,0,,我再加一些\\N{\\fs12}If I add a whole bunch more,\r\nDialogue: 0,0:08:25.27,0:08:30.41,yin,,0,0,0,,我可以添加Flickr处获得的上传日期 这是日期\\N{\\fs12}you can see I've added an upload date that I got from Flickr, so that's a date.\r\nDialogue: 0,0:08:30.41,0:08:32.05,yin,,0,0,0,,甚至缩略图数据\\N{\\fs12}Even thumbnail data, so\r\nDialogue: 0,0:08:32.05,0:08:35.21,yin,,0,0,0,,假设我下载了缩略图数据\\N{\\fs12}let's say I downloaded the thumbnail\r\nDialogue: 0,0:08:35.21,0:08:38.66,yin,,0,0,0,,这是Flickr照片的缩略图的图像数据\\N{\\fs12}image data, the image data for a little thumbnail of my photo from Flickr,\r\nDialogue: 0,0:08:38.66,0:08:42.81,yin,,0,0,0,,我可以把这些数据存入数据库 作为NSData\\N{\\fs12}I can actually put that data in the database as an NS data.\r\nDialogue: 0,0:08:42.81,0:08:45.64,yin,,0,0,0,,有些人问 这里能放多大的NSData\\N{\\fs12}Some people ask, how big an NS data could I put in there?\r\nDialogue: 0,0:08:45.64,0:08:49.72,yin,,0,0,0,,我能放实际尺寸照片那么大的NSData吗\\N{\\fs12}For example, could I put an NS data that is the real photo, the big, you know,\r\nDialogue: 0,0:08:49.72,0:08:51.94,yin,,0,0,0,,例如上MB大的照片\\N{\\fs12}maybe a megabyte-size photo,\r\nDialogue: 0,0:08:51.94,0:08:54.99,yin,,0,0,0,,答案是 当然能\\N{\\fs12}and the answer is absolutely, you can put them in here,\r\nDialogue: 0,0:08:54.99,0:08:57.27,yin,,0,0,0,,其实 有个开关你可以开启\\N{\\fs12}in fact, there's a little switch that you can turn\r\nDialogue: 0,0:08:57.27,0:09:01.87,yin,,0,0,0,,明确你要存放大东西在这里 让其存到另一个文件\\N{\\fs12}on that says I'm going to put something big here, store it in another file.\r\nDialogue: 0,0:09:01.87,0:09:04.70,yin,,0,0,0,,就算是存储在SQL文件中\\N{\\fs12}But even if you store it in the sequel file,\r\nDialogue: 0,0:09:04.70,0:09:08.64,yin,,0,0,0,,通常也能处理 只是这不符合最佳实践 效率很低\\N{\\fs12}it can usually manage it, it's probably not the best, most efficient way to do it,\r\nDialogue: 0,0:09:08.64,0:09:13.31,yin,,0,0,0,,不过没错 你确实可以将很大的数据存到Core Data中\\N{\\fs12}but yes, you can store big data blobs in core data, as well.\r\nDialogue: 0,0:09:13.31,0:09:15.86,yin,,0,0,0,,这里是一些属性的例子\\N{\\fs12}So, there's some example attributes.\r\nDialogue: 0,0:09:15.86,0:09:17.99,yin,,0,0,0,,我们换种方式来看这个\\N{\\fs12}Let's look at this a different way.\r\nDialogue: 0,0:09:17.99,0:09:19.18,yin,,0,0,0,,看下面那里\\N{\\fs12}If you see down at the bottom there\r\nDialogue: 0,0:09:19.18,0:09:22.64,yin,,0,0,0,,那里有编辑样式 我点这个\\N{\\fs12}where it says editor style, right, I clicked on that\r\nDialogue: 0,0:09:22.64,0:09:26.43,yin,,0,0,0,,它展示的还是相同的东西 不过这次是以图像格式\\N{\\fs12}and it switched over to showing the same thing, but in a graphical format.\r\nDialogue: 0,0:09:26.43,0:09:28.05,yin,,0,0,0,,看 这里是我的照片实体\\N{\\fs12}So you see, here's my photo entity,\r\nDialogue: 0,0:09:28.05,0:09:30.99,yin,,0,0,0,,我可以看到属性 看到了吧 列在那里\\N{\\fs12}I can see the attributes, see them there, listed there?\r\nDialogue: 0,0:09:30.99,0:09:34.30,yin,,0,0,0,,我还是可以在这个视图中创建一个实体\\N{\\fs12}And I can still create an entity in this view, so I'm going\r\nDialogue: 0,0:09:34.30,0:09:36.72,yin,,0,0,0,,我来创建这个实体 也就是我的拍照者\\N{\\fs12}to create another entity, which is my photographer.\r\nDialogue: 0,0:09:36.72,0:09:42.07,yin,,0,0,0,,创建这个实体 名称改成Photographer\\N{\\fs12}I create that, entity, I'm going to change the name to photographer, it changes it.\r\nDialogue: 0,0:09:42.07,0:09:45.64,yin,,0,0,0,,我还可以在这个视图中添加属性\\N{\\fs12}I can also add attributes in this view.\r\nDialogue: 0,0:09:45.64,0:09:48.34,yin,,0,0,0,,我往下到这个按钮 添加属性\\N{\\fs12}So I just go down to this button here, add attribute,\r\nDialogue: 0,0:09:48.34,0:09:51.28,yin,,0,0,0,,这里添加属性 命名为name\\N{\\fs12}I'm going to add an attribute here and I'm going to call it name,\r\nDialogue: 0,0:09:51.29,0:09:53.77,yin,,0,0,0,,这是拍照者的名字\\N{\\fs12}so that's the name of the photographer.\r\nDialogue: 0,0:09:53.77,0:09:56.31,yin,,0,0,0,,你也可以编辑这些属性\\N{\\fs12}You can also edit these attributes,\r\nDialogue: 0,0:09:56.31,0:09:59.04,yin,,0,0,0,,在这个视图中 通过点击它们\\N{\\fs12}here in this view, by clicking on them.\r\nDialogue: 0,0:09:59.41,0:10:00.90,yin,,0,0,0,,点击名字\\N{\\fs12}Alright, by clicking on the name,\r\nDialogue: 0,0:10:00.91,0:10:04.70,yin,,0,0,0,,然后到上面这里的属性检查器来\\N{\\fs12}and then going up to this attributes inspector up here.\r\nDialogue: 0,0:10:04.70,0:10:09.23,yin,,0,0,0,,这就像是Xcode中另一个环境下的属性检查器\\N{\\fs12}So this is kind of like the attributes inspector in other environments inside of Xcode,\r\nDialogue: 0,0:10:09.23,0:10:10.57,yin,,0,0,0,,点击这个\\N{\\fs12}so if I click on that,\r\nDialogue: 0,0:10:10.57,0:10:14.30,yin,,0,0,0,,我就能够得到我的属性的一系列属性\\N{\\fs12}you can see I get a bunch of attributes of my attributes.\r\nDialogue: 0,0:10:14.30,0:10:17.88,yin,,0,0,0,,这是name这个 它有名称\\N{\\fs12}So here's the name one, and you can see there's the name of it\r\nDialogue: 0,0:10:17.88,0:10:20.68,yin,,0,0,0,,还有属性类型 这里是未定义\\N{\\fs12}and there's the attribute type, which you can see is undefined,\r\nDialogue: 0,0:10:20.68,0:10:22.70,yin,,0,0,0,,这就是上面显示有错误的原因\\N{\\fs12}that's why we have the error up there.\r\nDialogue: 0,0:10:22.70,0:10:24.12,yin,,0,0,0,,属性类型未定义\\N{\\fs12}It's the attribute type undefined.\r\nDialogue: 0,0:10:24.12,0:10:28.77,yin,,0,0,0,,点这个 在下拉列表中将未定义改为字符串\\N{\\fs12}So I'm going to click on that popup right there and change that undefined to be string.\r\nDialogue: 0,0:10:28.77,0:10:31.20,yin,,0,0,0,,拍照者的名字也是字符串\\N{\\fs12}The photographers name is also a string.\r\nDialogue: 0,0:10:31.20,0:10:32.60,yin,,0,0,0,,我们于是有了这个\\N{\\fs12}So we got that.\r\nDialogue: 0,0:10:32.60,0:10:35.62,yin,,0,0,0,,我还可以在这些对象之间创建关系\\N{\\fs12}I can also create relationships between these objects,\r\nDialogue: 0,0:10:35.62,0:10:39.44,yin,,0,0,0,,照片和拍照者 很明显这两者具有关系\\N{\\fs12}photos and photographers, clearly a photo and a photographer have a relationship.\r\nDialogue: 0,0:10:39.44,0:10:41.46,yin,,0,0,0,,拍照者拍出照片\\N{\\fs12}A photographer takes photos.\r\nDialogue: 0,0:10:41.46,0:10:43.17,yin,,0,0,0,,照片是拍照者拍的\\N{\\fs12}A photo is taken by a photographer.\r\nDialogue: 0,0:10:43.17,0:10:47.36,yin,,0,0,0,,要创建它们之间的关系 我可以control拖动\\N{\\fs12}So I can create relationships between them by control, dragging,\r\nDialogue: 0,0:10:47.36,0:10:50.47,yin,,0,0,0,,我们很喜欢在Xcode中这样做 control拖动\\N{\\fs12}that's how we like to do things in Xcode, we control, drag.\r\nDialogue: 0,0:10:50.47,0:10:53.66,yin,,0,0,0,,在照片和拍照者之间control拖动\\N{\\fs12}So I'm going to control, drag between the photo and the photographer.\r\nDialogue: 0,0:10:53.66,0:10:57.32,yin,,0,0,0,,这就能够在它们之间创造新的关系\\N{\\fs12}And it's going to create this new relationship between them.\r\nDialogue: 0,0:10:57.32,0:11:01.16,yin,,0,0,0,,这个关系将在两侧具有不同的名称\\N{\\fs12}Now, the relationship will have a different name on each side.\r\nDialogue: 0,0:11:01.16,0:11:03.56,yin,,0,0,0,,在照片这一侧 我们称这个关系为\\N{\\fs12}On the photo side, we're going to call this relationship\r\nDialogue: 0,0:11:03.56,0:11:08.60,yin,,0,0,0,,whoTook 意思是照片是谁拍的\\N{\\fs12}who took, because this relationship is for the photo, who took it.\r\nDialogue: 0,0:11:08.60,0:11:11.31,yin,,0,0,0,,而拍照者一侧 我们则称之为photos\\N{\\fs12}And on the photographer side, we're going to call it photos,\r\nDialogue: 0,0:11:11.31,0:11:16.08,yin,,0,0,0,,因为一个拍照者可能会拍多张照片 所以称之为photos\\N{\\fs12}because a photographer can take multiple photos, so we'll call it photos.\r\nDialogue: 0,0:11:16.08,0:11:18.03,yin,,0,0,0,,这是相同的关系\\N{\\fs12}So this is the same relationship,\r\nDialogue: 0,0:11:18.03,0:11:21.47,yin,,0,0,0,,不过它在这两个对象上各有一个属性\\N{\\fs12}but it's going to have a property on each of these two objects,\r\nDialogue: 0,0:11:21.47,0:11:23.91,yin,,0,0,0,,在照片和拍照者两侧有所不同\\N{\\fs12}photos and photographers, it's a little different.\r\nDialogue: 0,0:11:23.91,0:11:26.56,yin,,0,0,0,,注意 在拍照者这一侧看来\\N{\\fs12}Now, notice that from a photographer's standpoint,\r\nDialogue: 0,0:11:26.56,0:11:29.22,yin,,0,0,0,,这个关系不是一一对应的\\N{\\fs12}this relationship is not just a one-to-one,\r\nDialogue: 0,0:11:29.22,0:11:31.77,yin,,0,0,0,,因为拍照者可以照多张照片\\N{\\fs12}because a photographer can take multiple photos,\r\nDialogue: 0,0:11:31.77,0:11:35.04,yin,,0,0,0,,在照片的检查器中可以看到 对于拍照者\\N{\\fs12}and you can see them in the inspector for photos, on photographer,\r\nDialogue: 0,0:11:35.04,0:11:37.55,yin,,0,0,0,,这里有个类型说To One(对一)\\N{\\fs12}there's a type that says to 1.\r\nDialogue: 0,0:11:37.55,0:11:40.29,yin,,0,0,0,,这意味着照片只有一个拍照者\\N{\\fs12}That means it's a 1 to 1, relationship.\r\nDialogue: 0,0:11:40.29,0:11:44.46,yin,,0,0,0,,我可以把这改成To Many(对多) 这样做之后\\N{\\fs12}I can actually change that to to many, and when I do that,\r\nDialogue: 0,0:11:44.46,0:11:49.49,yin,,0,0,0,,箭头的这一边变成了双箭头\\N{\\fs12}you're going to see that I get a double arrow head, on that side of the pointer there,\r\nDialogue: 0,0:11:49.49,0:11:53.06,yin,,0,0,0,,这是说一个拍照者可以拍多张照片\\N{\\fs12}that's saying a photographer can have multiple photos.\r\nDialogue: 0,0:11:53.06,0:11:55.95,yin,,0,0,0,,我们讲了 标题是字符串\\N{\\fs12}Now, we talked about how title is a string\r\nDialogue: 0,0:11:55.95,0:12:01.39,yin,,0,0,0,,上传日期是日期 那whoTook和photos又是什么类型呢\\N{\\fs12}and upload date is a date, what type is who took and photos?\r\nDialogue: 0,0:12:01.39,0:12:02.29,yin,,0,0,0,,是什么类型\\N{\\fs12}What type are those?\r\nDialogue: 0,0:12:02.29,0:12:06.76,yin,,0,0,0,,它们也是这些对象的属性 但它们的类型是什么\\N{\\fs12}Because they're just properties, as well, of these objects, but what's their type?\r\nDialogue: 0,0:12:06.76,0:12:13.85,yin,,0,0,0,,像photos这样对多的 实际上是NSSet\\N{\\fs12}And it turns out that something like photos, which is a to many, is an NS set.\r\nDialogue: 0,0:12:13.85,0:12:15.84,yin,,0,0,0,,这就是它的类型\\N{\\fs12}That's going to be its type.\r\nDialogue: 0,0:12:15.84,0:12:19.65,yin,,0,0,0,,就像title是NSString一样 photos是NSSet\\N{\\fs12}Just like title is a NS string, photos is an NS set.\r\nDialogue: 0,0:12:19.65,0:12:21.18,yin,,0,0,0,,whoTook呢\\N{\\fs12}What about who took?\r\nDialogue: 0,0:12:21.18,0:12:25.81,yin,,0,0,0,,whoTook实际上是NSManagedObject\\N{\\fs12}Who took turns out to be a NS-managed object star,\r\nDialogue: 0,0:12:25.81,0:12:28.83,yin,,0,0,0,,它是指向NSManagedObject的指针\\N{\\fs12}so it's a pointer to an NS-managed object.\r\nDialogue: 0,0:12:28.83,0:12:34.08,yin,,0,0,0,,NSManagedObject是数据库中所有对象的超类\\N{\\fs12}NS-managed object is the super class for all objects in the database,\r\nDialogue: 0,0:12:34.08,0:12:37.30,yin,,0,0,0,,照片是NSManagedObject\\N{\\fs12}okay, so photo is going to be an NS managed-object,\r\nDialogue: 0,0:12:37.31,0:12:39.59,yin,,0,0,0,,拍照者也是NSManagedObject\\N{\\fs12}a photographer is going to be a NS-managed object.\r\nDialogue: 0,0:12:39.59,0:12:41.35,yin,,0,0,0,,在Objective-C代码中\\N{\\fs12}In our objective C code, they're all going\r\nDialogue: 0,0:12:41.35,0:12:44.60,yin,,0,0,0,,它们都是NSManagedObject 显然whoTook指针\\N{\\fs12}to be NS-managed objects, so, of course, the who took pointer,\r\nDialogue: 0,0:12:44.60,0:12:46.28,yin,,0,0,0,,作为指向拍照者的指针\\N{\\fs12}which is a pointer to a photographer,\r\nDialogue: 0,0:12:46.28,0:12:48.60,yin,,0,0,0,,肯定会是NSManagedObject\\N{\\fs12}is going to be an NS-managed object star,\r\nDialogue: 0,0:12:48.60,0:12:51.10,yin,,0,0,0,,我们会看到如何创建NSManagedObject的子类\\N{\\fs12}and we're going to see how we can subclass NS-managed object\r\nDialogue: 0,0:12:51.10,0:12:53.63,yin,,0,0,0,,添加所有这些属性 等等\\N{\\fs12}to add all these properties, and all this stuff,\r\nDialogue: 0,0:12:53.63,0:12:57.19,yin,,0,0,0,,那时它将是Photographer* 总之 whoTook就是这样\\N{\\fs12}and then it would be a photographer star, but that's what who took is.\r\nDialogue: 0,0:12:57.19,0:12:59.38,yin,,0,0,0,,它不过就是一个指针而已\\N{\\fs12}It's going to be exactly what you would expect, it's a pointer\r\nDialogue: 0,0:12:59.38,0:13:02.02,yin,,0,0,0,,指向另一个对象\\N{\\fs12}to an object, which is that other object.\r\nDialogue: 0,0:13:05.02,0:13:07.37,yin,,0,0,0,,这里有个删除规则\\N{\\fs12}This little delete rule right there, I'm not going\r\nDialogue: 0,0:13:07.37,0:13:09.35,yin,,0,0,0,,我不打算细讲\\N{\\fs12}to go into detail about this,\r\nDialogue: 0,0:13:09.35,0:13:13.36,yin,,0,0,0,,删除规则明确了 删除拍照者后 whoTook会怎样\\N{\\fs12}but the delete rule specifies what to do to who took, okay,\r\nDialogue: 0,0:13:13.36,0:13:15.21,yin,,0,0,0,,这是photos的删除规则\\N{\\fs12}this is the delete rule for photos,\r\nDialogue: 0,0:13:15.21,0:13:17.98,yin,,0,0,0,,看到这里是photos 这个删除规则说\\N{\\fs12}you see I'm inspecting photos there, this is the delete rule\r\nDialogue: 0,0:13:17.98,0:13:22.52,yin,,0,0,0,,如果我删除了一个拍照者 whoTook会怎样\\N{\\fs12}that says if I delete a photographer, what happens to who took?\r\nDialogue: 0,0:13:22.52,0:13:24.95,yin,,0,0,0,,whoTook是一个指向拍照者的指针\\N{\\fs12}Because who took was pointing to this photographer\r\nDialogue: 0,0:13:24.95,0:13:27.14,yin,,0,0,0,,如果我从数据库中删除了拍照者\\N{\\fs12}and if I delete that photographer from the database,\r\nDialogue: 0,0:13:27.14,0:13:29.82,yin,,0,0,0,,这里的删除规则是nullify\\N{\\fs12}and the answer here, this delete rule is nullify,\r\nDialogue: 0,0:13:29.82,0:13:32.28,yin,,0,0,0,,也就是whoTook会被设为nil\\N{\\fs12}which means who took would be set to nil.\r\nDialogue: 0,0:13:32.28,0:13:36.86,yin,,0,0,0,,这里还有其它规则 例如cascade\\N{\\fs12}But there are other rules, for example, cascade,\r\nDialogue: 0,0:13:36.86,0:13:39.43,yin,,0,0,0,,也就是说 删除拍照者时\\N{\\fs12}which means delete, when you delete the photographer,\r\nDialogue: 0,0:13:39.43,0:13:42.23,yin,,0,0,0,,它指向的所有照片也都删除\\N{\\fs12}delete every single photo that it points to.\r\nDialogue: 0,0:13:42.23,0:13:45.20,yin,,0,0,0,,cascade会把数据库中相关内容删干净\\N{\\fs12}Cascade the delete throughout the database.\r\nDialogue: 0,0:13:45.20,0:13:47.18,yin,,0,0,0,,你需要知道这里是什么情况\\N{\\fs12}So, you really want to know what you're doing here.\r\nDialogue: 0,0:13:47.18,0:13:49.84,yin,,0,0,0,,最安全的通常是nullify 将指针指向nil\\N{\\fs12}The safest one is usually nullify, set things to nil,\r\nDialogue: 0,0:13:49.84,0:13:52.37,yin,,0,0,0,,如果指针指向nil时 你的数据库没有意义\\N{\\fs12}but if your database doesn't make sense if a pointer points to nil,\r\nDialogue: 0,0:13:52.37,0:13:55.38,yin,,0,0,0,,这里你可能就需要更复杂的删除规则了\\N{\\fs12}you might need more complicated delete rules there,\r\nDialogue: 0,0:13:55.38,0:13:59.31,yin,,0,0,0,,不过在作业中 你们不需要考虑更复杂的东西\\N{\\fs12}but, in your homework, you won't need anything more complicated than that.\r\nDialogue: 0,0:13:59.31,0:14:05.18,yin,,0,0,0,,这就是在对象和数据库之间建立映射的方式\\N{\\fs12}So that's basically how we build this map between objects and the database.\r\nDialogue: 0,0:14:05.18,0:14:08.68,yin,,0,0,0,,有了这个映射之后 你就能做很多事情\\N{\\fs12}So, there's a lot of things that you can do once you have this map.\r\nDialogue: 0,0:14:08.68,0:14:12.40,yin,,0,0,0,,我们将聚焦于创建实体 属性\\N{\\fs12}We're going to focus on the creating entities, attributes,\r\nDialogue: 0,0:14:12.40,0:14:15.35,yin,,0,0,0,,和关系 然后设定它们的属性\\N{\\fs12}and relationships, and then setting their attributes\r\nDialogue: 0,0:14:15.35,0:14:17.53,yin,,0,0,0,,然后为它们进行查询 等等\\N{\\fs12}and then querying for them and things like that.\r\nDialogue: 0,0:14:17.53,0:14:19.57,yin,,0,0,0,,总之 Core Data中 你能做的事很多\\N{\\fs12}But there's a lot of other things you can do in core data,\r\nDialogue: 0,0:14:19.57,0:14:22.55,yin,,0,0,0,,我在最后会提到一些 如果有兴趣\\N{\\fs12}I'll mention some of them at the end and you can go read up on it\r\nDialogue: 0,0:14:22.55,0:14:25.53,yin,,0,0,0,,你也可以去进一步了解\\N{\\fs12}if you want to do more sophisticated database things.\r\nDialogue: 0,0:14:25.53,0:14:30.10,yin,,0,0,0,,创建了这个映射之后 如何访问代码中的这些东西呢\\N{\\fs12}So, how do we access all of this stuff in our code, once we've created this map?\r\nDialogue: 0,0:14:30.10,0:14:34.43,yin,,0,0,0,,答案是 我们需要一个NSManagedObjectContext\\N{\\fs12}And the answer is we need an NS-managed object context.\r\nDialogue: 0,0:14:34.43,0:14:36.19,yin,,0,0,0,,NSManagedObjectContext\\N{\\fs12}An NS-managed object context.\r\nDialogue: 0,0:14:36.19,0:14:39.87,yin,,0,0,0,,这个context就是我们所需的衔接\\N{\\fs12}This context is kind of the hook we need\r\nDialogue: 0,0:14:39.87,0:14:44.61,yin,,0,0,0,,无论是在数据库中创建对象 设置对象属性\\N{\\fs12}to go create objects in the database, set attributes of objects in the database,\r\nDialogue: 0,0:14:44.61,0:14:48.13,yin,,0,0,0,,还是查询对象 都需要通过这个context\\N{\\fs12}query for objects for the database, we all do these through this context.\r\nDialogue: 0,0:14:48.13,0:14:50.04,yin,,0,0,0,,如何获得一个context呢\\N{\\fs12}So, how do we get a context?\r\nDialogue: 0,0:14:50.04,0:14:52.03,yin,,0,0,0,,做法有两种\\N{\\fs12}Well, there's really two ways to do it.\r\nDialogue: 0,0:14:52.03,0:14:57.35,yin,,0,0,0,,一是使用UIManagedDocument这个类\\N{\\fs12}One is you use this class UI managed object, which I'm, or managed document rather,\r\nDialogue: 0,0:14:57.35,0:14:59.06,yin,,0,0,0,,这个我会讲到\\N{\\fs12}which I'm going to talk about.\r\nDialogue: 0,0:14:59.06,0:15:01.69,yin,,0,0,0,,另一种做法我不打算讲\\N{\\fs12}And the second way, which I'm not going to talk about,\r\nDialogue: 0,0:15:01.69,0:15:05.13,yin,,0,0,0,,也就是alloc init一个NSManagedObjectContext\\N{\\fs12}is that you can alloc init a NS-managed object context.\r\nDialogue: 0,0:15:05.13,0:15:06.90,yin,,0,0,0,,我不打算讲它的原因在于\\N{\\fs12}The reason I'm not going to talk about it is,\r\nDialogue: 0,0:15:06.90,0:15:10.31,yin,,0,0,0,,你需要对context及其工作方式有一定了解\\N{\\fs12}you got to know a little bit about context and how they work\r\nDialogue: 0,0:15:10.31,0:15:13.10,yin,,0,0,0,,知道它们如何保证线程安全这些\\N{\\fs12}and how they do thread safety and things like that,\r\nDialogue: 0,0:15:13.10,0:15:15.33,yin,,0,0,0,,这些我不打算详细讲解\\N{\\fs12}that I really don't want to get into the details of,\r\nDialogue: 0,0:15:15.33,0:15:19.04,yin,,0,0,0,,UIManagedDocument为我们处理好了所有这些\\N{\\fs12}and that UI-managed document takes care of it all for us.\r\nDialogue: 0,0:15:19.04,0:15:22.31,yin,,0,0,0,,因此 我只打算讲解UIManagedDocument这种做法\\N{\\fs12}So that's why I'm going to focus on the UI-managed document way.\r\nDialogue: 0,0:15:22.31,0:15:24.52,yin,,0,0,0,,如果你想了解如何\\N{\\fs12}If you want to see how the way\r\nDialogue: 0,0:15:24.52,0:15:26.76,yin,,0,0,0,,alloc init一个NSManagedObjectContext…\\N{\\fs12}of alloc initing an NS-managed object context,\r\nDialogue: 0,0:15:26.76,0:15:29.06,yin,,0,0,0,,要知道 这会变得非常复杂\\N{\\fs12}because there's more then that you need to do, like you've got\r\nDialogue: 0,0:15:29.06,0:15:32.00,yin,,0,0,0,,你需要指定文件在哪 持久性存储在哪\\N{\\fs12}to specify where the file is, the persistent store for it,\r\nDialogue: 0,0:15:32.00,0:15:34.63,yin,,0,0,0,,你需要把这个映射进来\\N{\\fs12}you got to get this map into the picture.\r\nDialogue: 0,0:15:34.63,0:15:38.49,yin,,0,0,0,,不使用UIManagedDocument的话 这些都需要手动去做\\N{\\fs12}All that stuff you'd have to do manually if you don't use UI-managed document.\r\nDialogue: 0,0:15:38.49,0:15:40.38,yin,,0,0,0,,如果你在创建一个新项目时\\N{\\fs12}If you go when creating a new project\r\nDialogue: 0,0:15:40.38,0:15:44.03,yin,,0,0,0,,说master/detail 而不是单个视图控制器\\N{\\fs12}and say master detail instead of single view controller,\r\nDialogue: 0,0:15:44.03,0:15:46.66,yin,,0,0,0,,会有一个按钮说 使用Core Data\\N{\\fs12}it'll actually have a button that says use core data\r\nDialogue: 0,0:15:46.66,0:15:49.23,yin,,0,0,0,,创建这个新的之后 你就会看到很多\\N{\\fs12}and when you create that new one, you'll see a whole bunch\r\nDialogue: 0,0:15:49.23,0:15:53.13,yin,,0,0,0,,Core Data代码 来处理所有这些工作\\N{\\fs12}of core data code that does all this business in there.\r\nDialogue: 0,0:15:53.13,0:15:55.63,yin,,0,0,0,,不过 你没必要去看那个\\N{\\fs12}But, there's no need for you to go look at that,\r\nDialogue: 0,0:15:55.63,0:16:00.54,yin,,0,0,0,,UIManagedDocument能更简洁地让你得到一个\\N{\\fs12}UI-managed document is a much simpler, cleaner way to get yourself a UI,\r\nDialogue: 0,0:16:00.54,0:16:04.06,yin,,0,0,0,,NSManagedObjectContext 这正是我们想要的\\N{\\fs12}or an NS-managed object context, which is what we're trying to do.\r\nDialogue: 0,0:16:04.06,0:16:07.47,yin,,0,0,0,,我们下面详细讲讲UIManagedDocument\\N{\\fs12}So let's talk about UI-managed document and how that works.\r\nDialogue: 0,0:16:07.47,0:16:10.00,yin,,0,0,0,,它继承自一个叫作UIDocument的类\\N{\\fs12}It inherits from a class called UI document.\r\nDialogue: 0,0:16:10.00,0:16:15.63,yin,,0,0,0,,UIDocument是一系列用于管理存储的机制\\N{\\fs12}UI document is a whole bunch of mechanism for managing some storage.\r\nDialogue: 0,0:16:15.63,0:16:17.04,yin,,0,0,0,,UIManagedDocument\\N{\\fs12}UI-managed document\r\nDialogue: 0,0:16:17.04,0:16:20.11,yin,,0,0,0,,将Core Data数据库放入某存储空间\\N{\\fs12}puts a core data database in some storage.\r\nDialogue: 0,0:16:20.11,0:16:23.17,yin,,0,0,0,,因此 你是在管理Core Data数据库的存储\\N{\\fs12}So you're managing the storage of your core data database,\r\nDialogue: 0,0:16:23.17,0:16:26.72,yin,,0,0,0,,你可以这样考虑UIManagedDocument\\N{\\fs12}so you can think of UI-managed document as just like a thing\r\nDialogue: 0,0:16:26.72,0:16:29.72,yin,,0,0,0,,它为你容纳你的Core Data数据库\\N{\\fs12}that contains your core data database for you.\r\nDialogue: 0,0:16:29.72,0:16:33.99,yin,,0,0,0,,你所做的只是打开或存储\\N{\\fs12}And all you ever really do is open, or save,\r\nDialogue: 0,0:16:34.00,0:16:36.77,yin,,0,0,0,,或者说 打开或创建一个UIManagedDocument\\N{\\fs12}or open or create, a UI-managed document\r\nDialogue: 0,0:16:36.77,0:16:38.98,yin,,0,0,0,,然后抓取它的ManagedObjectContext\\N{\\fs12}and then grab its managed object context,\r\nDialogue: 0,0:16:38.98,0:16:40.77,yin,,0,0,0,,然后用它来做数据库\\N{\\fs12}and then use it to do your database.\r\nDialogue: 0,0:16:40.77,0:16:41.65,yin,,0,0,0,,就是这样了\\N{\\fs12}That's it.\r\nDialogue: 0,0:16:41.65,0:16:43.46,yin,,0,0,0,,这就是我们要讲的\\N{\\fs12}So that's what we're going to talk about.\r\nDialogue: 0,0:16:43.46,0:16:46.69,yin,,0,0,0,,如何打开或创建一个UIManagedDocument\\N{\\fs12}How to open, or create, a UI-managed document,\r\nDialogue: 0,0:16:46.69,0:16:49.32,yin,,0,0,0,,并获得它的ManagedObjectContext 然后再回头\\N{\\fs12}and then get its managed object context and we'll dive back\r\nDialogue: 0,0:16:49.32,0:16:52.61,yin,,0,0,0,,考虑有了context 如何做Core Data\\N{\\fs12}into now that we have a context, how do we do core data?\r\nDialogue: 0,0:16:52.61,0:16:55.86,yin,,0,0,0,,这就是创建UIManagedDocument的方式\\N{\\fs12}So here's how you create a UI-managed document.\r\nDialogue: 0,0:16:55.86,0:16:56.85,yin,,0,0,0,,使用alloc init\\N{\\fs12}You alloc init it.\r\nDialogue: 0,0:16:56.85,0:17:01.07,yin,,0,0,0,,它的指定初始化器是initWithFileURL\\N{\\fs12}Its designated initializer is init with file URL,\r\nDialogue: 0,0:17:01.07,0:17:02.74,yin,,0,0,0,,你需要给它一个URL\\N{\\fs12}you have to give it the URL\r\nDialogue: 0,0:17:02.74,0:17:06.66,yin,,0,0,0,,这是这个Core Data数据库存储的地方\\N{\\fs12}where this core data database is going to be stored.\r\nDialogue: 0,0:17:06.66,0:17:11.97,yin,,0,0,0,,在黄色代码前面 我还写有四行白色代码\\N{\\fs12}I've put these four lines of code that are in white, that are before the yellow here,\r\nDialogue: 0,0:17:11.97,0:17:13.03,yin,,0,0,0,,它们描述的是\\N{\\fs12}they describe how\r\nDialogue: 0,0:17:13.03,0:17:15.97,yin,,0,0,0,,如何在用户文档目录中\\N{\\fs12}you would create a document called My Document\r\nDialogue: 0,0:17:15.98,0:17:19.07,yin,,0,0,0,,创建一个叫作MyDocument的文档\\N{\\fs12}in the users documents directory.\r\nDialogue: 0,0:17:19.07,0:17:23.28,yin,,0,0,0,,我们还没有谈到过存储文件 对吧\\N{\\fs12}So when you're, we haven't really talked about storing files, right?\r\nDialogue: 0,0:17:23.28,0:17:27.67,yin,,0,0,0,,之前讲的内容都没有涉及到文件系统\\N{\\fs12}We haven't accessed the file system at all, in anything we've ever done.\r\nDialogue: 0,0:17:27.67,0:17:30.13,yin,,0,0,0,,这需要通过这个类 NSFileManager(文件管理器)\\N{\\fs12}We do this with this class NS file manager.\r\nDialogue: 0,0:17:30.13,0:17:32.72,yin,,0,0,0,,这一周我不打算讲这个\\N{\\fs12}I'm not really going to cover that this week.\r\nDialogue: 0,0:17:32.72,0:17:36.48,yin,,0,0,0,,只需要知道 文件管理器能够\\N{\\fs12}Suffice it to say the file manager can give you the URL\r\nDialogue: 0,0:17:36.48,0:17:39.23,yin,,0,0,0,,给你用户文件目录的URL\\N{\\fs12}of the documents directory, for the user,\r\nDialogue: 0,0:17:39.23,0:17:41.42,yin,,0,0,0,,这就是第二行代码\\N{\\fs12}that's what the second line of code there is,\r\nDialogue: 0,0:17:41.42,0:17:45.50,yin,,0,0,0,,然后你可以附加上你想要的文档名\\N{\\fs12}and then you can just append whatever you want the name of your document to be,\r\nDialogue: 0,0:17:45.50,0:17:48.05,yin,,0,0,0,,例如 MyDocument 或是FlickrDatabase\\N{\\fs12}like my document or Flickr database,\r\nDialogue: 0,0:17:48.05,0:17:49.76,yin,,0,0,0,,或是别的什么\\N{\\fs12}or whatever you would want to call it.\r\nDialogue: 0,0:17:49.76,0:17:53.68,yin,,0,0,0,,这将是为你存储这一Core Data数据库的URL\\N{\\fs12}This is going to be the URL where it's going to put that core data database for you.\r\nDialogue: 0,0:17:53.68,0:17:55.36,yin,,0,0,0,,有了URL以后\\N{\\fs12}So now you have the URL,\r\nDialogue: 0,0:17:55.36,0:17:59.43,yin,,0,0,0,,你就可以用alloc init创建一个UIManagedDocument\\N{\\fs12}you just say alloc init to create a UI-managed document.\r\nDialogue: 0,0:17:59.43,0:18:01.97,yin,,0,0,0,,不过UIManagedDocument\\N{\\fs12}So, this UI-managed document though,\r\nDialogue: 0,0:18:01.97,0:18:03.38,yin,,0,0,0,,你只是alloc init了\\N{\\fs12}you've only alloc init it,\r\nDialogue: 0,0:18:03.38,0:18:05.74,yin,,0,0,0,,你还没有把它创建到磁盘上\\N{\\fs12}you haven't actually created it on disk.\r\nDialogue: 0,0:18:05.74,0:18:08.47,yin,,0,0,0,,它还不存在于磁盘上\\N{\\fs12}It doesn't exist on disc yet.\r\nDialogue: 0,0:18:08.47,0:18:12.70,yin,,0,0,0,,我们需要做些工作 让它存在于磁盘上\\N{\\fs12}So, we've got some work to do to make this thing exist on disc,\r\nDialogue: 0,0:18:12.70,0:18:14.03,yin,,0,0,0,,怎么做呢\\N{\\fs12}and how do we do that?\r\nDialogue: 0,0:18:14.03,0:18:19.08,yin,,0,0,0,,如果它不存在 我们就需要创建它\\N{\\fs12}Well, we have to create it if it doesn't exist,\r\nDialogue: 0,0:18:19.08,0:18:21.83,yin,,0,0,0,,如果它存在 我们就需要打开它\\N{\\fs12}and we have to open it if it does exist.\r\nDialogue: 0,0:18:21.83,0:18:23.92,yin,,0,0,0,,换言之 我们之前用过它\\N{\\fs12}In other words, we've used it before.\r\nDialogue: 0,0:18:23.92,0:18:26.48,yin,,0,0,0,,要弄清它是否存在于磁盘上\\N{\\fs12}So to find out whether it exists on disc,\r\nDialogue: 0,0:18:26.48,0:18:30.42,yin,,0,0,0,,我们需要这个文件管理器的方法 fileExistsAtPath\\N{\\fs12}we have to do this file manager thing, fileExistsAtPath.\r\nDialogue: 0,0:18:30.42,0:18:32.51,yin,,0,0,0,,我们有了URL 你说\\N{\\fs12}So you have the URL to it, you say,\r\nDialogue: 0,0:18:32.51,0:18:34.25,yin,,0,0,0,,NSFileManager defaultManager\\N{\\fs12}NS file manager default manager,\r\nDialogue: 0,0:18:34.25,0:18:35.89,yin,,0,0,0,,这就像是一个共享的文件管理器\\N{\\fs12}that's like a shared file manager.\r\nDialogue: 0,0:18:35.89,0:18:36.87,yin,,0,0,0,,fileExistsAtPath\\N{\\fs12}fileExistsAtPath,\r\nDialogue: 0,0:18:36.87,0:18:39.69,yin,,0,0,0,,它会返回一个布尔值 关于文件是否存在\\N{\\fs12}it returns a Boolean whether the file already exists.\r\nDialogue: 0,0:18:39.69,0:18:42.30,yin,,0,0,0,,如果文件存在\\N{\\fs12}If it does exist, in other words the file exists,\r\nDialogue: 0,0:18:42.30,0:18:44.17,yin,,0,0,0,,那么我们就会打开它\\N{\\fs12}then we're going to open it, and the way we're going\r\nDialogue: 0,0:18:44.17,0:18:46.58,yin,,0,0,0,,这要使用UIManagedDocument方法\\N{\\fs12}to open it is with the UI-managed document method\r\nDialogue: 0,0:18:46.58,0:18:48.73,yin,,0,0,0,,openWithCompletionHandler\\N{\\fs12}open with completion handler.\r\nDialogue: 0,0:18:50.10,0:18:51.39,yin,,0,0,0,,如果不存在\\N{\\fs12}If it doesn't exist,\r\nDialogue: 0,0:18:51.39,0:18:56.74,yin,,0,0,0,,那么我们将要创建文档到磁盘上 使用saveToURL\\N{\\fs12}then we're going to create that document on disc with save to URL.\r\nDialogue: 0,0:18:56.74,0:18:58.18,yin,,0,0,0,,forSaveOperation\\N{\\fs12}For save operation,\r\nDialogue: 0,0:18:58.18,0:19:00.85,yin,,0,0,0,,UIDocumentSaveForCreating是这里的参数\\N{\\fs12}UI document save for creating is the argument we want there,\r\nDialogue: 0,0:19:00.85,0:19:04.55,yin,,0,0,0,,因为我们在创建这个文件 competionHandler\\N{\\fs12}because we're creating this file, completion handler.\r\nDialogue: 0,0:19:04.55,0:19:07.67,yin,,0,0,0,,competionHandler是搞什么的\\N{\\fs12}What's that completion handler business all about?\r\nDialogue: 0,0:19:07.67,0:19:11.80,yin,,0,0,0,,为什么这些打开和保存… 这里说是保存到URL\\N{\\fs12}Okay, why do these open and save and create this, it says save\r\nDialogue: 0,0:19:11.80,0:19:14.43,yin,,0,0,0,,实际上则是在URL处创建\\N{\\fs12}to URL, but really it's create at URL.\r\nDialogue: 0,0:19:14.43,0:19:16.96,yin,,0,0,0,,为什么有这个competionHandler\\N{\\fs12}Why do they have this completion handler?\r\nDialogue: 0,0:19:16.96,0:19:20.52,yin,,0,0,0,,因为这些是异步的\\N{\\fs12}Well, it's because these are asynchronous.\r\nDialogue: 0,0:19:20.52,0:19:23.69,yin,,0,0,0,,这两个方法 打开和创建\\N{\\fs12}These two methods open and create, basically,\r\nDialogue: 0,0:19:23.69,0:19:26.37,yin,,0,0,0,,是异步的 并不立刻发生\\N{\\fs12}are asynchronous, they don't happen immediately.\r\nDialogue: 0,0:19:26.37,0:19:32.01,yin,,0,0,0,,当你请UIManagedDocument为你打开或是创建什么时\\N{\\fs12}When you ask the UI-managed document please open this or please create this for me,\r\nDialogue: 0,0:19:32.01,0:19:34.22,yin,,0,0,0,,它可能会需要一些时间\\N{\\fs12}it might take it a little bit of time.\r\nDialogue: 0,0:19:34.22,0:19:36.33,yin,,0,0,0,,为什么要时间呢\\N{\\fs12}Why might it take some time?\r\nDialogue: 0,0:19:36.33,0:19:38.67,yin,,0,0,0,,要时间的原因可能是\\N{\\fs12}Well, it's possible it could take some time\r\nDialogue: 0,0:19:38.67,0:19:41.35,yin,,0,0,0,,文件系统需要一定时间 不过\\N{\\fs12}because the file system takes a certain amount of time, but,\r\nDialogue: 0,0:19:41.35,0:19:43.87,yin,,0,0,0,,这里还涉及到其它我们不会讨论的东西\\N{\\fs12}yeah, there's other things involved that we're not going to talk about,\r\nDialogue: 0,0:19:43.89,0:19:46.33,yin,,0,0,0,,例如iCloud 它可能需要\\N{\\fs12}like iCloud, where maybe it needs\r\nDialogue: 0,0:19:46.33,0:19:49.92,yin,,0,0,0,,检查一些网络缓存或别的什么\\N{\\fs12}to go check something with some network cache or something\r\nDialogue: 0,0:19:49.92,0:19:56.01,yin,,0,0,0,,因为这个文档将要到iCloud上 到其它设备上\\N{\\fs12}like that, because this document is going to be on iCloud, okay, in other devices.\r\nDialogue: 0,0:19:56.01,0:19:59.64,yin,,0,0,0,,在Core Data数据库中使用UIManagedDocument\\N{\\fs12}Now, one great thing about UI-managed document and using that\r\nDialogue: 0,0:19:59.64,0:20:04.66,yin,,0,0,0,,一大好处就在于 你处在通往iCloud的快通道上\\N{\\fs12}to do your core data database, is you're on the fast-track to iCloud.\r\nDialogue: 0,0:20:04.66,0:20:07.25,yin,,0,0,0,,iCloud更容易 更直接\\N{\\fs12}iCloud much easier, more straightforward\r\nDialogue: 0,0:20:07.25,0:20:09.54,yin,,0,0,0,,只要你使用UIManagedDocument\\N{\\fs12}if you just start with UI-managed document.\r\nDialogue: 0,0:20:09.54,0:20:12.10,yin,,0,0,0,,不过你们只需要知道 这两个东西\\N{\\fs12}But anyway, suffice it to say, these two things,\r\nDialogue: 0,0:20:12.10,0:20:15.16,yin,,0,0,0,,打开文档和创建文档 是异步的\\N{\\fs12}opening a document and creating document, are asynchronous,\r\nDialogue: 0,0:20:15.16,0:20:19.02,yin,,0,0,0,,这意味着这个competionHandler 这一点小小的句法\\N{\\fs12}which means that completion handler, that little syntax there,\r\nDialogue: 0,0:20:19.02,0:20:21.95,yin,,0,0,0,,这个competionHandler会被调用\\N{\\fs12}but that completion handler gets called\r\nDialogue: 0,0:20:21.95,0:20:25.52,yin,,0,0,0,,回到你调用这些方法的线程上\\N{\\fs12}back on the thread you called these methods on,\r\nDialogue: 0,0:20:25.52,0:20:28.61,yin,,0,0,0,,也就是主线程 因为这是UIManagedDocument\\N{\\fs12}which has got to be the main thread because this is UI-managed document,\r\nDialogue: 0,0:20:28.61,0:20:31.25,yin,,0,0,0,,这是一个UIKit对象 这些方法的调用\\N{\\fs12}this is a UI kit object, you have to call these methods\r\nDialogue: 0,0:20:31.25,0:20:32.97,yin,,0,0,0,,需要在主线程 主队列上\\N{\\fs12}on the main thread, the main queue.\r\nDialogue: 0,0:20:32.97,0:20:34.96,yin,,0,0,0,,这个competionHandler\\N{\\fs12}So that completion handler\r\nDialogue: 0,0:20:34.96,0:20:38.32,yin,,0,0,0,,在完成时被调用回主队列上\\N{\\fs12}will get called back on the main queue when it's done.\r\nDialogue: 0,0:20:38.32,0:20:40.77,yin,,0,0,0,,无论多久 它会被调用\\N{\\fs12}No matter how long it takes, it'll get called later\r\nDialogue: 0,0:20:40.77,0:20:42.77,yin,,0,0,0,,这是完成时 然后在这个代码块\\N{\\fs12}when it's done, and then in that block,\r\nDialogue: 0,0:20:42.77,0:20:44.89,yin,,0,0,0,,你可以做你想做的事\\N{\\fs12}you just start doing what you want to do.\r\nDialogue: 0,0:20:44.89,0:20:47.05,yin,,0,0,0,,我来讲讲\\N{\\fs12}Alright? So let's talk about what you might,\r\nDialogue: 0,0:20:47.05,0:20:49.45,yin,,0,0,0,,这是怎么样的\\N{\\fs12}how this might look to\r\nDialogue: 0,0:20:49.45,0:20:51.41,yin,,0,0,0,,看文件是否存在\\N{\\fs12}see if the file exists\r\nDialogue: 0,0:20:51.42,0:20:54.41,yin,,0,0,0,,如果存在就打开 如果不存在就创建\\N{\\fs12}and if it does open it and if it doesn't, create it,\r\nDialogue: 0,0:20:54.42,0:20:55.59,yin,,0,0,0,,它是这样的\\N{\\fs12}it looks something like this.\r\nDialogue: 0,0:20:55.59,0:20:57.55,yin,,0,0,0,,在competionHandler中\\N{\\fs12}And inside that completion handler,\r\nDialogue: 0,0:20:57.55,0:21:00.74,yin,,0,0,0,,如果成功打开或成功创建了的话\\N{\\fs12}if you successfully opened or successfully created it,\r\nDialogue: 0,0:21:00.74,0:21:02.51,yin,,0,0,0,,你会调用一些你的方法\\N{\\fs12}you're going to call some method of yours,\r\nDialogue: 0,0:21:02.51,0:21:04.78,yin,,0,0,0,,我将它称作documentIsReady\\N{\\fs12}I've called it document is ready, you can call\r\nDialogue: 0,0:21:04.78,0:21:08.06,yin,,0,0,0,,你也可以起别的名称\\N{\\fs12}that method anything you want, that says okay,\r\nDialogue: 0,0:21:08.06,0:21:11.26,yin,,0,0,0,,文档已就绪 你现在可以用它了\\N{\\fs12}the documents ready to go, now you can go use it.\r\nDialogue: 0,0:21:11.26,0:21:13.23,yin,,0,0,0,,两种情况下我都做了相同的事情\\N{\\fs12}Alright? And I'm doing the same thing in either case.\r\nDialogue: 0,0:21:13.23,0:21:17.47,yin,,0,0,0,,苹果在这里没给打开或创建这样的方法 显得有些懒\\N{\\fs12}It's a little bit of a bummer that there's no method like open or create,\r\nDialogue: 0,0:21:17.47,0:21:18.89,yin,,0,0,0,,苹果只给出了这些东西\\N{\\fs12}and it just does it all in once, that you have\r\nDialogue: 0,0:21:18.89,0:21:21.89,yin,,0,0,0,,只有fileExists这些 不过你也没办法\\N{\\fs12}to do this file exist business, but you do, so you're going\r\nDialogue: 0,0:21:21.89,0:21:24.53,yin,,0,0,0,,这段代码几乎会出现在任何\\N{\\fs12}to have this little sequence of code\r\nDialogue: 0,0:21:24.53,0:21:28.07,yin,,0,0,0,,使用UIManagedDocument的app中\\N{\\fs12}in almost any app that uses a UI-managed document.\r\nDialogue: 0,0:21:28.07,0:21:33.13,yin,,0,0,0,,这有些愚蠢 因为都是很简单很类似的东西\\N{\\fs12}It's kind of silly, because it's all very, very simple, similar,\r\nDialogue: 0,0:21:33.13,0:21:35.62,yin,,0,0,0,,不过它就是这样的\\N{\\fs12}if then there, but that's what it looks like.\r\nDialogue: 0,0:21:35.62,0:21:38.68,yin,,0,0,0,,documentIsReady方法又是怎样的呢\\N{\\fs12}So now, what does that document is ready method look like?\r\nDialogue: 0,0:21:38.68,0:21:40.16,yin,,0,0,0,,大致是这样的\\N{\\fs12}It looks something like this.\r\nDialogue: 0,0:21:40.16,0:21:42.59,yin,,0,0,0,,在documentIsReady方法最开始\\N{\\fs12}One thing I might do at the beginning\r\nDialogue: 0,0:21:42.59,0:21:45.71,yin,,0,0,0,,我可以检查文档的状态\\N{\\fs12}of my document is ready is check the state of the document\r\nDialogue: 0,0:21:45.71,0:21:47.64,yin,,0,0,0,,看它是否处于正常状态\\N{\\fs12}to see if it's in the normal state,\r\nDialogue: 0,0:21:47.64,0:21:50.68,yin,,0,0,0,,正常状态是说 它准备好了\\N{\\fs12}normal state means this guys is ready to go.\r\nDialogue: 0,0:21:50.68,0:21:52.95,yin,,0,0,0,,它可以有哪些状态呢\\N{\\fs12}What other states could it be in?\r\nDialogue: 0,0:21:52.95,0:21:55.40,yin,,0,0,0,,状态还可以是关闭\\N{\\fs12}Well it could be in the state closed,\r\nDialogue: 0,0:21:55.40,0:21:57.67,yin,,0,0,0,,关闭是说 还没有打开\\N{\\fs12}closed means you haven't opened it yet\r\nDialogue: 0,0:21:57.67,0:21:59.32,yin,,0,0,0,,或者还没有创建\\N{\\fs12}or you haven't created it yet.\r\nDialogue: 0,0:21:59.32,0:22:01.23,yin,,0,0,0,,这两种都是关闭状态\\N{\\fs12}Either case it's going to be closed.\r\nDialogue: 0,0:22:01.23,0:22:03.62,yin,,0,0,0,,关闭状态的文档不能使用\\N{\\fs12}You cannot use a document once in the closed state.\r\nDialogue: 0,0:22:03.62,0:22:06.80,yin,,0,0,0,,还有一些状态 例如保存错误\\N{\\fs12}Some of these other states, like there was a saving error\r\nDialogue: 0,0:22:06.80,0:22:08.93,yin,,0,0,0,,或是编辑暂时禁用\\N{\\fs12}or editing is temporarily disabled\r\nDialogue: 0,0:22:08.93,0:22:12.04,yin,,0,0,0,,因为iCloud中有其他人正在编辑这个文档\\N{\\fs12}because someone else is editing this document in iCloud\r\nDialogue: 0,0:22:12.04,0:22:13.75,yin,,0,0,0,,例如它在更新\\N{\\fs12}and its updating, for example.\r\nDialogue: 0,0:22:13.75,0:22:16.45,yin,,0,0,0,,这门课中你不会碰到这些\\N{\\fs12}You're not going to run into those in this class,\r\nDialogue: 0,0:22:16.45,0:22:18.57,yin,,0,0,0,,但你应该知道有这些东西\\N{\\fs12}but you should know that they are there.\r\nDialogue: 0,0:22:18.57,0:22:22.27,yin,,0,0,0,,在最开始检查这个\\N{\\fs12}So, checking that, at the beginning to, you know,\r\nDialogue: 0,0:22:22.27,0:22:24.64,yin,,0,0,0,,这是一个位掩码 因此我使用了那个&符号\\N{\\fs12}it's a bit mask there, that's why I'm using that ampersand,\r\nDialogue: 0,0:22:24.64,0:22:27.33,yin,,0,0,0,,我只是检查那个位 看我的文档是否在正常状态\\N{\\fs12}right, I'm just checking that bit, do my documents stay normal?\r\nDialogue: 0,0:22:27.33,0:22:28.96,yin,,0,0,0,,看文档是否准备就绪\\N{\\fs12}Just to see if the document is ready to go.\r\nDialogue: 0,0:22:28.96,0:22:31.16,yin,,0,0,0,,这是第一件事 检查其状态\\N{\\fs12}So that might be the first thing I do is check its state\r\nDialogue: 0,0:22:31.16,0:22:33.90,yin,,0,0,0,,确保它就绪了 如果没就绪 例如是关闭的\\N{\\fs12}to make sure it's ready to go, if it's not, like if it was closed,\r\nDialogue: 0,0:22:33.90,0:22:36.23,yin,,0,0,0,,那我就需要回头尝试打开或创建它\\N{\\fs12}then I might go back and try to open it, or create it again.\r\nDialogue: 0,0:22:36.23,0:22:41.54,yin,,0,0,0,,如果有错误 我可能会等一下 再试一下 等等\\N{\\fs12}If it's got an error, I might wait awhile and try this again, or something like that.\r\nDialogue: 0,0:22:41.54,0:22:46.32,yin,,0,0,0,,无论如何 假设我的文档处在正常状态 再怎么做呢\\N{\\fs12}So anyway, let's say I have this document in a normal state, now what am I going to do?\r\nDialogue: 0,0:22:46.32,0:22:49.28,yin,,0,0,0,,我要抓取那个NSManagedObjectContext\\N{\\fs12}Now I'm going to grab that NS-managed object context\r\nDialogue: 0,0:22:49.28,0:22:51.84,yin,,0,0,0,,开始做一些Core Data方面的事\\N{\\fs12}and go start doing some core data stuff.\r\nDialogue: 0,0:22:51.84,0:22:53.69,yin,,0,0,0,,就是这样\\N{\\fs12}And that's it.\r\nDialogue: 0,0:22:53.69,0:22:56.12,yin,,0,0,0,,我们就是这样开始\\N{\\fs12}So this is how we get started.\r\nDialogue: 0,0:22:56.12,0:23:00.28,yin,,0,0,0,,在具体考虑如何处理NSManagedObjectContext前\\N{\\fs12}Now, before we dive into what we're going to do with that NS-managed object context,\r\nDialogue: 0,0:23:00.28,0:23:02.91,yin,,0,0,0,,我还要再讲几点UIManagedDocument的内容\\N{\\fs12}a couple more things about UI-managed document,\r\nDialogue: 0,0:23:02.91,0:23:06.78,yin,,0,0,0,,一是 它是自动保存的\\N{\\fs12}one is that it is auto saved.\r\nDialogue: 0,0:23:06.78,0:23:09.09,yin,,0,0,0,,你不需要手动保存\\N{\\fs12}You do not have to save it.\r\nDialogue: 0,0:23:09.09,0:23:12.03,yin,,0,0,0,,你可以用这里的方法来保存它\\N{\\fs12}And you can save it using this method you see here,\r\nDialogue: 0,0:23:12.03,0:23:15.72,yin,,0,0,0,,但一般我们不这样做 我们会让它自动保存\\N{\\fs12}but generally we don't, we let it auto save.\r\nDialogue: 0,0:23:15.72,0:23:17.99,yin,,0,0,0,,存储方式还是原来那个方法\\N{\\fs12}The way we save it is with the same method\r\nDialogue: 0,0:23:17.99,0:23:20.81,yin,,0,0,0,,我们说UIDocumentSaveForOverwriting\\N{\\fs12}that we used before, but we say UI document save for overwriting,\r\nDialogue: 0,0:23:20.82,0:23:22.91,yin,,0,0,0,,不过我们一般不会调用这个方法\\N{\\fs12}but generally, we don't call this method.\r\nDialogue: 0,0:23:22.91,0:23:24.89,yin,,0,0,0,,我们让它自动保存\\N{\\fs12}We let it auto save.\r\nDialogue: 0,0:23:24.89,0:23:27.91,yin,,0,0,0,,理解这个非常重要\\N{\\fs12}So that's an important thing to understand.\r\nDialogue: 0,0:23:27.91,0:23:31.62,yin,,0,0,0,,第二点 关闭文档\\N{\\fs12}Second thing, closing the document.\r\nDialogue: 0,0:23:31.62,0:23:34.67,yin,,0,0,0,,实际上 它也能自动关闭\\N{\\fs12}Well, it kind of auto closes, as well.\r\nDialogue: 0,0:23:34.67,0:23:35.84,yin,,0,0,0,,什么时候关闭呢\\N{\\fs12}When does it close?\r\nDialogue: 0,0:23:35.84,0:23:37.87,yin,,0,0,0,,当没有任何强指针指向它时\\N{\\fs12}When there are no more strong pointers to it.\r\nDialogue: 0,0:23:37.87,0:23:39.88,yin,,0,0,0,,换言之 当没有任何强指针指向它时\\N{\\fs12}In other words, when there are no more strong pointers to it,\r\nDialogue: 0,0:23:39.88,0:23:44.12,yin,,0,0,0,,当它要离开堆时 它就会自动关闭\\N{\\fs12}when it's going to leave the heap, it gets closed automatically.\r\nDialogue: 0,0:23:44.12,0:23:47.45,yin,,0,0,0,,因此 你一般也不用调用关闭 虽然你可以这么做\\N{\\fs12}So you generally don't call a close either, but you can do that as well.\r\nDialogue: 0,0:23:47.45,0:23:51.18,yin,,0,0,0,,关闭和保存一样 也是异步的\\N{\\fs12}And close, just like saving, are asynchronous,\r\nDialogue: 0,0:23:51.18,0:23:53.98,yin,,0,0,0,,你需要实现completionHander 来做你想做的事\\N{\\fs12}and you got to implement these completion handlers to do whatever you want\r\nDialogue: 0,0:23:53.98,0:23:56.28,yin,,0,0,0,,当它们完成关闭或是完成保存时\\N{\\fs12}when they're done closing or done saving.\r\nDialogue: 0,0:23:56.28,0:23:57.51,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:24:01.21,0:24:01.87,yin,,0,0,0,,对\\N{\\fs12}Correct. Yes.\r\nDialogue: 0,0:24:01.87,0:24:04.23,yin,,0,0,0,,问题是 关闭之前它是否会自动保存\\N{\\fs12}So the question, does it auto save before closing?\r\nDialogue: 0,0:24:04.23,0:24:04.89,yin,,0,0,0,,当然会\\N{\\fs12}Absolutely.\r\nDialogue: 0,0:24:04.89,0:24:08.19,yin,,0,0,0,,你要它关闭 或是不再有强指针指向它时\\N{\\fs12}If you say close, or if you stop having a strong pointer to it,\r\nDialogue: 0,0:24:08.19,0:24:10.91,yin,,0,0,0,,它就会保存然后关闭\\N{\\fs12}it will save and then close.\r\nDialogue: 0,0:24:10.91,0:24:17.10,yin,,0,0,0,,关于保存和自动保存我还想说一点\\N{\\fs12}One thing I will say about saving, the auto saving,\r\nDialogue: 0,0:24:17.10,0:24:18.42,yin,,0,0,0,,在调试时\\N{\\fs12}when you're in debugging, you know,\r\nDialogue: 0,0:24:18.42,0:24:20.88,yin,,0,0,0,,你处在开发模式 你在调试\\N{\\fs12}when you're in development mode and you're debugging,\r\nDialogue: 0,0:24:20.88,0:24:22.96,yin,,0,0,0,,有时学生会有些困扰\\N{\\fs12}sometimes students will get a little confused,\r\nDialogue: 0,0:24:22.96,0:24:24.73,yin,,0,0,0,,因为他们会做点什么\\N{\\fs12}because they'll go and they'll do something,\r\nDialogue: 0,0:24:24.73,0:24:27.75,yin,,0,0,0,,更新数据库 然后停在调试器中\\N{\\fs12}update their database, and then they'll stop in the debugger,\r\nDialogue: 0,0:24:27.75,0:24:30.39,yin,,0,0,0,,改一下代码 再次运行 结果数据不见了\\N{\\fs12}made a code change and run again, and the data won't be there.\r\nDialogue: 0,0:24:30.39,0:24:32.75,yin,,0,0,0,,因为它没有自动保存的机会\\N{\\fs12}Well, because it didn't have a chance to auto save.\r\nDialogue: 0,0:24:32.75,0:24:36.42,yin,,0,0,0,,在开发模式中 你需要明确放一些保存进来\\N{\\fs12}So when you're in development mode, you might want to throw in some explicit saves\r\nDialogue: 0,0:24:36.42,0:24:40.05,yin,,0,0,0,,如果你总要在调试器中点停止的话\\N{\\fs12}if you're going to be hitting stop in the debugger all the time.\r\nDialogue: 0,0:24:41.25,0:24:43.65,yin,,0,0,0,,好 我们再来讨论相同文档上\\N{\\fs12}Alright, so let's talk about multiple instances\r\nDialogue: 0,0:24:43.65,0:24:47.00,yin,,0,0,0,,UIManagedDocument的多实例\\N{\\fs12}of UI-managed document on the same document.\r\nDialogue: 0,0:24:47.00,0:24:50.09,yin,,0,0,0,,能不能 我对文件URL进行alloc init\\N{\\fs12}Am I allowed to alloc init file URL\r\nDialogue: 0,0:24:50.09,0:24:52.54,yin,,0,0,0,,来创建一个UIManagedDocument\\N{\\fs12}to create a UI-managed document, and then somewhere else\r\nDialogue: 0,0:24:52.54,0:24:57.08,yin,,0,0,0,,然后其他人对相同文件URL进行alloc init\\N{\\fs12}in my code, alloc init file URL, the same URL, and have two\r\nDialogue: 0,0:24:57.08,0:25:01.42,yin,,0,0,0,,让两者着眼于相同文档 你可能会认为这行不通\\N{\\fs12}of them looking at the same document, you might think, oh that can't work,\r\nDialogue: 0,0:25:01.42,0:25:03.58,yin,,0,0,0,,但实际上 这完全可以\\N{\\fs12}but actually it does, it works perfectly fine.\r\nDialogue: 0,0:25:03.58,0:25:05.99,yin,,0,0,0,,完全没问题\\N{\\fs12}It works absolutely no problem,\r\nDialogue: 0,0:25:05.99,0:25:09.00,yin,,0,0,0,,两者有自身的ManagedObjectContext\\N{\\fs12}the two have their own managed object context\r\nDialogue: 0,0:25:09.00,0:25:11.22,yin,,0,0,0,,这是不同的 不过context都着眼于\\N{\\fs12}that are different, but they're both, contexts are looking\r\nDialogue: 0,0:25:11.22,0:25:15.39,yin,,0,0,0,,相同的数据库 它们都发生变化时 会发生保存\\N{\\fs12}at the same database and when they both make changes, it's going to save.\r\nDialogue: 0,0:25:15.39,0:25:17.53,yin,,0,0,0,,这也有可能出现问题\\N{\\fs12}There is the possible problem though\r\nDialogue: 0,0:25:17.53,0:25:21.75,yin,,0,0,0,,一个UIManagedDocument实例试图进行一种操作\\N{\\fs12}that one set of changes in this instance of the UI-managed document,\r\nDialogue: 0,0:25:21.75,0:25:23.09,yin,,0,0,0,,另一个却有冲突\\N{\\fs12}and this one might conflict.\r\nDialogue: 0,0:25:23.09,0:25:25.47,yin,,0,0,0,,一个可能想删除对象\\N{\\fs12}They might be trying to, one's trying to delete an object,\r\nDialogue: 0,0:25:25.47,0:25:28.28,yin,,0,0,0,,但同时 另一个可能想设置属性\\N{\\fs12}but another one is trying to set an attribute of it at the same time.\r\nDialogue: 0,0:25:28.28,0:25:31.36,yin,,0,0,0,,如果确实是多实例 冲突是很有可能出现的\\N{\\fs12}So, if you do have this, it is possible to get conflicts,\r\nDialogue: 0,0:25:31.36,0:25:33.38,yin,,0,0,0,,不过通常 多实例\\N{\\fs12}but usually if we have multiple instances,\r\nDialogue: 0,0:25:33.38,0:25:36.52,yin,,0,0,0,,只有一个能写 其它那些只能读\\N{\\fs12}it's because we have one writer and many readers.\r\nDialogue: 0,0:25:36.52,0:25:41.83,yin,,0,0,0,,两个控制器或什么 每个都能作出修改\\N{\\fs12}It's pretty rare to have two separate controllers or something, each having a document\r\nDialogue: 0,0:25:41.83,0:25:43.99,yin,,0,0,0,,这是很罕见的情况\\N{\\fs12}and their both making changes, that's pretty rare.\r\nDialogue: 0,0:25:43.99,0:25:46.29,yin,,0,0,0,,同时作出修改就更不用说了\\N{\\fs12}Especially both making changes at the same time,\r\nDialogue: 0,0:25:46.29,0:25:51.14,yin,,0,0,0,,屏幕上只有这么些空间可供修改决策的作出\\N{\\fs12}there's only so much screen for changes to be being made on.\r\nDialogue: 0,0:25:51.14,0:25:54.34,yin,,0,0,0,,这里有一点需要小心\\N{\\fs12}One thing to be careful of here is\r\nDialogue: 0,0:25:54.34,0:25:57.75,yin,,0,0,0,,如果一个文档修改了数据库\\N{\\fs12}that if one document changes the database,\r\nDialogue: 0,0:25:57.75,0:26:01.32,yin,,0,0,0,,另一个并不能自动看到相应变化\\N{\\fs12}the other one doesn't automatically see those changes.\r\nDialogue: 0,0:26:01.32,0:26:02.61,yin,,0,0,0,,你可能会说\\N{\\fs12}It's not like\r\nDialogue: 0,0:26:02.61,0:26:05.68,yin,,0,0,0,,哦 我加了一个对象到一个ManagedDocument\\N{\\fs12}oh I added an object in one managed document,\r\nDialogue: 0,0:26:05.68,0:26:07.34,yin,,0,0,0,,哦 我在另一个中看不到\\N{\\fs12}oh, I don't see it in the other one.\r\nDialogue: 0,0:26:07.34,0:26:08.26,yin,,0,0,0,,为什么看不到呢\\N{\\fs12}Why don't you see it?\r\nDialogue: 0,0:26:08.26,0:26:10.46,yin,,0,0,0,,看不到是因为context不同\\N{\\fs12}Well you don't see it because they have different context,\r\nDialogue: 0,0:26:10.46,0:26:12.30,yin,,0,0,0,,不同的NSManagedObjectContext\\N{\\fs12}different NS-managed object contexts,\r\nDialogue: 0,0:26:12.30,0:26:14.33,yin,,0,0,0,,不过你仍然是在修改相同的数据库\\N{\\fs12}but you're still modifying the same database.\r\nDialogue: 0,0:26:14.33,0:26:18.47,yin,,0,0,0,,那如何知道另一个文档是否进行了修改呢\\N{\\fs12}So how could you find out, if you wanted to find out if another document is doing,\r\nDialogue: 0,0:26:18.47,0:26:20.73,yin,,0,0,0,,答案是 广播站\\N{\\fs12}and the answer is, the radio station.\r\nDialogue: 0,0:26:20.73,0:26:23.80,yin,,0,0,0,,我们可以使用NSNotification\\N{\\fs12}We could use NS notification.\r\nDialogue: 0,0:26:23.80,0:26:26.98,yin,,0,0,0,,这是一个例子 有一个控制器\\N{\\fs12}And so, here's an example of having a controller,\r\nDialogue: 0,0:26:26.98,0:26:30.36,yin,,0,0,0,,到屏幕上时 开始监听\\N{\\fs12}when it comes on screen, start listening at,\r\nDialogue: 0,0:26:30.36,0:26:35.05,yin,,0,0,0,,不同文档的ManagedObjectContext\\N{\\fs12}to the managed object context, there, of a different document.\r\nDialogue: 0,0:26:35.05,0:26:37.48,yin,,0,0,0,,不是它打开的文档 而是别的\\N{\\fs12}Not the document it has open, but some other,\r\nDialogue: 0,0:26:37.48,0:26:40.92,yin,,0,0,0,,UIManagedDocument的其它实例\\N{\\fs12}some other instance of a UI-managed document,\r\nDialogue: 0,0:26:40.92,0:26:43.39,yin,,0,0,0,,而且它在找广播站\\N{\\fs12}and it's looking for the radio station,\r\nDialogue: 0,0:26:43.39,0:26:46.22,yin,,0,0,0,,NSManagedObjectContextDidSaveNotification\\N{\\fs12}NS-managed object context did save notification.\r\nDialogue: 0,0:26:46.22,0:26:50.16,yin,,0,0,0,,另一个文档自动保存时 它就会\\N{\\fs12}So whenever that other document auto saves, then it's going\r\nDialogue: 0,0:26:50.16,0:26:53.76,yin,,0,0,0,,获得NSNotification说 哦 它变了\\N{\\fs12}to get a NS notification saying oh, it changed.\r\nDialogue: 0,0:26:53.76,0:26:57.19,yin,,0,0,0,,我把这个方法叫contextChanged 或是别的什么\\N{\\fs12}Alright? And I'm going to call this method context changed or whatever.\r\nDialogue: 0,0:26:57.19,0:27:00.12,yin,,0,0,0,,这个发生时我要做什么呢\\N{\\fs12}And what would I do when that happens?\r\nDialogue: 0,0:27:00.12,0:27:05.09,yin,,0,0,0,,两点 一是我可以重新取回我的所有对象\\N{\\fs12}Well, two things, one, I could just refetch all my objects.\r\nDialogue: 0,0:27:05.09,0:27:06.86,yin,,0,0,0,,我知道数据库发生了变化\\N{\\fs12}Okay, I know the database is changed,\r\nDialogue: 0,0:27:06.86,0:27:08.83,yin,,0,0,0,,我重新取回它们 我还没讲取回\\N{\\fs12}I'll just refetch them all, we haven't talked about fetching,\r\nDialogue: 0,0:27:08.83,0:27:11.78,yin,,0,0,0,,不过 我可以重新取回 更新所有东西\\N{\\fs12}but I could refetch and get a fresh set of everything.\r\nDialogue: 0,0:27:11.78,0:27:15.71,yin,,0,0,0,,但实际上 这个ContextDidSaveNotification\\N{\\fs12}But, actually this context change did save notification,\r\nDialogue: 0,0:27:15.71,0:27:17.24,yin,,0,0,0,,会给你一个数组\\N{\\fs12}gives you an array,\r\nDialogue: 0,0:27:17.24,0:27:19.73,yin,,0,0,0,,在它用户信息中的是一个字典\\N{\\fs12}inside of its user info is a dictionary,\r\nDialogue: 0,0:27:19.73,0:27:24.20,yin,,0,0,0,,有三个数组 这是所有变化了的对象的列表\\N{\\fs12}with three arrays that are a list of all the objects that changed.\r\nDialogue: 0,0:27:24.20,0:27:28.25,yin,,0,0,0,,你可以把这些变化合并到你的context中\\N{\\fs12}And you can merge those changes\r\nDialogue: 0,0:27:28.25,0:27:31.45,yin,,0,0,0,,使用这个NSManagedObjectContext方法\\N{\\fs12}into your context using this NS-managed object context\r\nDialogue: 0,0:27:31.45,0:27:34.26,yin,,0,0,0,,mergeChangesFromContextDidSaveNotification\\N{\\fs12}method, merge changes from context did save notification,\r\nDialogue: 0,0:27:34.26,0:27:35.85,yin,,0,0,0,,你把notification给它\\N{\\fs12}you just give it the notification,\r\nDialogue: 0,0:27:35.85,0:27:38.87,yin,,0,0,0,,它会自动将所有变化合并到你的context中\\N{\\fs12}and it'll automatically merge all those changes into your context,\r\nDialogue: 0,0:27:38.87,0:27:39.78,yin,,0,0,0,,非常酷\\N{\\fs12}which is pretty cool.\r\nDialogue: 0,0:27:39.78,0:27:41.46,yin,,0,0,0,,这是一个很酷的方法\\N{\\fs12}This is a very cool method.\r\nDialogue: 0,0:27:41.46,0:27:44.70,yin,,0,0,0,,这个方法的酷经常会被人们低估\\N{\\fs12}Very underappreciated coolness of this method.\r\nDialogue: 0,0:27:44.70,0:27:46.76,yin,,0,0,0,,你在监视其它context\\N{\\fs12}So you're watching some other context that's\r\nDialogue: 0,0:27:46.76,0:27:49.30,yin,,0,0,0,,同你的具有相同数据库 但context不同\\N{\\fs12}on the same database as yours, but it's a different context,\r\nDialogue: 0,0:27:49.30,0:27:51.99,yin,,0,0,0,,你获得一个notification 将变化合并到你的里面\\N{\\fs12}you get a notification, you can merge those changes into yours,\r\nDialogue: 0,0:27:51.99,0:27:53.90,yin,,0,0,0,,就好像这些变化是你做出的一样\\N{\\fs12}as if you had made those changes.\r\nDialogue: 0,0:27:53.90,0:27:56.81,yin,,0,0,0,,两个文档同时存储时也没问题\\N{\\fs12}And it's all going to be fine when both documents save\r\nDialogue: 0,0:27:56.81,0:27:59.51,yin,,0,0,0,,因为你合并了相同的变化\\N{\\fs12}because you're merging in the same changes\r\nDialogue: 0,0:27:59.51,0:28:01.70,yin,,0,0,0,,Core Data会自动处理\\N{\\fs12}and this is, core data automatically deals\r\nDialogue: 0,0:28:01.70,0:28:04.74,yin,,0,0,0,,当相同变化由两个不同context同时完成\\N{\\fs12}with when the same change is being made by two different contexts,\r\nDialogue: 0,0:28:04.74,0:28:08.62,yin,,0,0,0,,只有冲突的才会让你产生问题\\N{\\fs12}only when conflicting ones happen is it a problem for you.\r\nDialogue: 0,0:28:08.62,0:28:11.17,yin,,0,0,0,,这些都能奇妙地良好运作\\N{\\fs12}So this all kind of just magically works.\r\nDialogue: 0,0:28:11.17,0:28:12.89,yin,,0,0,0,,这是监视另一个context\\N{\\fs12}So that's watching another context.\r\nDialogue: 0,0:28:12.89,0:28:14.41,yin,,0,0,0,,作业中可能不需要这些\\N{\\fs12}Probably not going to be necessary in homework,\r\nDialogue: 0,0:28:14.41,0:28:17.26,yin,,0,0,0,,你们或许会采取一种不同策略\\N{\\fs12}because you're probably going to take a different strategy,\r\nDialogue: 0,0:28:17.26,0:28:20.29,yin,,0,0,0,,也就是只有一个UIManagedDocument\\N{\\fs12}which is have one managed document, UI-managed document,\r\nDialogue: 0,0:28:20.29,0:28:23.40,yin,,0,0,0,,然后将它的context用到app的所有地方\\N{\\fs12}and you use its context everywhere in your app.\r\nDialogue: 0,0:28:23.40,0:28:25.05,yin,,0,0,0,,这样做显然更简单\\N{\\fs12}That's kind of a simpler way to do it,\r\nDialogue: 0,0:28:25.05,0:28:27.09,yin,,0,0,0,,作业中 我建议你们这样做\\N{\\fs12}and that's what I recommend for your homework.\r\nDialogue: 0,0:28:27.09,0:28:31.05,yin,,0,0,0,,我们会在演示中看到 演示中我会展示这个\\N{\\fs12}And we'll see in the demo, I'm going to do that in the demo.\r\nDialogue: 0,0:28:31.05,0:28:33.71,yin,,0,0,0,,好 现在我们有了NSManagedObjectContext\\N{\\fs12}Alright. So now we have an NS-managed object context\r\nDialogue: 0,0:28:33.71,0:28:36.43,yin,,0,0,0,,来自于我们的文档 我们能用它做什么\\N{\\fs12}that we got from our document, what can we do with it?\r\nDialogue: 0,0:28:36.43,0:28:38.82,yin,,0,0,0,,我们可以插入和删除对象\\N{\\fs12}Well, we can insert and delete objects,\r\nDialogue: 0,0:28:38.82,0:28:41.61,yin,,0,0,0,,我们可以修改属性 我们还可以查询对象\\N{\\fs12}we can change attributes, and we can query for objects.\r\nDialogue: 0,0:28:41.61,0:28:43.62,yin,,0,0,0,,我们来谈谈这些\\N{\\fs12}So let's talk about doing all those things.\r\nDialogue: 0,0:28:43.62,0:28:45.00,yin,,0,0,0,,首先是插入\\N{\\fs12}Let's start with inserting.\r\nDialogue: 0,0:28:45.00,0:28:48.40,yin,,0,0,0,,假设我要添加一张新照片 或是一个新的拍照人\\N{\\fs12}So let's say I want to put a new photo, or put a new photographer\r\nDialogue: 0,0:28:48.40,0:28:51.04,yin,,0,0,0,,到数据库中 我可以用这个方法\\N{\\fs12}into the database, I do that with this method right here,\r\nDialogue: 0,0:28:51.04,0:28:53.89,yin,,0,0,0,,这是一个NSEntityDescription上的类方法\\N{\\fs12}it's a class method on NS entity description\r\nDialogue: 0,0:28:53.89,0:28:56.69,yin,,0,0,0,,叫insertNewObjectForEntityForName\\N{\\fs12}called insert new object for entity for name\r\nDialogue: 0,0:28:56.70,0:28:58.24,yin,,0,0,0,,inManagedObjectContext\\N{\\fs12}in managed object context.\r\nDialogue: 0,0:28:58.24,0:29:02.30,yin,,0,0,0,,可以看到 没有context 我是无法插入对象的\\N{\\fs12}So you can see, I can't insert an object without having a context.\r\nDialogue: 0,0:29:02.30,0:29:06.07,yin,,0,0,0,,必须context牵线搭桥 才能插入对象到数据库中\\N{\\fs12}The context is the hook that lets you insert things\r\nDialogue: 0,0:29:06.07,0:29:09.83,yin,,0,0,0,,或是查询 或是做别的任何事情 context是必须的\\N{\\fs12}in the database or query or anything, so you have to have a context.\r\nDialogue: 0,0:29:09.83,0:29:15.47,yin,,0,0,0,,第一个参数@\"Photo\" 这是实体的名称\\N{\\fs12}And, that first argument, at sign photo, that is the name of the entity.\r\nDialogue: 0,0:29:15.47,0:29:18.41,yin,,0,0,0,,记得在映射中我创建了一个Photo实体吗\\N{\\fs12}So remember in the mapping thing when I made a photo entity\r\nDialogue: 0,0:29:18.41,0:29:22.35,yin,,0,0,0,,我还创建了一个Photographer实体 这就是实体名\\N{\\fs12}and I made a photographer entity, this is a string which is the name.\r\nDialogue: 0,0:29:22.35,0:29:24.66,yin,,0,0,0,,这里创建一张照片\\N{\\fs12}So here I am making a photo.\r\nDialogue: 0,0:29:24.66,0:29:26.06,yin,,0,0,0,,它返回什么呢\\N{\\fs12}And what does it return?\r\nDialogue: 0,0:29:26.06,0:29:28.65,yin,,0,0,0,,它会返回NSManagedObject *photo\\N{\\fs12}It returns NS-managed object star photo,\r\nDialogue: 0,0:29:28.65,0:29:31.48,yin,,0,0,0,,我讲过 数据库中的所有对象\\N{\\fs12}and I told you that all of the objects in the database\r\nDialogue: 0,0:29:31.48,0:29:35.27,yin,,0,0,0,,都是NSManagedObject或其子类\\N{\\fs12}are NS-managed objects or subclasses thereof.\r\nDialogue: 0,0:29:35.27,0:29:36.76,yin,,0,0,0,,这就是实际情况\\N{\\fs12}And, in fact, that's exactly what happened.\r\nDialogue: 0,0:29:36.76,0:29:39.38,yin,,0,0,0,,这里就会创建一个 并返回出来\\N{\\fs12}So this is just going to make one for you and return it.\r\nDialogue: 0,0:29:39.38,0:29:42.93,yin,,0,0,0,,它会是空的\\N{\\fs12}It's going to be blank, or empty.\r\nDialogue: 0,0:29:42.93,0:29:45.88,yin,,0,0,0,,这可能意味着 所有属性都是nil\\N{\\fs12}Now, that could mean that all of its attributes are nil,\r\nDialogue: 0,0:29:45.88,0:29:48.28,yin,,0,0,0,,但我们在Xcode中没看到这个\\N{\\fs12}but we didn't see this in Xcode,\r\nDialogue: 0,0:29:48.29,0:29:50.33,yin,,0,0,0,,在Xcode中检查属性时\\N{\\fs12}but it, when you inspect a property in Xcode,\r\nDialogue: 0,0:29:50.33,0:29:52.70,yin,,0,0,0,,你可以指定一个默认值\\N{\\fs12}you can actually specify a default value,\r\nDialogue: 0,0:29:52.70,0:29:54.30,yin,,0,0,0,,它会用那个值\\N{\\fs12}and it'll have that value.\r\nDialogue: 0,0:29:54.30,0:29:57.98,yin,,0,0,0,,或许 你希望它让上传日期\\N{\\fs12}So maybe you want it to have the upload date\r\nDialogue: 0,0:29:57.98,0:30:01.15,yin,,0,0,0,,默认为对象创建的日期或是别的什么\\N{\\fs12}by default be the date the object was created or something,\r\nDialogue: 0,0:30:01.15,0:30:05.42,yin,,0,0,0,,你可以创建某个固定日期\\N{\\fs12}you can go in and create some fixed date\r\nDialogue: 0,0:30:05.42,0:30:08.48,yin,,0,0,0,,或者 你希望标题总是至少为空字符串\\N{\\fs12}or you want the title to always be at least the empty string\r\nDialogue: 0,0:30:08.48,0:30:10.82,yin,,0,0,0,,诸如此类 你可以设置默认\\N{\\fs12}or something like that, you can set defaults,\r\nDialogue: 0,0:30:10.82,0:30:14.49,yin,,0,0,0,,在Xcode中 这些需要是常数\\N{\\fs12}they have to be constants basically, in Xcode,\r\nDialogue: 0,0:30:14.49,0:30:18.49,yin,,0,0,0,,在这些字段处 NSObject会带着这些默认设置回来\\N{\\fs12}to do that and NS object will come back with those defaults set in those fields,\r\nDialogue: 0,0:30:18.50,0:30:20.08,yin,,0,0,0,,否则就是nil\\N{\\fs12}and otherwise nil.\r\nDialogue: 0,0:30:20.08,0:30:21.94,yin,,0,0,0,,如果不想设置这些默认值\\N{\\fs12}But if you don't do any of that default setting,\r\nDialogue: 0,0:30:21.94,0:30:24.77,yin,,0,0,0,,这个照片中的一切属性都将是nil\\N{\\fs12}all the properties in this photo will be nil.\r\nDialogue: 0,0:30:24.77,0:30:27.07,yin,,0,0,0,,标题是nil 副标题是nil\\N{\\fs12}So the title will be nil, subtitle will be nil,\r\nDialogue: 0,0:30:27.07,0:30:30.62,yin,,0,0,0,,whoTook是nil 都是nil\\N{\\fs12}the who took will be nil, it'll all be nil.\r\nDialogue: 0,0:30:30.62,0:30:36.15,yin,,0,0,0,,很好 现在我有了对象 那如何设定属性呢\\N{\\fs12}So, great, now I have an object, how do I set those attributes?\r\nDialogue: 0,0:30:36.15,0:30:37.55,yin,,0,0,0,,我要设定标题\\N{\\fs12}I want to set the title.\r\nDialogue: 0,0:30:37.55,0:30:40.30,yin,,0,0,0,,我要设定副标题 我还要设定whoTook\\N{\\fs12}I want to set the subtitle, I even want to set who took?\r\nDialogue: 0,0:30:40.30,0:30:41.38,yin,,0,0,0,,怎么做呢\\N{\\fs12}How do I do that?\r\nDialogue: 0,0:30:41.38,0:30:45.62,yin,,0,0,0,,这要用到KeyValueCoding协议\\N{\\fs12}You do that using the key value coding protocol.\r\nDialogue: 0,0:30:45.62,0:30:48.27,yin,,0,0,0,,你们其实已经用过这个协议了\\N{\\fs12}And you've already used this protocol actually.\r\nDialogue: 0,0:30:48.29,0:30:50.13,yin,,0,0,0,,它是valueForKey\\N{\\fs12}It is value for key,\r\nDialogue: 0,0:30:50.13,0:30:51.78,yin,,0,0,0,,setValue forKey\\N{\\fs12}set value for key,\r\nDialogue: 0,0:30:51.78,0:30:53.00,yin,,0,0,0,,valueForKeyPath\\N{\\fs12}value for key path,\r\nDialogue: 0,0:30:53.00,0:30:55.29,yin,,0,0,0,,和setValue forKeyPath\\N{\\fs12}and set value for key path.\r\nDialogue: 0,0:30:55.29,0:31:00.80,yin,,0,0,0,,这个协议 由NSDictionary实现\\N{\\fs12}So this protocol, which is implemented by NS dictionary,\r\nDialogue: 0,0:31:00.80,0:31:03.53,yin,,0,0,0,,例如 这就是我们使用valueForKeyPath的方式\\N{\\fs12}for example, that's how we used value for key path\r\nDialogue: 0,0:31:03.53,0:31:05.65,yin,,0,0,0,,在NSDictionary中\\N{\\fs12}in those NS dictionaries, to do the things like\r\nDialogue: 0,0:31:05.65,0:31:08.53,yin,,0,0,0,,做description._content这样的事 记得吗\\N{\\fs12}description dot under bar contents, remember that,\r\nDialogue: 0,0:31:08.53,0:31:10.49,yin,,0,0,0,,来自Flickr\\N{\\fs12}from Flickr?\r\nDialogue: 0,0:31:10.49,0:31:12.84,yin,,0,0,0,,这就是NSManagedObject的工作方式\\N{\\fs12}This is how NS-managed object works.\r\nDialogue: 0,0:31:12.84,0:31:16.36,yin,,0,0,0,,它实现了所有这些 而且你可以说valueForKey\\N{\\fs12}It implements all these and you can say value for key,\r\nDialogue: 0,0:31:16.36,0:31:20.27,yin,,0,0,0,,@号 引号 标题 这就能得到照片的标题\\N{\\fs12}at sign quote title, and you can get the title of a photo.\r\nDialogue: 0,0:31:20.27,0:31:22.26,yin,,0,0,0,,你也可以说setValue 然后是你想设的\\N{\\fs12}Or you can say set value, whatever you want,\r\nDialogue: 0,0:31:22.26,0:31:24.31,yin,,0,0,0,,forKey @号 引号 标题\\N{\\fs12}for key at sign quote title,\r\nDialogue: 0,0:31:24.32,0:31:27.83,yin,,0,0,0,,这就为标题设了值 很简单\\N{\\fs12}and set the value of a title, simple as that.\r\nDialogue: 0,0:31:27.83,0:31:29.57,yin,,0,0,0,,valueForKey setValue forKey\\N{\\fs12}Value for key, set value for key.\r\nDialogue: 0,0:31:29.57,0:31:32.12,yin,,0,0,0,,这方面有问题吗\\N{\\fs12}Any questions about that?\r\nDialogue: 0,0:31:32.12,0:31:35.60,yin,,0,0,0,,好 显然 键只是一个字符串\\N{\\fs12}Okay. So, the, the key is obviously just a string,\r\nDialogue: 0,0:31:35.60,0:31:39.03,yin,,0,0,0,,早些时候我们创建的可视映射中的属性名\\N{\\fs12}the name of the property in your visual map that we built earlier.\r\nDialogue: 0,0:31:39.03,0:31:44.21,yin,,0,0,0,,值只是一个对象 例如如果是标题 那就是NSString\\N{\\fs12}The value would be just an object, like an NS string, if it was a title,\r\nDialogue: 0,0:31:44.21,0:31:46.91,yin,,0,0,0,,如果上传日期 那就是NSDate\\N{\\fs12}and NS date if it was the upload date\r\nDialogue: 0,0:31:46.91,0:31:51.56,yin,,0,0,0,,如果是缩略图数据什么的 那就是NSData\\N{\\fs12}and NS data if it was the thumbnail UR, thumbnail data or whatever.\r\nDialogue: 0,0:31:51.56,0:31:55.19,yin,,0,0,0,,你还可以用setValue forKey来设定关系\\N{\\fs12}You can also set, using set value for key, the relationships.\r\nDialogue: 0,0:31:55.19,0:31:56.78,yin,,0,0,0,,如果你有一个拍照者\\N{\\fs12}So if you had a photographer,\r\nDialogue: 0,0:31:56.78,0:31:59.61,yin,,0,0,0,,或许你也插入了实体描述这些\\N{\\fs12}which maybe you inserted with that entity description thing,\r\nDialogue: 0,0:31:59.61,0:32:02.69,yin,,0,0,0,,有了拍照者 你可以说\\N{\\fs12}so now you have photographer, as well, you can just say the,\r\nDialogue: 0,0:32:02.69,0:32:05.82,yin,,0,0,0,,照片 setValue 引号 whoTook\\N{\\fs12}the photo set value, quote who took,\r\nDialogue: 0,0:32:05.82,0:32:06.98,yin,,0,0,0,,设置值\\N{\\fs12}set the value,\r\nDialogue: 0,0:32:06.98,0:32:07.80,yin,,0,0,0,,拍照者\\N{\\fs12}the photographer,\r\nDialogue: 0,0:32:07.80,0:32:10.13,yin,,0,0,0,,forKey 引号 whoTook\\N{\\fs12}for the key quote who took.\r\nDialogue: 0,0:32:10.94,0:32:15.99,yin,,0,0,0,,有趣的是 如果你设置whoTook的值\\N{\\fs12}Now, what' really interesting is that if you set that value who took,\r\nDialogue: 0,0:32:16.01,0:32:21.98,yin,,0,0,0,,拍照者中的照片集合将会自动更新\\N{\\fs12}the photo set, in the photographer, will automatically be updated.\r\nDialogue: 0,0:32:21.98,0:32:24.72,yin,,0,0,0,,你不需要同时设置关系的两侧\\N{\\fs12}You do not have to set both sides of the relationship.\r\nDialogue: 0,0:32:24.72,0:32:25.66,yin,,0,0,0,,反之亦然\\N{\\fs12}And vice versa.\r\nDialogue: 0,0:32:25.66,0:32:31.68,yin,,0,0,0,,如果我有一个拍照者 我在其照片集中添加一张照片\\N{\\fs12}If I have a photographer and I add a photo to its photos set,\r\nDialogue: 0,0:32:31.68,0:32:34.16,yin,,0,0,0,,whoTook也会自动设置\\N{\\fs12}it'll automatically set who took.\r\nDialogue: 0,0:32:34.16,0:32:39.81,yin,,0,0,0,,这是因为这个数据库 需要维持自身的内部一致性\\N{\\fs12}And that's because this database has to maintain self internal consistency\r\nDialogue: 0,0:32:39.81,0:32:43.17,yin,,0,0,0,,Core Data会为你做所有这些 这非常酷\\N{\\fs12}and so core data does that all for you, which is really cool?\r\nDialogue: 0,0:32:43.17,0:32:44.89,yin,,0,0,0,,你可以设置任何一侧\\N{\\fs12}So you can set either side\r\nDialogue: 0,0:32:44.89,0:32:46.91,yin,,0,0,0,,另一侧都会自动设置\\N{\\fs12}and it'll automatically set the other side.\r\nDialogue: 0,0:32:48.51,0:32:51.53,yin,,0,0,0,,之前我说过 很多的是NSSet\\N{\\fs12}As I said before, the too many ones are NS sets,\r\nDialogue: 0,0:32:51.53,0:32:56.73,yin,,0,0,0,,不那么多的是NSManagedObject\\N{\\fs12}and the non-too many ones are just NS-managed object stars.\r\nDialogue: 0,0:32:56.73,0:33:00.09,yin,,0,0,0,,你进行的所有这些修改\\N{\\fs12}Now, all these changes that you're making,\r\nDialogue: 0,0:33:00.09,0:33:04.33,yin,,0,0,0,,插入对象 设置各种属性 这些都只发生在内存中\\N{\\fs12}inserting objects, setting all those properties, those only happen in memory.\r\nDialogue: 0,0:33:04.33,0:33:08.23,yin,,0,0,0,,不发生在磁盘上 直到context得到保存\\N{\\fs12}They're not happening on disc, until the context is saved.\r\nDialogue: 0,0:33:08.23,0:33:10.61,yin,,0,0,0,,context有一个保存方法\\N{\\fs12}Now the context has a save method.\r\nDialogue: 0,0:33:10.62,0:33:12.75,yin,,0,0,0,,你可以去看NSManagedObjectContext\\N{\\fs12}If you go look in NS-managed object context,\r\nDialogue: 0,0:33:12.75,0:33:16.10,yin,,0,0,0,,它有一个保存方法 但你不会调用它\\N{\\fs12}it has a save method, but you're not going to call that, because you're going\r\nDialogue: 0,0:33:16.10,0:33:20.04,yin,,0,0,0,,因为你会让UIManagedDocument自动保存context\\N{\\fs12}to let UI-managed documents auto save, save the context.\r\nDialogue: 0,0:33:20.04,0:33:24.42,yin,,0,0,0,,如果你保存文档 或者 你也可以发送信息给context\\N{\\fs12}Alright? So if you save the document or you can actually send a message\r\nDialogue: 0,0:33:24.42,0:33:25.89,yin,,0,0,0,,来保存它自身\\N{\\fs12}to the context to save itself.\r\nDialogue: 0,0:33:25.89,0:33:29.65,yin,,0,0,0,,无论哪种方式 它都会存到磁盘上 但这之前\\N{\\fs12}Either way, it will save out to disc, but until then,\r\nDialogue: 0,0:33:29.65,0:33:32.15,yin,,0,0,0,,所有修改都只存在于内存中\\N{\\fs12}all the changes you're making are just in memory.\r\nDialogue: 0,0:33:32.15,0:33:37.92,yin,,0,0,0,,Core Data内建有很让人难以置信的撤销与重做\\N{\\fs12}Now, core data has an incredible undo and redo built into it.\r\nDialogue: 0,0:33:37.92,0:33:41.49,yin,,0,0,0,,进行一些修改 然后说undo 修改就会撤销\\N{\\fs12}To, you make some changes, you say undo, it undoes them.\r\nDialogue: 0,0:33:41.49,0:33:44.00,yin,,0,0,0,,你还可以批处理 你可以撤销一组操作\\N{\\fs12}And you can batch them up and you can undo things as a group\r\nDialogue: 0,0:33:44.00,0:33:45.99,yin,,0,0,0,,你可以撤销最近一连串操作\\N{\\fs12}and can undo just the last chain, I can't,\r\nDialogue: 0,0:33:45.99,0:33:49.20,yin,,0,0,0,,我没时间讲所有这些 不过这非常酷\\N{\\fs12}I don't have time to talk about any of that, but it's really, really cool.\r\nDialogue: 0,0:33:49.20,0:33:52.27,yin,,0,0,0,,任何修改数据库数据的时候\\N{\\fs12}So anytime you have a situation where you're changing database\r\nDialogue: 0,0:33:52.27,0:33:56.55,yin,,0,0,0,,用户或许会要撤销 Core Data在这方面很棒\\N{\\fs12}and the user wants to be able to maybe undo, core data's awesome for that.\r\nDialogue: 0,0:33:58.00,0:34:02.88,yin,,0,0,0,,就像NSManagedObjectContextDidSaveNotification一样\\N{\\fs12}Just like you get UI, or NS-managed object did save notifications,\r\nDialogue: 0,0:34:02.88,0:34:06.04,yin,,0,0,0,,你还可以有UIManagedDocumentDidSaveNotification\\N{\\fs12}you can also get UI-managed document did save notification.\r\nDialogue: 0,0:34:06.04,0:34:08.56,yin,,0,0,0,,你可以使用这个广播站\\N{\\fs12}So you can sign up for that radio broadcast\r\nDialogue: 0,0:34:08.56,0:34:10.87,yin,,0,0,0,,弄清什么时候整个文档得到了保存\\N{\\fs12}and find out when the whole document did save.\r\nDialogue: 0,0:34:10.87,0:34:12.97,yin,,0,0,0,,这两种其实是半斤八两\\N{\\fs12}Kind of six, one-half dozen in the other in this case,\r\nDialogue: 0,0:34:12.97,0:34:14.78,yin,,0,0,0,,因为如果文档保存了\\N{\\fs12}because if the documents get saved,\r\nDialogue: 0,0:34:14.78,0:34:17.40,yin,,0,0,0,,那context显然也保存了\\N{\\fs12}then definitely the context is going to be saved, as well.\r\nDialogue: 0,0:34:20.48,0:34:23.92,yin,,0,0,0,,像这样调用valueForKey和setValue forKey\\N{\\fs12}Calling value for key and set value for a key like this though,\r\nDialogue: 0,0:34:23.92,0:34:26.21,yin,,0,0,0,,会导致一些很丑陋的代码\\N{\\fs12}it kind of results in some ugly code.\r\nDialogue: 0,0:34:26.21,0:34:29.18,yin,,0,0,0,,因为它没有类型检查 valueForKey\\N{\\fs12}Because it's not type checked, right, value for key\r\nDialogue: 0,0:34:29.18,0:34:31.06,yin,,0,0,0,,和setValue forKey\\N{\\fs12}and set value for key,\r\nDialogue: 0,0:34:31.06,0:34:34.18,yin,,0,0,0,,或许我该说setValue:forKey:\\N{\\fs12}that should be set value colon for key colon,\r\nDialogue: 0,0:34:34.18,0:34:36.84,yin,,0,0,0,,它只取id\\N{\\fs12}that just takes ID.\r\nDialogue: 0,0:34:36.84,0:34:40.20,yin,,0,0,0,,返回id 所以说 这里没有任何类型检查\\N{\\fs12}Right? Returns ID, so it's really not type checking any of that stuff,\r\nDialogue: 0,0:34:40.22,0:34:42.69,yin,,0,0,0,,而且 最终会有很多字符串字面量\\N{\\fs12}and also, you end up with a lot of literal strings,\r\nDialogue: 0,0:34:42.69,0:34:45.47,yin,,0,0,0,,例如@\"thumbnailURL\"\\N{\\fs12}like at sign quote thumbnail URL\r\nDialogue: 0,0:34:45.47,0:34:48.14,yin,,0,0,0,,如果你在可视映射中修改了这个的名称\\N{\\fs12}and if you ever changed the name of that in your visual map,\r\nDialogue: 0,0:34:48.14,0:34:51.94,yin,,0,0,0,,所有代码都将静静地停止工作 你甚至知都不知道\\N{\\fs12}all your code would just stop working silently and you wouldn't know, so,\r\nDialogue: 0,0:34:51.94,0:34:55.01,yin,,0,0,0,,我们这里实际想要的是属性\\N{\\fs12}really what we want here is properties.\r\nDialogue: 0,0:34:55.01,0:34:58.59,yin,,0,0,0,,我们希望能够设置标题 副标题和缩略图URL\\N{\\fs12}We want to be to set the title and subtitle and thumbnail URL\r\nDialogue: 0,0:34:58.59,0:35:03.78,yin,,0,0,0,,所有这些在我的照片中使用属性和点符号\\N{\\fs12}and all that stuff in my photo using properties and dot notation.\r\nDialogue: 0,0:35:03.78,0:35:08.53,yin,,0,0,0,,要做这些 我们需要为Photo创建一个子类\\N{\\fs12}So, all we need to do to do that is create subclasses for photo,\r\nDialogue: 0,0:35:08.53,0:35:10.44,yin,,0,0,0,,同时为Photographer创建一个子类\\N{\\fs12}and a subclass for photographer.\r\nDialogue: 0,0:35:10.44,0:35:12.69,yin,,0,0,0,,NSManagedObject的子类 对吧\\N{\\fs12}Subclasses of NS-managed object, right?\r\nDialogue: 0,0:35:12.69,0:35:15.33,yin,,0,0,0,,子类会实现所有这些属性\\N{\\fs12}And the subclasses will implement all these properties,\r\nDialogue: 0,0:35:15.33,0:35:19.71,yin,,0,0,0,,而且Xcode非常棒 它会帮你打理好这些\\N{\\fs12}and, of course, because Xcode is so nice, it's going to do that for you,\r\nDialogue: 0,0:35:19.71,0:35:21.57,yin,,0,0,0,,下面讨论一下如何\\N{\\fs12}so let's talk about now how\r\nDialogue: 0,0:35:21.57,0:35:26.42,yin,,0,0,0,,在Xcode中 为Photo和Photographer创建子类\\N{\\fs12}in Xcode we can make it generate subclasses for photo and photographer.\r\nDialogue: 0,0:35:26.42,0:35:30.15,yin,,0,0,0,,回到我的可视映射 点选Photo和Photographer\\N{\\fs12}So I'm going back to my visual map, I'm going to select photo and photographer,\r\nDialogue: 0,0:35:30.15,0:35:32.54,yin,,0,0,0,,然后从编辑器菜单\\N{\\fs12}and then I'm going to, from the editor menu,\r\nDialogue: 0,0:35:32.54,0:35:35.77,yin,,0,0,0,,选重要的菜单项 叫\\N{\\fs12}I'm going to pick this all important menu item called\r\nDialogue: 0,0:35:35.77,0:35:38.85,yin,,0,0,0,,创建NSManagedObject子类\\N{\\fs12}create NS-managed object subclass.\r\nDialogue: 0,0:35:38.85,0:35:40.84,yin,,0,0,0,,这正是我们要做的\\N{\\fs12}Because that's exactly what's it going to do.\r\nDialogue: 0,0:35:40.84,0:35:42.97,yin,,0,0,0,,这样做之后 它会问\\N{\\fs12}And when I do that, it's going to say okay,\r\nDialogue: 0,0:35:42.97,0:35:45.93,yin,,0,0,0,,哪个模型 这里我们只有一个\\N{\\fs12}which of your models, okay, we only have one,\r\nDialogue: 0,0:35:45.93,0:35:49.19,yin,,0,0,0,,Model.xcdatamodeld 不过 这里也可以有多个\\N{\\fs12}model dot xc data model d, but you could have multiple,\r\nDialogue: 0,0:35:49.19,0:35:54.15,yin,,0,0,0,,你希望为哪个模型生成NSManagedObject的子类\\N{\\fs12}which of your models do you want to generate managed object subclasses for?\r\nDialogue: 0,0:35:54.15,0:35:57.41,yin,,0,0,0,,我们选择这个模型 它会问\\N{\\fs12}So we'll just pick model, and then, it says okay, well,\r\nDialogue: 0,0:35:57.41,0:36:00.83,yin,,0,0,0,,你想为哪些类 哪些实体创建子类\\N{\\fs12}which of the classes, which of the entities you want to create a subclass for?\r\nDialogue: 0,0:36:00.83,0:36:05.35,yin,,0,0,0,,两个我都选上 Photo和Photographer\\N{\\fs12}We'll pick them both, both photo and photographer here, and,\r\nDialogue: 0,0:36:05.35,0:36:07.33,yin,,0,0,0,,它又问 存在哪呢\\N{\\fs12}it's going to say where do you want to store them,\r\nDialogue: 0,0:36:07.33,0:36:09.65,yin,,0,0,0,,存在存其它东西的地方\\N{\\fs12}we'll store then where we store everything else, and then,\r\nDialogue: 0,0:36:09.65,0:36:13.72,yin,,0,0,0,,有了 Photo.m和.h 以及Photographer.m和.h\\N{\\fs12}bingo, photo dot m and h, and photographer dot m and h,\r\nDialogue: 0,0:36:13.72,0:36:17.02,yin,,0,0,0,,看到了吗 这些得以创建\\N{\\fs12}you see those there, that got created for us?\r\nDialogue: 0,0:36:17.02,0:36:20.20,yin,,0,0,0,,这些是NSManagedObject的子类\\N{\\fs12}So, those are subclasses of NS-managed object,\r\nDialogue: 0,0:36:20.20,0:36:22.93,yin,,0,0,0,,将一个对象插入数据库时\\N{\\fs12}and when you insert an object in the database,\r\nDialogue: 0,0:36:22.94,0:36:25.23,yin,,0,0,0,,或是取回对象 这个我们还没讲到\\N{\\fs12}or get one back on a fetch, which we haven't talked about,\r\nDialogue: 0,0:36:25.23,0:36:27.56,yin,,0,0,0,,如果你将一个对象插入数据库 当它返回时\\N{\\fs12}if you insert an object in the database, when it comes back,\r\nDialogue: 0,0:36:27.56,0:36:29.58,yin,,0,0,0,,它将不再是NSManagedObject\\N{\\fs12}instead of being an NS-managed object star,\r\nDialogue: 0,0:36:29.58,0:36:33.22,yin,,0,0,0,,而是Photo *或Photographer\\N{\\fs12}it's going to be a photo star, or a photographer star.\r\nDialogue: 0,0:36:33.22,0:36:35.01,yin,,0,0,0,,这会自动生效\\N{\\fs12}It's just going to automatically work, that\r\nDialogue: 0,0:36:35.01,0:36:39.34,yin,,0,0,0,,这个insertNewObjectForEntityForName方法\\N{\\fs12}insert entity for, for entity for name method,\r\nDialogue: 0,0:36:39.34,0:36:41.19,yin,,0,0,0,,我总是记不清楚这个名字\\N{\\fs12}which I can never remember the name of,\r\nDialogue: 0,0:36:41.19,0:36:46.25,yin,,0,0,0,,如果有子类的话 返回的将是子类\\N{\\fs12}that will return, if there's a subclass to be had, the subclass.\r\nDialogue: 0,0:36:46.25,0:36:47.96,yin,,0,0,0,,我们来看看这个的代码\\N{\\fs12}Alright, so let's look at the code of this,\r\nDialogue: 0,0:36:47.96,0:36:50.81,yin,,0,0,0,,例如我们看看Photo.h 可以看到\\N{\\fs12}let's look at photo dot h, for example, so you can see,\r\nDialogue: 0,0:36:50.81,0:36:53.60,yin,,0,0,0,,Photo.h中有很多@property\\N{\\fs12}that photo dot h has made an at sign property for all\r\nDialogue: 0,0:36:53.60,0:36:56.12,yin,,0,0,0,,对应于照片的数据库属性\\N{\\fs12}of my database properties for photos,\r\nDialogue: 0,0:36:56.12,0:36:57.72,yin,,0,0,0,,有标题 照片URL\\N{\\fs12}see title, photo URL,\r\nDialogue: 0,0:36:57.72,0:37:00.19,yin,,0,0,0,,它们是正确的类型 NSDate NSData\\N{\\fs12}they're the right type, NS date, NS data,\r\nDialogue: 0,0:37:00.19,0:37:03.23,yin,,0,0,0,,甚至whoTook的类都正确\\N{\\fs12}even who took is the right class.\r\nDialogue: 0,0:37:03.23,0:37:05.62,yin,,0,0,0,,whoTook是一个Photographer\\N{\\fs12}You see who took is a photographer star.\r\nDialogue: 0,0:37:05.62,0:37:07.90,yin,,0,0,0,,有时 做这个时\\N{\\fs12}Now, sometimes you'll just, do this\r\nDialogue: 0,0:37:07.90,0:37:11.14,yin,,0,0,0,,whoTook将仍然是NSManagedObject\\N{\\fs12}and who took will still be an NS-managed object star.\r\nDialogue: 0,0:37:11.14,0:37:12.54,yin,,0,0,0,,为什么呢\\N{\\fs12}Why does that happen?\r\nDialogue: 0,0:37:12.54,0:37:14.78,yin,,0,0,0,,这是因为这是一次生成\\N{\\fs12}That's because this is a one-pass generation,\r\nDialogue: 0,0:37:14.78,0:37:18.75,yin,,0,0,0,,如果照片是在拍照者之前生成\\N{\\fs12}and if it happens to generate photo before it generated photographer,\r\nDialogue: 0,0:37:18.76,0:37:21.32,yin,,0,0,0,,它就不知道拍照者 这个就做不了\\N{\\fs12}it won't know about photographer and it won't be able to do this.\r\nDialogue: 0,0:37:21.32,0:37:23.61,yin,,0,0,0,,如果是这样 回到你的映射\\N{\\fs12}If that happens, just go back to your map\r\nDialogue: 0,0:37:23.61,0:37:26.34,yin,,0,0,0,,重新生成 这时它们就都存在了\\N{\\fs12}and generate them again, and this time they'll both exist,\r\nDialogue: 0,0:37:26.34,0:37:29.04,yin,,0,0,0,,这就能够得到正确的东西了\\N{\\fs12}beforehand, and so it'll, it'll make the right thing.\r\nDialogue: 0,0:37:29.04,0:37:31.16,yin,,0,0,0,,你想重新生成多少次都行\\N{\\fs12}So you can regenerate as many times as you want, and, in fact,\r\nDialogue: 0,0:37:31.16,0:37:33.97,yin,,0,0,0,,实际上 我们在变更方案\\N{\\fs12}we're going to be regenerating as we change scheme,\r\nDialogue: 0,0:37:33.97,0:37:36.35,yin,,0,0,0,,添加实体 添加属性时\\N{\\fs12}add more entities, add more properties,\r\nDialogue: 0,0:37:36.35,0:37:38.28,yin,,0,0,0,,也会不断进行重新生成\\N{\\fs12}we're going to be redoing that regenerate all the time.\r\nDialogue: 0,0:37:38.28,0:37:39.51,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:37:47.46,0:37:49.65,yin,,0,0,0,,是 问题是\\N{\\fs12}Yes. So, let's, the question is\r\nDialogue: 0,0:37:49.65,0:37:53.55,yin,,0,0,0,,讲讲为什么那上面用@class Photographer\\N{\\fs12}tell me about that at sign class photographer towards the top there.\r\nDialogue: 0,0:37:53.57,0:37:56.72,yin,,0,0,0,,为什么不是#import Photographer.h\\N{\\fs12}Why is that not pound sign import photographer dot h,\r\nDialogue: 0,0:37:56.72,0:37:59.21,yin,,0,0,0,,在Objective-C中\\N{\\fs12}well, in objective c,\r\nDialogue: 0,0:37:59.21,0:38:03.75,yin,,0,0,0,,如果你只是想声明某个东西是某个特定类型\\N{\\fs12}if all you want to be able to do is declare that something is of a certain type,\r\nDialogue: 0,0:38:03.76,0:38:05.17,yin,,0,0,0,,你不需要所有方法\\N{\\fs12}and you don't need all the methods,\r\nDialogue: 0,0:38:05.17,0:38:07.52,yin,,0,0,0,,你也不打算调用任何方法\\N{\\fs12}you're not going to call any of the methods or anything like that,\r\nDialogue: 0,0:38:07.54,0:38:09.69,yin,,0,0,0,,这时就可以用@class指令\\N{\\fs12}then you can just do this at sign class directive,\r\nDialogue: 0,0:38:09.69,0:38:12.57,yin,,0,0,0,,你也可以对协议这样做 你可以说@protocol\\N{\\fs12}you can do the same thing for protocols, you can say at sign protocol, whatever,\r\nDialogue: 0,0:38:12.58,0:38:14.82,yin,,0,0,0,,声明这个协议存在\\N{\\fs12}and just declare that protocol exists, so I don't,\r\nDialogue: 0,0:38:14.82,0:38:18.36,yin,,0,0,0,,我不打算调用或是实现任何方法\\N{\\fs12}I'm not going to call any of the methods in it or implement any of the methods.\r\nDialogue: 0,0:38:18.37,0:38:20.52,yin,,0,0,0,,这是一种前向声明\\N{\\fs12}So it's kind of a forward declaration\r\nDialogue: 0,0:38:20.52,0:38:23.01,yin,,0,0,0,,因为最终 会用到这个的任何人\\N{\\fs12}because eventually anyone who's going to use this is going to\r\nDialogue: 0,0:38:23.01,0:38:25.42,yin,,0,0,0,,都会开始调用Photographer方法 会导入它\\N{\\fs12}start calling photographer methods and they're going to import it,\r\nDialogue: 0,0:38:25.42,0:38:28.58,yin,,0,0,0,,不过 这是一种避免编译器警告的方式\\N{\\fs12}but this is just a way to suppress that compiler warning,\r\nDialogue: 0,0:38:28.59,0:38:31.09,yin,,0,0,0,,它没有说未知类Photographer\\N{\\fs12}so it doesn't say unknown class photographer,\r\nDialogue: 0,0:38:31.09,0:38:33.87,yin,,0,0,0,,同时又不用导入Photographer.h\\N{\\fs12}without having to import photographer dot h.\r\nDialogue: 0,0:38:33.87,0:38:35.54,yin,,0,0,0,,这让它们保持独立\\N{\\fs12}That kind of keeps them independent,\r\nDialogue: 0,0:38:35.55,0:38:38.43,yin,,0,0,0,,这样你就不需要在不想的时候生成Photographer.h\\N{\\fs12}that way you wouldn't have to generate photographer dot h if you didn't want to,\r\nDialogue: 0,0:38:38.43,0:38:41.00,yin,,0,0,0,,你只想要Photo 这是可以的\\N{\\fs12}you just wanted photo and then that could be,\r\nDialogue: 0,0:38:41.00,0:38:42.44,yin,,0,0,0,,其实并不是这样\\N{\\fs12}although, that wouldn't be true\r\nDialogue: 0,0:38:42.44,0:38:44.50,yin,,0,0,0,,因为这时它就是NSManagedObject 无论如何\\N{\\fs12}because then it would be NS-managed project, but anyway,\r\nDialogue: 0,0:38:44.50,0:38:47.20,yin,,0,0,0,,如果你在这里有NSManagedObject\\N{\\fs12}if you have NS-managed object, there,\r\nDialogue: 0,0:38:47.22,0:38:49.49,yin,,0,0,0,,你只需重新生成它们\\N{\\fs12}then just generate them again.\r\nDialogue: 0,0:38:49.49,0:38:51.89,yin,,0,0,0,,我们再来看Photographer.h\\N{\\fs12}Alright, so let's look at photographer dot h,\r\nDialogue: 0,0:38:51.89,0:38:56.00,yin,,0,0,0,,可以看到 它有name和photos两个属性\\N{\\fs12}you can see it has name and photos, right, as promised.\r\nDialogue: 0,0:38:56.01,0:38:58.87,yin,,0,0,0,,photos是一个NSSet 看到了吗\\N{\\fs12}Photos is an NS set, you see that?\r\nDialogue: 0,0:38:58.89,0:39:01.85,yin,,0,0,0,,这里它还给了我好多方法\\N{\\fs12}It also gave me a whole bunch of methods here\r\nDialogue: 0,0:39:01.85,0:39:05.23,yin,,0,0,0,,用于将照片加入到照片集中\\N{\\fs12}for adding photos to the photo set,\r\nDialogue: 0,0:39:05.24,0:39:09.14,yin,,0,0,0,,这个NSSet是一个NS不可变集合\\N{\\fs12}because that NS set, that's an NS immutable set,\r\nDialogue: 0,0:39:09.14,0:39:11.68,yin,,0,0,0,,如果我想设置一个照片列表\\N{\\fs12}so if I wanted to set the list of photos,\r\nDialogue: 0,0:39:11.70,0:39:13.56,yin,,0,0,0,,我需要创建一个可变集合\\N{\\fs12}I'd have to create a mutable set,\r\nDialogue: 0,0:39:13.56,0:39:15.83,yin,,0,0,0,,将我要的所有照片对象放到里面\\N{\\fs12}put all the photo objects that I wanted in there,\r\nDialogue: 0,0:39:15.83,0:39:17.91,yin,,0,0,0,,然后设置整个东西\\N{\\fs12}and then set the whole thing.\r\nDialogue: 0,0:39:17.93,0:39:22.59,yin,,0,0,0,,你知道的 我的拍照者点photos等于整个集合\\N{\\fs12}You know, say, you know, my photographer dot photos equals a whole set.\r\nDialogue: 0,0:39:22.59,0:39:25.52,yin,,0,0,0,,通过addPhotosObject或removePhotosObject\\N{\\fs12}With add photos object, or remove photos object,\r\nDialogue: 0,0:39:25.52,0:39:27.84,yin,,0,0,0,,我可以一次加一张照片\\N{\\fs12}I can just add one photo at a time.\r\nDialogue: 0,0:39:27.84,0:39:30.35,yin,,0,0,0,,这些都是很便利的方法\\N{\\fs12}So it's just kind of, those are convenience methods\r\nDialogue: 0,0:39:30.35,0:39:32.67,yin,,0,0,0,,用于将照片加到照片集\\N{\\fs12}for adding photos to that photoset.\r\nDialogue: 0,0:39:32.67,0:39:36.09,yin,,0,0,0,,再来看看这些.m文件\\N{\\fs12}So let's look at the dot m's of these though.\r\nDialogue: 0,0:39:36.09,0:39:38.90,yin,,0,0,0,,这些.m你们觉得会是怎样的呢\\N{\\fs12}And what do you imagine these dot m's look like?\r\nDialogue: 0,0:39:38.90,0:39:40.71,yin,,0,0,0,,像集合setter和getter\\N{\\fs12}Like set setters and getters?\r\nDialogue: 0,0:39:40.71,0:39:43.38,yin,,0,0,0,,或是@synthesize 诸如此类\\N{\\fs12}Or, at sign synthesizes or something like that?\r\nDialogue: 0,0:39:43.38,0:39:45.51,yin,,0,0,0,,答案是 这些都没有\\N{\\fs12}And the answer is none of that.\r\nDialogue: 0,0:39:45.51,0:39:51.36,yin,,0,0,0,,这些的实现只是@dynamic 用于所有这些属性\\N{\\fs12}The implementations of these just say at sign dynamic for all of the properties.\r\nDialogue: 0,0:39:51.36,0:39:55.17,yin,,0,0,0,,@dynamic是什么玩意 我们从没见过这个\\N{\\fs12}Now, what the heck is at sign dynamic, we never seen that before?\r\nDialogue: 0,0:39:55.18,0:39:57.52,yin,,0,0,0,,@dynamic其实也就是说\\N{\\fs12}At sign dynamic basically means\r\nDialogue: 0,0:39:57.52,0:40:01.45,yin,,0,0,0,,我知道我在做什么 不要为此发出警告\\N{\\fs12}hey I know what I'm doing, don't generate a warning for this.\r\nDialogue: 0,0:40:01.45,0:40:06.10,yin,,0,0,0,,NSManagedObject在这里是做什么的呢\\N{\\fs12}And what does NS-managed object do, in this case,\r\nDialogue: 0,0:40:06.10,0:40:08.12,yin,,0,0,0,,这里既没有@synthesize\\N{\\fs12}since there's no at sign synthesize,\r\nDialogue: 0,0:40:08.12,0:40:09.89,yin,,0,0,0,,也没有setter和getter\\N{\\fs12}there's no setters and getters here,\r\nDialogue: 0,0:40:09.89,0:40:12.94,yin,,0,0,0,,实现只是避免发出警告而已\\N{\\fs12}the implementation just suppresses the warning, basically,\r\nDialogue: 0,0:40:12.94,0:40:15.94,yin,,0,0,0,,答案是 Objective-C 运行时\\N{\\fs12}and the answer is objective C, the run time,\r\nDialogue: 0,0:40:15.96,0:40:18.07,yin,,0,0,0,,有一个避陷机制\\N{\\fs12}has a trapping mechanism where\r\nDialogue: 0,0:40:18.07,0:40:19.82,yin,,0,0,0,,如果发送信息给一个对象\\N{\\fs12}if you send a message to an object,\r\nDialogue: 0,0:40:19.84,0:40:21.96,yin,,0,0,0,,对象不懂这个方法\\N{\\fs12}and it doesn't understand that method, right,\r\nDialogue: 0,0:40:21.97,0:40:24.37,yin,,0,0,0,,无法实现 这就陷住了\\N{\\fs12}it doesn't implement that, it can trap.\r\nDialogue: 0,0:40:24.37,0:40:26.81,yin,,0,0,0,,它会尝试别的办法\\N{\\fs12}And go try to figure out something else to do.\r\nDialogue: 0,0:40:26.81,0:40:31.10,yin,,0,0,0,,以免崩溃 或是说无法响应选择器\\N{\\fs12}Without crashing or saying does not respond to selector.\r\nDialogue: 0,0:40:31.12,0:40:34.90,yin,,0,0,0,,而NSManagedObject 当它获得了不理解的信息时\\N{\\fs12}And, NS-managed object, when it gets sent a message it doesn't understand,\r\nDialogue: 0,0:40:34.91,0:40:36.97,yin,,0,0,0,,它会尝试valueForKey\\N{\\fs12}it tries to do value for key,\r\nDialogue: 0,0:40:36.98,0:40:39.44,yin,,0,0,0,,或是setValue forKey\\N{\\fs12}or set value for key on it.\r\nDialogue: 0,0:40:39.44,0:40:41.44,yin,,0,0,0,,如果这个行不通\\N{\\fs12}Alright? And if that doesn't work,\r\nDialogue: 0,0:40:41.44,0:40:43.58,yin,,0,0,0,,这时它就会说 无法识别选择器\\N{\\fs12}then it says does not recognize selector,\r\nDialogue: 0,0:40:43.58,0:40:46.02,yin,,0,0,0,,如果行得通 那就成了\\N{\\fs12}but if it does work, then it just works.\r\nDialogue: 0,0:40:46.02,0:40:47.61,yin,,0,0,0,,这就是这里的情况\\N{\\fs12}So that's what's going on here,\r\nDialogue: 0,0:40:47.61,0:40:48.82,yin,,0,0,0,,对于NSManagedObject\\N{\\fs12}NS-managed object\r\nDialogue: 0,0:40:48.82,0:40:52.10,yin,,0,0,0,,setter getter或其它方法发送给它时 它会陷住\\N{\\fs12}traps when setters and getters or any method is sent to it\r\nDialogue: 0,0:40:52.10,0:40:54.88,yin,,0,0,0,,它会尝试valueForKey和setValue forKey\\N{\\fs12}and it tries to do value for key and set value for key,\r\nDialogue: 0,0:40:54.88,0:40:57.77,yin,,0,0,0,,如果行得通 那就行了 如果行不通 它就会说\\N{\\fs12}and if it can, all is good, and if it can't, then it says,\r\nDialogue: 0,0:40:57.77,0:40:59.77,yin,,0,0,0,,无法理解选择器\\N{\\fs12}does not understand selector.\r\nDialogue: 0,0:40:59.77,0:41:01.70,yin,,0,0,0,,都理解了吗\\N{\\fs12}Everyone understand that?\r\nDialogue: 0,0:41:01.70,0:41:04.93,yin,,0,0,0,,这个@dynamic只是说 别发出警告\\N{\\fs12}So this at sign dynamic just says don't generate a warning\r\nDialogue: 0,0:41:04.93,0:41:09.87,yin,,0,0,0,,我没实现setter和getter 但我知道我在做什么\\N{\\fs12}that I don't implement the setter and getter, because I know what I'm doing.\r\nDialogue: 0,0:41:10.61,0:41:11.42,yin,,0,0,0,,好\\N{\\fs12}Alright.\r\nDialogue: 0,0:41:11.42,0:41:15.71,yin,,0,0,0,,有了这些子类 如何使用它们\\N{\\fs12}So, so now that I have these subclasses, how do I use them\r\nDialogue: 0,0:41:15.71,0:41:19.75,yin,,0,0,0,,来使用点符号访问我的属性呢\\N{\\fs12}to access my attributes using dot notation,\r\nDialogue: 0,0:41:19.75,0:41:22.53,yin,,0,0,0,,现在我说 NSEntityDescription\\N{\\fs12}and so now when I say NS entity description,\r\nDialogue: 0,0:41:22.53,0:41:24.48,yin,,0,0,0,,insertNewObjectForEntityForName\\N{\\fs12}insert new object for entity for name,\r\nDialogue: 0,0:41:24.48,0:41:25.76,yin,,0,0,0,,inManagedObjectContext\\N{\\fs12}in managed object context,\r\nDialogue: 0,0:41:25.76,0:41:29.42,yin,,0,0,0,,我没说 NSManagedObject *photo等于那个\\N{\\fs12}instead of saying NS-managed object star photo equals that,\r\nDialogue: 0,0:41:29.42,0:41:32.17,yin,,0,0,0,,而是说 Photo *photo等于那个\\N{\\fs12}I say photo star photo equals that,\r\nDialogue: 0,0:41:32.17,0:41:33.88,yin,,0,0,0,,insertNewObjectForEntityForName\\N{\\fs12}insert a new object for entity for name,\r\nDialogue: 0,0:41:33.88,0:41:35.41,yin,,0,0,0,,返回的是id类型\\N{\\fs12}by the way, returns an ID,\r\nDialogue: 0,0:41:35.41,0:41:40.80,yin,,0,0,0,,两种情况下 编译器都不会警告你或是报错\\N{\\fs12}so the compiler is not going to warn you or give an error in either case.\r\nDialogue: 0,0:41:40.80,0:41:43.30,yin,,0,0,0,,不过如果你说Photo *photo=那个\\N{\\fs12}But if you say photo star photo equals that,\r\nDialogue: 0,0:41:43.30,0:41:46.16,yin,,0,0,0,,那么你就可以说 photo.title =\\N{\\fs12}then you can just say photo dot title equals,\r\nDialogue: 0,0:41:46.16,0:41:47.55,yin,,0,0,0,,你想要的标题\\N{\\fs12}whatever you want the title to be,\r\nDialogue: 0,0:41:47.55,0:41:49.62,yin,,0,0,0,,例如像我这样是从Flickr下载的 我可能会说\\N{\\fs12}like if I'm downloading this Flickr, I might say\r\nDialogue: 0,0:41:49.62,0:41:52.40,yin,,0,0,0,,flickrData objectForKey:FLICKR_PHOTO_TITLE\\N{\\fs12}Flickr data object for key Flickr photo title,\r\nDialogue: 0,0:41:52.40,0:41:54.25,yin,,0,0,0,,从来自Flickr的字典中将其取出\\N{\\fs12}get it out of that dictionary that came from Flickr\r\nDialogue: 0,0:41:54.25,0:41:57.21,yin,,0,0,0,,我刚在数据库中设置了那个标题\\N{\\fs12}and I'm just setting that title in my database.\r\nDialogue: 0,0:41:57.21,0:42:01.28,yin,,0,0,0,,100%完全符合大家的预期\\N{\\fs12}Exactly 100 percent what you would think it would be.\r\nDialogue: 0,0:42:01.28,0:42:03.37,yin,,0,0,0,,你还可以做如下这些事情\\N{\\fs12}Here's a whole bunch of other examples of what you would do,\r\nDialogue: 0,0:42:03.37,0:42:05.77,yin,,0,0,0,,你显然可以调用getter\\N{\\fs12}you can also obviously call the getter,\r\nDialogue: 0,0:42:05.77,0:42:08.48,yin,,0,0,0,,我可以说 NSString *myThumbnail\\N{\\fs12}so I could NS string star my thumbnail\r\nDialogue: 0,0:42:08.48,0:42:11.03,yin,,0,0,0,,= photo.thumbnailURL\\N{\\fs12}equals photo dot thumbnail URL.\r\nDialogue: 0,0:42:11.03,0:42:13.52,yin,,0,0,0,,获得那个缩略图URL\\N{\\fs12}Get that thumbnail URL out of there, that,\r\nDialogue: 0,0:42:13.52,0:42:15.42,yin,,0,0,0,,注意 数据库中不能直接放URL\\N{\\fs12}notice that you can't put URL's in the database,\r\nDialogue: 0,0:42:15.42,0:42:19.88,yin,,0,0,0,,你需要用字符串 然后把它们转换成URL\\N{\\fs12}you have to put strings and convert them to URL's.\r\nDialogue: 0,0:42:19.88,0:42:24.00,yin,,0,0,0,,我可以说 photo.lastViewedDate = [NSDate date]\\N{\\fs12}I could say photo dot last view date equals NS date date, okay,\r\nDialogue: 0,0:42:24.00,0:42:26.63,yin,,0,0,0,,NSDate中的date方法能给出当前日期和时间\\N{\\fs12}the date method in NS date gives the current date and time,\r\nDialogue: 0,0:42:26.63,0:42:29.77,yin,,0,0,0,,我可以把这设为照片最近浏览的日期\\N{\\fs12}I could set that as the photo's last viewed date.\r\nDialogue: 0,0:42:29.77,0:42:31.97,yin,,0,0,0,,我显然还可以说\\N{\\fs12}I can even, I can obviously do\r\nDialogue: 0,0:42:31.97,0:42:34.94,yin,,0,0,0,,photo.whoTook = 某个拍照者对象\\N{\\fs12}photo dot who took equals some photographer object,\r\nDialogue: 0,0:42:34.94,0:42:39.52,yin,,0,0,0,,我甚至还可以说 photo.whoTook.name =\\N{\\fs12}but I can even say photo dot who took dot name equals\r\nDialogue: 0,0:42:39.52,0:42:41.12,yin,,0,0,0,,拍照者的名字\\N{\\fs12}the name of the photographer.\r\nDialogue: 0,0:42:41.12,0:42:43.53,yin,,0,0,0,,如果我有一张照片 一个Photo\\N{\\fs12}So if I have a photo, a photo star,\r\nDialogue: 0,0:42:43.53,0:42:45.47,yin,,0,0,0,,我可以将名字设为\\N{\\fs12}I can actually set the name\r\nDialogue: 0,0:42:45.47,0:42:49.43,yin,,0,0,0,,照片拍照者的名字\\N{\\fs12}of the photographer who took that photo.\r\nDialogue: 0,0:42:49.43,0:42:52.22,yin,,0,0,0,,我这里使用的不过是常规的点符号\\N{\\fs12}So I'm just using dot notations and normal dot notation,\r\nDialogue: 0,0:42:52.22,0:42:54.52,yin,,0,0,0,,只是Photographer实现name\\N{\\fs12}it's just that photographer implements name\r\nDialogue: 0,0:42:54.52,0:42:57.34,yin,,0,0,0,,Photo实现whoTook 而whoTook是一个Photographer\\N{\\fs12}and photo implements who took and who took is a photographer,\r\nDialogue: 0,0:42:57.34,0:42:59.35,yin,,0,0,0,,因此有photo.whoTook.name\\N{\\fs12}therefore, photo dot who took dot name.\r\nDialogue: 0,0:42:59.35,0:43:00.51,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:43:05.48,0:43:06.71,yin,,0,0,0,,问题是\\N{\\fs12}Alright, so the question is\r\nDialogue: 0,0:43:06.71,0:43:10.94,yin,,0,0,0,,如果photo.whoTook为nil\\N{\\fs12}would it auto create, if, if photo dot who took was nil,\r\nDialogue: 0,0:43:10.94,0:43:14.55,yin,,0,0,0,,它是否会自动在数据库中创建一个拍照者\\N{\\fs12}would it automatically create a photographer in the database,\r\nDialogue: 0,0:43:14.55,0:43:16.54,yin,,0,0,0,,这样它就可以说.name=什么\\N{\\fs12}so that it can say dot name equals whatever.\r\nDialogue: 0,0:43:16.54,0:43:17.71,yin,,0,0,0,,答案是否定的\\N{\\fs12}And the answer is no.\r\nDialogue: 0,0:43:17.71,0:43:19.94,yin,,0,0,0,,这是普通的属性\\N{\\fs12}This is normal properties.\r\nDialogue: 0,0:43:19.94,0:43:21.58,yin,,0,0,0,,如果photo.whoTook为nil\\N{\\fs12}If photo dot who took is nil,\r\nDialogue: 0,0:43:21.58,0:43:25.61,yin,,0,0,0,,那么setName将会被发送给nil 什么都不做\\N{\\fs12}then the set name will just be sent to nil, it will do nothing.\r\nDialogue: 0,0:43:25.61,0:43:28.13,yin,,0,0,0,,唯一在数据库中获得东西的方法是\\N{\\fs12}So the only way to get things in the database is\r\nDialogue: 0,0:43:28.13,0:43:31.46,yin,,0,0,0,,前面我们看到的insertNewObjectForEntityForName\\N{\\fs12}insert for entity for name, the thing we saw above there,\r\nDialogue: 0,0:43:31.46,0:43:33.48,yin,,0,0,0,,前面我们看到的insertNewObjectForEntityForName\\N{\\fs12}insert new object for entity for name,\r\nDialogue: 0,0:43:33.48,0:43:36.70,yin,,0,0,0,,不会自动创建[声音不清]\\N{\\fs12}okay, it doesn't auto create the [inaudible].\r\nDialogue: 0,0:43:36.70,0:43:39.30,yin,,0,0,0,,好 这就是我访问属性的做法\\N{\\fs12}Okay. So that's how I access my attributes.\r\nDialogue: 0,0:43:39.30,0:43:45.94,yin,,0,0,0,,如果我想在照片和拍照者类中添加代码又该怎样呢\\N{\\fs12}What if I, though, wanted to add code to my photo or my photographer classes?\r\nDialogue: 0,0:43:45.94,0:43:51.07,yin,,0,0,0,,我可以把代码放到Photo.m和h中 不过这有个问题\\N{\\fs12}I could put that code in photo dot m and h, but that would be a problem.\r\nDialogue: 0,0:43:51.07,0:43:52.49,yin,,0,0,0,,为什么呢\\N{\\fs12}And why is that?\r\nDialogue: 0,0:43:52.49,0:43:57.56,yin,,0,0,0,,出问题的原因在于… 首先 为什么我要这样做\\N{\\fs12}Well, that might be a problem because, well, first of all, why would I want to do that?\r\nDialogue: 0,0:43:57.56,0:44:00.91,yin,,0,0,0,,假设我想加一个class方法到Photo\\N{\\fs12}Let's say I wanted to add a class method to photo\r\nDialogue: 0,0:44:00.91,0:44:04.99,yin,,0,0,0,,将Flickr数据库 Flickr字典作为参数\\N{\\fs12}that took a Flickr database, a Flickr dictionary as an argument\r\nDialogue: 0,0:44:04.99,0:44:08.86,yin,,0,0,0,,在数据库中创建一张照片\\N{\\fs12}and created a photo in, in the database,\r\nDialogue: 0,0:44:08.86,0:44:12.01,yin,,0,0,0,,这在Photo中将是一个很便利的工具方法\\N{\\fs12}that would be an awfully convenient utility method to have in photo,\r\nDialogue: 0,0:44:12.01,0:44:14.59,yin,,0,0,0,,我可以说 开方括号 Photo\\N{\\fs12}right, I could open square bracket photo,\r\nDialogue: 0,0:44:14.59,0:44:17.86,yin,,0,0,0,,在这个context下用这个Flickr数据创建一张照片\\N{\\fs12}make a photo with this Flickr data, in a context,\r\nDialogue: 0,0:44:17.86,0:44:19.68,yin,,0,0,0,,它会这样做 这很酷\\N{\\fs12}and it could do it, right, so that would be cool.\r\nDialogue: 0,0:44:19.68,0:44:22.11,yin,,0,0,0,,或者 假设我想导出一个属性\\N{\\fs12}Or if I want to derive a property, like,\r\nDialogue: 0,0:44:22.11,0:44:24.73,yin,,0,0,0,,我有这个很好的属性thumbnailURL\\N{\\fs12}I've got this nice property thumbnail URL,\r\nDialogue: 0,0:44:24.73,0:44:27.22,yin,,0,0,0,,但很不幸 它是一个字符串\\N{\\fs12}but unfortunately it's a string, what if I wanted\r\nDialogue: 0,0:44:27.22,0:44:30.87,yin,,0,0,0,,如果我想要一个实际的UIImage缩略图呢\\N{\\fs12}to have a UI image which was the thumbnail UI image,\r\nDialogue: 0,0:44:30.87,0:44:33.67,yin,,0,0,0,,这时我就可以在Photo中有一个方法\\N{\\fs12}then I could have a little method in photo that just\r\nDialogue: 0,0:44:33.69,0:44:37.15,yin,,0,0,0,,只需要self.thumbnailURL 转为URL\\N{\\fs12}self dot thumbnail URL, turn it into URL,\r\nDialogue: 0,0:44:37.15,0:44:40.31,yin,,0,0,0,,然后查一下 并不一定要是因特网\\N{\\fs12}go look it up somewhere, preferably not on the internet,\r\nDialogue: 0,0:44:40.31,0:44:42.25,yin,,0,0,0,,或许吧 或许只是阻塞\\N{\\fs12}but maybe, maybe it would just be a blocking,\r\nDialogue: 0,0:44:42.25,0:44:44.56,yin,,0,0,0,,一个进行阻塞的方法 我不知道\\N{\\fs12}a method that would block, I don't know.\r\nDialogue: 0,0:44:44.56,0:44:47.60,yin,,0,0,0,,能够把这个加到Photo中也很酷 换句话说\\N{\\fs12}So that would be cool to add to photo, as well, so in other words, it would be nice\r\nDialogue: 0,0:44:47.60,0:44:49.85,yin,,0,0,0,,如果我们能将照片相关的所有这些\\N{\\fs12}if we could put all our photo-related stuff\r\nDialogue: 0,0:44:49.85,0:44:51.14,yin,,0,0,0,,放到Photo.m和h中\\N{\\fs12}in photo dot m and h,\r\nDialogue: 0,0:44:51.14,0:44:54.76,yin,,0,0,0,,而不只是各种属性的setter和getter 那就好了\\N{\\fs12}not just the setters and getters for all our properties.\r\nDialogue: 0,0:44:54.76,0:44:57.19,yin,,0,0,0,,为什么说这个存在问题呢 问题在于\\N{\\fs12}Why this is a problem though, the problem is\r\nDialogue: 0,0:44:57.19,0:44:59.18,yin,,0,0,0,,在改变可视映射时\\N{\\fs12}as you change your visual map,\r\nDialogue: 0,0:44:59.18,0:45:02.59,yin,,0,0,0,,你会不断调用重新生成方法\\N{\\fs12}you're constantly calling that regenerate method,\r\nDialogue: 0,0:45:02.59,0:45:04.94,yin,,0,0,0,,菜单项 创建NSManagedObject\\N{\\fs12}you know, menu item, the create NS-managed object,\r\nDialogue: 0,0:45:04.94,0:45:07.64,yin,,0,0,0,,这就总在重写它们\\N{\\fs12}so it's called always rewriting them, okay,\r\nDialogue: 0,0:45:07.64,0:45:10.95,yin,,0,0,0,,其中的东西总会被破坏 因此我们不能这样做\\N{\\fs12}it's always blasting what's in there, so we can't do it.\r\nDialogue: 0,0:45:10.95,0:45:14.09,yin,,0,0,0,,如果我们编辑了Photo.m和h 那么我们就不再能\\N{\\fs12}If we edit photo m and h then we can no longer go\r\nDialogue: 0,0:45:14.09,0:45:17.50,yin,,0,0,0,,在Xcode中说 创建NSManagedObject的子类\\N{\\fs12}into Xcode and say create NS managed object subclasses for me anymore,\r\nDialogue: 0,0:45:17.50,0:45:18.27,yin,,0,0,0,,这很不好\\N{\\fs12}and that's a bummer.\r\nDialogue: 0,0:45:18.27,0:45:20.56,yin,,0,0,0,,因为 特别是在开发中 我们会迭代\\N{\\fs12}Because, especially in development, we're iterating,\r\nDialogue: 0,0:45:20.56,0:45:23.05,yin,,0,0,0,,会添加属性 会添加实体\\N{\\fs12}we're adding some properties, we're adding some entities,\r\nDialogue: 0,0:45:23.05,0:45:25.28,yin,,0,0,0,,改变关系 我们希望不断回头\\N{\\fs12}changing some relationships, we want to constantly be going back\r\nDialogue: 0,0:45:25.28,0:45:27.87,yin,,0,0,0,,重新生成这些东西\\N{\\fs12}and regenerating those things.\r\nDialogue: 0,0:45:27.87,0:45:29.51,yin,,0,0,0,,有问题吗\\N{\\fs12}Question?\r\nDialogue: 0,0:45:45.13,0:45:48.35,yin,,0,0,0,,问题是 我能否设定默认值\\N{\\fs12}Yeah, so, the question is could I set the default for the\r\nDialogue: 0,0:45:48.35,0:45:51.71,yin,,0,0,0,,让whoTook属性为Photographer alloc init\\N{\\fs12}who took property to be photographer alloc init,\r\nDialogue: 0,0:45:51.71,0:45:54.91,yin,,0,0,0,,这样默认就总是创建一个新的拍摄者\\N{\\fs12}basically, so the, the default would always default to creating a photographer\r\nDialogue: 0,0:45:54.91,0:45:57.36,yin,,0,0,0,,很不幸 这很酷 但你做不到\\N{\\fs12}and unfortunately you can't do that, but that'd be cool.\r\nDialogue: 0,0:45:58.53,0:46:03.33,yin,,0,0,0,,默认都必须是我说的静态的 [声音不清]\\N{\\fs12}The defaults all have to be kind of like I say, static, [inaudible].\r\nDialogue: 0,0:46:04.44,0:46:07.04,yin,,0,0,0,,我们要怎么做呢\\N{\\fs12}Alright, so, what are we going to do then, because we want\r\nDialogue: 0,0:46:07.04,0:46:09.52,yin,,0,0,0,,我希望往Photo.m和h中添加方法\\N{\\fs12}to add methods to photo dot m and h,\r\nDialogue: 0,0:46:09.52,0:46:11.39,yin,,0,0,0,,我们希望往Photographer.m和h中添加方法\\N{\\fs12}and we want to add methods to photographer at m and h,\r\nDialogue: 0,0:46:11.39,0:46:13.62,yin,,0,0,0,,但我们又不想去碰这些文件\\N{\\fs12}but we don't want to have to touch those files.\r\nDialogue: 0,0:46:13.62,0:46:16.97,yin,,0,0,0,,我们将用到到一个新的Objective-C语言特性\\N{\\fs12}Well, we're going to use a new objective C language feature.\r\nDialogue: 0,0:46:16.97,0:46:19.24,yin,,0,0,0,,这是我要教你们的最后一个\\N{\\fs12}The last one I'm going to teach you.\r\nDialogue: 0,0:46:19.24,0:46:22.42,yin,,0,0,0,,这之后你们都要掌握 它叫category(类别)\\N{\\fs12}I think you know them all after this, called categories.\r\nDialogue: 0,0:46:22.42,0:46:29.21,yin,,0,0,0,,category让你能够添加方法到一个类\\N{\\fs12}Categories, let's you add a method to a class\r\nDialogue: 0,0:46:29.21,0:46:32.63,yin,,0,0,0,,而无需创建它的子类\\N{\\fs12}without sub classing it.\r\nDialogue: 0,0:46:33.48,0:46:34.88,yin,,0,0,0,,而且\\N{\\fs12}And,\r\nDialogue: 0,0:46:34.88,0:46:39.54,yin,,0,0,0,,你甚至不需要有该类的源代码\\N{\\fs12}you don't even have to have the source for that class that you're adding the method to.\r\nDialogue: 0,0:46:39.54,0:46:41.71,yin,,0,0,0,,有哪些例子呢\\N{\\fs12}So what are some of examples of this?\r\nDialogue: 0,0:46:41.71,0:46:45.54,yin,,0,0,0,,在UIKit中 NSAttributedString有个方法\\N{\\fs12}Well, in the UI kit, there's a method NS attributed string,\r\nDialogue: 0,0:46:45.54,0:46:46.59,yin,,0,0,0,,叫drawAtPoint\\N{\\fs12}draw at point,\r\nDialogue: 0,0:46:46.59,0:46:48.86,yin,,0,0,0,,而NSAttributedString在Foundation中\\N{\\fs12}well NS attributed string is in foundation,\r\nDialogue: 0,0:46:48.86,0:46:50.29,yin,,0,0,0,,它并不是UIKit的东西\\N{\\fs12}it's not a UI kit thing,\r\nDialogue: 0,0:46:50.29,0:46:53.53,yin,,0,0,0,,它只是一个通用的带有属性的字符串\\N{\\fs12}it's just a generic attributes on a string thing,\r\nDialogue: 0,0:46:53.53,0:46:56.26,yin,,0,0,0,,但UIKit添加了所有这些 drawAtPoint是一例\\N{\\fs12}but UI kit adds all these, you know, draw at point,\r\nDialogue: 0,0:46:56.26,0:46:59.27,yin,,0,0,0,,它还定义了其它各种属性\\N{\\fs12}and it defines all these other attributes that can be on there,\r\nDialogue: 0,0:46:59.27,0:47:01.34,yin,,0,0,0,,这都是在UIKit中进行的\\N{\\fs12}and it does all that in UI kit,\r\nDialogue: 0,0:47:01.34,0:47:04.39,yin,,0,0,0,,这甚至不需要NSAttributedString的源代码\\N{\\fs12}and it doesn't even need the source for NS attributed string.\r\nDialogue: 0,0:47:04.39,0:47:06.76,yin,,0,0,0,,只需要知道该类存在即可\\N{\\fs12}It just needs to know that class exists.\r\nDialogue: 0,0:47:06.76,0:47:08.33,yin,,0,0,0,,NSIndexPath也一样\\N{\\fs12}Same thing, NS index path.\r\nDialogue: 0,0:47:08.33,0:47:11.68,yin,,0,0,0,,我只说了NSIndexPath有两个方法\\N{\\fs12}I told you NS index path only had two methods on it,\r\nDialogue: 0,0:47:11.68,0:47:12.98,yin,,0,0,0,,row和section\\N{\\fs12}row and section,\r\nDialogue: 0,0:47:12.98,0:47:15.44,yin,,0,0,0,,实际上 NSIndexPath有很多方法\\N{\\fs12}but actually NS index path has a whole bunch of methods on it,\r\nDialogue: 0,0:47:15.44,0:47:16.54,yin,,0,0,0,,它在Foundation中\\N{\\fs12}it's in foundation,\r\nDialogue: 0,0:47:16.54,0:47:18.91,yin,,0,0,0,,它只是一个通用的索引指针\\N{\\fs12}it's just a generic index pointer\r\nDialogue: 0,0:47:18.91,0:47:22.67,yin,,0,0,0,,指向任意的链表\\N{\\fs12}into an arbitrary, you know, linked list of items,\r\nDialogue: 0,0:47:22.67,0:47:25.50,yin,,0,0,0,,只是UITableView希望调用row和section\\N{\\fs12}it's just that UI table view wants to call it row and section,\r\nDialogue: 0,0:47:25.50,0:47:29.96,yin,,0,0,0,,于是它将row和section属性添加到NSIndexPath\\N{\\fs12}so it adds the property's row and section to NS index path,\r\nDialogue: 0,0:47:29.96,0:47:32.95,yin,,0,0,0,,虽然UITableView在UIKit中\\N{\\fs12}even though, again, table view is in UI kit,\r\nDialogue: 0,0:47:32.95,0:47:36.72,yin,,0,0,0,,但NSIndexPath却在Foundation中 框架都不一样\\N{\\fs12}NS index path is in foundation, not even the same framework.\r\nDialogue: 0,0:47:36.72,0:47:38.93,yin,,0,0,0,,这是如何工作的呢\\N{\\fs12}So, how does this work?\r\nDialogue: 0,0:47:38.93,0:47:40.79,yin,,0,0,0,,它是这样的\\N{\\fs12}And it looks like this.\r\nDialogue: 0,0:47:40.79,0:47:43.03,yin,,0,0,0,,你有一个接口和实现\\N{\\fs12}You have an interface and implementation,\r\nDialogue: 0,0:47:43.03,0:47:45.69,yin,,0,0,0,,就像类 不过你这里说的不是\\N{\\fs12}just like the class, but you say, instead of saying\r\nDialogue: 0,0:47:45.69,0:47:49.44,yin,,0,0,0,,@interface 类名 冒号 超类\\N{\\fs12}at sign interface, name of class, colon, superclass,\r\nDialogue: 0,0:47:49.44,0:47:53.40,yin,,0,0,0,,而是@interface 要添加方法的类名\\N{\\fs12}you say at sign interface, the name of the class I want to add methods to,\r\nDialogue: 0,0:47:53.40,0:47:56.28,yin,,0,0,0,,这里括号中就是category的名称\\N{\\fs12}and then in parentheses, what I'm going to call this category,\r\nDialogue: 0,0:47:56.28,0:47:57.40,yin,,0,0,0,,任何名字都行\\N{\\fs12}and you can call it anything you want.\r\nDialogue: 0,0:47:57.40,0:48:00.23,yin,,0,0,0,,我叫它AddOn 你也可以叫它Flickr\\N{\\fs12}So here I've called it add on, but you could call it Flickr,\r\nDialogue: 0,0:48:00.23,0:48:02.04,yin,,0,0,0,,或是Create 什么都行\\N{\\fs12}you could call it Create, whatever you wanted to do.\r\nDialogue: 0,0:48:02.04,0:48:05.33,yin,,0,0,0,,然后你只需要列出你想添加的所有方法\\N{\\fs12}And then you just list all the methods you want to add to this class,\r\nDialogue: 0,0:48:05.34,0:48:07.12,yin,,0,0,0,,也可以是属性\\N{\\fs12}and they can be properties,\r\nDialogue: 0,0:48:07.12,0:48:10.23,yin,,0,0,0,,这里我有只读属性 还有另外一个方法\\N{\\fs12}here I have a read-only property and another method.\r\nDialogue: 0,0:48:10.23,0:48:13.27,yin,,0,0,0,,把这些东西添加到这里之后 @end收尾\\N{\\fs12}You just add, put them on there, and then at sign end.\r\nDialogue: 0,0:48:13.27,0:48:15.25,yin,,0,0,0,,你只需要做这些\\N{\\fs12}So that's all you need to do.\r\nDialogue: 0,0:48:15.25,0:48:17.45,yin,,0,0,0,,想要调用这些方法的人只需要\\N{\\fs12}Now anyone who wants to call these methods just has\r\nDialogue: 0,0:48:17.45,0:48:20.72,yin,,0,0,0,,导入这个的头文件\\N{\\fs12}to import this header file that has this in there.\r\nDialogue: 0,0:48:20.72,0:48:23.68,yin,,0,0,0,,不过 category有一个很大的局限\\N{\\fs12}Now, there's a big restriction on categories,\r\nDialogue: 0,0:48:23.68,0:48:27.65,yin,,0,0,0,,巨大的局限 你不能使用实例变量\\N{\\fs12}gigantic restriction, you can't use any instance variables.\r\nDialogue: 0,0:48:27.65,0:48:30.37,yin,,0,0,0,,你的方法的实现\\N{\\fs12}So the implementation of your methods\r\nDialogue: 0,0:48:30.37,0:48:34.24,yin,,0,0,0,,不能使用任何实例变量 或是任何存储数据\\N{\\fs12}cannot use any instance variables, or any stored data at all.\r\nDialogue: 0,0:48:34.24,0:48:37.77,yin,,0,0,0,,有办法绕过 不过这都是非法的\\N{\\fs12}There are ways kind of around it, but they're hacks.\r\nDialogue: 0,0:48:37.77,0:48:40.28,yin,,0,0,0,,一般而言 category只适用于方法\\N{\\fs12}So generally, categories is for methods,\r\nDialogue: 0,0:48:40.28,0:48:42.46,yin,,0,0,0,,没有状态 这有什么好的\\N{\\fs12}they have no state, well what good is that?\r\nDialogue: 0,0:48:42.46,0:48:46.28,yin,,0,0,0,,你添加方法的对象本身 它有很多状态\\N{\\fs12}Well, the object that you're adding the methods to, it has a lot of state\r\nDialogue: 0,0:48:46.28,0:48:48.48,yin,,0,0,0,,因此 这些方法的显现\\N{\\fs12}and so these methods would be all implemented\r\nDialogue: 0,0:48:48.48,0:48:51.94,yin,,0,0,0,,都可以使用针对对象的状态\\N{\\fs12}by using the state of the object you're adding the methods to.\r\nDialogue: 0,0:48:51.94,0:48:55.29,yin,,0,0,0,,让我们看看这两个方法的例子\\N{\\fs12}So, like let's look at an example for these two methods.\r\nDialogue: 0,0:48:55.29,0:48:57.61,yin,,0,0,0,,这是实现 @implementation\\N{\\fs12}So here's the implementation, the at sign implementation\r\nDialogue: 0,0:48:57.61,0:49:00.76,yin,,0,0,0,,Photo 照片 AddOn category\\N{\\fs12}of photo, photos add on category,\r\nDialogue: 0,0:49:00.76,0:49:03.25,yin,,0,0,0,,我把这两个方法加到Photo类\\N{\\fs12}so I'm adding these two methods to the photo class,\r\nDialogue: 0,0:49:03.25,0:49:05.52,yin,,0,0,0,,这是我们在Xcode中生成的类\\N{\\fs12}which is that thing we generated in Xcode,\r\nDialogue: 0,0:49:05.52,0:49:06.22,yin,,0,0,0,,图像\\N{\\fs12}image,\r\nDialogue: 0,0:49:06.22,0:49:09.47,yin,,0,0,0,,注意 这里只用了self.photoURL\\N{\\fs12}you see it just uses self dot photo URL,\r\nDialogue: 0,0:49:09.47,0:49:11.36,yin,,0,0,0,,self是照片\\N{\\fs12}self, is the photo,\r\nDialogue: 0,0:49:11.36,0:49:13.56,yin,,0,0,0,,因为这些方法被加到了Photo类\\N{\\fs12}because these methods are being added to photo class.\r\nDialogue: 0,0:49:13.56,0:49:15.33,yin,,0,0,0,,因此self是照片\\N{\\fs12}So, self is a photo,\r\nDialogue: 0,0:49:15.33,0:49:19.04,yin,,0,0,0,,.photoURL能获取属性 获取数据\\N{\\fs12}dot photo URL gets that attribute, gets that, that data.\r\nDialogue: 0,0:49:19.04,0:49:23.68,yin,,0,0,0,,也许 这里实际上应该是\\N{\\fs12}That's probably, it actually probably would be self,\r\nDialogue: 0,0:49:23.68,0:49:26.44,yin,,0,0,0,,来自字符串的NSURL\\N{\\fs12}it would NS URL from string,\r\nDialogue: 0,0:49:26.45,0:49:28.35,yin,,0,0,0,,self.photoURL字符串\\N{\\fs12}self dot photo URL string,\r\nDialogue: 0,0:49:28.35,0:49:30.33,yin,,0,0,0,,因为我们无法直接将URL放到数据库中\\N{\\fs12}because we can't put URL's directly in the database,\r\nDialogue: 0,0:49:30.33,0:49:31.86,yin,,0,0,0,,无论如何 然后我们说return\\N{\\fs12}but anyway, and then it would say return\r\nDialogue: 0,0:49:31.86,0:49:35.14,yin,,0,0,0,,UIImage imageWithData 返回图像\\N{\\fs12}UI image, image with data, and return the image.\r\nDialogue: 0,0:49:35.14,0:49:37.23,yin,,0,0,0,,这里没有实例变量\\N{\\fs12}So no instance variables there,\r\nDialogue: 0,0:49:37.23,0:49:39.17,yin,,0,0,0,,isOld也一样\\N{\\fs12}it's not using any [inaudible], same thing with is old,\r\nDialogue: 0,0:49:39.17,0:49:42.58,yin,,0,0,0,,它可以说self.uploadDate timeIntervalSinceNow\\N{\\fs12}it might say self dot upload date, time interval since now\r\nDialogue: 0,0:49:42.58,0:49:44.42,yin,,0,0,0,,大于一天时间\\N{\\fs12}is greater than a day ago.\r\nDialogue: 0,0:49:45.31,0:49:46.51,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:49:51.50,0:49:54.01,yin,,0,0,0,,不 我是说 你不能声明任何新的\\N{\\fs12}No I mean you cannot declare any new ones.\r\nDialogue: 0,0:49:54.01,0:49:56.86,yin,,0,0,0,,这里不能使用任何实例变量\\N{\\fs12}So you cannot use any instance variables here,\r\nDialogue: 0,0:49:56.86,0:49:58.59,yin,,0,0,0,,你只能用类中的实例变量\\N{\\fs12}you could only use instance variables in the class,\r\nDialogue: 0,0:49:58.59,0:50:01.51,yin,,0,0,0,,如果你要用类的 你必须通过属性等让其为公共\\N{\\fs12}you're adding a two if they make them public, via properties or whatever.\r\nDialogue: 0,0:50:09.24,0:50:12.46,yin,,0,0,0,,category不能有任何实例变量 句号\\N{\\fs12}Okay. You can't have any instance variables in a category, period.\r\nDialogue: 0,0:50:12.46,0:50:14.46,yin,,0,0,0,,你不能声明任何一个\\N{\\fs12}Okay, you cannot declare any.\r\nDialogue: 0,0:50:14.46,0:50:16.21,yin,,0,0,0,,如果你想使用你要添加方法的类的实例变量\\N{\\fs12}If you want to use instance variables\r\nDialogue: 0,0:50:16.21,0:50:18.45,yin,,0,0,0,,如果你想使用你要添加方法的类的实例变量\\N{\\fs12}of the class you're adding the methods to,\r\nDialogue: 0,0:50:18.45,0:50:20.37,yin,,0,0,0,,这些变量必须是公共的\\N{\\fs12}then they have to be public\r\nDialogue: 0,0:50:20.37,0:50:23.20,yin,,0,0,0,,因为你只能看到公共头文件\\N{\\fs12}because all you can do is see the public header file,\r\nDialogue: 0,0:50:23.20,0:50:25.22,yin,,0,0,0,,你看不到Photo的实现\\N{\\fs12}you don't see the implementation of photo,\r\nDialogue: 0,0:50:25.22,0:50:26.79,yin,,0,0,0,,加这些方法时你是盲的\\N{\\fs12}you're adding these methods to it blind,\r\nDialogue: 0,0:50:26.79,0:50:29.69,yin,,0,0,0,,你对这些实现一无所知\\N{\\fs12}you don't know anything about its implementation.\r\nDialogue: 0,0:50:31.14,0:50:33.26,yin,,0,0,0,,总之 这就是category\\N{\\fs12}So anyway, so this is called categories,\r\nDialogue: 0,0:50:33.26,0:50:37.24,yin,,0,0,0,,我没有很早就讲这个 因为它很容易被滥用\\N{\\fs12}I don't teach this to you early on because this is easily abused, alright?\r\nDialogue: 0,0:50:37.24,0:50:40.84,yin,,0,0,0,,你可以为UIKit类添加方法 你没有理由不可以\\N{\\fs12}You could add methods to UI kit classes, there's no reason you couldn't.\r\nDialogue: 0,0:50:40.84,0:50:44.01,yin,,0,0,0,,你可以Foundation类添加方法\\N{\\fs12}You could add methods to, you know, foundation classes,\r\nDialogue: 0,0:50:44.01,0:50:45.71,yin,,0,0,0,,完全不受限\\N{\\fs12}completely unrestricted.\r\nDialogue: 0,0:50:45.71,0:50:47.71,yin,,0,0,0,,只是这样做的时候\\N{\\fs12}The only thing is when you start doing that,\r\nDialogue: 0,0:50:47.71,0:50:49.79,yin,,0,0,0,,你的代码会变得有些模糊不清\\N{\\fs12}you're code can kind of get a little obfuscated,\r\nDialogue: 0,0:50:49.79,0:50:52.30,yin,,0,0,0,,人们会说 什么 我不知道\\N{\\fs12}people are like what, I didn't know that, you know,\r\nDialogue: 0,0:50:52.30,0:50:54.79,yin,,0,0,0,,这个UIKit类有这个方法\\N{\\fs12}this UI kit class had that method,\r\nDialogue: 0,0:50:54.79,0:50:56.77,yin,,0,0,0,,因为这是你在category中加的\\N{\\fs12}and it's because you've added it as a category over here\r\nDialogue: 0,0:50:56.77,0:50:58.57,yin,,0,0,0,,这会变得很难理解\\N{\\fs12}and so it's just kind of hard to understand,\r\nDialogue: 0,0:50:58.57,0:51:02.00,yin,,0,0,0,,不过有时像这样 我们希望这样做 原因在于\\N{\\fs12}but sometimes like this, we want to do that because it kind\r\nDialogue: 0,0:51:02.00,0:51:04.72,yin,,0,0,0,,它能将代码汇集在一起 让其看起来很好\\N{\\fs12}of it, it collects our code and it makes things look nicer.\r\nDialogue: 0,0:51:04.72,0:51:05.70,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:51:10.41,0:51:13.59,yin,,0,0,0,,问题是 我能否重写\\N{\\fs12}So the question is can I override or overwrite,\r\nDialogue: 0,0:51:13.59,0:51:16.28,yin,,0,0,0,,一个已经存在的方法\\N{\\fs12}really, a method that already exists?\r\nDialogue: 0,0:51:16.28,0:51:19.05,yin,,0,0,0,,答案是 不要这样做\\N{\\fs12}And the answer is don't do that.\r\nDialogue: 0,0:51:19.05,0:51:21.56,yin,,0,0,0,,这会很难理解\\N{\\fs12}That is really hard to understand\r\nDialogue: 0,0:51:21.56,0:51:24.27,yin,,0,0,0,,读你代码的人会摸不着头脑\\N{\\fs12}for people reading your code, what you mean by that.\r\nDialogue: 0,0:51:24.27,0:51:29.04,yin,,0,0,0,,只添加方法 不要尝试替换或是按别的方式\\N{\\fs12}So only add methods, don't try to replace or otherwise,\r\nDialogue: 0,0:51:29.04,0:51:31.74,yin,,0,0,0,,使用相同方法\\N{\\fs12}you know, use the same method.\r\nDialogue: 0,0:51:31.74,0:51:33.66,yin,,0,0,0,,问得很好\\N{\\fs12}That's a good question.\r\nDialogue: 0,0:51:33.66,0:51:36.51,yin,,0,0,0,,好 这里有一个很常见的category方法\\N{\\fs12}Alright, so, here's a common category method\r\nDialogue: 0,0:51:36.51,0:51:39.94,yin,,0,0,0,,我们经常会给NSManagedObject的子类添加\\N{\\fs12}we add for subclasses of NS-managed object,\r\nDialogue: 0,0:51:39.94,0:51:41.29,yin,,0,0,0,,也就是创建\\N{\\fs12}which is creation. So,\r\nDialogue: 0,0:51:41.31,0:51:45.86,yin,,0,0,0,,假设我有这个category 叫作Photo (Create)\\N{\\fs12}imagine I had this category called photo create,\r\nDialogue: 0,0:51:45.86,0:51:48.31,yin,,0,0,0,,这是我要添加的方法\\N{\\fs12}and I'm going to have this method that I'm going to add\r\nDialogue: 0,0:51:48.31,0:51:50.37,yin,,0,0,0,,Photo在ManagedObjectContext\\N{\\fs12}to photo called photo with Flickr data\r\nDialogue: 0,0:51:50.37,0:51:52.17,yin,,0,0,0,,调用photoWithFlickrData\\N{\\fs12}in managed object context,\r\nDialogue: 0,0:51:52.17,0:51:56.26,yin,,0,0,0,,它会查询数据库 看这张照片是否存在\\N{\\fs12}and it's going to query that database, see if that photo already exists,\r\nDialogue: 0,0:51:56.26,0:51:58.20,yin,,0,0,0,,如果存在就将它返回 如果不存在\\N{\\fs12}it's going to return it if it does, if not,\r\nDialogue: 0,0:51:58.20,0:52:00.53,yin,,0,0,0,,就insertNewObjectForEntityForName\\N{\\fs12}it's going to insert new object for entity for name,\r\nDialogue: 0,0:52:00.53,0:52:02.95,yin,,0,0,0,,从你发送的字典初始化照片\\N{\\fs12}initialize the photo from the dictionary you sent,\r\nDialogue: 0,0:52:02.95,0:52:06.51,yin,,0,0,0,,等等等 这一个方法会做所有这些工作\\N{\\fs12}etc. etc. etc. It's going to do all the work, all in one method.\r\nDialogue: 0,0:52:06.51,0:52:10.05,yin,,0,0,0,,如果有人想用Flickr数据创建一张新照片\\N{\\fs12}So that if someone wants to create a new photo using Flickr data,\r\nDialogue: 0,0:52:10.05,0:52:13.38,yin,,0,0,0,,他可以调用这个方法 Photo中的类方法\\N{\\fs12}they can just call this one method, class method in photo.\r\nDialogue: 0,0:52:13.38,0:52:17.24,yin,,0,0,0,,这就是我们这样做的经典原因\\N{\\fs12}So this is a classic reason why we would do this.\r\nDialogue: 0,0:52:18.61,0:52:20.64,yin,,0,0,0,,如何创建一个category呢\\N{\\fs12}So, how do we create a category.\r\nDialogue: 0,0:52:20.64,0:52:23.18,yin,,0,0,0,,我们到Objective-C 当然是新文件了\\N{\\fs12}So we go to objective C, new file, of course,\r\nDialogue: 0,0:52:23.18,0:52:27.33,yin,,0,0,0,,这里我们要的不是这里的Objective-C类\\N{\\fs12}and instead of saying objective C class, right, you see objective C class there,\r\nDialogue: 0,0:52:27.33,0:52:29.54,yin,,0,0,0,,而是Objective-C category\\N{\\fs12}you say objective C category,\r\nDialogue: 0,0:52:29.54,0:52:32.40,yin,,0,0,0,,这里Xcode不会问你要类和超类\\N{\\fs12}and instead of asking you the class and the super class,\r\nDialogue: 0,0:52:32.40,0:52:35.12,yin,,0,0,0,,它只会问你 你想把它添加到什么类去\\N{\\fs12}it's going to say what class do you want to add a method to\r\nDialogue: 0,0:52:35.12,0:52:36.63,yin,,0,0,0,,以及category取什么名称\\N{\\fs12}and what do you want to call this category.\r\nDialogue: 0,0:52:36.63,0:52:38.38,yin,,0,0,0,,我要给Photo添加方法\\N{\\fs12}So I'm going to add methods to photo,\r\nDialogue: 0,0:52:38.38,0:52:41.08,yin,,0,0,0,,而category名叫Flickr\\N{\\fs12}and I'm going to call the category Flickr.\r\nDialogue: 0,0:52:41.08,0:52:44.84,yin,,0,0,0,,这时 它创建了Photo+Flickr.h\\N{\\fs12}And then it creates photo plus Flickr dot h\r\nDialogue: 0,0:52:44.84,0:52:47.29,yin,,0,0,0,,和Photo+Flickr.m\\N{\\fs12}and photo plus Flickr dot m.\r\nDialogue: 0,0:52:47.29,0:52:51.14,yin,,0,0,0,,这是category的标准命名惯例\\N{\\fs12}Now, this is kind of the standard naming convention, for a category.\r\nDialogue: 0,0:52:51.14,0:52:56.54,yin,,0,0,0,,要加方法的类名+category名\\N{\\fs12}You call it name of the class you're adding the methods to plus the name of the category.\r\nDialogue: 0,0:52:56.54,0:52:58.44,yin,,0,0,0,,+表示分隔符\\N{\\fs12}Okay, the plus as a separator,\r\nDialogue: 0,0:52:58.44,0:53:01.53,yin,,0,0,0,,同时也表示你要加这些方法\\N{\\fs12}and also because plus means you're adding these methods to it.\r\nDialogue: 0,0:53:01.53,0:53:02.74,yin,,0,0,0,,这是命名惯例\\N{\\fs12}So it's kind of a naming convention.\r\nDialogue: 0,0:53:02.74,0:53:04.02,yin,,0,0,0,,这些头文件\\N{\\fs12}You could call those header file\r\nDialogue: 0,0:53:04.02,0:53:06.16,yin,,0,0,0,,以及实现文件 其实你叫什么都可以\\N{\\fs12}and the implementation file anything you want, really,\r\nDialogue: 0,0:53:06.16,0:53:09.00,yin,,0,0,0,,不过我们100%都会这么叫\\N{\\fs12}but this is what we one hundred percent of the time call it.\r\nDialogue: 0,0:53:09.00,0:53:11.56,yin,,0,0,0,,类名+category名\\N{\\fs12}Name of class, plus category.\r\nDialogue: 0,0:53:11.56,0:53:14.55,yin,,0,0,0,,可以看到 它创建了一个.h和一个.m文件\\N{\\fs12}And you can see that it's created a dot h for me and a dot m,\r\nDialogue: 0,0:53:14.55,0:53:16.99,yin,,0,0,0,,我将我要加的方法放到.h中\\N{\\fs12}and I just put the methods I want to add in the dot h\r\nDialogue: 0,0:53:16.99,0:53:19.08,yin,,0,0,0,,然后在.m中实现它们\\N{\\fs12}and then I implement them in the dot m,\r\nDialogue: 0,0:53:19.08,0:53:23.59,yin,,0,0,0,,只不过我不能有任何实例变量 很遗憾\\N{\\fs12}it's just that I can't, unfortunately, have any instance variables.\r\nDialogue: 0,0:53:24.14,0:53:25.51,yin,,0,0,0,,有问题\\N{\\fs12}Yeah, question.\r\nDialogue: 0,0:53:34.24,0:53:37.66,yin,,0,0,0,,问题是 如果不是使用新文件 category\\N{\\fs12}Yeah, so the question is instead of using new file, category,\r\nDialogue: 0,0:53:37.66,0:53:42.10,yin,,0,0,0,,而是创建一个空文件 直接键入这些东西\\N{\\fs12}if I just created an empty file and started typing this stuff in,\r\nDialogue: 0,0:53:42.10,0:53:46.14,yin,,0,0,0,,Objective-C如何知道这是一个category\\N{\\fs12}how does objective C know this is a category, well, the,\r\nDialogue: 0,0:53:46.14,0:53:48.27,yin,,0,0,0,,到新文件中找category\\N{\\fs12}when you go new file in category,\r\nDialogue: 0,0:53:48.27,0:53:51.35,yin,,0,0,0,,其实只是为你提供了一种便利\\N{\\fs12}that's just a convenience, it's just creating this for you as a convenience.\r\nDialogue: 0,0:53:51.35,0:53:53.17,yin,,0,0,0,,你显然可以直接键入\\N{\\fs12}You could certainly just type this stuff in,\r\nDialogue: 0,0:53:53.17,0:53:54.85,yin,,0,0,0,,Objective-C认得它是category\\N{\\fs12}it knows it's a category because it's\r\nDialogue: 0,0:53:54.85,0:53:57.81,yin,,0,0,0,,因为有@interface Photo (Flickr)\\N{\\fs12}at sign interface photo, parentheses Flickr, right,\r\nDialogue: 0,0:53:57.81,0:53:59.76,yin,,0,0,0,,它认识这个括号\\N{\\fs12}it knows that that parentheses thing,\r\nDialogue: 0,0:53:59.76,0:54:02.69,yin,,0,0,0,,有@符号 又有括号中的某个名称\\N{\\fs12}if you have at sign parentheses with some word in there,\r\nDialogue: 0,0:54:02.69,0:54:04.29,yin,,0,0,0,,它就知道这是category\\N{\\fs12}it knows that means a category,\r\nDialogue: 0,0:54:04.29,0:54:06.43,yin,,0,0,0,,在实现端也是一样 它能认出\\N{\\fs12}and then same thing on the implementation side, you say okay,\r\nDialogue: 0,0:54:06.43,0:54:08.68,yin,,0,0,0,,我提供的是该category的实现\\N{\\fs12}I'm providing implementation of that category.\r\nDialogue: 0,0:54:08.68,0:54:10.74,yin,,0,0,0,,答案是 你可以直接键入\\N{\\fs12}So the answer is yeah, you can do that,\r\nDialogue: 0,0:54:10.74,0:54:15.12,yin,,0,0,0,,新文件只是为你提供一点便利 仅此而已\\N{\\fs12}new file is just making it easy for you so it does this, that's all.\r\nDialogue: 0,0:54:15.12,0:54:16.56,yin,,0,0,0,,这方面还有问题吗\\N{\\fs12}Okay, any question about this?\r\nDialogue: 0,0:54:16.56,0:54:18.72,yin,,0,0,0,,周三的演示上我们会看到这个\\N{\\fs12}And we'll see this in the demo on Wednesday\r\nDialogue: 0,0:54:18.72,0:54:22.24,yin,,0,0,0,,我们会为Photo加一个category\\N{\\fs12}where it will add a category, to photo.\r\nDialogue: 0,0:54:22.24,0:54:26.03,yin,,0,0,0,,好 现在你知道了如何插入对象 如何改变其属性\\N{\\fs12}Okay. So now you know how to insert an object, you know how to change their properties.\r\nDialogue: 0,0:54:26.03,0:54:29.97,yin,,0,0,0,,如何创建自定义子类 这些都可以用点符号\\N{\\fs12}We know how to create the custom subclass, so we can do all this with dot notation,\r\nDialogue: 0,0:54:29.97,0:54:32.70,yin,,0,0,0,,那从数据库中删除对象呢\\N{\\fs12}what about deleting objects from the database.\r\nDialogue: 0,0:54:32.70,0:54:36.75,yin,,0,0,0,,这太简单不过了 就像黑武士喜欢说的 太容易了\\N{\\fs12}This is all too easy, okay, as Darth Vader would say, all too easy.\r\nDialogue: 0,0:54:36.75,0:54:41.54,yin,,0,0,0,,你只需要在context上调用deleteObject\\N{\\fs12}You just call delete object on the context, give the object,\r\nDialogue: 0,0:54:41.54,0:54:43.41,yin,,0,0,0,,删除就完成了\\N{\\fs12}bam, it deletes it.\r\nDialogue: 0,0:54:43.41,0:54:46.89,yin,,0,0,0,,不过 删除对象还会有分支\\N{\\fs12}Now, deleting the object can have ramifications.\r\nDialogue: 0,0:54:46.89,0:54:50.63,yin,,0,0,0,,删除一个拍照者 whoTook会被设为nil\\N{\\fs12}You delete a photographer, it's going to set that who took to nil.\r\nDialogue: 0,0:54:50.63,0:54:52.78,yin,,0,0,0,,假设你没有选cascade式删除规则\\N{\\fs12}Assuming you don't do that cascade delete rule\r\nDialogue: 0,0:54:52.78,0:54:54.87,yin,,0,0,0,,这时它会直接删掉拍照者\\N{\\fs12}in which case it would delete the photographer, but, okay,\r\nDialogue: 0,0:54:54.87,0:54:57.20,yin,,0,0,0,,反正 删除会有分支\\N{\\fs12}so deleting, you know, has ramifications,\r\nDialogue: 0,0:54:57.20,0:55:01.26,yin,,0,0,0,,你需要知道你在删什么 这很简单\\N{\\fs12}you got to know what you're doing and deleting, it's very easy to do.\r\nDialogue: 0,0:55:01.26,0:55:02.58,yin,,0,0,0,,关于这个考虑两点\\N{\\fs12}Two things to think about this.\r\nDialogue: 0,0:55:02.58,0:55:05.28,yin,,0,0,0,,一 记住 它并不实际删除照片\\N{\\fs12}One, remember it doesn't actually delete the photo\r\nDialogue: 0,0:55:05.28,0:55:07.55,yin,,0,0,0,,或者说删除对象 在保存之前\\N{\\fs12}or delete the object until you save,\r\nDialogue: 0,0:55:07.55,0:55:09.56,yin,,0,0,0,,自动保存后 删除才会发生\\N{\\fs12}so the auto save comes around and it'll be deleted.\r\nDialogue: 0,0:55:09.56,0:55:11.32,yin,,0,0,0,,这是很简单很明显的一点\\N{\\fs12}That's just a minor point, it's kind of obvious.\r\nDialogue: 0,0:55:11.32,0:55:13.22,yin,,0,0,0,,你做的所有修改也一样\\N{\\fs12}Same thing with all the changes you make,\r\nDialogue: 0,0:55:13.22,0:55:16.20,yin,,0,0,0,,在自动保存或是你手动保存之前\\N{\\fs12}that they don't happen on the database until that auto save happens,\r\nDialogue: 0,0:55:16.20,0:55:18.00,yin,,0,0,0,,它们并不发生在数据库上\\N{\\fs12}or until you explicitly save.\r\nDialogue: 0,0:55:18.00,0:55:19.40,yin,,0,0,0,,关于删除的第二点\\N{\\fs12}But the second thing with deletion,\r\nDialogue: 0,0:55:19.40,0:55:22.37,yin,,0,0,0,,你需要非常小心 看到参数photo了吗\\N{\\fs12}you got to be really careful is, see that argument photo?\r\nDialogue: 0,0:55:22.37,0:55:24.32,yin,,0,0,0,,deleteObject:photo\\N{\\fs12}Delete object colon photo?\r\nDialogue: 0,0:55:24.32,0:55:27.94,yin,,0,0,0,,如果这个photo由一个指针强引用\\N{\\fs12}If that photo is a strongly-held to a pointer,\r\nDialogue: 0,0:55:27.94,0:55:30.55,yin,,0,0,0,,你最好在这之后将其设为nil\\N{\\fs12}you better set it to nil right after this.\r\nDialogue: 0,0:55:30.55,0:55:36.19,yin,,0,0,0,,因为你无法再访问这个photo 它已经失效\\N{\\fs12}Because you cannot access that photo anymore, it is invalid.\r\nDialogue: 0,0:55:36.19,0:55:39.96,yin,,0,0,0,,删除照片后 或者说删除对象之后\\N{\\fs12}After you hit delete photo, or delete object rather,\r\nDialogue: 0,0:55:39.96,0:55:43.24,yin,,0,0,0,,记得删除掉所有指向它的强指针\\N{\\fs12}that thing you deleted, get rid of all your strong pointers to it,\r\nDialogue: 0,0:55:43.24,0:55:44.91,yin,,0,0,0,,因为这不好\\N{\\fs12}because it's no good.\r\nDialogue: 0,0:55:44.91,0:55:46.57,yin,,0,0,0,,它已经被删除了\\N{\\fs12}It's been deleted.\r\nDialogue: 0,0:55:46.57,0:55:51.19,yin,,0,0,0,,如果下一行你又说photo.title=什么\\N{\\fs12}So if you tried to say photo dot title equals something on the next line,\r\nDialogue: 0,0:55:51.19,0:55:54.10,yin,,0,0,0,,肯定会出现很糟糕的情况 别这样做\\N{\\fs12}I don't even know what would happen, something bad, don't do it.\r\nDialogue: 0,0:55:54.10,0:55:55.91,yin,,0,0,0,,这非常明显 对吧\\N{\\fs12}I mean, that's completely obvious, right?\r\nDialogue: 0,0:55:55.91,0:56:00.01,yin,,0,0,0,,但总有人忘记 结果发现程序又出问题了\\N{\\fs12}But, it's something people forget and then they're like, wow, it's not working.\r\nDialogue: 0,0:56:00.01,0:56:04.88,yin,,0,0,0,,删除有一点很酷\\N{\\fs12}One of the things about deletion that's kind of cool.\r\nDialogue: 0,0:56:04.88,0:56:08.22,yin,,0,0,0,,Core Data会发送方法\\N{\\fs12}Core data will send the method,\r\nDialogue: 0,0:56:08.22,0:56:13.92,yin,,0,0,0,,发生消息 prepareForDeletion 给所有对象\\N{\\fs12}send a message, prepare for deletion to all objects\r\nDialogue: 0,0:56:13.92,0:56:15.99,yin,,0,0,0,,当你发送deleteObject时\\N{\\fs12}when you send delete object.\r\nDialogue: 0,0:56:15.99,0:56:19.24,yin,,0,0,0,,如果我说deleteObject:photo 这个photo会被发送\\N{\\fs12}So if I say delete object photo, that photo will be sent,\r\nDialogue: 0,0:56:19.24,0:56:21.11,yin,,0,0,0,,如果它实现它 prepareForDeletion\\N{\\fs12}if it implements it, prepare for deletion.\r\nDialogue: 0,0:56:21.11,0:56:22.57,yin,,0,0,0,,很酷的是\\N{\\fs12}And the cool thing is,\r\nDialogue: 0,0:56:22.57,0:56:25.71,yin,,0,0,0,,你可以把这个prepareForDeletion放到一个category中\\N{\\fs12}you can put this prepare for deletion in a category.\r\nDialogue: 0,0:56:25.71,0:56:29.00,yin,,0,0,0,,你可以在一个category中 把prepareForDeletion方法\\N{\\fs12}So you can add the prepare for deletion method to photo,\r\nDialogue: 0,0:56:29.00,0:56:31.28,yin,,0,0,0,,加给Photo或是Photographer\\N{\\fs12}or photographer, in a category.\r\nDialogue: 0,0:56:31.28,0:56:33.96,yin,,0,0,0,,prepareForDeletion中你打算做什么呢\\N{\\fs12}Now what would you do in that prepare for deletion, well,\r\nDialogue: 0,0:56:33.96,0:56:37.10,yin,,0,0,0,,你不需要对whoTook或是photos做任何事情\\N{\\fs12}you don't need to do anything with the who took or the photos\r\nDialogue: 0,0:56:37.10,0:56:39.02,yin,,0,0,0,,这些都帮你处理了\\N{\\fs12}or anything that, that's all taken care of you for you,\r\nDialogue: 0,0:56:39.02,0:56:42.68,yin,,0,0,0,,但如果数据库中某处有另一个属性呢\\N{\\fs12}but what if you had another property somewhere in the database,\r\nDialogue: 0,0:56:42.68,0:56:46.14,yin,,0,0,0,,它在为photos计数 诸如此类\\N{\\fs12}which was counting the photos, or something like that,\r\nDialogue: 0,0:56:46.14,0:56:49.19,yin,,0,0,0,,删除某张照片会改变计数值\\N{\\fs12}and deleting this photo would change that count,\r\nDialogue: 0,0:56:49.19,0:56:51.40,yin,,0,0,0,,为什么要有这种东西\\N{\\fs12}and why would you have such a thing?\r\nDialogue: 0,0:56:51.40,0:56:54.44,yin,,0,0,0,,因为你有可能要查询照片计数\\N{\\fs12}Because it's possible to just query the counted photos,\r\nDialogue: 0,0:56:54.44,0:56:56.79,yin,,0,0,0,,例如一个拍照者拍了多少\\N{\\fs12}that a photographer has, for example.\r\nDialogue: 0,0:56:56.79,0:57:00.31,yin,,0,0,0,,也许 计数是出于效率考虑\\N{\\fs12}Maybe, you know, it's your, its account, for efficiency,\r\nDialogue: 0,0:57:00.31,0:57:02.85,yin,,0,0,0,,你检查照片信息 跟踪计数\\N{\\fs12}you're checking something about the photo and keeping this count.\r\nDialogue: 0,0:57:02.85,0:57:05.35,yin,,0,0,0,,在删除照片后 你或许应当更新计数\\N{\\fs12}And maybe if you delete the photo you need to update that count.\r\nDialogue: 0,0:57:05.35,0:57:08.59,yin,,0,0,0,,所有这些 都可以在prepareForDeletion中做到\\N{\\fs12}Well you can do that, all that kind of stuff here and prepare for deletion.\r\nDialogue: 0,0:57:08.59,0:57:10.28,yin,,0,0,0,,在prepareForDeletion中\\N{\\fs12}You can basically do anything in the database\r\nDialogue: 0,0:57:10.28,0:57:12.72,yin,,0,0,0,,你可以做任何数据库中你想做的事\\N{\\fs12}you want in prepare for deletion,\r\nDialogue: 0,0:57:12.72,0:57:15.70,yin,,0,0,0,,而要删除的东西还没被删除\\N{\\fs12}and the thing that's being deleted is not yet deleted.\r\nDialogue: 0,0:57:15.70,0:57:18.23,yin,,0,0,0,,这个调用时 它还在数据库中\\N{\\fs12}So it's still it the database that this is called.\r\nDialogue: 0,0:57:18.23,0:57:22.41,yin,,0,0,0,,但在从这个方法返回后 对象就会被删除\\N{\\fs12}But after you return from this method, then the object's going to be deleted,\r\nDialogue: 0,0:57:22.41,0:57:25.37,yin,,0,0,0,,你最好是按需求更新了数据库\\N{\\fs12}so you have better have updated the database however you need.\r\nDialogue: 0,0:57:27.14,0:57:28.88,yin,,0,0,0,,明白了吗\\N{\\fs12}Got that?\r\nDialogue: 0,0:57:28.99,0:57:32.64,yin,,0,0,0,,好 你可以插入创建对象\\N{\\fs12}Alright. So, now you can create objects with insert,\r\nDialogue: 0,0:57:32.64,0:57:35.47,yin,,0,0,0,,获取和设置属性 删除对象\\N{\\fs12}you can get and set the properties, you can delete the objects.\r\nDialogue: 0,0:57:35.47,0:57:39.06,yin,,0,0,0,,数据库中还有最后一点 query(查询)\\N{\\fs12}One last thing to want to do in a database, query, okay,\r\nDialogue: 0,0:57:39.06,0:57:44.05,yin,,0,0,0,,也就是到数据库中获取匹配标准的所有对象\\N{\\fs12}which means go out into the database and get me objects that match some criteria.\r\nDialogue: 0,0:57:44.97,0:57:48.51,yin,,0,0,0,,Core Data中可以通过一种对象做到这个\\N{\\fs12}So, we do this, in core data,\r\nDialogue: 0,0:57:48.52,0:57:51.24,yin,,0,0,0,,也就是NSFetchRequest(取回请求)\\N{\\fs12}with an object called NS fetch request.\r\nDialogue: 0,0:57:51.24,0:57:53.31,yin,,0,0,0,,顾名思义 很好理解\\N{\\fs12}It's exactly what you think it is,\r\nDialogue: 0,0:57:53.31,0:57:55.96,yin,,0,0,0,,你提出请求 从数据库中取回一些对象\\N{\\fs12}you're requesting to fetch some objects from the database.\r\nDialogue: 0,0:57:55.96,0:57:58.78,yin,,0,0,0,,你需要四个要素来得到NSFetchRequest\\N{\\fs12}You need four things to make an NS fetch request.\r\nDialogue: 0,0:57:58.78,0:58:01.32,yin,,0,0,0,,要取回的实体 这个很有趣\\N{\\fs12}The entity to fetch, and this is an interesting one\r\nDialogue: 0,0:58:01.32,0:58:04.76,yin,,0,0,0,,因为在数据库中去取时 你只能取回…\\N{\\fs12}because when you fetch from the database, you can only fetch,\r\nDialogue: 0,0:58:04.76,0:58:08.21,yin,,0,0,0,,在你执行它时 它会返回一个对象数组\\N{\\fs12}fetch, when you execute it, it returns an array of objects,\r\nDialogue: 0,0:58:08.21,0:58:09.80,yin,,0,0,0,,一个NSManagedObject数组\\N{\\fs12}an array of NS-managed objects,\r\nDialogue: 0,0:58:09.80,0:58:12.28,yin,,0,0,0,,或是其子类的数组 很好理解\\N{\\fs12}or subclasses thereof, as you might imagine.\r\nDialogue: 0,0:58:12.28,0:58:16.29,yin,,0,0,0,,这个数组都需要是相同类型的实体\\N{\\fs12}That array all have to be the same type of entity.\r\nDialogue: 0,0:58:16.29,0:58:19.82,yin,,0,0,0,,你在数据库中取回的数组不可能\\N{\\fs12}So there are no way to do a fetch in a database that gives you an array back,\r\nDialogue: 0,0:58:19.82,0:58:22.34,yin,,0,0,0,,一部分是Photo 一部分是Photographer\\N{\\fs12}some of the things are photos and some are photographers.\r\nDialogue: 0,0:58:22.34,0:58:25.28,yin,,0,0,0,,要么都是Photo 要么都是Photographer\\N{\\fs12}They all have to be photos, all have to be photographers.\r\nDialogue: 0,0:58:25.28,0:58:30.30,yin,,0,0,0,,你需要指定你要取回的实体\\N{\\fs12}So you have to specify the entity that you're trying to fetch.\r\nDialogue: 0,0:58:30.30,0:58:32.11,yin,,0,0,0,,理解吗\\N{\\fs12}Understand what I mean by that?\r\nDialogue: 0,0:58:32.11,0:58:34.14,yin,,0,0,0,,这是最重要的了\\N{\\fs12}That's the most important thing, in fact, the,\r\nDialogue: 0,0:58:34.14,0:58:36.43,yin,,0,0,0,,实际上 要创建FetchRequest\\N{\\fs12}the way you create the fetch request is by\r\nDialogue: 0,0:58:36.43,0:58:39.49,yin,,0,0,0,,就必须指定你要取回的是哪类实体\\N{\\fs12}specifying what kind of entity you're trying to fetch.\r\nDialogue: 0,0:58:39.49,0:58:41.21,yin,,0,0,0,,然后可选地 你可以指定\\N{\\fs12}Then you can specify, optionally,\r\nDialogue: 0,0:58:41.21,0:58:43.84,yin,,0,0,0,,你希望接收多少个对象\\N{\\fs12}how many of those objects you're willing to accept\r\nDialogue: 0,0:58:43.84,0:58:45.79,yin,,0,0,0,,一批有多大\\N{\\fs12}and how big a batch,\r\nDialogue: 0,0:58:45.79,0:58:48.39,yin,,0,0,0,,如果你要取的很多\\N{\\fs12}if, if you're fetching a whole bunch of them,\r\nDialogue: 0,0:58:48.39,0:58:50.94,yin,,0,0,0,,你可以指定你一次取多少\\N{\\fs12}you can specify how many to get at a time,\r\nDialogue: 0,0:58:50.94,0:58:53.38,yin,,0,0,0,,要知道 在取照片时\\N{\\fs12}because it's not going to, if you say\r\nDialogue: 0,0:58:53.38,0:58:56.24,yin,,0,0,0,,如果匹配的有一万张\\N{\\fs12}get me these photos and it matches 10,000,\r\nDialogue: 0,0:58:56.24,0:58:59.98,yin,,0,0,0,,你不可能将一万个都取出数据库 存到内存\\N{\\fs12}it's not going to load 10,000 things out of the database and into memory.\r\nDialogue: 0,0:58:59.98,0:59:02.69,yin,,0,0,0,,它会给你一万个占位符\\N{\\fs12}It's going to kind of give you 10,000 placeholders\r\nDialogue: 0,0:59:02.69,0:59:05.43,yin,,0,0,0,,然后一小批一小批地取回\\N{\\fs12}and then it's going to fetch them in little batches,\r\nDialogue: 0,0:59:05.43,0:59:09.44,yin,,0,0,0,,你可以指定批大小 具体要看你怎么使用对象\\N{\\fs12}and you can specify the batch size depending on how you're going to use the object,\r\nDialogue: 0,0:59:09.44,0:59:12.07,yin,,0,0,0,,如果你是使用信息 如果是在表格视图中显示\\N{\\fs12}if you use the information, if you're displaying it in a table view,\r\nDialogue: 0,0:59:12.07,0:59:15.39,yin,,0,0,0,,你可以把批大小设得很小 例如10到20\\N{\\fs12}well you can set the batch size real small, like 10 or 20, however many,\r\nDialogue: 0,0:59:15.39,0:59:17.77,yin,,0,0,0,,满足表格视图中一般滚动所需即可\\N{\\fs12}you know, would scroll around on a table view.\r\nDialogue: 0,0:59:17.77,0:59:22.14,yin,,0,0,0,,一次一般只能看到10到20个 这时可以用小的批大小\\N{\\fs12}We can only see, you know, 10 or 20 at a time, so you've got a small batch size.\r\nDialogue: 0,0:59:22.14,0:59:23.47,yin,,0,0,0,,你可以控制这个\\N{\\fs12}So you control that.\r\nDialogue: 0,0:59:23.47,0:59:25.55,yin,,0,0,0,,SortDescriptor(排序描述器) 我们会讲到\\N{\\fs12}Sort descriptors, which we're going to talk about,\r\nDialogue: 0,0:59:25.55,0:59:26.99,yin,,0,0,0,,也就是如何对结果排序\\N{\\fs12}which is how to sort the results,\r\nDialogue: 0,0:59:26.99,0:59:29.99,yin,,0,0,0,,要知道 结果是一个数组 而不是集合\\N{\\fs12}because the results are an array, not a set.\r\nDialogue: 0,0:59:29.99,0:59:31.75,yin,,0,0,0,,数组就必然有顺序\\N{\\fs12}So the array means it's ordered,\r\nDialogue: 0,0:59:31.75,0:59:35.11,yin,,0,0,0,,你必须指定对象给回来的顺序\\N{\\fs12}so you got to specify what order to give those objects back in.\r\nDialogue: 0,0:59:35.11,0:59:37.40,yin,,0,0,0,,然后最重要的是Predicate(谓词)\\N{\\fs12}And then, most importantly, the predicate,\r\nDialogue: 0,0:59:37.40,0:59:42.40,yin,,0,0,0,,谓词是说 你想要哪些实体 哪些照片\\N{\\fs12}and the predicate says which of those entities you want, which photos?\r\nDialogue: 0,0:59:42.40,0:59:44.08,yin,,0,0,0,,哪些拍照者\\N{\\fs12}Which photographers?\r\nDialogue: 0,0:59:44.08,0:59:46.13,yin,,0,0,0,,我们来看看这四大要素\\N{\\fs12}So let's look at these four things.\r\nDialogue: 0,0:59:46.13,0:59:48.31,yin,,0,0,0,,FetchRequest是这样的\\N{\\fs12}Here's what a fetch request looks like.\r\nDialogue: 0,0:59:48.31,0:59:50.86,yin,,0,0,0,,用fetchRequestWithEntityName创建\\N{\\fs12}You create it with fetch request with entity name,\r\nDialogue: 0,0:59:50.86,0:59:53.14,yin,,0,0,0,,这告诉你是从哪取回的\\N{\\fs12}that tells you what you're fetching out of there,\r\nDialogue: 0,0:59:53.14,0:59:56.50,yin,,0,0,0,,然后你可以设置批大小 批限制\\N{\\fs12}and then you can set things like the batch size and the batch limit,\r\nDialogue: 0,0:59:56.50,0:59:58.55,yin,,0,0,0,,这些都是request上的属性\\N{\\fs12}they're just properties on the request,\r\nDialogue: 0,0:59:58.55,1:00:01.57,yin,,0,0,0,,然后sortDescriptors是一个SortDescriptor数组\\N{\\fs12}and then the sort descriptors is an array of sort descriptors,\r\nDialogue: 0,1:00:01.57,1:00:03.57,yin,,0,0,0,,我们会谈到为什么这是数组\\N{\\fs12}we'll talk about why that's an array.\r\nDialogue: 0,1:00:03.57,1:00:05.88,yin,,0,0,0,,然后谓词是NSPredicate\\N{\\fs12}And then the predicate is, is NS predicate.\r\nDialogue: 0,1:00:05.88,1:00:08.78,yin,,0,0,0,,这就是创建一个FetchRequest的方式\\N{\\fs12}So this is how you would set up a fetch request.\r\nDialogue: 0,1:00:08.78,1:00:10.75,yin,,0,0,0,,非常简单\\N{\\fs12}Very simple.\r\nDialogue: 0,1:00:10.75,1:00:15.77,yin,,0,0,0,,你可以查NSFetchRequest 具体看批大小\\N{\\fs12}So, you can look up in NS fetch request how batch size works,\r\nDialogue: 0,1:00:15.77,1:00:17.67,yin,,0,0,0,,批限制 具体我不打算讲\\N{\\fs12}how fetch limits works, I'm not going to get into detail\r\nDialogue: 0,1:00:17.67,1:00:19.05,yin,,0,0,0,,毕竟时间有限\\N{\\fs12}about that for time reasons,\r\nDialogue: 0,1:00:19.05,1:00:21.30,yin,,0,0,0,,不过我打算仔细考虑排序描述器和谓词\\N{\\fs12}but I am going to focus on sort descriptors and predicate\r\nDialogue: 0,1:00:21.30,1:00:23.84,yin,,0,0,0,,因为这些很重要 这是排序描述器\\N{\\fs12}because those are really important, so let's look at the sort descriptor.\r\nDialogue: 0,1:00:23.84,1:00:28.64,yin,,0,0,0,,创建排序描述器用这个类NSSortDescriptor\\N{\\fs12}You create a sort descriptor using this class NS sort descriptor.\r\nDialogue: 0,1:00:28.64,1:00:31.93,yin,,0,0,0,,创建它有很多种类方法\\N{\\fs12}And it has quite a number of class methods to create it,\r\nDialogue: 0,1:00:31.93,1:00:34.91,yin,,0,0,0,,你可以自己去文档查\\N{\\fs12}so you should go look at the documentation and familiarize yourself,\r\nDialogue: 0,1:00:34.91,1:00:38.31,yin,,0,0,0,,不过一般都是形如sortDescriptorWithKey\\N{\\fs12}but they're generally of the form sort descriptor with key,\r\nDialogue: 0,1:00:38.31,1:00:40.21,yin,,0,0,0,,这是排序所根据的键\\N{\\fs12}so that's the key you want to sort by,\r\nDialogue: 0,1:00:40.21,1:00:41.75,yin,,0,0,0,,如果我要取照片\\N{\\fs12}so if I were fetching for photos,\r\nDialogue: 0,1:00:41.75,1:00:45.34,yin,,0,0,0,,我可以让照片按标题排序\\N{\\fs12}I want to get the result sorted by the title of the photo,\r\nDialogue: 0,1:00:45.34,1:00:47.01,yin,,0,0,0,,这是最典型的做法\\N{\\fs12}that would be a classic thing.\r\nDialogue: 0,1:00:47.01,1:00:48.17,yin,,0,0,0,,ascending(升序)\\N{\\fs12}Ascending is whether\r\nDialogue: 0,1:00:48.17,1:00:50.94,yin,,0,0,0,,YES是字母顺序 NO是反字母顺序\\N{\\fs12}it's alphabetical order or reverse alphabetical order,\r\nDialogue: 0,1:00:50.94,1:00:53.27,yin,,0,0,0,,然后selector(选择器)很有趣\\N{\\fs12}and then the selector is interesting there.\r\nDialogue: 0,1:00:53.27,1:01:00.39,yin,,0,0,0,,这个方法将被用于在排序过程中对比照片\\N{\\fs12}That is the method that will be used to compare photos, while it's sorting them.\r\nDialogue: 0,1:01:02.23,1:01:07.60,yin,,0,0,0,,结果将会依标题排序\\N{\\fs12}So, it's going to sort the results by the title,\r\nDialogue: 0,1:01:07.60,1:01:09.40,yin,,0,0,0,,它会用到这个方法\\N{\\fs12}and it's going to be using the method here,\r\nDialogue: 0,1:01:09.40,1:01:11.68,yin,,0,0,0,,localizedStandardCompare\\N{\\fs12}localized standard compare\r\nDialogue: 0,1:01:11.68,1:01:15.99,yin,,0,0,0,,来对比标题 以明确如何排序\\N{\\fs12}to compare the titles to know how to sort them.\r\nDialogue: 0,1:01:15.99,1:01:20.25,yin,,0,0,0,,首先看 什么是localizedStandardCompare\\N{\\fs12}Now, A, what is localized standard compare?\r\nDialogue: 0,1:01:20.25,1:01:21.73,yin,,0,0,0,,localizedStandardCompare是说\\N{\\fs12}Localized standard compare means\r\nDialogue: 0,1:01:21.74,1:01:26.23,yin,,0,0,0,,像Mac finder中的方法一样排序\\N{\\fs12}sort them like they would look in the Mac finder, basically.\r\nDialogue: 0,1:01:26.23,1:01:29.09,yin,,0,0,0,,或者说得更直白一些\\N{\\fs12}Or, that's kind of colloquial way of saying it, but basically,\r\nDialogue: 0,1:01:29.09,1:01:33.58,yin,,0,0,0,,按照一般人认为应该的方法来排序\\N{\\fs12}sort them how real people think things should be sorted,\r\nDialogue: 0,1:01:33.58,1:01:35.44,yin,,0,0,0,,对大小写不敏感\\N{\\fs12}not case insensitively,\r\nDialogue: 0,1:01:35.44,1:01:37.38,yin,,0,0,0,,对发音符做出正确反应\\N{\\fs12}do the right thing with diacritic marks,\r\nDialogue: 0,1:01:37.38,1:01:40.28,yin,,0,0,0,,如果语言中带有发音符 这类\\N{\\fs12}if it's a language that has a lot of diacritics, that kind of thing.\r\nDialogue: 0,1:01:40.28,1:01:42.87,yin,,0,0,0,,这就是localizedStandardCompare\\N{\\fs12}That's what localized standard compare is.\r\nDialogue: 0,1:01:42.87,1:01:45.86,yin,,0,0,0,,此外还有其它一些选择器可用\\N{\\fs12}There are other selectors that are sensible\r\nDialogue: 0,1:01:45.86,1:01:49.12,yin,,0,0,0,,如果是字符串类型的属性\\N{\\fs12}if it was a string type property,\r\nDialogue: 0,1:01:49.12,1:01:51.70,yin,,0,0,0,,例如localizedCaseInsensitiveCompare\\N{\\fs12}like localized case insensitive compare,\r\nDialogue: 0,1:01:51.70,1:01:53.11,yin,,0,0,0,,听起来一样\\N{\\fs12}which sounds the same,\r\nDialogue: 0,1:01:53.11,1:01:54.59,yin,,0,0,0,,大小写不敏感的排序\\N{\\fs12}case insensitive sorting,\r\nDialogue: 0,1:01:54.59,1:01:57.29,yin,,0,0,0,,但这里 发音符的处理方式会不同\\N{\\fs12}but the diacritics are handled differently in that case.\r\nDialogue: 0,1:01:57.29,1:01:58.98,yin,,0,0,0,,因此 你会希望使用标准对比\\N{\\fs12}So that's why you would want to use standard compare.\r\nDialogue: 0,1:01:58.98,1:02:04.09,yin,,0,0,0,,你可以查阅SortDescriptor 看有哪些内建方法\\N{\\fs12}So you can look up in sort descriptors, see what kind of methods are kind of built in.\r\nDialogue: 0,1:02:04.09,1:02:07.45,yin,,0,0,0,,除了字符串 别的也可以排序\\N{\\fs12}If you were, you can sort by things besides strings,\r\nDialogue: 0,1:02:07.45,1:02:10.30,yin,,0,0,0,,例如你可以使用上传日期的排序描述器\\N{\\fs12}you can say sort descriptor with key upload date,\r\nDialogue: 0,1:02:10.30,1:02:13.71,yin,,0,0,0,,这时选择器将是compare:\\N{\\fs12}and then the selector would want to be compare colon.\r\nDialogue: 0,1:02:13.71,1:02:16.87,yin,,0,0,0,,compare:是大多数甚至所有…\\N{\\fs12}Compare colon is a method most things, if not all,\r\nDialogue: 0,1:02:16.87,1:02:18.75,yin,,0,0,0,,或许除了NSData\\N{\\fs12}except for NS data maybe,\r\nDialogue: 0,1:02:18.75,1:02:21.69,yin,,0,0,0,,数据库中的东西几乎都会对它作出响应\\N{\\fs12}things in the database will respond to,\r\nDialogue: 0,1:02:21.69,1:02:23.60,yin,,0,0,0,,compare:可以说是默认对比\\N{\\fs12}compare colon, it's kind of the default compare,\r\nDialogue: 0,1:02:23.60,1:02:25.99,yin,,0,0,0,,不过通常对于字符串 它并不是最好的\\N{\\fs12}but it's not going to do what you want, usually with reverse string,\r\nDialogue: 0,1:02:25.99,1:02:27.37,yin,,0,0,0,,你希望用更好的\\N{\\fs12}so you want a better one,\r\nDialogue: 0,1:02:27.37,1:02:32.53,yin,,0,0,0,,不过它对于日期和数字这些还是可以的\\N{\\fs12}but it will work for dates and things like, and numbers, things like that.\r\nDialogue: 0,1:02:32.53,1:02:34.61,yin,,0,0,0,,这是选择器\\N{\\fs12}So that's the selector.\r\nDialogue: 0,1:02:34.61,1:02:39.09,yin,,0,0,0,,创建SortDescriptor时 你可以不用选择器\\N{\\fs12}You can leave that selector off, when you create the sort descriptor,\r\nDialogue: 0,1:02:39.09,1:02:41.19,yin,,0,0,0,,只说sortDescriptorWithKey和ascending\\N{\\fs12}just say sort descriptor with key ascending,\r\nDialogue: 0,1:02:41.19,1:02:44.36,yin,,0,0,0,,闭方括号 你也会得到对比\\N{\\fs12}close square bracket, and you'll get compare.\r\nDialogue: 0,1:02:44.36,1:02:48.19,yin,,0,0,0,,这时对比使用的是默认值\\N{\\fs12}So, compare is kind of the default one you get.\r\nDialogue: 0,1:02:48.19,1:02:52.57,yin,,0,0,0,,为什么要给FetchRequest一个数组呢\\N{\\fs12}Why do we give an array of these things to the fetch request?\r\nDialogue: 0,1:02:52.57,1:02:55.87,yin,,0,0,0,,我们看到request.sortDescriptors\\N{\\fs12}Okay, when, we saw request dot sort descriptors,\r\nDialogue: 0,1:02:55.87,1:02:58.05,yin,,0,0,0,,这是一个描述器的数组\\N{\\fs12}it was an array of these,\r\nDialogue: 0,1:02:58.05,1:03:00.70,yin,,0,0,0,,这是很久就有的姓名问题\\N{\\fs12}well that's the old last name, first name thing.\r\nDialogue: 0,1:03:00.70,1:03:03.79,yin,,0,0,0,,我可能要取回一些人\\N{\\fs12}If I said hey, I'm going to fetch some people,\r\nDialogue: 0,1:03:03.79,1:03:08.74,yin,,0,0,0,,从雇员数据库中取一些雇员 我要按姓排序\\N{\\fs12}some employees out of an employee database, and I want you to sort it by last name.\r\nDialogue: 0,1:03:08.74,1:03:12.19,yin,,0,0,0,,显然 所有史密斯都排到了一起\\N{\\fs12}Well, of course, all the Smith's would all sort to the same thing.\r\nDialogue: 0,1:03:12.19,1:03:15.47,yin,,0,0,0,,然后 你希望再对其名排序\\N{\\fs12}So, you want to then sort those by the first name.\r\nDialogue: 0,1:03:15.47,1:03:18.12,yin,,0,0,0,,这就要两个排序描述器 一个按姓来\\N{\\fs12}So you provide 2 sort descriptors, one that sorts by last name,\r\nDialogue: 0,1:03:18.12,1:03:22.26,yin,,0,0,0,,这是主要排序 然后根据名排序 这是次要排序\\N{\\fs12}that's the primary sorting, and then one by first name is the secondary sorting.\r\nDialogue: 0,1:03:22.26,1:03:24.81,yin,,0,0,0,,另一个很常见的情况是表格视图 注意了\\N{\\fs12}Another common one is a table view, pay attention,\r\nDialogue: 0,1:03:24.81,1:03:27.11,yin,,0,0,0,,因为作业中 你们需要考虑到这个\\N{\\fs12}because your homework, you might have to do this, is\r\nDialogue: 0,1:03:27.11,1:03:30.60,yin,,0,0,0,,或许我的表格视图就像你们这次的作业一样\\N{\\fs12}maybe I'm doing the table view like you're doing your current assignment,\r\nDialogue: 0,1:03:30.60,1:03:36.52,yin,,0,0,0,,我排序是地方的名字\\N{\\fs12}and I'm sorting, you know, basically by the name of the place, in the place one,\r\nDialogue: 0,1:03:36.52,1:03:39.34,yin,,0,0,0,,不过我还要对section的国家进行排序\\N{\\fs12}but I'm supposed to do it by countries, sections by country,\r\nDialogue: 0,1:03:39.34,1:03:42.18,yin,,0,0,0,,而且我应当首先对国家排序\\N{\\fs12}so really I need to sort first by country,\r\nDialogue: 0,1:03:42.18,1:03:45.70,yin,,0,0,0,,然后才排序国家内的地名\\N{\\fs12}then I sort by the name of the place in the country.\r\nDialogue: 0,1:03:45.70,1:03:50.26,yin,,0,0,0,,这就是使用两种排序描述器的例子\\N{\\fs12}So, that's an example where you might use two sort descriptors.\r\nDialogue: 0,1:03:50.26,1:03:52.37,yin,,0,0,0,,国家排序 然后地方\\N{\\fs12}Country sort then the place.\r\nDialogue: 0,1:03:52.37,1:03:56.51,yin,,0,0,0,,我让所有地名排好序 国家放前面\\N{\\fs12}That's so that I can get them in order so that the, their by country first.\r\nDialogue: 0,1:03:56.51,1:03:59.10,yin,,0,0,0,,明白了吗\\N{\\fs12}That make sense?\r\nDialogue: 0,1:03:59.10,1:04:01.79,yin,,0,0,0,,好 再看谓词 这非常核心\\N{\\fs12}Alright, predicates, so this is the guts, this is the thing\r\nDialogue: 0,1:04:01.79,1:04:06.20,yin,,0,0,0,,它说的是 我要哪些照片 哪些拍照者\\N{\\fs12}that says which photos do I want, which photographers do I want, and,\r\nDialogue: 0,1:04:06.20,1:04:12.18,yin,,0,0,0,,而且在创建时 NSPredicate和NSString很像\\N{\\fs12}and NS predicate looks a lot like NS string when it comes to creating them.\r\nDialogue: 0,1:04:12.18,1:04:14.54,yin,,0,0,0,,就像NSString stringWithFormat\\N{\\fs12}So just like we have NS string, string with format,\r\nDialogue: 0,1:04:14.54,1:04:18.17,yin,,0,0,0,,这里有NSPredicate predicateWithFormat\\N{\\fs12}we actually have NS predicate, predicate with format.\r\nDialogue: 0,1:04:18.17,1:04:20.39,yin,,0,0,0,,你可以指定任意字符串\\N{\\fs12}And you can specify this arbitrary string.\r\nDialogue: 0,1:04:20.39,1:04:22.79,yin,,0,0,0,,这是一把双刃剑\\N{\\fs12}Now, this is good and bad.\r\nDialogue: 0,1:04:22.79,1:04:25.65,yin,,0,0,0,,好消息是 这非常灵活\\N{\\fs12}The good news is this is incredibly flexible\r\nDialogue: 0,1:04:25.65,1:04:30.55,yin,,0,0,0,,你可以指定很多难以置信的标准\\N{\\fs12}and you can specify unbelievable kinds of criteria\r\nDialogue: 0,1:04:30.55,1:04:32.94,yin,,0,0,0,,用于寻找数据库中的内容\\N{\\fs12}for finding what things you want in the database.\r\nDialogue: 0,1:04:32.94,1:04:34.81,yin,,0,0,0,,坏消息是 你需要学一些东西\\N{\\fs12}The bad thing is, it's a little bit for you to learn,\r\nDialogue: 0,1:04:34.81,1:04:37.39,yin,,0,0,0,,看起来就像你要学习一门语言\\N{\\fs12}because it's almost like you have to learn a little bit of a language here,\r\nDialogue: 0,1:04:37.40,1:04:40.69,yin,,0,0,0,,谓词语言 关于如何指定你要选择的东西\\N{\\fs12}the predicate language for how you specify what you want to choose.\r\nDialogue: 0,1:04:40.69,1:04:47.78,yin,,0,0,0,,基本格式让你能够进行%@符号替换\\N{\\fs12}The basic format allows you to do the percent at sign replacement,\r\nDialogue: 0,1:04:47.79,1:04:50.18,yin,,0,0,0,,就像NSString中一样 例如这里\\N{\\fs12}just like you could with NS string, so here, for example,\r\nDialogue: 0,1:04:50.18,1:04:54.51,yin,,0,0,0,,我在找所有来自flickr-5服务器的缩略图URL\\N{\\fs12}I'm looking for all the thumbnail URLs that come off of Flickr five server.\r\nDialogue: 0,1:04:54.51,1:04:58.81,yin,,0,0,0,,于是我这里说 谓词是thumbnailURL 包含flickr-5\\N{\\fs12}So I'm saying predicate is thumbnail URL contains Flickr five,\r\nDialogue: 0,1:04:58.81,1:05:00.85,yin,,0,0,0,,但这里没有直接写flickr-5\\N{\\fs12}but I don't put the Flickr five right in there,\r\nDialogue: 0,1:05:00.85,1:05:03.71,yin,,0,0,0,,我使用%@符号 而且它是一个参数\\N{\\fs12}I use percent at sign, and it's an argument.\r\nDialogue: 0,1:05:03.71,1:05:05.54,yin,,0,0,0,,我可以用%@来替换\\N{\\fs12}So I can use percent at sign for replacement,\r\nDialogue: 0,1:05:05.54,1:05:09.41,yin,,0,0,0,,我不仅可以替换右侧 包含的对象\\N{\\fs12}and I can replace not only the right side, what's contained,\r\nDialogue: 0,1:05:09.41,1:05:11.35,yin,,0,0,0,,我还可以替换左侧\\N{\\fs12}but I can replace the left side,\r\nDialogue: 0,1:05:11.35,1:05:14.95,yin,,0,0,0,,例如我要搜索是否包含flickr-5的属性\\N{\\fs12}like which property I want to search to see if it contains Flickr five.\r\nDialogue: 0,1:05:14.95,1:05:18.51,yin,,0,0,0,,等下我会讲到包含(contains) 有问题\\N{\\fs12}And we'll talk about contains in a second, question?\r\nDialogue: 0,1:05:25.88,1:05:29.42,yin,,0,0,0,,对 问题是 这是不是\\N{\\fs12}Correct. Yeah so, this is not just, the question is is\r\nDialogue: 0,1:05:29.42,1:05:31.45,yin,,0,0,0,,生成一个字符串然后传递\\N{\\fs12}that just making a string and passing it off\r\nDialogue: 0,1:05:31.45,1:05:32.67,yin,,0,0,0,,答案是否定的\\N{\\fs12}and the answer is no,\r\nDialogue: 0,1:05:32.67,1:05:35.79,yin,,0,0,0,,NSPredicate会看你在解析什么\\N{\\fs12}NS predicate is actually looking at what you're parsing and,\r\nDialogue: 0,1:05:35.79,1:05:39.40,yin,,0,0,0,,不过 它不知道你正在什么数据库中进行取回\\N{\\fs12}now it's, it can't know what database you're doing a fetch into,\r\nDialogue: 0,1:05:39.40,1:05:42.29,yin,,0,0,0,,因此 它只在取回时才会失败\\N{\\fs12}so it won't be until fetch time that it might fail.\r\nDialogue: 0,1:05:42.29,1:05:45.60,yin,,0,0,0,,如果你说thumbnailFoo包含什么\\N{\\fs12}If you say thumbnail foo, contains whatever,\r\nDialogue: 0,1:05:45.60,1:05:47.70,yin,,0,0,0,,你可以创建这个谓词\\N{\\fs12}its predicate is going to let you create that predicate,\r\nDialogue: 0,1:05:47.70,1:05:49.13,yin,,0,0,0,,但在真正取回时\\N{\\fs12}but then when you go to do the fetch it's going\r\nDialogue: 0,1:05:49.13,1:05:53.26,yin,,0,0,0,,你会被告知 本数据库中没有thumbnailFoo\\N{\\fs12}to say no property thumbnail foo in this database.\r\nDialogue: 0,1:05:53.90,1:05:56.63,yin,,0,0,0,,好 你们看到这里有contains\\N{\\fs12}Okay, so, you see this one's contained.\r\nDialogue: 0,1:05:56.63,1:06:00.01,yin,,0,0,0,,contains是说 一个字符串包含在另一个字符串之中\\N{\\fs12}Contains means, you know, that string is contained in the other string,\r\nDialogue: 0,1:06:00.02,1:06:00.75,yin,,0,0,0,,顾名思义\\N{\\fs12}exactly what you want,\r\nDialogue: 0,1:06:00.75,1:06:04.29,yin,,0,0,0,,contains是用于创建谓词的一点语言词汇\\N{\\fs12}so contains is one of the words in this little language for setting up predicates.\r\nDialogue: 0,1:06:04.29,1:06:05.93,yin,,0,0,0,,这里还有很多别的例子\\N{\\fs12}Here's a whole bunch of other examples.\r\nDialogue: 0,1:06:05.93,1:06:08.42,yin,,0,0,0,,今天我不可能把所有谓词都讲完\\N{\\fs12}I'm not going to teach you all of predicate today, you're going\r\nDialogue: 0,1:06:08.42,1:06:10.43,yin,,0,0,0,,你们需要自己去查NSPredicate的文档\\N{\\fs12}to have to look at NS predicate documentation,\r\nDialogue: 0,1:06:10.43,1:06:12.18,yin,,0,0,0,,不过这里有一些例子\\N{\\fs12}see what it can do, but here's a bunch of examples.\r\nDialogue: 0,1:06:12.18,1:06:14.00,yin,,0,0,0,,显然 这里有等于\\N{\\fs12}Obviously, you have equals,\r\nDialogue: 0,1:06:14.00,1:06:17.33,yin,,0,0,0,,你可以说uniqueId = %@\\N{\\fs12}so you can say unique ID equals percent at sign,\r\nDialogue: 0,1:06:17.33,1:06:22.69,yin,,0,0,0,,或许是Flickr对象 Flickr照片 唯一ID\\N{\\fs12}maybe the Flickr object, the Flickr photos, unique ID,\r\nDialogue: 0,1:06:22.69,1:06:26.59,yin,,0,0,0,,你可以说name contains[c]\\N{\\fs12}you can say name contains with square bracket C,\r\nDialogue: 0,1:06:26.59,1:06:30.25,yin,,0,0,0,,这是说大小写不敏感地包含\\N{\\fs12}that means contains case insensitively.\r\nDialogue: 0,1:06:30.25,1:06:33.78,yin,,0,0,0,,这是一种contains 你还可以有大于和小于\\N{\\fs12}So that's part of the thing, you can have greater than and less than,\r\nDialogue: 0,1:06:33.78,1:06:36.63,yin,,0,0,0,,假设我有一个日期属性叫viewed(被阅览)\\N{\\fs12}so if I had a date property called viewed,\r\nDialogue: 0,1:06:36.63,1:06:39.48,yin,,0,0,0,,我可以说 如果viewed大于特定日期\\N{\\fs12}I could say if viewed is greater than a certain date,\r\nDialogue: 0,1:06:39.48,1:06:41.89,yin,,0,0,0,,例如今天的日期\\N{\\fs12}like today's date, for example,\r\nDialogue: 0,1:06:41.89,1:06:43.89,yin,,0,0,0,,或许小于今天的日期会更合理\\N{\\fs12}or, it would be, I guess, less than today's date\r\nDialogue: 0,1:06:43.89,1:06:46.08,yin,,0,0,0,,或是小于今天的日期减24小时 诸如此类\\N{\\fs12}or less than today's date minus 24 hours, whatever,\r\nDialogue: 0,1:06:46.08,1:06:48.11,yin,,0,0,0,,你可以用大于或小于\\N{\\fs12}so you can use greater than or less than.\r\nDialogue: 0,1:06:48.15,1:06:51.38,yin,,0,0,0,,你还可以用点符号来跟踪关系\\N{\\fs12}You can use dot notation to follow relationships.\r\nDialogue: 0,1:06:51.38,1:06:56.51,yin,,0,0,0,,你可以说 whoTook.name = CS193P授课者\\N{\\fs12}So you can say who took dot name equals CS193p instructor, right?\r\nDialogue: 0,1:06:56.51,1:06:59.50,yin,,0,0,0,,这里可以是一个查询 或者谓词\\N{\\fs12}So you could have, this would be a query or a predicate\r\nDialogue: 0,1:06:59.50,1:07:02.61,yin,,0,0,0,,用于搜索照片 实体\\N{\\fs12}for searching in the photos, entities,\r\nDialogue: 0,1:07:02.62,1:07:04.70,yin,,0,0,0,,你希望获得照片实体\\N{\\fs12}so you're trying to get photos entities,\r\nDialogue: 0,1:07:04.70,1:07:10.93,yin,,0,0,0,,但是照片实体要求满足拍照者名字是某个人名\\N{\\fs12}but you want photos entities where the who took name is some photographers name.\r\nDialogue: 0,1:07:10.93,1:07:15.09,yin,,0,0,0,,你所获得的东西是照片 但是查询\\N{\\fs12}So, the things you're getting are photos, but the query,\r\nDialogue: 0,1:07:15.09,1:07:16.85,yin,,0,0,0,,用于找它们的谓词\\N{\\fs12}the predicate you're using to find them,\r\nDialogue: 0,1:07:16.85,1:07:20.50,yin,,0,0,0,,却是用点符号考察拍照者名字\\N{\\fs12}is looking over at the photographer using dot notation,\r\nDialogue: 0,1:07:20.50,1:07:22.09,yin,,0,0,0,,明白吗\\N{\\fs12}you understand this?\r\nDialogue: 0,1:07:22.09,1:07:24.57,yin,,0,0,0,,要做好作业 理解这些是必须的\\N{\\fs12}You definitely need to understand this for your homework.\r\nDialogue: 0,1:07:24.57,1:07:26.60,yin,,0,0,0,,你可以进行很强大的搜索\\N{\\fs12}And you can do really powerful searches like\r\nDialogue: 0,1:07:26.60,1:07:30.17,yin,,0,0,0,,如 给我标题包含某内容的任何照片\\N{\\fs12}give me any photo who's title contains,\r\nDialogue: 0,1:07:30.17,1:07:33.12,yin,,0,0,0,,抱歉 这里是 拍照者查询\\N{\\fs12}sorry, give me, this would be a photographer query,\r\nDialogue: 0,1:07:33.12,1:07:34.87,yin,,0,0,0,,我要搜的是拍照者\\N{\\fs12}so let's say I'm searching photographers,\r\nDialogue: 0,1:07:34.87,1:07:41.06,yin,,0,0,0,,给我照片标题包含这个的任何(any)拍照者\\N{\\fs12}give me any photographer where any of its photos title contains this.\r\nDialogue: 0,1:07:41.06,1:07:43.73,yin,,0,0,0,,这个any就是这里所特有的\\N{\\fs12}So that any is kind of a special thing,\r\nDialogue: 0,1:07:43.73,1:07:47.24,yin,,0,0,0,,意思是说 我要找拍照者\\N{\\fs12}and that means I'm the photographer, look at all my,\r\nDialogue: 0,1:07:47.24,1:07:49.53,yin,,0,0,0,,在数据库中搜所有拍照者\\N{\\fs12}look at, in the database at all the photographers,\r\nDialogue: 0,1:07:49.53,1:07:52.77,yin,,0,0,0,,看它们拍的照片的集合\\N{\\fs12}look through their, their photos set,\r\nDialogue: 0,1:07:52.77,1:07:56.62,yin,,0,0,0,,看其中所有照片 看所有照片的标题\\N{\\fs12}to look at all their photos, look at all the titles of all those photos,\r\nDialogue: 0,1:07:56.62,1:07:58.28,yin,,0,0,0,,看是否包含这个字符串\\N{\\fs12}see if it contains this string,\r\nDialogue: 0,1:07:58.28,1:08:01.24,yin,,0,0,0,,如果包含 返回这个拍照者\\N{\\fs12}and if it does, return that photographer.\r\nDialogue: 0,1:08:01.24,1:08:04.65,yin,,0,0,0,,你肯定会说 哇 这得消耗多少计算力啊\\N{\\fs12}Now this seems, I'm sure you're like whoa, that is going to take\r\nDialogue: 0,1:08:04.65,1:08:10.16,yin,,0,0,0,,如果有成千上万的照片 成百上千的拍照者怎么办\\N{\\fs12}a lot of computing power if I had thousands of photos and hundreds of photographers,\r\nDialogue: 0,1:08:10.16,1:08:13.62,yin,,0,0,0,,实际上 数据库能够很好地完成这个\\N{\\fs12}but actually, databases know how to do this really, really well.\r\nDialogue: 0,1:08:13.62,1:08:16.13,yin,,0,0,0,,你所做的事情不过是\\N{\\fs12}And all this stuff that you're doing is\r\nDialogue: 0,1:08:16.13,1:08:18.66,yin,,0,0,0,,生成SQL侧发生的东西\\N{\\fs12}generating stuff that happens on the sequel side,\r\nDialogue: 0,1:08:18.66,1:08:21.18,yin,,0,0,0,,你会得到一个大的SQL语句生成在这里\\N{\\fs12}so you're going to get a big sequel statement generated here\r\nDialogue: 0,1:08:21.18,1:08:23.93,yin,,0,0,0,,将表格结合在一起 进行搜索\\N{\\fs12}to join these tables, do these searches,\r\nDialogue: 0,1:08:23.93,1:08:26.10,yin,,0,0,0,,这会非常高效\\N{\\fs12}it's going to be incredibly efficient,\r\nDialogue: 0,1:08:26.10,1:08:30.04,yin,,0,0,0,,Core Data很重要的一点便是 它非常高效\\N{\\fs12}and one thing to understand about core data is it's very efficient.\r\nDialogue: 0,1:08:30.04,1:08:34.66,yin,,0,0,0,,它生成的SQL最大程度地进行了优化\\N{\\fs12}The sequel it generates is totally tuned to the max.\r\nDialogue: 0,1:08:34.66,1:08:36.28,yin,,0,0,0,,话虽如此\\N{\\fs12}Having said that,\r\nDialogue: 0,1:08:36.28,1:08:39.06,yin,,0,0,0,,有些查询还是会比其它更高效\\N{\\fs12}there are certain queries that are more efficient than others\r\nDialogue: 0,1:08:39.06,1:08:40.96,yin,,0,0,0,,虽然达成的目的都是一样的\\N{\\fs12}that can accomplish the same goals.\r\nDialogue: 0,1:08:40.96,1:08:45.36,yin,,0,0,0,,如果你想成为Core Data专家 要创建大数据库\\N{\\fs12}So, if you get to be a core data expert and you start building big databases\r\nDialogue: 0,1:08:45.36,1:08:47.88,yin,,0,0,0,,在大数据集上要进行很多工作量巨大的查询\\N{\\fs12}and you're making a lot of big queries on big data sets,\r\nDialogue: 0,1:08:47.88,1:08:50.64,yin,,0,0,0,,你会最终了解 什么查询好\\N{\\fs12}you will eventually learn what makes a good query,\r\nDialogue: 0,1:08:50.64,1:08:53.09,yin,,0,0,0,,什么查询不那么好\\N{\\fs12}what makes a not so good query, etc.\r\nDialogue: 0,1:08:53.09,1:08:55.05,yin,,0,0,0,,但在作业中 你还不需要担心这些\\N{\\fs12}For your homework, you don't have to worry about that yet.\r\nDialogue: 0,1:08:55.05,1:08:56.38,yin,,0,0,0,,首先只需打好基础\\N{\\fs12}Let's get the basics first.\r\nDialogue: 0,1:08:56.38,1:08:57.51,yin,,0,0,0,,有问题\\N{\\fs12}Question.\r\nDialogue: 0,1:09:03.52,1:09:05.55,yin,,0,0,0,,问题是不是\\N{\\fs12}So the question, you mean like\r\nDialogue: 0,1:09:05.55,1:09:09.51,yin,,0,0,0,,大于和小于这些能否作为%@符号传入\\N{\\fs12}the greater than and less than, can I pass that in as a percent sign?\r\nDialogue: 0,1:09:13.82,1:09:15.70,yin,,0,0,0,,你不能进行SQL…\\N{\\fs12}Yes. You can't do sequel,\r\nDialogue: 0,1:09:15.70,1:09:19.12,yin,,0,0,0,,问题是 能否使用%@符号进行SQL隐码攻击\\N{\\fs12}the question is can I do sequel injection by using the percent at sign to,\r\nDialogue: 0,1:09:19.12,1:09:22.47,yin,,0,0,0,,从而让运算符可配置\\N{\\fs12}to basically make the operator be, you know,\r\nDialogue: 0,1:09:22.47,1:09:24.86,yin,,0,0,0,,答案是不能\\N{\\fs12}configurable, and the answer is you can't do that.\r\nDialogue: 0,1:09:24.88,1:09:27.19,yin,,0,0,0,,NSPredicate会报错\\N{\\fs12}NS predicate would complain about that.\r\nDialogue: 0,1:09:27.19,1:09:30.60,yin,,0,0,0,,NSPredicate知道什么时候%@符号在右侧\\N{\\fs12}NS predicate does know when a percent at sign is a right-hand\r\nDialogue: 0,1:09:30.60,1:09:33.56,yin,,0,0,0,,什么时候在这些表达式左侧\\N{\\fs12}or a left-hand of one of these expressions, so\r\nDialogue: 0,1:09:33.57,1:09:36.24,yin,,0,0,0,,答案是不 你不能那样做\\N{\\fs12}the answer is no. You can't do that.\r\nDialogue: 0,1:09:36.75,1:09:40.18,yin,,0,0,0,,好 这里有一些例子 我只是给一些例子\\N{\\fs12}Okay, so there's a bunch of examples, again, I'm just trying to give you the examples,\r\nDialogue: 0,1:09:40.18,1:09:44.43,yin,,0,0,0,,这里我不打算把所有谓词都讲一遍\\N{\\fs12}we're not trying to teach you predicate here.\r\nDialogue: 0,1:09:44.43,1:09:46.48,yin,,0,0,0,,还有一个复合谓词\\N{\\fs12}There's also a compound predicate.\r\nDialogue: 0,1:09:46.48,1:09:50.02,yin,,0,0,0,,在NSPredicate中 你可以说AND或OR\\N{\\fs12}In the NS predicate, you can say and or or.\r\nDialogue: 0,1:09:50.02,1:09:50.93,yin,,0,0,0,,例如你可以说\\N{\\fs12}So you could say\r\nDialogue: 0,1:09:50.93,1:09:54.15,yin,,0,0,0,,(name = %@) OR (title = %@)\\N{\\fs12}name equals percent at sign or title equals percent at sign,\r\nDialogue: 0,1:09:54.15,1:09:56.81,yin,,0,0,0,,如果你的对象有一个name和一个title\\N{\\fs12}okay, if you had an object that had a name and a title.\r\nDialogue: 0,1:09:56.81,1:09:57.64,yin,,0,0,0,,你也可以说\\N{\\fs12}Or you could say\r\nDialogue: 0,1:09:57.65,1:10:01.31,yin,,0,0,0,,(whoTook.name=%@) OR (title=%@)\\N{\\fs12}who took dot name equals blah, or title equals blah,\r\nDialogue: 0,1:10:01.31,1:10:03.50,yin,,0,0,0,,虽然没什么意义 但你可以这样做\\N{\\fs12}it kind of wouldn't make much sense, but you could.\r\nDialogue: 0,1:10:03.50,1:10:07.96,yin,,0,0,0,,在代码中创建复合谓词还可以使用\\N{\\fs12}You can also create compound predicates in code by doing,\r\nDialogue: 0,1:10:07.96,1:10:11.77,yin,,0,0,0,,NSCompoundPredicate中的and谓词或or谓词\\N{\\fs12}using and predicate or or predicate in NS compound predicate.\r\nDialogue: 0,1:10:11.77,1:10:16.91,yin,,0,0,0,,它会取一个谓词的数组 形成复合谓词\\N{\\fs12}And it just takes an array of other predicates and makes a compound one.\r\nDialogue: 0,1:10:16.91,1:10:21.94,yin,,0,0,0,,这就像是代码中if-then的and和or\\N{\\fs12}That's like if you want the and-ing and or-ing to kind of be if then, okay, in code,\r\nDialogue: 0,1:10:21.94,1:10:25.16,yin,,0,0,0,,只是内建到字符串中\\N{\\fs12}as opposed to just built into the string.\r\nDialogue: 0,1:10:25.16,1:10:28.82,yin,,0,0,0,,高级查询 出于时间考虑 我打算跳过这个\\N{\\fs12}Advanced querying, for time reasons I'm going to skip this,\r\nDialogue: 0,1:10:28.82,1:10:31.71,yin,,0,0,0,,不过键值编码也就是\\N{\\fs12}but key value coding, which is the thing\r\nDialogue: 0,1:10:31.71,1:10:36.10,yin,,0,0,0,,让你使用点符号在字典内往下搜索的东西\\N{\\fs12}that lets you use dot notation to search down inside of a dictionary,\r\nDialogue: 0,1:10:36.10,1:10:38.62,yin,,0,0,0,,它是valueForKeyPath那些\\N{\\fs12}it's the value for key path business.\r\nDialogue: 0,1:10:38.62,1:10:42.25,yin,,0,0,0,,你可以在数据库中使用valueForKeyPath\\N{\\fs12}You can kind of do value for key path in the database,\r\nDialogue: 0,1:10:42.25,1:10:44.80,yin,,0,0,0,,我们没有讨论过这些\\N{\\fs12}and there is, we didn't talk about this,\r\nDialogue: 0,1:10:44.80,1:10:47.68,yin,,0,0,0,,不过键值编码中有一点很酷\\N{\\fs12}but there is a really cool thing in key value coding,\r\nDialogue: 0,1:10:47.68,1:10:50.33,yin,,0,0,0,,也就是函数 其中有个函数\\N{\\fs12}which is functions, and one of the functions,\r\nDialogue: 0,1:10:50.33,1:10:55.37,yin,,0,0,0,,或许在你的作业中有用 注意了 是@count\\N{\\fs12}which you probably will need for your homework, so pay attention, is at sign count.\r\nDialogue: 0,1:10:55.37,1:11:01.12,yin,,0,0,0,,如果你将@count放到你要查询的东西里面\\N{\\fs12}So, if you put at sign count in the thing you're querying for,\r\nDialogue: 0,1:11:01.12,1:11:04.81,yin,,0,0,0,,只要它左侧是一个集合 一个NSSet\\N{\\fs12}as long as the thing to the left of it is an array, or a set,\r\nDialogue: 0,1:11:04.81,1:11:07.22,yin,,0,0,0,,只要它左侧是一个集合 一个NSSet\\N{\\fs12}sorry, a set, one of these NS sets,\r\nDialogue: 0,1:11:07.22,1:11:12.50,yin,,0,0,0,,那它就会将它替换为集合中元素的计数值\\N{\\fs12}then it will replace that with the count of how many things are in that set.\r\nDialogue: 0,1:11:12.50,1:11:16.00,yin,,0,0,0,,例如 如果我想找的所有拍照者\\N{\\fs12}So, for example, if I wanted to find out all the photographers,\r\nDialogue: 0,1:11:16.00,1:11:19.42,yin,,0,0,0,,满足条件拍的照片多于五张\\N{\\fs12}give me back all of the photographers who have taken more than five photos,\r\nDialogue: 0,1:11:19.42,1:11:24.79,yin,,0,0,0,,我的谓词将是photos.@count>5\\N{\\fs12}my predicate would be photos dot at sign count is greater than five.\r\nDialogue: 0,1:11:24.79,1:11:28.59,yin,,0,0,0,,还有其它@ 例如@avg(平均值)等等\\N{\\fs12}And there are other at signs, at sign average, at sign,\r\nDialogue: 0,1:11:28.59,1:11:30.99,yin,,0,0,0,,你可以自己去查有哪些 这里我给了个链接\\N{\\fs12}you can look through and find out what there is, I put a link in here,\r\nDialogue: 0,1:11:30.99,1:11:32.94,yin,,0,0,0,,你们知道 我很少在幻灯片中给链接\\N{\\fs12}you know I don't, I usually don't put links in my slides,\r\nDialogue: 0,1:11:32.94,1:11:34.87,yin,,0,0,0,,不过这个确实值得一看\\N{\\fs12}but this one is worth looking at.\r\nDialogue: 0,1:11:34.87,1:11:38.71,yin,,0,0,0,,这个能对任何键值编码的东西奏效\\N{\\fs12}And, this also works, it works for any key value coding things,\r\nDialogue: 0,1:11:38.71,1:11:40.59,yin,,0,0,0,,例如对字典\\N{\\fs12}like for dictionaries, so\r\nDialogue: 0,1:11:40.59,1:11:42.76,yin,,0,0,0,,你可以回Shutterbug\\N{\\fs12}go back to the shutter bug\r\nDialogue: 0,1:11:42.76,1:11:45.66,yin,,0,0,0,,尝试propertyListResults valueForKeyPath\\N{\\fs12}and try doing property list results, value for key path,\r\nDialogue: 0,1:11:45.66,1:11:49.69,yin,,0,0,0,,photos.photo.@avg.latitude\\N{\\fs12}photos dot photo dot average dot latitude.\r\nDialogue: 0,1:11:49.69,1:11:52.74,yin,,0,0,0,,有人试着答下 这个会返回什么吗\\N{\\fs12}Anyone hazard what that returns?\r\nDialogue: 0,1:11:54.96,1:11:56.51,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,1:11:59.48,1:12:04.89,yin,,0,0,0,,对 它会返回所有照片的平均纬度值\\N{\\fs12}Correct. It returns the average latitude of all the photos.\r\nDialogue: 0,1:12:04.89,1:12:07.94,yin,,0,0,0,,这是给你们留的 祝玩的开心\\N{\\fs12}So, that's something for you to, to have fun with.\r\nDialogue: 0,1:12:07.94,1:12:10.58,yin,,0,0,0,,你还可以创建更复杂的表达式\\N{\\fs12}You can build even more complicated expressions\r\nDialogue: 0,1:12:10.58,1:12:13.05,yin,,0,0,0,,有一个机制可以到数据库中查询\\N{\\fs12}and there's a mechanism to query into the database\r\nDialogue: 0,1:12:13.05,1:12:15.98,yin,,0,0,0,,但不获得NSManagedObject\\N{\\fs12}and not get back an array of NS-managed objects,\r\nDialogue: 0,1:12:15.98,1:12:20.76,yin,,0,0,0,,而获得对其中内容进行计算后得到的数据\\N{\\fs12}but to actually get kind of data that's been calculated from,\r\nDialogue: 0,1:12:20.76,1:12:22.68,yin,,0,0,0,,这样做时 你得到的\\N{\\fs12}from what's in there, and when you do that,\r\nDialogue: 0,1:12:22.68,1:12:26.33,yin,,0,0,0,,将不是NSManagedObject数组 而是NSDictionary数组\\N{\\fs12}instead of getting an array of NS-managed objects, you get an array of NS dictionaries,\r\nDialogue: 0,1:12:26.33,1:12:29.61,yin,,0,0,0,,这些字典包含键和值 这正是你要找的数据\\N{\\fs12}and those dictionaries contain keys and values, which is the data you look for.\r\nDialogue: 0,1:12:29.61,1:12:33.60,yin,,0,0,0,,这些都是高级内容 看到标题了吗 高级查询\\N{\\fs12}This is all super advanced, see the title of this thing, advanced querying,\r\nDialogue: 0,1:12:33.60,1:12:35.53,yin,,0,0,0,,我不打算在课上细讲\\N{\\fs12}not going to talk about it in this class,\r\nDialogue: 0,1:12:35.53,1:12:40.34,yin,,0,0,0,,我只是想让你们知道 FetchRequest可以被用于\\N{\\fs12}but just so you know, that fetch request can be used to create something\r\nDialogue: 0,1:12:40.34,1:12:44.83,yin,,0,0,0,,实际取回数据 而不是取回ManagedObject\\N{\\fs12}that's actually fetching data rather than just fetching managed objects.\r\nDialogue: 0,1:12:44.83,1:12:48.62,yin,,0,0,0,,好 我们把所有这些为request综合起来\\N{\\fs12}Alright. So, let's put it all together for the request.\r\nDialogue: 0,1:12:48.62,1:12:51.15,yin,,0,0,0,,这是一个request\\N{\\fs12}So I created, this is a request.\r\nDialogue: 0,1:12:51.15,1:12:52.98,yin,,0,0,0,,请求所有拍照者\\N{\\fs12}That's going to get all the photographers,\r\nDialogue: 0,1:12:52.98,1:12:55.04,yin,,0,0,0,,代码是fetchRequestWithEntityName Photographer\\N{\\fs12}so I say fetch request fetchRequestWithEntityName photographer,\r\nDialogue: 0,1:12:55.04,1:12:57.71,yin,,0,0,0,,请求过去24小时内拍过照的\\N{\\fs12}who have taken a photo in the last 24 hours,\r\nDialogue: 0,1:12:57.71,1:12:59.86,yin,,0,0,0,,昨天 这需要NSDate\\N{\\fs12}so I get yesterday, which is NS date,\r\nDialogue: 0,1:12:59.86,1:13:03.77,yin,,0,0,0,,dateWithTimeIntervalSinceNow -24小时\\N{\\fs12}date with time interval since now minus 24 hours.\r\nDialogue: 0,1:13:03.77,1:13:09.69,yin,,0,0,0,,谓词 any photos.uploadDate > 某某\\N{\\fs12}Predicate, any photos dot upload date greater than whatever.\r\nDialogue: 0,1:13:09.69,1:13:10.66,yin,,0,0,0,,昨天\\N{\\fs12}Yesterday.\r\nDialogue: 0,1:13:10.66,1:13:13.09,yin,,0,0,0,,然后 我要按拍照者名字排序\\N{\\fs12}And then I'm going to sort it by the photographer's name,\r\nDialogue: 0,1:13:13.09,1:13:16.88,yin,,0,0,0,,一个SortDescriptor的数组 按名字排序\\N{\\fs12}so an array of one sort descriptor, where the sort descriptor's the name,\r\nDialogue: 0,1:13:16.88,1:13:18.66,yin,,0,0,0,,这里会用compare\\N{\\fs12}it's going to be using compare here,\r\nDialogue: 0,1:13:18.66,1:13:19.95,yin,,0,0,0,,这可能不好\\N{\\fs12}which is probably not good, I probably\r\nDialogue: 0,1:13:19.95,1:13:23.33,yin,,0,0,0,,或许@selector(localizedStandardCompare:)会更好\\N{\\fs12}want to say selector at sign localized compare.\r\nDialogue: 0,1:13:23.33,1:13:26.08,yin,,0,0,0,,这就是创建request的方式\\N{\\fs12}So that's I would create a request.\r\nDialogue: 0,1:13:26.08,1:13:29.28,yin,,0,0,0,,有了request后 如何执行呢\\N{\\fs12}Now that I have a request, how do I execute it?\r\nDialogue: 0,1:13:29.28,1:13:30.47,yin,,0,0,0,,答案是\\N{\\fs12}And the answer is\r\nDialogue: 0,1:13:30.47,1:13:33.08,yin,,0,0,0,,我们使用NSManagedObjectContext中的\\N{\\fs12}we use the method execute fetch request\r\nDialogue: 0,1:13:33.08,1:13:34.97,yin,,0,0,0,,executeFetchRequest方法\\N{\\fs12}in NS-managed object context.\r\nDialogue: 0,1:13:34.97,1:13:37.89,yin,,0,0,0,,NSManagedObjectContext是一切的中心\\N{\\fs12}So I told you NS manage object context is the hub of everything\r\nDialogue: 0,1:13:37.89,1:13:40.24,yin,,0,0,0,,也是查询的中心\\N{\\fs12}and it's the hub of querying, as well.\r\nDialogue: 0,1:13:40.24,1:13:42.24,yin,,0,0,0,,可以看到 它有一个额外的参数\\N{\\fs12}And you can see it has a little extra argument there,\r\nDialogue: 0,1:13:42.24,1:13:45.01,yin,,0,0,0,,error:&error 这会返回NSError\\N{\\fs12}error colon, at sign error, which will return an NS error\r\nDialogue: 0,1:13:45.01,1:13:47.88,yin,,0,0,0,,发生错误时 这会告诉你错误在哪\\N{\\fs12}and tell you what went wrong if things went wrong,\r\nDialogue: 0,1:13:47.88,1:13:50.65,yin,,0,0,0,,如果executeFetchRequest返回nil 你能知道出错了\\N{\\fs12}and you can tell things went wrong with the fetch request\r\nDialogue: 0,1:13:50.65,1:13:54.50,yin,,0,0,0,,这是使用FetchRequest时的情况\\N{\\fs12}if execute fetch request returns nil.\r\nDialogue: 0,1:13:54.50,1:13:57.82,yin,,0,0,0,,如果executeFetchRequest返回nil 那就肯定出错了\\N{\\fs12}If execute fetch request returns nil, something went wrong,\r\nDialogue: 0,1:13:57.82,1:14:00.35,yin,,0,0,0,,&error会填入某种错误\\N{\\fs12}and that at sign error will be filled out with some error.\r\nDialogue: 0,1:14:00.35,1:14:04.74,yin,,0,0,0,,如果返回的是空数组 不是nil\\N{\\fs12}If it returns an empty array, that's not nil,\r\nDialogue: 0,1:14:04.74,1:14:05.83,yin,,0,0,0,,而是空数组\\N{\\fs12}empty array,\r\nDialogue: 0,1:14:05.83,1:14:09.20,yin,,0,0,0,,这意味着 没有匹配请求的内容\\N{\\fs12}that means nothing matches what you're requesting.\r\nDialogue: 0,1:14:09.20,1:14:10.10,yin,,0,0,0,,没有错误\\N{\\fs12}So no error.\r\nDialogue: 0,1:14:10.10,1:14:14.62,yin,,0,0,0,,只是你请求的对象没有 它们都不匹配你的谓词\\N{\\fs12}It's just that you requested objects and there aren't any that match that predicate.\r\nDialogue: 0,1:14:14.62,1:14:20.46,yin,,0,0,0,,否则 它会返回一个NSManagedObject数组\\N{\\fs12}Otherwise, it's going to return an array of NS-managed objects.\r\nDialogue: 0,1:14:20.46,1:14:23.68,yin,,0,0,0,,或是其子类 Photo\\N{\\fs12}Or, subclasses thereof, photos stars,\r\nDialogue: 0,1:14:23.68,1:14:26.26,yin,,0,0,0,,Photographer * 这些你所设置的实体名\\N{\\fs12}photographer stars, whatever you set as the entity name,\r\nDialogue: 0,1:14:26.26,1:14:28.83,yin,,0,0,0,,它会传回这些组成的数组\\N{\\fs12}it's going to pass an array of them.\r\nDialogue: 0,1:14:28.83,1:14:29.96,yin,,0,0,0,,就这了\\N{\\fs12}That's it.\r\nDialogue: 0,1:14:29.96,1:14:32.96,yin,,0,0,0,,查询不能再简单了\\N{\\fs12}It could not be simpler to query.\r\nDialogue: 0,1:14:32.96,1:14:35.41,yin,,0,0,0,,查询结果有一点我想提下\\N{\\fs12}One thing about the query results, by the way,\r\nDialogue: 0,1:14:35.41,1:14:39.27,yin,,0,0,0,,如果你想找一万个东西 你不会得到一万个东西\\N{\\fs12}if you query 10,000 things, you're not going to get 10,000 things,\r\nDialogue: 0,1:14:39.27,1:14:41.36,yin,,0,0,0,,你会得到一万个占位符\\N{\\fs12}you're going to get 10,000 placeholders\r\nDialogue: 0,1:14:41.36,1:14:43.91,yin,,0,0,0,,在你开始看属性时\\N{\\fs12}and as you start looking at the attributes,\r\nDialogue: 0,1:14:43.91,1:14:46.66,yin,,0,0,0,,你才会从数据库中获得它们\\N{\\fs12}then it'll start faulting them in from the database.\r\nDialogue: 0,1:14:46.66,1:14:50.06,yin,,0,0,0,,这里隐藏有很多性能优化方面的内容\\N{\\fs12}So there's a lot of performance optimization going on behind the scenes\r\nDialogue: 0,1:14:50.06,1:14:51.78,yin,,0,0,0,,你现在并不需要知道\\N{\\fs12}that you don't really need to know about,\r\nDialogue: 0,1:14:51.78,1:14:53.32,yin,,0,0,0,,但获取会发生\\N{\\fs12}but faulting is happening,\r\nDialogue: 0,1:14:53.32,1:14:56.07,yin,,0,0,0,,有些专注数据库的人 可能对此感到担忧\\N{\\fs12}for those of you who are database heads and you're probably worried about this,\r\nDialogue: 0,1:14:56.07,1:14:59.95,yin,,0,0,0,,别担心 并非所有数据都从表格中取出了\\N{\\fs12}no worries, it's not actually pulling all that data out of those tables,\r\nDialogue: 0,1:14:59.95,1:15:03.24,yin,,0,0,0,,在访问过程中 你能获得它们\\N{\\fs12}it faults them in as you access them.\r\nDialogue: 0,1:15:03.24,1:15:06.85,yin,,0,0,0,,简单讲下Core Data线程安全\\N{\\fs12}Quick thing about core data thread safety.\r\nDialogue: 0,1:15:06.85,1:15:10.29,yin,,0,0,0,,NSManagedObjectContext并不线程安全 换言之\\N{\\fs12}NS-managed object is not thread safe, in other words,\r\nDialogue: 0,1:15:10.29,1:15:12.93,yin,,0,0,0,,你不能简单在多线程中用它\\N{\\fs12}you can't just use it in multiple threads,\r\nDialogue: 0,1:15:12.93,1:15:15.06,yin,,0,0,0,,不过你可以安全访问它们\\N{\\fs12}but you can safely access them.\r\nDialogue: 0,1:15:15.06,1:15:16.37,yin,,0,0,0,,大多数ManagedObject\\N{\\fs12}Most managed objects,\r\nDialogue: 0,1:15:16.37,1:15:19.49,yin,,0,0,0,,创建时都用了线程包含\\N{\\fs12}we create them with this kind of thread containment,\r\nDialogue: 0,1:15:19.49,1:15:22.17,yin,,0,0,0,,线程并发机制\\N{\\fs12}thread concurrency mechanism.\r\nDialogue: 0,1:15:22.17,1:15:24.90,yin,,0,0,0,,NSManagedObjectContext中有一个方法\\N{\\fs12}There's a method in NS-managed object context,\r\nDialogue: 0,1:15:24.90,1:15:27.39,yin,,0,0,0,,你会希望用到 叫performBlock\\N{\\fs12}which you will want to use, called perform block,\r\nDialogue: 0,1:15:27.39,1:15:29.78,yin,,0,0,0,,它没有参数 而是取一段代码\\N{\\fs12}it just takes a block with no arguments.\r\nDialogue: 0,1:15:29.78,1:15:34.17,yin,,0,0,0,,任何你希望对context做的事 插入对象 查询等等\\N{\\fs12}Anything you want to do on a context, inserting objects, querying, anything,\r\nDialogue: 0,1:15:34.17,1:15:36.91,yin,,0,0,0,,都可以在performBlock中执行\\N{\\fs12}do it inside a perform block.\r\nDialogue: 0,1:15:36.91,1:15:38.08,yin,,0,0,0,,为什么这样做呢\\N{\\fs12}Why do you do that?\r\nDialogue: 0,1:15:38.08,1:15:41.73,yin,,0,0,0,,它会对context在安全队列中执行\\N{\\fs12}It'll do it on the safe queue for that context,\r\nDialogue: 0,1:15:41.73,1:15:44.11,yin,,0,0,0,,这就确保了线程安全\\N{\\fs12}and it'll guaranteed to be safe, thread safe.\r\nDialogue: 0,1:15:44.11,1:15:46.44,yin,,0,0,0,,这个安全队列有可能是主队列\\N{\\fs12}Now, that safe queue might be the main queue,\r\nDialogue: 0,1:15:46.44,1:15:50.16,yin,,0,0,0,,因此 这并不一定能让你拥有多线程\\N{\\fs12}so this will not necessarily give you multithreaded.\r\nDialogue: 0,1:15:50.16,1:15:52.94,yin,,0,0,0,,但它会很安全 请养成这样做的习惯\\N{\\fs12}But it will be safe, so get in the habit of doing this,\r\nDialogue: 0,1:15:52.94,1:15:54.73,yin,,0,0,0,,或许以后哪一天\\N{\\fs12}because if you do come, come to a day\r\nDialogue: 0,1:15:54.73,1:15:56.51,yin,,0,0,0,,你就会使用NSManagedObjectContext\\N{\\fs12}when you're using NS-managed object context\r\nDialogue: 0,1:15:56.51,1:15:58.35,yin,,0,0,0,,并在不同队列上创建它们\\N{\\fs12}and you're creating them on different queues,\r\nDialogue: 0,1:15:58.35,1:16:00.01,yin,,0,0,0,,你可以在一个队列载入一个数据库\\N{\\fs12}so you can load the database in one queue\r\nDialogue: 0,1:16:00.01,1:16:01.58,yin,,0,0,0,,同时在另一个队列中查看\\N{\\fs12}while you look at another, whatever,\r\nDialogue: 0,1:16:01.58,1:16:02.56,yin,,0,0,0,,这都是可行的\\N{\\fs12}which is all doable,\r\nDialogue: 0,1:16:02.56,1:16:05.51,yin,,0,0,0,,你需要这个performBlock 至少这样做没有坏处\\N{\\fs12}you need to be doing this perform block, it doesn't hurt to do it,\r\nDialogue: 0,1:16:05.51,1:16:07.48,yin,,0,0,0,,我建议你们养成习惯这样做\\N{\\fs12}so might as well do it.\r\nDialogue: 0,1:16:07.48,1:16:10.46,yin,,0,0,0,,父上下文我没时间讲\\N{\\fs12}And parent context I don't have time to talk about.\r\nDialogue: 0,1:16:10.46,1:16:13.58,yin,,0,0,0,,实际上 Core Data还有很多东西我都没时间讲\\N{\\fs12}There is a ton other stuff, actually, in core data I don't have time to talk about\r\nDialogue: 0,1:16:13.58,1:16:15.22,yin,,0,0,0,,因为今天的课就快完了\\N{\\fs12}because we're at the end of lecture today.\r\nDialogue: 0,1:16:15.22,1:16:17.18,yin,,0,0,0,,乐观锁\\N{\\fs12}Optimistic locking,\r\nDialogue: 0,1:16:17.18,1:16:22.10,yin,,0,0,0,,回滚未保存状态变化 这很好理解\\N{\\fs12}rolling back unsaved changes to, you know, states that make sense,\r\nDialogue: 0,1:16:22.10,1:16:24.05,yin,,0,0,0,,撤销和重做我讲过\\N{\\fs12}undo and redo I talked about.\r\nDialogue: 0,1:16:24.05,1:16:26.96,yin,,0,0,0,,不刷新时间 也就是取回后数据要待多长时间\\N{\\fs12}Staleness, you do a fetch and it sits around for a long time,\r\nDialogue: 0,1:16:26.96,1:16:28.28,yin,,0,0,0,,而不被刷新\\N{\\fs12}the data could be stale,\r\nDialogue: 0,1:16:28.29,1:16:31.10,yin,,0,0,0,,一定时间后 需要重新取回\\N{\\fs12}it might need to be refetched, thrown out and refetched.\r\nDialogue: 0,1:16:31.10,1:16:34.63,yin,,0,0,0,,这里有很多东西 我都讲不了\\N{\\fs12}It just, a massive amount of stuff, can't talk about it.\r\nDialogue: 0,1:16:34.63,1:16:38.12,yin,,0,0,0,,从这里 你需要熟练掌握\\N{\\fs12}When you walk out of here, what you really want to be comfortable with is you know how\r\nDialogue: 0,1:16:38.12,1:16:41.95,yin,,0,0,0,,如何创建可视映射 插入对象 创建子类\\N{\\fs12}to create the visual map, insert objects, make the subclasses,\r\nDialogue: 0,1:16:41.95,1:16:46.46,yin,,0,0,0,,使用点符号来访问 删除对象 查询对象\\N{\\fs12}use dot notation to access them, delete objects, and query for them.\r\nDialogue: 0,1:16:46.46,1:16:50.03,yin,,0,0,0,,这就是Core Data基础 这就是我们今天的内容\\N{\\fs12}Okay, that's the fundamentals of core data, that's what we talked about today,\r\nDialogue: 0,1:16:50.03,1:16:53.19,yin,,0,0,0,,这就是你们需要从这门课中学到的\\N{\\fs12}that's what you should, need to know how to do for this class.\r\nDialogue: 0,1:16:53.19,1:16:55.83,yin,,0,0,0,,此外 你只需要知道还有很多内容\\N{\\fs12}And then outside of that, you just need to know that there's a lot more,\r\nDialogue: 0,1:16:55.83,1:16:57.72,yin,,0,0,0,,如果你要严肃了解数据库方面\\N{\\fs12}and if you're going to do serious database work,\r\nDialogue: 0,1:16:57.72,1:17:00.70,yin,,0,0,0,,这些都需要你自己去读\\N{\\fs12}you need to some reading up on that.\r\nDialogue: 0,1:17:00.70,1:17:02.27,yin,,0,0,0,,好 就这些了\\N{\\fs12}Okay, so that's it.\r\nDialogue: 0,1:17:02.27,1:17:05.79,yin,,0,0,0,,很抱歉我拖了几分钟堂 周三再见\\N{\\fs12}Sorry to keep you a couple minutes over and I will see you on Wednesday\r\nDialogue: 0,1:17:05.79,1:17:08.97,yin,,0,0,0,,到时会有一个大的演示\\N{\\fs12}with a big demo of all this stuff.\r\nDialogue: 0,1:17:08.97,1:17:12.68,yin,,0,0,0,,更多内容 请访问我校官网stanford.edu\\N{\\fs12}> For more, please visit us at stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/13. Core Data and Table View.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.2.0\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage]\r\nActive Line: 3\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:04.61,0:00:08.05,yin,,0,0,0,,斯坦福大学\\N{\\fs12}Stanford University\r\nDialogue: 0,0:00:10.75,0:00:17.96,yin,,0,0,0,,欢迎来到CS193P课程 2013-14秋季第13讲\\N{\\fs12}Welcome to number 13 of Stanford CS193p, the fall of 2013-14,\r\nDialogue: 0,0:00:17.96,0:00:21.47,yin,,0,0,0,,今天 我打算讲下期末项目的要求\\N{\\fs12}and today, I'm going to go over the requirements for your final project,\r\nDialogue: 0,0:00:21.47,0:00:24.20,yin,,0,0,0,,然后我将再用几张幻灯片\\N{\\fs12}and then I'm going to talk a little more, a few more slides\r\nDialogue: 0,0:00:24.20,0:00:25.65,yin,,0,0,0,,讲解Core Data\\N{\\fs12}about Core Data,\r\nDialogue: 0,0:00:25.65,0:00:28.15,yin,,0,0,0,,以及它如何同UITableView关联在一起\\N{\\fs12}and how it hooks up with UI TableView,\r\nDialogue: 0,0:00:28.15,0:00:29.81,yin,,0,0,0,,这两者可以说是天生一对\\N{\\fs12}because those two are a match made in heaven,\r\nDialogue: 0,0:00:29.81,0:00:36.00,yin,,0,0,0,,然后将是巨大的Core Data和TableView的演示\\N{\\fs12}and then I'm going to do this gigantic Core Data with TableViews demo.\r\nDialogue: 0,0:00:36.00,0:00:38.11,yin,,0,0,0,,期末项目\\N{\\fs12}Alright, so you're final projects.\r\nDialogue: 0,0:00:38.11,0:00:42.47,yin,,0,0,0,,期末项目分两阶段 第一阶段是提交提案\\N{\\fs12}There's kind of two phases to your final project; one is you have to submit a proposal\r\nDialogue: 0,0:00:42.47,0:00:43.81,yin,,0,0,0,,我们会审核\\N{\\fs12}for us, which we'll review.\r\nDialogue: 0,0:00:43.81,0:00:45.94,yin,,0,0,0,,我们审核的主要是范围\\N{\\fs12}We're mostly just reviewing it for scope,\r\nDialogue: 0,0:00:45.94,0:00:49.90,yin,,0,0,0,,确保你选的项目没有太大或是太小\\N{\\fs12}to make sure you haven't picked too big a project or too small a project.\r\nDialogue: 0,0:00:49.90,0:00:53.85,yin,,0,0,0,,我们不会去查看你提案中的每一个细节\\N{\\fs12}Okay, we're not, you know, looking in detail of every single thing you're going to do.\r\nDialogue: 0,0:00:53.85,0:00:56.39,yin,,0,0,0,,我们只打算检查你的大方向对不对\\N{\\fs12}We're just trying to make sure you're headed in the right direction.\r\nDialogue: 0,0:00:56.39,0:00:58.56,yin,,0,0,0,,在期末项目的过程中\\N{\\fs12}Because over the course of the final project,\r\nDialogue: 0,0:00:58.56,0:01:01.68,yin,,0,0,0,,你们将和我们进行交流 向我们提问题\\N{\\fs12}you're going to of course talk to us, and ask us questions and interact\r\nDialogue: 0,0:01:01.68,0:01:05.70,yin,,0,0,0,,过程中获得一些点子 最终很好地达成目的\\N{\\fs12}with us to kind of get an idea of getting, you know, hitting a good target at the end.\r\nDialogue: 0,0:01:05.71,0:01:08.66,yin,,0,0,0,,请快速完成这一阶段\\N{\\fs12}So, that is really, do immediate.\r\nDialogue: 0,0:01:08.66,0:01:11.39,yin,,0,0,0,,想好要做什么之后\\N{\\fs12}We'd like you to get us your proposal. If you know what you're going to do,\r\nDialogue: 0,0:01:11.39,0:01:13.89,yin,,0,0,0,,请尽快把提案交给我们\\N{\\fs12}please submit a proposal as soon as possible.\r\nDialogue: 0,0:01:13.89,0:01:17.92,yin,,0,0,0,,还没想好的人要快想 并尽快提交\\N{\\fs12}If you don't get on it right away, and submit it as soon as possible, really though\r\nDialogue: 0,0:01:17.92,0:01:21.28,yin,,0,0,0,,下周三将是提交的截止日期\\N{\\fs12}by next Wednesday would be the latest we'd want to hear from you.\r\nDialogue: 0,0:01:21.28,0:01:23.89,yin,,0,0,0,,我很不想这样 不过你们很多人\\N{\\fs12}And, I hate to say that, because I know a lot of you wait\r\nDialogue: 0,0:01:23.89,0:01:27.48,yin,,0,0,0,,都喜欢把事拖到最后一天再定 我很理解\\N{\\fs12}until the day before deadline to do anything, and I understand\r\nDialogue: 0,0:01:27.48,0:01:29.65,yin,,0,0,0,,但是这个提案需要越早越好\\N{\\fs12}that impulse, but this is something where you want to get\r\nDialogue: 0,0:01:29.65,0:01:33.02,yin,,0,0,0,,这样就算出现问题 我们也有时间找你\\N{\\fs12}that proposal in sooner, in case we have issues, and we can get back to you,\r\nDialogue: 0,0:01:33.02,0:01:36.19,yin,,0,0,0,,如果这个方案不行 你可以写一个新的提案\\N{\\fs12}and you either write, maybe come up with a whole new proposal if what you're thinking\r\nDialogue: 0,0:01:36.19,0:01:38.40,yin,,0,0,0,,如果这个方案不行 你可以写一个新的提案\\N{\\fs12}about is just not going to work.\r\nDialogue: 0,0:01:38.40,0:01:40.52,yin,,0,0,0,,然后第二阶段是期末项目本身\\N{\\fs12}Then the second phase is the final project itself,\r\nDialogue: 0,0:01:40.52,0:01:43.63,yin,,0,0,0,,这个项目的代码\\N{\\fs12}and that project, the code for the project,\r\nDialogue: 0,0:01:43.63,0:01:48.18,yin,,0,0,0,,还有关于项目的两分钟主题演讲幻灯片\\N{\\fs12}along with the keynote, set of keynote slides for a two minute presentation about your\r\nDialogue: 0,0:01:48.18,0:01:51.69,yin,,0,0,0,,定在12月6日周五交\\N{\\fs12}project are due on Friday, December 6.\r\nDialogue: 0,0:01:51.69,0:01:56.41,yin,,0,0,0,,看起来挺远的 有一个月时间\\N{\\fs12}So, that seems like that's far away, I know, that's over a month away, right.\r\nDialogue: 0,0:01:56.41,0:01:59.52,yin,,0,0,0,,现在是11月6日 但这中间有感恩节\\N{\\fs12}It's November 6 right now, but you got Thanksgiving in there,\r\nDialogue: 0,0:01:59.52,0:02:04.10,yin,,0,0,0,,其实并没有多长时间 这个期末项目\\N{\\fs12}so it's really not that far away, and so your final project,\r\nDialogue: 0,0:02:04.10,0:02:05.65,yin,,0,0,0,,同其它课中的一样\\N{\\fs12}like a final project in any class,\r\nDialogue: 0,0:02:05.65,0:02:07.76,yin,,0,0,0,,你有很多周时间来做\\N{\\fs12}where you get multiple weeks to do it, you do not want to wait\r\nDialogue: 0,0:02:07.76,0:02:10.38,yin,,0,0,0,,千万别等到最后一周才开始做\\N{\\fs12}to the last week to get started.\r\nDialogue: 0,0:02:10.38,0:02:11.81,yin,,0,0,0,,请尽快开始\\N{\\fs12}So, get started immediately.\r\nDialogue: 0,0:02:11.81,0:02:15.71,yin,,0,0,0,,到现在 创建一个应用程序所需的知识你们都已经学了\\N{\\fs12}You have everything you need now to start building an application.\r\nDialogue: 0,0:02:15.71,0:02:19.62,yin,,0,0,0,,对 期末项目不允许迟交\\N{\\fs12}Yeah, no late days on the final project at all. Simply will not accept it late.\r\nDialogue: 0,0:02:19.62,0:02:22.72,yin,,0,0,0,,12月6日午夜 做成怎样都得上交\\N{\\fs12}Whatever you have on December 6 at midnight, submit it.\r\nDialogue: 0,0:02:22.72,0:02:26.11,yin,,0,0,0,,因为我只接受这之前上交的东西\\N{\\fs12}I don't care what it is; submit it, because that's all. I'm not going to accept anything.\r\nDialogue: 0,0:02:26.11,0:02:28.44,yin,,0,0,0,,因为学生太多了\\N{\\fs12}I just can't, because I've got a lot of students\r\nDialogue: 0,0:02:28.44,0:02:31.26,yin,,0,0,0,,我要给所有人评分\\N{\\fs12}who are taking this for a grade especially, and that's a lot\r\nDialogue: 0,0:02:31.26,0:02:33.72,yin,,0,0,0,,要保证公平 我需要很长时间\\N{\\fs12}of time I have to be fair to those people, and also,\r\nDialogue: 0,0:02:33.72,0:02:35.83,yin,,0,0,0,,因此 我需要尽快开始评分\\N{\\fs12}I have to get started grading immediately.\r\nDialogue: 0,0:02:35.83,0:02:38.72,yin,,0,0,0,,你们的陈述将是两分钟\\N{\\fs12}The presentation that you're going to do, two minutes,\r\nDialogue: 0,0:02:38.72,0:02:44.47,yin,,0,0,0,,你需要给我们和同学们讲解项目的要点\\N{\\fs12}it's really just going to be pitching your project to us, to your fellow classmates.\r\nDialogue: 0,0:02:44.47,0:02:48.03,yin,,0,0,0,,你要把这想成争取风投资金\\N{\\fs12}If you can imagine, it's like you're trying to pitch a VC\r\nDialogue: 0,0:02:48.03,0:02:51.17,yin,,0,0,0,,让风投投资到你的公司或你的app\\N{\\fs12}to invest in your company or to do the app,\r\nDialogue: 0,0:02:51.17,0:02:53.56,yin,,0,0,0,,或者 你要说服别人买你的东西\\N{\\fs12}or you're just trying to get people to buy it, or whatever.\r\nDialogue: 0,0:02:53.56,0:02:55.65,yin,,0,0,0,,陈述要达到这个效果 具体的你们自己看着办\\N{\\fs12}It's that kind of presentation. I'll leave it up to you.\r\nDialogue: 0,0:02:55.65,0:02:58.28,yin,,0,0,0,,如果你想 你也可以实况演示程序\\N{\\fs12}You can certainly do a live demo if you want.\r\nDialogue: 0,0:02:58.28,0:03:03.98,yin,,0,0,0,,你需要iPhone 4S及以上或iPad 2及以上的设备\\N{\\fs12}You'll need iPhone 4S or later, or you'll need an iPad 2 or later, in order to hook\r\nDialogue: 0,0:03:03.98,0:03:09.61,yin,,0,0,0,,来使用这个奇妙的投影系统 使用Apple TV Mirroring\\N{\\fs12}up to this wonder projection system we have using Apple TV mirroring.\r\nDialogue: 0,0:03:09.61,0:03:12.60,yin,,0,0,0,,不过陈述并不一定要是实况演示\\N{\\fs12}But, you don't have to do a live demo.\r\nDialogue: 0,0:03:12.60,0:03:17.76,yin,,0,0,0,,实况演示很危险 我在课上就经常出错\\N{\\fs12}Live demos are perilous, as you can see, what I do each lecture,\r\nDialogue: 0,0:03:17.76,0:03:19.73,yin,,0,0,0,,不过实况演示很高效\\N{\\fs12}but they also kind of can be effective,\r\nDialogue: 0,0:03:19.73,0:03:22.76,yin,,0,0,0,,能够很好地展示你的app 你们自己决定\\N{\\fs12}and a really good way to show off your app, so it's kind of up to you.\r\nDialogue: 0,0:03:22.76,0:03:24.85,yin,,0,0,0,,项目陈述是必须的\\N{\\fs12}And, that presentation is required.\r\nDialogue: 0,0:03:24.85,0:03:26.57,yin,,0,0,0,,我还有一个备选陈述时间\\N{\\fs12}I will have an alternate presentation time,\r\nDialogue: 0,0:03:26.57,0:03:28.71,yin,,0,0,0,,也就是季度的最后一堂课\\N{\\fs12}which is the last lecture of the quarter,\r\nDialogue: 0,0:03:28.71,0:03:32.63,yin,,0,0,0,,也就是期末考时段前的那一周\\N{\\fs12}which is the week before the final exam period.\r\nDialogue: 0,0:03:32.63,0:03:36.54,yin,,0,0,0,,这是这个\\N{\\fs12}So, that's that.\r\nDialogue: 0,0:03:36.54,0:03:40.38,yin,,0,0,0,,程序大小是三周作业那么大的工作量\\N{\\fs12}Yeah, the scope is basically three weeks of homework worth of work.\r\nDialogue: 0,0:03:40.38,0:03:43.54,yin,,0,0,0,,你们现在应该知道这大概是多少\\N{\\fs12}You should know by now approximately what that is.\r\nDialogue: 0,0:03:43.54,0:03:46.15,yin,,0,0,0,,记得原来 学生需要同时通过作业\\N{\\fs12}Remember in the past when the people have to pass both the homework section\r\nDialogue: 0,0:03:46.15,0:03:47.38,yin,,0,0,0,,和期末项目\\N{\\fs12}and the final project separately.\r\nDialogue: 0,0:03:47.38,0:03:52.12,yin,,0,0,0,,你只要一个不合格 就算另一个得A 你也过不了这门课\\N{\\fs12}You can't bomb one, and get an A on the other, and pass this class.\r\nDialogue: 0,0:03:52.12,0:03:53.89,yin,,0,0,0,,期末项目需要能在硬件上奏效\\N{\\fs12}Your final project has to work on hardware.\r\nDialogue: 0,0:03:53.89,0:03:57.12,yin,,0,0,0,,你需要证明 可以是在2分钟的demo演示中\\N{\\fs12}You have to show it working, either in a demo in your two minutes,\r\nDialogue: 0,0:03:57.12,0:04:03.13,yin,,0,0,0,,如果没有2分钟demo演示 你就需要展示给助教\\N{\\fs12}or if you don't show a live demo in your two minutes, you have to show your TA.\r\nDialogue: 0,0:04:03.13,0:04:08.07,yin,,0,0,0,,只算iOS-SDK代码 如果你的app有后台\\N{\\fs12}Only iOS-SD code counts, so if your app has a backend,\r\nDialogue: 0,0:04:08.07,0:04:10.66,yin,,0,0,0,,某处有服务器 这方面你不会额外得分\\N{\\fs12}some server somewhere, you get no credit for any of that really.\r\nDialogue: 0,0:04:10.66,0:04:14.93,yin,,0,0,0,,你只能从iOS代码得分\\N{\\fs12}You're only getting credit for iOS code, okay.\r\nDialogue: 0,0:04:14.93,0:04:17.49,yin,,0,0,0,,有后台你可以模拟\\N{\\fs12}So, simulate your backend if you have to,\r\nDialogue: 0,0:04:17.49,0:04:20.61,yin,,0,0,0,,当然 其它某处有后台 那也没问题\\N{\\fs12}or if you have the backend from somewhere else, that's fine,\r\nDialogue: 0,0:04:20.61,0:04:23.74,yin,,0,0,0,,不过 不要浪费时间写非iOS代码\\N{\\fs12}but don't waste time doing non-iOS code\r\nDialogue: 0,0:04:23.74,0:04:27.06,yin,,0,0,0,,毕竟只有三周时间 非iOS代码没有任何额外加分\\N{\\fs12}in this three weeks, because you're not going to get any credit for that work.\r\nDialogue: 0,0:04:27.06,0:04:29.74,yin,,0,0,0,,评分将基于你对SDK的适当使用\\N{\\fs12}And, you'll be graded on your proper use of the SDK,\r\nDialogue: 0,0:04:29.74,0:04:35.87,yin,,0,0,0,,还有合适的面向对象编程以及代码优雅性\\N{\\fs12}and also proper object-oriented programming, and your aesthetics will matter.\r\nDialogue: 0,0:04:35.87,0:04:43.45,yin,,0,0,0,,不要写一大堆垃圾UI 这会让程序看起来很糟糕\\N{\\fs12}So, don't put a big junky-looking UI that just like, really looks terrible, and yeah,\r\nDialogue: 0,0:04:43.45,0:04:45.70,yin,,0,0,0,,别分心去写非iOS代码\\N{\\fs12}don't get sidetracked on non-iOS code.\r\nDialogue: 0,0:04:45.70,0:04:48.09,yin,,0,0,0,,这同之前讲的重复了\\N{\\fs12}That's kind of a repeat of all that slide there, so.\r\nDialogue: 0,0:04:48.09,0:04:53.62,yin,,0,0,0,,项目陈述质量也是评价范围 不过占比很小\\N{\\fs12}The presentation quality matters a tiny bit. It does matter.\r\nDialogue: 0,0:04:53.62,0:04:57.54,yin,,0,0,0,,有效陈述是一个很重要的技能\\N{\\fs12}Giving your presentation, effective presentation is a very important skill to have.\r\nDialogue: 0,0:04:57.54,0:05:00.81,yin,,0,0,0,,斯坦福学生毕业的时候都应该擅于演讲陈述\\N{\\fs12}All of you at Stanford should be good at that by the time you get\r\nDialogue: 0,0:05:00.81,0:05:02.84,yin,,0,0,0,,这里我又提供了一个机会\\N{\\fs12}out of here, so here's just another chance\r\nDialogue: 0,0:05:02.84,0:05:05.03,yin,,0,0,0,,让你练好的演讲陈述\\N{\\fs12}to really practice doing a good presentation.\r\nDialogue: 0,0:05:05.03,0:05:07.16,yin,,0,0,0,,计下时 看你花了多久\\N{\\fs12}Time it; see how long it's going to take.\r\nDialogue: 0,0:05:07.16,0:05:09.57,yin,,0,0,0,,演讲之前务必演练几次\\N{\\fs12}You know, run through it a couple times practicing.\r\nDialogue: 0,0:05:11.55,0:05:14.27,yin,,0,0,0,,提案中需要有两部分\\N{\\fs12}You proposal needs to have 2 sections in it.\r\nDialogue: 0,0:05:14.27,0:05:18.36,yin,,0,0,0,,第一部分是关于你做了什么的总体描述\\N{\\fs12}Okay, the first section is kind of an overall description. What am I doing?\r\nDialogue: 0,0:05:18.36,0:05:21.99,yin,,0,0,0,,这个用例子来讲最好 这里就是一个例子\\N{\\fs12}This is best shown by example, so I have this example here,\r\nDialogue: 0,0:05:21.99,0:05:24.06,yin,,0,0,0,,这是一个莎士比亚导演程序\\N{\\fs12}which is a Shakespeare Director App,\r\nDialogue: 0,0:05:24.06,0:05:29.21,yin,,0,0,0,,假设你是一家戏剧公司的导演\\N{\\fs12}so let's say you're a director at a theater company,\r\nDialogue: 0,0:05:29.21,0:05:31.81,yin,,0,0,0,,你要导演莎士比亚的戏剧\\N{\\fs12}and you're going to be direction some Shakespeare plays,\r\nDialogue: 0,0:05:31.81,0:05:33.30,yin,,0,0,0,,这个程序能够帮你\\N{\\fs12}and this is an app to help you do that.\r\nDialogue: 0,0:05:33.30,0:05:39.88,yin,,0,0,0,,它能设法从Folio数据库中找出一段莎士比亚戏剧\\N{\\fs12}And so, it has a way to bring up a Shakespeare play from the folio database,\r\nDialogue: 0,0:05:39.88,0:05:41.95,yin,,0,0,0,,然后进行布局\\N{\\fs12}and then you can lay out the blocking,\r\nDialogue: 0,0:05:41.95,0:05:44.06,yin,,0,0,0,,像场景设在哪里\\N{\\fs12}which is like where the scene is set up,\r\nDialogue: 0,0:05:44.06,0:05:48.10,yin,,0,0,0,,人站在哪 所有这些东西\\N{\\fs12}where the people are standing and all that stuff of each scene,\r\nDialogue: 0,0:05:48.10,0:05:51.29,yin,,0,0,0,,同对话保持一致\\N{\\fs12}lined up with the dialogue.\r\nDialogue: 0,0:05:51.29,0:05:54.17,yin,,0,0,0,,然后 它还有一个对话学习模式\\N{\\fs12}And then, it's also got a dialogue learning mode\r\nDialogue: 0,0:05:54.17,0:05:57.54,yin,,0,0,0,,给要学习对话的人 学习他们的对白\\N{\\fs12}for people who want to learn the dialogue, learn their lines.\r\nDialogue: 0,0:05:57.54,0:06:01.68,yin,,0,0,0,,它可以说出其它部分 你则需要说出你自己的部分\\N{\\fs12}It will say the other parts, and then you can say your own part.\r\nDialogue: 0,0:06:01.68,0:06:05.56,yin,,0,0,0,,这里描述的是程序能做什么\\N{\\fs12}So, you can see that this is kind of a description of what it does,\r\nDialogue: 0,0:06:05.58,0:06:08.52,yin,,0,0,0,,而不是你怎么做\\N{\\fs12}as opposed to how you're going to do it.\r\nDialogue: 0,0:06:08.52,0:06:12.47,yin,,0,0,0,,第二部分是 你要用哪些iOS部分来实现它\\N{\\fs12}Section 2 is what parts of iOS are you going to use to implement it.\r\nDialogue: 0,0:06:12.47,0:06:14.81,yin,,0,0,0,,它有TableView 使用自定义单元格\\N{\\fs12}Okay, it's going to have TableView with custom cells.\r\nDialogue: 0,0:06:14.81,0:06:16.37,yin,,0,0,0,,会用到摄像头\\N{\\fs12}It's going to use the camera.\r\nDialogue: 0,0:06:16.37,0:06:19.10,yin,,0,0,0,,有文本字段在弹窗里面\\N{\\fs12}It's going; you know text fields with in popovers.\r\nDialogue: 0,0:06:19.10,0:06:20.45,yin,,0,0,0,,用AVFoundation\\N{\\fs12}It's going to use AV foundation.\r\nDialogue: 0,0:06:20.45,0:06:21.86,yin,,0,0,0,,有NSTimer\\N{\\fs12}It's going to have NS Timer.\r\nDialogue: 0,0:06:21.86,0:06:22.89,yin,,0,0,0,,有Core Data\\N{\\fs12}It's going to have Core Data,\r\nDialogue: 0,0:06:22.89,0:06:24.76,yin,,0,0,0,,我的实体会在这里\\N{\\fs12}and where there are going to be my entities.\r\nDialogue: 0,0:06:24.76,0:06:29.57,yin,,0,0,0,,将对话这些东西打印到打印机\\N{\\fs12}It's going to print out the blocking things to printer,\r\nDialogue: 0,0:06:29.57,0:06:32.70,yin,,0,0,0,,这是我们课上没讲的东西\\N{\\fs12}which is something we don't cover in class.\r\nDialogue: 0,0:06:32.70,0:06:37.82,yin,,0,0,0,,我们要求你使用至少一种课上没讲过的特性\\N{\\fs12}And, you're required to have one feature, at least, that it was not covered in lecture.\r\nDialogue: 0,0:06:37.82,0:06:40.09,yin,,0,0,0,,这是给你们的一个任务\\N{\\fs12}Okay, and so that task is on there;\r\nDialogue: 0,0:06:40.09,0:06:42.46,yin,,0,0,0,,让你必须自己从说明文档中去学东西\\N{\\fs12}not only so you have to learn something from a documentation,\r\nDialogue: 0,0:06:42.46,0:06:45.20,yin,,0,0,0,,而不是都由我来给你们讲\\N{\\fs12}instead of my kind of getting you started with it,\r\nDialogue: 0,0:06:45.20,0:06:48.81,yin,,0,0,0,,这还能让你仔细去看iOS里面还有些什么\\N{\\fs12}but also so that you peruse all of iOS and find out what's in there.\r\nDialogue: 0,0:06:48.81,0:06:51.50,yin,,0,0,0,,不要找我问 你能否告诉我一个\\N{\\fs12}So, don't come to me and say, oh, can you tell me a feature\r\nDialogue: 0,0:06:51.50,0:06:54.19,yin,,0,0,0,,课堂上没讲的特性用于项目\\N{\\fs12}to do for non-iOS not covered in lecture?\r\nDialogue: 0,0:06:54.19,0:06:56.06,yin,,0,0,0,,要知道 这就是你任务的一部分\\N{\\fs12}It's like, that's part of the task for you to go figure\r\nDialogue: 0,0:06:56.06,0:06:58.50,yin,,0,0,0,,去找找并选出某些特性\\N{\\fs12}out what's out there and pick something.\r\nDialogue: 0,0:06:58.52,0:07:01.85,yin,,0,0,0,,这就是提案中需要包括的两大部分\\N{\\fs12}So, that's what your proposal needs to have, these two sections.\r\nDialogue: 0,0:07:01.85,0:07:03.00,yin,,0,0,0,,你要做什么\\N{\\fs12}What it is you're opting to do,\r\nDialogue: 0,0:07:03.00,0:07:07.91,yin,,0,0,0,,你要用到哪些已经学过的iOS API\\N{\\fs12}and then what iOS APIs you're going to use that you know of right now to implement.\r\nDialogue: 0,0:07:11.53,0:07:13.04,yin,,0,0,0,,这里有一些注释\\N{\\fs12}And, here's some notes,\r\nDialogue: 0,0:07:13.04,0:07:15.60,yin,,0,0,0,,这些幻灯片 你们都可以在线下重新看\\N{\\fs12}again, you're going to review these slides offline to feel\r\nDialogue: 0,0:07:15.60,0:07:19.02,yin,,0,0,0,,看怎么写一份好的提案\\N{\\fs12}really get a good for what makes a good proposal,\r\nDialogue: 0,0:07:19.02,0:07:22.09,yin,,0,0,0,,你还可以到Piazza上要求我们进一步阐明\\N{\\fs12}and you can ask on Piazza for clarifications, etc.\r\nDialogue: 0,0:07:22.09,0:07:26.39,yin,,0,0,0,,下面我要讲的还是Core Data\\N{\\fs12}Okay, so, the next topic I want to talk about is Core Data still,\r\nDialogue: 0,0:07:26.39,0:07:30.74,yin,,0,0,0,,关于Core Data与TableView如何共同协作\\N{\\fs12}but its Core Data and TableView. How Core Data and TableView go together.\r\nDialogue: 0,0:07:30.74,0:07:33.52,yin,,0,0,0,,Core Data是一系列对象\\N{\\fs12}Because Core Data is a bunch of, you know, objects,\r\nDialogue: 0,0:07:33.52,0:07:35.11,yin,,0,0,0,,一个大的对象图\\N{\\fs12}a big object graph,\r\nDialogue: 0,0:07:35.12,0:07:40.36,yin,,0,0,0,,而TableView在遍历对象图方面很擅长\\N{\\fs12}and TableViews are really good for traversing through object graphs.\r\nDialogue: 0,0:07:40.36,0:07:41.84,yin,,0,0,0,,怎么做呢\\N{\\fs12}So, how do we do this?\r\nDialogue: 0,0:07:41.84,0:07:43.84,yin,,0,0,0,,iOS中有一个很好的类\\N{\\fs12}There's a great class in iOS\r\nDialogue: 0,0:07:43.84,0:07:46.29,yin,,0,0,0,,叫NSFetchedResultsController(取回结果控制器)\\N{\\fs12}called NSFetched Results Controller.\r\nDialogue: 0,0:07:46.29,0:07:50.49,yin,,0,0,0,,这个类的唯一作用是将一个NSFetchRequest\\N{\\fs12}This class' only purpose in life is to link an NSFetchRequest,\r\nDialogue: 0,0:07:50.49,0:07:52.85,yin,,0,0,0,,这是两天前的内容 但愿你们记得\\N{\\fs12}which hopefully you'll remember from two days' ago lecture\r\nDialogue: 0,0:07:52.85,0:07:55.93,yin,,0,0,0,,和一个UITableView关联起来\\N{\\fs12}with a UI TableView. That's what it does,\r\nDialogue: 0,0:07:55.93,0:07:59.54,yin,,0,0,0,,它的作用是将这两者关联起来 这样一来\\N{\\fs12}it basically bonds those two things together, so that\r\nDialogue: 0,0:07:59.54,0:08:02.65,yin,,0,0,0,,Fetch取回的任何东西都总会显示在TableView中\\N{\\fs12}the Fetch; anything that Fetch would be fetching is always showing in the TableView,\r\nDialogue: 0,0:08:02.65,0:08:06.02,yin,,0,0,0,,哪怕数据库在FetchRequest之下发生改变\\N{\\fs12}even if the database is changing underneath that FetchRequest.\r\nDialogue: 0,0:08:06.02,0:08:08.24,yin,,0,0,0,,它仍然会更新TableView\\N{\\fs12}Okay, it's still going to be updating the TableView.\r\nDialogue: 0,0:08:08.24,0:08:13.31,yin,,0,0,0,,工作方式方面 FetchedResultsController有两部分\\N{\\fs12}So, the way this works, it's really two parts for the Fetched Results Controller.\r\nDialogue: 0,0:08:13.31,0:08:14.43,yin,,0,0,0,,一是 它回答了\\N{\\fs12}One is it answers\r\nDialogue: 0,0:08:14.43,0:08:17.40,yin,,0,0,0,,UITableViewDataSource协议中的所有问题\\N{\\fs12}all the questions in the UI-TableView data source protocol,\r\nDialogue: 0,0:08:17.40,0:08:20.25,yin,,0,0,0,,例如有多少行 多少section\\N{\\fs12}like how many sections, how many rows and sections,\r\nDialogue: 0,0:08:20.25,0:08:22.63,yin,,0,0,0,,甚至一些你们不知道的进阶问题\\N{\\fs12}and even some ones that you don't know about, some more advanced ones.\r\nDialogue: 0,0:08:22.63,0:08:24.37,yin,,0,0,0,,这些它都回答了\\N{\\fs12}It answers those questions as well.\r\nDialogue: 0,0:08:24.37,0:08:28.98,yin,,0,0,0,,它可以使用这样的代码回答所有这些问题\\N{\\fs12}So, it's able to answer all those questions, using code kind of like that.\r\nDialogue: 0,0:08:28.98,0:08:33.10,yin,,0,0,0,,此外 它还能在任何给定时刻告诉你\\N{\\fs12}Also, it can tell you at any given time,\r\nDialogue: 0,0:08:33.10,0:08:39.77,yin,,0,0,0,,数据库中的什么实体显示在给定行中\\N{\\fs12}what thing in your database, what entity in your database is being shown in a given row.\r\nDialogue: 0,0:08:39.77,0:08:44.38,yin,,0,0,0,,表格中的行同数据库中的对象之间有一一映射关系\\N{\\fs12}There's a one to one mapping between a row in the table and some object in the database.\r\nDialogue: 0,0:08:44.38,0:08:49.03,yin,,0,0,0,,我们知道进行FetchRequest时 只会返回特定类型的对象\\N{\\fs12}Alright, of course we know when you do a FetchRequest, it can only return objects\r\nDialogue: 0,0:08:49.03,0:08:51.00,yin,,0,0,0,,一个对象的数组\\N{\\fs12}of a certain kind; an array of objects.\r\nDialogue: 0,0:08:51.00,0:08:52.68,yin,,0,0,0,,这会让你得到它\\N{\\fs12}And so, this will let you get it.\r\nDialogue: 0,0:08:52.68,0:08:56.44,yin,,0,0,0,,理解这个方法很重要 也就是objectAtIndexPath\\N{\\fs12}And, it's a very important method to understand, which is objectAtIndexPath.\r\nDialogue: 0,0:08:56.44,0:08:58.63,yin,,0,0,0,,你将这发给FetchedResultsController\\N{\\fs12}Okay, you send that to the Fetched Results Controller,\r\nDialogue: 0,0:08:58.63,0:09:02.57,yin,,0,0,0,,它会返回一个Photo *给你 或Photographer\\N{\\fs12}and it will return you a photo star, or a photograph photographer star\r\nDialogue: 0,0:09:02.57,0:09:06.41,yin,,0,0,0,,或某个NSManagedObject * 这是那一行处的对象\\N{\\fs12}or some NS Managed ObjectStar, which is the object that's at that row,\r\nDialogue: 0,0:09:06.41,0:09:08.31,yin,,0,0,0,,然后你可以抽出属性\\N{\\fs12}and then you can pull out the attributes,\r\nDialogue: 0,0:09:08.31,0:09:10.78,yin,,0,0,0,,将它们放到UITableViewCell\\N{\\fs12}and put them in to your UI-TableView cell\r\nDialogue: 0,0:09:10.78,0:09:13.00,yin,,0,0,0,,使用cellForRowAtIndexPath\\N{\\fs12}in cellForRowAtIndexPath.\r\nDialogue: 0,0:09:13.00,0:09:15.69,yin,,0,0,0,,理解这个方法很重要\\N{\\fs12}It's really important to understand that method.\r\nDialogue: 0,0:09:15.69,0:09:19.92,yin,,0,0,0,,如何创建这种NSFetchedResultsController呢\\N{\\fs12}How to you create one of these NS Fetched Results Controller.\r\nDialogue: 0,0:09:19.92,0:09:22.46,yin,,0,0,0,,它的alloc init是这样的\\N{\\fs12}Okay, its Allocinit looks like this.\r\nDialogue: 0,0:09:22.46,0:09:25.76,yin,,0,0,0,,它取一个FetchRequest 一个context\\N{\\fs12}It takes a FetchRequest, a context.\r\nDialogue: 0,0:09:25.76,0:09:28.63,yin,,0,0,0,,这显然是我们要进行取回的位置\\N{\\fs12}That's obvious where we're going to be doing the fetching.\r\nDialogue: 0,0:09:28.65,0:09:31.02,yin,,0,0,0,,它还可以处理section header\\N{\\fs12}It will even do section headers,\r\nDialogue: 0,0:09:31.02,0:09:33.48,yin,,0,0,0,,你指定你要取回的对象中\\N{\\fs12}so you specify which attribute in the objects\r\nDialogue: 0,0:09:33.48,0:09:36.30,yin,,0,0,0,,哪个属性是section的名称\\N{\\fs12}that you're fetching is the section, the name of the section,\r\nDialogue: 0,0:09:36.30,0:09:38.47,yin,,0,0,0,,然后它会将表格分成section\\N{\\fs12}and then it will divide the table into sections.\r\nDialogue: 0,0:09:38.47,0:09:40.55,yin,,0,0,0,,它还可以进行缓存\\N{\\fs12}And, it can also do caching, okay, so we'll talk\r\nDialogue: 0,0:09:40.55,0:09:42.63,yin,,0,0,0,,等下我会讲到后面那两点\\N{\\fs12}about those last two things in a minute here.\r\nDialogue: 0,0:09:42.63,0:09:45.98,yin,,0,0,0,,先看我们要创建哪种FetchRequest\\N{\\fs12}But, let's take a look at what kind of FetchRequest we might create\r\nDialogue: 0,0:09:45.98,0:09:48.80,yin,,0,0,0,,并放入到FetchedResultsController\\N{\\fs12}to put into a Fetched Requests Controller,\r\nDialogue: 0,0:09:48.80,0:09:52.81,yin,,0,0,0,,这里我创建了一个照片请求 我要取回照片\\N{\\fs12}so here I'm creating a photo request, so I'm going to be fetching photos.\r\nDialogue: 0,0:09:52.81,0:09:54.31,yin,,0,0,0,,我需要一个排序描述器\\N{\\fs12}I need a sort descriptor\r\nDialogue: 0,0:09:54.31,0:09:57.41,yin,,0,0,0,,说明这些照片在TableView是什么顺序\\N{\\fs12}that says what order these photos are going to be in in the TableView,\r\nDialogue: 0,0:09:57.41,0:09:59.96,yin,,0,0,0,,假设我要按标题排序\\N{\\fs12}so I'll sort them by their title, let's say.\r\nDialogue: 0,0:09:59.96,0:10:01.27,yin,,0,0,0,,然后是谓词\\N{\\fs12}And, then a predicate.\r\nDialogue: 0,0:10:01.27,0:10:04.87,yin,,0,0,0,,我想取回的所有照片满足\\N{\\fs12}I'm going to get all the photos\r\nDialogue: 0,0:10:04.87,0:10:08.70,yin,,0,0,0,,具有给定名字为photogName的拍照者\\N{\\fs12}that were taken by a photographer with a given name, photogName.\r\nDialogue: 0,0:10:08.70,0:10:10.05,yin,,0,0,0,,这就指明了谓词\\N{\\fs12}Okay, so I just specify the predicate.\r\nDialogue: 0,0:10:10.05,0:10:12.85,yin,,0,0,0,,我这里只是创建了一个普通的NSFetchRequest\\N{\\fs12}So, you I just basically create a normal NS FetchRequest,\r\nDialogue: 0,0:10:12.85,0:10:17.53,yin,,0,0,0,,然后我使用这个FetchedResultsController alloc\\N{\\fs12}and then I just do this FetchedResultsController alloc,\r\nDialogue: 0,0:10:17.53,0:10:19.13,yin,,0,0,0,,FetchRequest context\\N{\\fs12}FetchRequest context,\r\nDialogue: 0,0:10:19.14,0:10:21.14,yin,,0,0,0,,sectionNameKeyPath和cache\\N{\\fs12}section key name and cache.\r\nDialogue: 0,0:10:21.14,0:10:23.64,yin,,0,0,0,,就这么简单\\N{\\fs12}It's as simple as that.\r\nDialogue: 0,0:10:23.64,0:10:26.29,yin,,0,0,0,,然后讲下最后两项\\N{\\fs12}Now, oh, yeah, so, those last two items.\r\nDialogue: 0,0:10:26.29,0:10:31.25,yin,,0,0,0,,cache 关于缓存的有一点 如果你指定nil 它不会缓存\\N{\\fs12}The cache by way, one thing about the cache, if you specify nil, it won't cache.\r\nDialogue: 0,0:10:31.25,0:10:34.96,yin,,0,0,0,,缓存是说 它会缓存取回的结果\\N{\\fs12}Caching means that it will cache the results of that fetch\r\nDialogue: 0,0:10:34.96,0:10:36.51,yin,,0,0,0,,在你app启动之间\\N{\\fs12}between launching of your app.\r\nDialogue: 0,0:10:36.53,0:10:39.26,yin,,0,0,0,,换言之 它会永久性地在磁盘上进行缓存\\N{\\fs12}In other words, it will permanently, you know, on disc, cache it.\r\nDialogue: 0,0:10:39.26,0:10:40.88,yin,,0,0,0,,而不是在内存中缓存\\N{\\fs12}This is not caching it in memory.\r\nDialogue: 0,0:10:40.90,0:10:42.94,yin,,0,0,0,,这里总是内存内的缓存\\N{\\fs12}You know, it's always going to do it in memory caching.\r\nDialogue: 0,0:10:42.94,0:10:44.12,yin,,0,0,0,,Core Data会这样\\N{\\fs12}Core Data does that.\r\nDialogue: 0,0:10:44.12,0:10:45.66,yin,,0,0,0,,这是在启动之间\\N{\\fs12}So, this will make so between launches,\r\nDialogue: 0,0:10:45.66,0:10:49.64,yin,,0,0,0,,它会有结果缓存 但如果你设置它为非nil\\N{\\fs12}it has this result cached, but if you set that to non-Nil,\r\nDialogue: 0,0:10:49.64,0:10:52.89,yin,,0,0,0,,你最好让FetchRequest保持完全一样\\N{\\fs12}okay, you better keep your FetchRequest exactly the same.\r\nDialogue: 0,0:10:52.89,0:10:55.35,yin,,0,0,0,,如果FetchRequest中改了任何东西\\N{\\fs12}If you change anything about your FetchRequest, and come back\r\nDialogue: 0,0:10:55.35,0:10:57.99,yin,,0,0,0,,然后尝试使用缓存 它就会失效\\N{\\fs12}and try to use your cache, it's going to fail.\r\nDialogue: 0,0:10:57.99,0:11:02.84,yin,,0,0,0,,这只针对总有相同FetchRequest的TableView\\N{\\fs12}So, this is only really for TableViews that have the same Fetch Request all the time,\r\nDialogue: 0,0:11:02.84,0:11:04.83,yin,,0,0,0,,完全相同的谓词和描述器\\N{\\fs12}exact same predicates or descriptors.\r\nDialogue: 0,0:11:04.83,0:11:06.20,yin,,0,0,0,,一切都相同\\N{\\fs12}Everything's the same.\r\nDialogue: 0,0:11:06.20,0:11:10.60,yin,,0,0,0,,如果你要使用sectionNameKeyPath\\N{\\fs12}If you're going to use that section key thing,\r\nDialogue: 0,0:11:10.60,0:11:12.63,yin,,0,0,0,,尝试把section放到TableView中\\N{\\fs12}try and put sections in your table view,\r\nDialogue: 0,0:11:12.63,0:11:15.24,yin,,0,0,0,,排序描述器就需要匹配section键\\N{\\fs12}the sort descriptors have to match up with the section keys.\r\nDialogue: 0,0:11:15.24,0:11:16.94,yin,,0,0,0,,换言之 表中的行\\N{\\fs12}In other words, the rows in the table,\r\nDialogue: 0,0:11:16.94,0:11:18.27,yin,,0,0,0,,你取回的照片\\N{\\fs12}the photos that you fetch,\r\nDialogue: 0,0:11:18.27,0:11:21.33,yin,,0,0,0,,必须和section header具有相同顺序\\N{\\fs12}have to be in the exact same order that section headers would be,\r\nDialogue: 0,0:11:21.33,0:11:23.45,yin,,0,0,0,,这是一个常规的TableView东西\\N{\\fs12}and this is a normal TableView thing, right?\r\nDialogue: 0,0:11:23.45,0:11:25.86,yin,,0,0,0,,section header总要同行使用相同顺序\\N{\\fs12}The section headers always have to be in the same order as the rows.\r\nDialogue: 0,0:11:25.86,0:11:27.41,yin,,0,0,0,,这里也是一样\\N{\\fs12}Well, that's true here too.\r\nDialogue: 0,0:11:27.41,0:11:30.78,yin,,0,0,0,,几乎总有 你的第一个排序描述器\\N{\\fs12}So, almost always, your first sort descriptor will be the\r\nDialogue: 0,0:11:30.78,0:11:32.26,yin,,0,0,0,,是section键header\\N{\\fs12}section key header,\r\nDialogue: 0,0:11:32.26,0:11:35.71,yin,,0,0,0,,确保一切都是按照相同顺序排序\\N{\\fs12}to make sure everything is sorting in the same order.\r\nDialogue: 0,0:11:37.14,0:11:39.93,yin,,0,0,0,,FetchedResultsController还有一个委托\\N{\\fs12}The Fetched Results Controller also has a delegate,\r\nDialogue: 0,0:11:39.93,0:11:44.25,yin,,0,0,0,,使用这个委托 它能监视Core Data中发生的事情\\N{\\fs12}and using that delegate, it can watch what's happening in Core Data,\r\nDialogue: 0,0:11:44.25,0:11:47.76,yin,,0,0,0,,当有东西变化时 FetchRequest会受影响\\N{\\fs12}and when something changes that would affect your FetchRequest,\r\nDialogue: 0,0:11:47.76,0:11:50.89,yin,,0,0,0,,你的表格会变化 这是很了不起\\N{\\fs12}it will change your table, which is incredibly cool.\r\nDialogue: 0,0:11:50.89,0:11:52.87,yin,,0,0,0,,也就是说 如果你添加一张照片\\N{\\fs12}Okay, that means if you added a photo,\r\nDialogue: 0,0:11:52.87,0:11:54.95,yin,,0,0,0,,它匹配你的FetchRequest\\N{\\fs12}and if it would have matched your FetchRequest,\r\nDialogue: 0,0:11:54.95,0:11:56.34,yin,,0,0,0,,表格中也会随之增加一行\\N{\\fs12}it will add a row to the table,\r\nDialogue: 0,0:11:56.34,0:11:58.05,yin,,0,0,0,,你什么都不用做 因为它在监视\\N{\\fs12}and you don't have to do anything, because it's watching.\r\nDialogue: 0,0:11:58.05,0:12:01.47,yin,,0,0,0,,它在使用NSObjectManagedContext\\N{\\fs12}It's using that NS Object Managed Context,\r\nDialogue: 0,0:12:01.47,0:12:05.06,yin,,0,0,0,,didChangeObject广播站 它在监听这个\\N{\\fs12}objects did change radio station, it's listening to that,\r\nDialogue: 0,0:12:05.06,0:12:08.25,yin,,0,0,0,,它会用这样的方法相应做出变化\\N{\\fs12}and it's changing it with methods like this.\r\nDialogue: 0,0:12:08.25,0:12:09.44,yin,,0,0,0,,这里有两点\\N{\\fs12}So, there's really two things\r\nDialogue: 0,0:12:09.44,0:12:12.18,yin,,0,0,0,,来让FetchedResultsController同表格关联起来\\N{\\fs12}to get a Fetched Request Controller hooked up to your table.\r\nDialogue: 0,0:12:12.18,0:12:13.24,yin,,0,0,0,,一是使用它\\N{\\fs12}One is, you've got to use it\r\nDialogue: 0,0:12:13.24,0:12:15.44,yin,,0,0,0,,实现所有UITableViewDataSource的东西\\N{\\fs12}to implement all those UI-TableView data source things,\r\nDialogue: 0,0:12:15.44,0:12:17.08,yin,,0,0,0,,二是设置它的委托\\N{\\fs12}and two, is you've got to set its delegate,\r\nDialogue: 0,0:12:17.08,0:12:19.87,yin,,0,0,0,,然后使用所有这些方法来监视\\N{\\fs12}and then use all these methods to have it watch,\r\nDialogue: 0,0:12:19.87,0:12:21.56,yin,,0,0,0,,不过我帮了你们一把\\N{\\fs12}but we've made that easy for you.\r\nDialogue: 0,0:12:21.56,0:12:24.66,yin,,0,0,0,,我创建了一个类叫CoreDataTableViewController\\N{\\fs12}I've created a class called Core Data TableView Controller,\r\nDialogue: 0,0:12:24.66,0:12:26.83,yin,,0,0,0,,我会把它发给你们\\N{\\fs12}and I'm going to make it available to you.\r\nDialogue: 0,0:12:26.83,0:12:30.64,yin,,0,0,0,,它会做到上述两件事 欢迎你们看看它的实现\\N{\\fs12}All it does it those two things, and you're welcome to look at the implementation of it.\r\nDialogue: 0,0:12:30.64,0:12:32.51,yin,,0,0,0,,几乎都是一行代码\\N{\\fs12}It's all pretty much just one liners\r\nDialogue: 0,0:12:32.51,0:12:37.47,yin,,0,0,0,,使用FetchedResultsController来实现数据源\\N{\\fs12}that are just using the Fetched Results Controller to implement the data source,\r\nDialogue: 0,0:12:37.47,0:12:39.86,yin,,0,0,0,,然后做这些委托的事情\\N{\\fs12}and to do the delegate business.\r\nDialogue: 0,0:12:41.86,0:12:46.67,yin,,0,0,0,,使用FetchedResultsController时你只需要知道\\N{\\fs12}And, the only thing you need to know to use Core Data TableView Controller,\r\nDialogue: 0,0:12:46.67,0:12:49.85,yin,,0,0,0,,它有一个属性叫fetchResultsController\\N{\\fs12}it has a property called Fetch Results Controller\r\nDialogue: 0,0:12:49.85,0:12:54.12,yin,,0,0,0,,你把这个设为一个FetchedResultsController就行了\\N{\\fs12}and you just set that to a Fetch Results Controller, and it will just work.\r\nDialogue: 0,0:12:54.12,0:12:55.50,yin,,0,0,0,,不需要做别的事了\\N{\\fs12}Nothing else required to do.\r\nDialogue: 0,0:12:55.50,0:12:59.03,yin,,0,0,0,,设定这个后 CoreDataTableViewController就会\\N{\\fs12}You just set that, and Core Data TableView Controlled will then\r\nDialogue: 0,0:12:59.03,0:13:01.19,yin,,0,0,0,,使用它来回答所有的数据源问题\\N{\\fs12}use it to answer all those data source questions,\r\nDialogue: 0,0:13:01.19,0:13:03.75,yin,,0,0,0,,并设置FetchedResultsController的委托\\N{\\fs12}and also it will set the delegates of the Fetched Results Controller,\r\nDialogue: 0,0:13:03.75,0:13:06.28,yin,,0,0,0,,让它合适地监视数据库\\N{\\fs12}and make it so it watches the database properly.\r\nDialogue: 0,0:13:07.67,0:13:09.59,yin,,0,0,0,,这会在你们的作业中出现\\N{\\fs12}So, that will be included in your homework.\r\nDialogue: 0,0:13:09.59,0:13:12.69,yin,,0,0,0,,作业中要用到 今天的演示或许也会用到\\N{\\fs12}You will definitely want that for your homework. I will be using that in the demo today.\r\nDialogue: 0,0:13:12.69,0:13:14.40,yin,,0,0,0,,好 讲到演示\\N{\\fs12}Alright, so speaking of the demo.\r\nDialogue: 0,0:13:14.40,0:13:16.21,yin,,0,0,0,,这是一个很大的演示\\N{\\fs12}This is a huge demo.\r\nDialogue: 0,0:13:16.21,0:13:18.26,yin,,0,0,0,,或许我都做不完\\N{\\fs12}I may not get all the way through it.\r\nDialogue: 0,0:13:18.26,0:13:20.56,yin,,0,0,0,,其中包含了一些课上还没讲到的东西\\N{\\fs12}It covers some things that I haven't covered in lecture yet,\r\nDialogue: 0,0:13:20.56,0:13:21.60,yin,,0,0,0,,这是故意的\\N{\\fs12}and that's kind of intentionally.\r\nDialogue: 0,0:13:21.60,0:13:23.10,yin,,0,0,0,,只有这一讲中我这样做了\\N{\\fs12}This is the only lecture I really do that,\r\nDialogue: 0,0:13:23.10,0:13:25.04,yin,,0,0,0,,我只是想给你们展示一些\\N{\\fs12}but I just wanted to kind of show you some things\r\nDialogue: 0,0:13:25.04,0:13:27.25,yin,,0,0,0,,我不想专门花课上时间讲解的东西\\N{\\fs12}that I didn't really want to spend lecture time on.\r\nDialogue: 0,0:13:27.25,0:13:30.28,yin,,0,0,0,,以后的课上我可能会回顾这些 无论如何\\N{\\fs12}I might come back to these in future lecture, but anyway,\r\nDialogue: 0,0:13:30.28,0:13:31.96,yin,,0,0,0,,这里有很多东西要讲\\N{\\fs12}there's a lot, lot there to cover,\r\nDialogue: 0,0:13:31.96,0:13:33.37,yin,,0,0,0,,而你们有这些幻灯片可以用\\N{\\fs12}and you have these slides in front of you.\r\nDialogue: 0,0:13:33.37,0:13:35.63,yin,,0,0,0,,但愿你们能够看清这个列表\\N{\\fs12}Hopefully you can see what the list there is.\r\nDialogue: 0,0:13:35.63,0:13:39.17,yin,,0,0,0,,等下我就不开幻灯片了 先看以后的展望\\N{\\fs12}I'm not going to back to the slide, so coming up;\r\nDialogue: 0,0:13:39.17,0:13:41.09,yin,,0,0,0,,今天是最后一次作业\\N{\\fs12}today's your last homework.\r\nDialogue: 0,0:13:41.09,0:13:45.69,yin,,0,0,0,,我们有Instruments要讲 它是Xcode的性能监控助手\\N{\\fs12}We have an instrument, which is performance monitoring adjunct\r\nDialogue: 0,0:13:45.69,0:13:48.35,yin,,0,0,0,,我们会在周五课外辅导讲到 然后下周\\N{\\fs12}to X code on Friday's section, and then next week,\r\nDialogue: 0,0:13:48.35,0:13:49.90,yin,,0,0,0,,我们会简单谈到多任务处理\\N{\\fs12}we're going to talk a little bit about multitasking.\r\nDialogue: 0,0:13:49.90,0:13:53.50,yin,,0,0,0,,我会更多讲到 因为今天演示中我会谈到一些\\N{\\fs12}I say more multitasking, because I'm going to do some of that in the demo today,\r\nDialogue: 0,0:13:53.50,0:13:56.62,yin,,0,0,0,,然后我们会讲一些更进阶的segue\\N{\\fs12}and then we're going to do some more advancing segue.\r\nDialogue: 0,0:13:56.62,0:13:59.78,yin,,0,0,0,,我们之前所讲的segue只是\\N{\\fs12}So far the only segueing we've done is,\r\nDialogue: 0,0:13:59.78,0:14:02.53,yin,,0,0,0,,UINavigationController push segue\\N{\\fs12}UI-Navigation Controller pushed segues basically,\r\nDialogue: 0,0:14:02.53,0:14:05.89,yin,,0,0,0,,之后我还讲了一点iPad replace segue\\N{\\fs12}and then also, we talked a little bit about iPad replace segues,\r\nDialogue: 0,0:14:05.89,0:14:08.64,yin,,0,0,0,,替换掉整个detail视图 这个segue比较奇特\\N{\\fs12}where you replace the entire detail view, which is kind of a weird segue.\r\nDialogue: 0,0:14:08.64,0:14:12.43,yin,,0,0,0,,以后我们还会谈到更多的segue\\N{\\fs12}We're going to talk about some more kinds of segues that we can do as well.\r\nDialogue: 0,0:14:12.43,0:14:16.34,yin,,0,0,0,,或许下周 或许下下周 我们还会讲到MapKit\\N{\\fs12}And, maybe we'll get to Mapkit next week or maybe the week after.\r\nDialogue: 0,0:14:17.76,0:14:21.54,yin,,0,0,0,,在进入这个巨型demo之前 有任何问题吗\\N{\\fs12}Alright, any questions before I dive into this monster demo?\r\nDialogue: 0,0:14:21.54,0:14:23.12,yin,,0,0,0,,请随时打断我\\N{\\fs12}Okay, feel free to stop me.\r\nDialogue: 0,0:14:23.12,0:14:24.97,yin,,0,0,0,,demo进行时 我经常都在打字\\N{\\fs12}A lot of time when I'm demo, I'm typing away,\r\nDialogue: 0,0:14:24.97,0:14:27.92,yin,,0,0,0,,没注意到你们举手 你们可以大声叫出来\\N{\\fs12}I'm not seeing you raise your hand, so feel free to shout out.\r\nDialogue: 0,0:14:29.37,0:14:32.82,yin,,0,0,0,,这里我要创建一个新项目\\N{\\fs12}So, I'm going to create a new project here, and I'm going\r\nDialogue: 0,0:14:32.82,0:14:34.75,yin,,0,0,0,,我要用单视图应用\\N{\\fs12}to do single view application, even though I'm going\r\nDialogue: 0,0:14:34.75,0:14:37.58,yin,,0,0,0,,我要用Core Data 我说过你可以点这个\\N{\\fs12}to use Core Data, and I told you that if you click on this one,\r\nDialogue: 0,0:14:37.58,0:14:39.67,yin,,0,0,0,,你可以看到一些生成的Core Data代码\\N{\\fs12}you can see some generated Core Data code.\r\nDialogue: 0,0:14:39.67,0:14:42.18,yin,,0,0,0,,我并不打算使用这里生成的代码\\N{\\fs12}I'm actually going to use the code that's generated here,\r\nDialogue: 0,0:14:42.18,0:14:45.99,yin,,0,0,0,,不过我会把它搁到应用委托的类别里\\N{\\fs12}but I put it off into a category of my application delegates,\r\nDialogue: 0,0:14:45.99,0:14:48.37,yin,,0,0,0,,这样你就不需要真正去看它\\N{\\fs12}so that you don't really need to look at it.\r\nDialogue: 0,0:14:48.37,0:14:51.12,yin,,0,0,0,,我会把它包含在demo中 你会看到\\N{\\fs12}I'll include it in the demo, and you can see it.\r\nDialogue: 0,0:14:51.12,0:14:52.58,yin,,0,0,0,,不过 在作业中\\N{\\fs12}But, for your homework, you're going\r\nDialogue: 0,0:14:52.58,0:14:57.10,yin,,0,0,0,,你们会用到UIManagedDocument来做Core Data的东西\\N{\\fs12}to do your Core Data stuff using a document. UI-managed document,\r\nDialogue: 0,0:14:57.10,0:14:58.26,yin,,0,0,0,,我不打算展示这个\\N{\\fs12}and I'm not going to show that.\r\nDialogue: 0,0:14:58.26,0:14:59.72,yin,,0,0,0,,因为我要你们\\N{\\fs12}Because I want you to kind of go through\r\nDialogue: 0,0:14:59.72,0:15:01.82,yin,,0,0,0,,自己去经历和熟悉这个过程\\N{\\fs12}the process of trying to figure that out for yourself.\r\nDialogue: 0,0:15:01.82,0:15:04.75,yin,,0,0,0,,我要创建一个和平常一样的普通单视图应用\\N{\\fs12}So, I'm just going to create our normal single view application like we usually do.\r\nDialogue: 0,0:15:04.75,0:15:07.45,yin,,0,0,0,,名字称作Photomania\\N{\\fs12}I'm going to call is Photo Mania,\r\nDialogue: 0,0:15:07.45,0:15:11.58,yin,,0,0,0,,这是一个通用app 但我这里只演示iPhone版\\N{\\fs12}and it's going to be universal app, although I'm only going to use the iPhone version.\r\nDialogue: 0,0:15:11.58,0:15:14.83,yin,,0,0,0,,我只打算演示这个应用的梗概\\N{\\fs12}I'm only going to do the bare bones of this application.\r\nDialogue: 0,0:15:14.83,0:15:19.73,yin,,0,0,0,,这个应用的作用是查询Flickr 那些URL\\N{\\fs12}What this application is going to do, it's just going to query Flickr those URL,\r\nDialogue: 0,0:15:19.73,0:15:23.98,yin,,0,0,0,,最新地理参考照片的URL 同Shutterbug中一样\\N{\\fs12}the URL for recent geo reference photo theme, the same thing we did for Shutterbug.\r\nDialogue: 0,0:15:23.98,0:15:26.68,yin,,0,0,0,,不过这里将不仅仅是展示照片\\N{\\fs12}But instead of just showing the photos,\r\nDialogue: 0,0:15:26.68,0:15:31.00,yin,,0,0,0,,它还会展示这些照片的拍摄者清单\\N{\\fs12}it's going to show you the list of photographers who took those photos.\r\nDialogue: 0,0:15:31.00,0:15:33.63,yin,,0,0,0,,在这个demo后 你可以很容易做成\\N{\\fs12}And then, you know, after this demo, you could easily make it\r\nDialogue: 0,0:15:33.63,0:15:37.10,yin,,0,0,0,,点击拍照者 它就能展示这个拍照者的照片\\N{\\fs12}so if you click on a photographer, it shows you the photos by that photographer.\r\nDialogue: 0,0:15:37.10,0:15:40.85,yin,,0,0,0,,点击照片 使用图像视图控制器展示给你一张图片\\N{\\fs12}Click on the photo; use the image view controller to show you an image.\r\nDialogue: 0,0:15:40.85,0:15:42.53,yin,,0,0,0,,这就是我们要创建的应用\\N{\\fs12}So, that's kind of the application we're trying to build.\r\nDialogue: 0,0:15:42.53,0:15:45.35,yin,,0,0,0,,我们不打算创建其它那些TableView\\N{\\fs12}We won't get all the way to building those other TableViews.\r\nDialogue: 0,0:15:45.35,0:15:48.96,yin,,0,0,0,,我们只打算着眼于主TableView 这就是它的作用了\\N{\\fs12}We're just going to do this main TableView, but that's what this is going to do.\r\nDialogue: 0,0:15:49.78,0:15:53.11,yin,,0,0,0,,要展示那些拍照者\\N{\\fs12}And, the way it's going to do that; the way it's going to show those photographers\r\nDialogue: 0,0:15:53.11,0:15:56.25,yin,,0,0,0,,策略就会同Shutterbug略有不同\\N{\\fs12}is kind of a little bit different strategy than we saw with Shutterbug.\r\nDialogue: 0,0:15:56.25,0:15:59.87,yin,,0,0,0,,我打算在应用的后台\\N{\\fs12}I'm going, in the background, basically of my application,\r\nDialogue: 0,0:15:59.87,0:16:04.75,yin,,0,0,0,,持续每隔一段时间查询Flickr 并获得更多照片\\N{\\fs12}be constantly querying Flickr every once in awhile, and getting more and more photos,\r\nDialogue: 0,0:16:04.75,0:16:07.50,yin,,0,0,0,,然后把这些都丢到Core Data数据库中\\N{\\fs12}and then just throwing them into a Core Data database.\r\nDialogue: 0,0:16:07.50,0:16:09.59,yin,,0,0,0,,把它们丢到后台\\N{\\fs12}Okay, just throwing them in there in the background.\r\nDialogue: 0,0:16:09.59,0:16:12.68,yin,,0,0,0,,同时 我还会有TableView看着这些数据\\N{\\fs12}Meanwhile, I'm going to have TableViews that are going to be looking at that data.\r\nDialogue: 0,0:16:12.68,0:16:14.60,yin,,0,0,0,,看着拍照者 点击他们\\N{\\fs12}Looking at the photographers, clicking on them,\r\nDialogue: 0,0:16:14.60,0:16:15.97,yin,,0,0,0,,看着照片\\N{\\fs12}looking at the photos,\r\nDialogue: 0,0:16:15.98,0:16:19.23,yin,,0,0,0,,而且这将一直自动更新\\N{\\fs12}and that's just going to be always be updating automatically, all the time.\r\nDialogue: 0,0:16:19.23,0:16:21.35,yin,,0,0,0,,这就是我们所要创建的app\\N{\\fs12}Okay, so that's the app that we're going to build.\r\nDialogue: 0,0:16:21.35,0:16:23.24,yin,,0,0,0,,这里有些东西需要讲\\N{\\fs12}So, there's some things to talk about here.\r\nDialogue: 0,0:16:23.24,0:16:25.79,yin,,0,0,0,,如何创建一个Core Data数据库\\N{\\fs12}How to build a Core Data database.\r\nDialogue: 0,0:16:25.79,0:16:28.84,yin,,0,0,0,,如何使用FetchedResultsController关联它和TableView\\N{\\fs12}How to hook it up to a TableView with the Fetched Results Controller.\r\nDialogue: 0,0:16:28.84,0:16:31.24,yin,,0,0,0,,如何在后台进行取回\\N{\\fs12}How to fetch things in the background.\r\nDialogue: 0,0:16:31.24,0:16:34.80,yin,,0,0,0,,今天我们会讲到所有这些 如果时间够的话\\N{\\fs12}We're going to talk about all those things today if we have time.\r\nDialogue: 0,0:16:34.80,0:16:37.00,yin,,0,0,0,,好 起名叫作Photomania\\N{\\fs12}Alright, I'm going to call this Photo Mania.\r\nDialogue: 0,0:16:37.00,0:16:39.18,yin,,0,0,0,,把它放到通常的Developer里面\\N{\\fs12}I'm put it the developer where I usually put things.\r\nDialogue: 0,0:16:39.18,0:16:39.74,yin,,0,0,0,,这里\\N{\\fs12}Here it is.\r\nDialogue: 0,0:16:39.74,0:16:45.26,yin,,0,0,0,,我将直接创建我的数据模型\\N{\\fs12}I'm going to dive right in with building my data model.\r\nDialogue: 0,0:16:45.26,0:16:48.67,yin,,0,0,0,,我的schema 这就是数据库世界的叫法\\N{\\fs12}My schema, as you would call it in the database world.\r\nDialogue: 0,0:16:48.67,0:16:52.21,yin,,0,0,0,,这是对所有实体及所有这些东西的描述\\N{\\fs12}This is a description of all the entities and all that stuff.\r\nDialogue: 0,0:16:52.21,0:16:54.23,yin,,0,0,0,,我们在幻灯片中也看过这怎么做\\N{\\fs12}We saw how to do this all in the slide, so I'm going\r\nDialogue: 0,0:16:54.23,0:16:56.71,yin,,0,0,0,,我这里打算实况演示一下\\N{\\fs12}to just going to show you what it looks like live.\r\nDialogue: 0,0:16:56.71,0:17:00.12,yin,,0,0,0,,要创建新schema 我点新文件\\N{\\fs12}So, when I want to create a new schema, I do new file.\r\nDialogue: 0,0:17:00.12,0:17:02.64,yin,,0,0,0,,我要创建新文件\\N{\\fs12}Okay, so I'm going to do new file.\r\nDialogue: 0,0:17:02.64,0:17:06.47,yin,,0,0,0,,到这里的Core Data 选择这个数据模型\\N{\\fs12}I'm going to go up here to Core Data, and pick this data model,\r\nDialogue: 0,0:17:06.47,0:17:09.93,yin,,0,0,0,,不是映射模型 而是这里的数据模型 点它\\N{\\fs12}not mapping model, data model right here, so click that.\r\nDialogue: 0,0:17:09.93,0:17:12.23,yin,,0,0,0,,叫什么名字都行\\N{\\fs12}We can call it anything you want.\r\nDialogue: 0,0:17:12.23,0:17:16.03,yin,,0,0,0,,这个就用app名吧 Photomania\\N{\\fs12}I'm going to call this one the name of my app, photo mania,\r\nDialogue: 0,0:17:16.03,0:17:18.55,yin,,0,0,0,,问我要放到哪\\N{\\fs12}and it's asking where do you want to put it, and I'm going\r\nDialogue: 0,0:17:18.55,0:17:21.68,yin,,0,0,0,,我要把它放到顶层 和其它东西一起\\N{\\fs12}to put it at the top level here where all the rest of my stuff is.\r\nDialogue: 0,0:17:21.68,0:17:24.29,yin,,0,0,0,,这是我的控制器 委托等等\\N{\\fs12}Here's my controller and delegates something like that,\r\nDialogue: 0,0:17:24.29,0:17:27.09,yin,,0,0,0,,我就把数据模型文件放这里\\N{\\fs12}so I'll put this data modeling file there.\r\nDialogue: 0,0:17:27.09,0:17:30.14,yin,,0,0,0,,这就创建了数据模型文件 它是空的\\N{\\fs12}And, so it creates this data modeling file. You can see it's empty.\r\nDialogue: 0,0:17:30.14,0:17:34.07,yin,,0,0,0,,没有任何实体 属性 取回属性这些\\N{\\fs12}I've no entities or attributes or Fetch Properties or any of that business.\r\nDialogue: 0,0:17:34.07,0:17:36.33,yin,,0,0,0,,我们下面就来添加一些\\N{\\fs12}So, let's just start adding some.\r\nDialogue: 0,0:17:36.33,0:17:39.14,yin,,0,0,0,,到下面这里 添加实体\\N{\\fs12}So, I'm going to go down here to the bottom, add entity.\r\nDialogue: 0,0:17:39.14,0:17:39.73,yin,,0,0,0,,点这个\\N{\\fs12}Click that.\r\nDialogue: 0,0:17:39.73,0:17:41.28,yin,,0,0,0,,加了一个 叫Entity\\N{\\fs12}It added one, called entity.\r\nDialogue: 0,0:17:41.28,0:17:43.73,yin,,0,0,0,,双击 改名为Photo\\N{\\fs12}I'm going to double click, and call it photo.\r\nDialogue: 0,0:17:43.73,0:17:45.03,yin,,0,0,0,,我需要照片\\N{\\fs12}So, I need photo, and\r\nDialogue: 0,0:17:45.03,0:17:49.27,yin,,0,0,0,,我还需要显示拍照者 因此还要添加Photographer\\N{\\fs12}I display photographers too, so I better add photographer.\r\nDialogue: 0,0:17:49.27,0:17:50.65,yin,,0,0,0,,有一点非常重要\\N{\\fs12}Now one thing that's really important\r\nDialogue: 0,0:17:50.65,0:17:54.38,yin,,0,0,0,,创建schema时 你需要把实体\\N{\\fs12}when you make a schema is you want to put the entities\r\nDialogue: 0,0:17:54.38,0:17:58.85,yin,,0,0,0,,和属性放到这里 支持你所创建的UI\\N{\\fs12}and the attributes in there that support the kind of UI you're building.\r\nDialogue: 0,0:17:58.85,0:18:01.41,yin,,0,0,0,,这对于作业是非常重要的内容\\N{\\fs12}Okay, and that's really important for you to understand in your homework.\r\nDialogue: 0,0:18:01.41,0:18:04.06,yin,,0,0,0,,我这次布置的作业很简单\\N{\\fs12}Okay, this homework that I'm assigning you is pretty\r\nDialogue: 0,0:18:04.06,0:18:07.23,yin,,0,0,0,,前提是你要选一个好的schema\\N{\\fs12}straightforward, as long as you pick a good schema.\r\nDialogue: 0,0:18:07.23,0:18:10.36,yin,,0,0,0,,如果选择对了数据库中的实体和属性\\N{\\fs12}If you pick the right entities and attributes in the database,\r\nDialogue: 0,0:18:10.36,0:18:13.40,yin,,0,0,0,,将信息表格就很容易搞定\\N{\\fs12}it's just really easy to just throw up tables of information.\r\nDialogue: 0,0:18:13.40,0:18:16.21,yin,,0,0,0,,否则的话 如果schema都错了\\N{\\fs12}If you don't, if you have kind of the wrong schema\r\nDialogue: 0,0:18:16.21,0:18:18.15,yin,,0,0,0,,或是schema太简单\\N{\\fs12}or just too simplistic of a schema, you don't put\r\nDialogue: 0,0:18:18.15,0:18:21.05,yin,,0,0,0,,没有足够属性让UI正常运作\\N{\\fs12}in a couple of attributes that you need to make your UI work,\r\nDialogue: 0,0:18:21.05,0:18:23.45,yin,,0,0,0,,你就会很难得到信息\\N{\\fs12}it can be like ah, how do I get that information.\r\nDialogue: 0,0:18:23.45,0:18:25.89,yin,,0,0,0,,schema是你的奴隶\\N{\\fs12}So, the schema is your slave,\r\nDialogue: 0,0:18:25.89,0:18:27.80,yin,,0,0,0,,你要创建好schema\\N{\\fs12}you get to make the schema however, you think it's going\r\nDialogue: 0,0:18:27.80,0:18:31.27,yin,,0,0,0,,最好地支持你创建的应用程序\\N{\\fs12}to best support the application that you're building.\r\nDialogue: 0,0:18:31.27,0:18:34.42,yin,,0,0,0,,照片和拍照者\\N{\\fs12}So, photo and photographer.\r\nDialogue: 0,0:18:34.42,0:18:37.46,yin,,0,0,0,,Photo有哪些属性呢\\N{\\fs12}What kind of attributes does a photo have?\r\nDialogue: 0,0:18:37.46,0:18:42.17,yin,,0,0,0,,显然它有标题 还有副标题\\N{\\fs12}Well, let's see, of course it has its title, and it has a subtitle.\r\nDialogue: 0,0:18:42.17,0:18:44.44,yin,,0,0,0,,这是来自Flickr的简述\\N{\\fs12}That's that little description from Flickr.\r\nDialogue: 0,0:18:44.44,0:18:47.87,yin,,0,0,0,,它还有来自Flickr的图像URL\\N{\\fs12}It has the URL of its image from Flickr.\r\nDialogue: 0,0:18:47.87,0:18:51.11,yin,,0,0,0,,或许还有缩略图的URL\\N{\\fs12}Probably has the URL of its thumbnail as well.\r\nDialogue: 0,0:18:51.11,0:18:53.29,yin,,0,0,0,,实际上 我们还可以存储缩略图数据\\N{\\fs12}In fact, we could even store the thumbnail data,\r\nDialogue: 0,0:18:53.29,0:18:55.66,yin,,0,0,0,,你们在作业中需要这样做 这里\\N{\\fs12}which you're going to want to in your homework, right in here,\r\nDialogue: 0,0:18:55.66,0:19:01.01,yin,,0,0,0,,将数据放进来 不只是URL 还有一点很重要\\N{\\fs12}put the data in, not just the URLs, and also importantly,\r\nDialogue: 0,0:19:01.01,0:19:03.82,yin,,0,0,0,,照片有一个标识符 来自Flickr\\N{\\fs12}photos have a unique identifier that comes from Flickr.\r\nDialogue: 0,0:19:03.82,0:19:06.99,yin,,0,0,0,,当我从Flickr获取数据时 我不希望…\\N{\\fs12}Because when I get data from Flickr, I don't want to be,\r\nDialogue: 0,0:19:06.99,0:19:09.34,yin,,0,0,0,,有时点Flickr 你会得到相同的照片\\N{\\fs12}sometimes you click Flickr, you get the same photo again,\r\nDialogue: 0,0:19:09.34,0:19:12.15,yin,,0,0,0,,我不想把这个复制到我的Core Data数据库\\N{\\fs12}and I don't want to be duplicating that in my Core Data database.\r\nDialogue: 0,0:19:12.15,0:19:14.45,yin,,0,0,0,,我要查看Flickr中的这个唯一标识符\\N{\\fs12}So, I'm going to look at that unique ID from Flickr,\r\nDialogue: 0,0:19:14.45,0:19:17.32,yin,,0,0,0,,让这些在我的Core Data数据库中也成为唯一的\\N{\\fs12}and make those unique in my Core Data database as well.\r\nDialogue: 0,0:19:17.32,0:19:21.72,yin,,0,0,0,,添加了这些后 我看到这里有个红色警告或错误\\N{\\fs12}So, I've added these, but I've got to set their, you can tab warning here, or any error,\r\nDialogue: 0,0:19:21.72,0:19:23.10,yin,,0,0,0,,因为这些还没设\\N{\\fs12}because I haven't set these.\r\nDialogue: 0,0:19:23.10,0:19:24.66,yin,,0,0,0,,点这个 你可以看到\\N{\\fs12}If I click on this, you'll see.\r\nDialogue: 0,0:19:24.66,0:19:27.39,yin,,0,0,0,,必须定义类型 我们来设定类型\\N{\\fs12}Must have a defined type, so we got to set a type for these.\r\nDialogue: 0,0:19:27.39,0:19:30.30,yin,,0,0,0,,这四个都是字符串\\N{\\fs12}These all happen to be strings; all four of these,\r\nDialogue: 0,0:19:30.30,0:19:33.04,yin,,0,0,0,,不过可以设想 这里也可以有日期\\N{\\fs12}but you could image putting things like dates,\r\nDialogue: 0,0:19:33.04,0:19:36.35,yin,,0,0,0,,例如作业中 你要有最近标签\\N{\\fs12}like for your recent tab in your homework.\r\nDialogue: 0,0:19:36.35,0:19:39.90,yin,,0,0,0,,你会有最近浏览日期这些\\N{\\fs12}You probably want to have some sort of last viewed date or something like that.\r\nDialogue: 0,0:19:39.90,0:19:42.96,yin,,0,0,0,,放到这里很合理 还有数字这些东西\\N{\\fs12}That's perfectly reasonable to put in here, and numbers and all that stuff.\r\nDialogue: 0,0:19:42.96,0:19:44.73,yin,,0,0,0,,让我们这样做\\N{\\fs12}So, we'll just do that.\r\nDialogue: 0,0:19:44.73,0:19:46.52,yin,,0,0,0,,Photographer更简单一些\\N{\\fs12}Photographers are a little simpler.\r\nDialogue: 0,0:19:46.52,0:19:47.60,yin,,0,0,0,,它们只有name\\N{\\fs12}They just have a name.\r\nDialogue: 0,0:19:47.60,0:19:49.30,yin,,0,0,0,,拍照者只有名字\\N{\\fs12}Okay, a photographer has a name.\r\nDialogue: 0,0:19:49.30,0:19:50.29,yin,,0,0,0,,这是字符串\\N{\\fs12}That's a string.\r\nDialogue: 0,0:19:50.29,0:19:51.41,yin,,0,0,0,,就这了\\N{\\fs12}That's about it.\r\nDialogue: 0,0:19:51.68,0:19:55.00,yin,,0,0,0,,我讲过 我们可以从图像上看这些实体\\N{\\fs12}And, remember I told you we could look at these entities graphically\r\nDialogue: 0,0:19:55.00,0:19:56.81,yin,,0,0,0,,点下面这个小按钮就行了\\N{\\fs12}with this little button down here.\r\nDialogue: 0,0:19:56.81,0:19:57.48,yin,,0,0,0,,这里\\N{\\fs12}Here it is right here.\r\nDialogue: 0,0:19:57.48,0:20:00.80,yin,,0,0,0,,它们重叠到了一起 不过我可以选取移动\\N{\\fs12}They're kind of smashed on top of each other, but I can pick them up and move them.\r\nDialogue: 0,0:20:00.80,0:20:04.22,yin,,0,0,0,,当我移动一个时 中间就会得到空间\\N{\\fs12}And, you can see that as I move one, it kind of makes space,\r\nDialogue: 0,0:20:04.22,0:20:07.22,yin,,0,0,0,,如果在它们之间创建关系\\N{\\fs12}alright, keep them, and if I have relationships between them,\r\nDialogue: 0,0:20:07.22,0:20:11.55,yin,,0,0,0,,这些关系也会在移动过程中得到保持\\N{\\fs12}it will keep those relationships sensible as I move them around.\r\nDialogue: 0,0:20:11.55,0:20:13.36,yin,,0,0,0,,让我们创建一个关系\\N{\\fs12}So, let's create a relationship.\r\nDialogue: 0,0:20:13.36,0:20:15.79,yin,,0,0,0,,照片和拍照者之间是什么关系\\N{\\fs12}What is the relationship between a photo and photographer?\r\nDialogue: 0,0:20:15.79,0:20:19.65,yin,,0,0,0,,幻灯片上我就讲过 whoTook 这里我control拖动\\N{\\fs12}As we saw on the slides, who took, basically, so I'm just control dragging.\r\nDialogue: 0,0:20:19.65,0:20:24.12,yin,,0,0,0,,按住control键 从照片到拍照者拖动\\N{\\fs12}I'm holding down control right now, and dragging from photo to photographer,\r\nDialogue: 0,0:20:24.12,0:20:26.66,yin,,0,0,0,,这样新关系就得以创建了\\N{\\fs12}and I have this new relationship created.\r\nDialogue: 0,0:20:26.66,0:20:29.45,yin,,0,0,0,,如果移动这些东西\\N{\\fs12}And again, if I move these things around,\r\nDialogue: 0,0:20:29.45,0:20:31.37,yin,,0,0,0,,这个会保持不变\\N{\\fs12}this things will stay with,\r\nDialogue: 0,0:20:31.37,0:20:33.80,yin,,0,0,0,,下面给这些关系命名\\N{\\fs12}so let's go ahead and give these relationships names.\r\nDialogue: 0,0:20:33.80,0:20:36.16,yin,,0,0,0,,在照片一侧 这是whoTook关系\\N{\\fs12}On the photo side, this is the who took relationship,\r\nDialogue: 0,0:20:36.16,0:20:42.39,yin,,0,0,0,,在拍照者一侧 这是photos 我们可以在检查器中查看\\N{\\fs12}and on the photographer side, this is the photos, and we can inspect this right here\r\nDialogue: 0,0:20:42.39,0:20:44.76,yin,,0,0,0,,查看器在这里\\N{\\fs12}with this little guy right here; the inspector.\r\nDialogue: 0,0:20:44.76,0:20:48.83,yin,,0,0,0,,我们可以看到属性中的各种东西\\N{\\fs12}And, we can see all kinds of things about our particular properties.\r\nDialogue: 0,0:20:48.83,0:20:51.81,yin,,0,0,0,,对属性和关系都是如此\\N{\\fs12}This is true for properties, and also for relationships.\r\nDialogue: 0,0:20:51.81,0:20:52.99,yin,,0,0,0,,当然 我们知道\\N{\\fs12}And, of course, we know\r\nDialogue: 0,0:20:52.99,0:20:55.08,yin,,0,0,0,,这是一个To Many关系\\N{\\fs12}that this is a to many relationship, right?\r\nDialogue: 0,0:20:55.08,0:20:58.74,yin,,0,0,0,,因为拍照者可以拍多张照片 这就得到了双箭头\\N{\\fs12}Because a photographer can have many photos, so we get this double arrow here.\r\nDialogue: 0,0:20:58.74,0:21:03.54,yin,,0,0,0,,不过这里是To One关系 因为一张照片只有一个拍照者\\N{\\fs12}But, it's a to one relationship here, because a photo, only one guy took the photo.\r\nDialogue: 0,0:21:03.54,0:21:05.41,yin,,0,0,0,,移动这些\\N{\\fs12}And so, if you move these things around,\r\nDialogue: 0,0:21:05.41,0:21:09.53,yin,,0,0,0,,所有这些关系仍会保持\\N{\\fs12}it will keep this all kind of looking okay.\r\nDialogue: 0,0:21:09.53,0:21:12.89,yin,,0,0,0,,这里 我们就设置好了我们需要的一切\\N{\\fs12}Alright? So, now, we've kind of set up everything here that we need.\r\nDialogue: 0,0:21:12.89,0:21:16.48,yin,,0,0,0,,这是一个很简单的应用 我们不再需要任何的属性\\N{\\fs12}This is a pretty simple application, so we don't need any more attributes.\r\nDialogue: 0,0:21:16.48,0:21:18.56,yin,,0,0,0,,不过在你的应用中 你至少还要有\\N{\\fs12}But, in your application, you're going to have at least one\r\nDialogue: 0,0:21:18.56,0:21:20.76,yin,,0,0,0,,一两个实体和一些属性\\N{\\fs12}or more two more entities and some attributes on there,\r\nDialogue: 0,0:21:20.76,0:21:24.60,yin,,0,0,0,,照片上也需要更多一些属性\\N{\\fs12}and some more attributes on photo.\r\nDialogue: 0,0:21:24.60,0:21:28.45,yin,,0,0,0,,我留了一些工作给你们做\\N{\\fs12}So, I left with some work to do.\r\nDialogue: 0,0:21:28.45,0:21:33.19,yin,,0,0,0,,有了这个之后 我们希望能够访问这些东西\\N{\\fs12}Okay, so now that we have this, we want to be able to access all this stuff\r\nDialogue: 0,0:21:33.19,0:21:39.06,yin,,0,0,0,,在Objective-C代码中 使用属性和常规类句法\\N{\\fs12}in our objective C code using properties and normal class syntax.\r\nDialogue: 0,0:21:39.06,0:21:40.70,yin,,0,0,0,,我们要做我讲过的这个\\N{\\fs12}So, we're going to do this thing we talked about,\r\nDialogue: 0,0:21:40.70,0:21:44.90,yin,,0,0,0,,也就是 生成ManagedObject的子类\\N{\\fs12}which is generating manage object subclasses.\r\nDialogue: 0,0:21:44.90,0:21:47.30,yin,,0,0,0,,我选择我要的类\\N{\\fs12}So, I'm going to pick the classes that I want.\r\nDialogue: 0,0:21:47.30,0:21:52.08,yin,,0,0,0,,到这里 为Photomania创建NSManagedObject的子类\\N{\\fs12}I'm going to go here and say create NS managed objects subclass for photo mania,\r\nDialogue: 0,0:21:52.08,0:21:54.73,yin,,0,0,0,,这里同时创建Photo和Photographer\\N{\\fs12}and we'll do photo and photographer, both of them.\r\nDialogue: 0,0:21:54.73,0:21:56.83,yin,,0,0,0,,点这里 放到你想放的地方\\N{\\fs12}And, we click this, says where do you want them?\r\nDialogue: 0,0:21:56.83,0:21:58.06,yin,,0,0,0,,也都放到顶层\\N{\\fs12}I'll put those also at the top.\r\nDialogue: 0,0:21:58.06,0:22:00.39,yin,,0,0,0,,这样所有东西就都在顶层了\\N{\\fs12}I'm going to put everything at the top level here.\r\nDialogue: 0,0:22:00.39,0:22:03.63,yin,,0,0,0,,这里 我有Photo和Photographer\\N{\\fs12}And here, I have my photo and photographer,\r\nDialogue: 0,0:22:03.63,0:22:05.74,yin,,0,0,0,,Photo看起来很好\\N{\\fs12}and I can see that photo looks okay.\r\nDialogue: 0,0:22:05.74,0:22:07.61,yin,,0,0,0,,它有Photographer whoTook\\N{\\fs12}It's got photographer who took,\r\nDialogue: 0,0:22:07.61,0:22:09.74,yin,,0,0,0,,但Photographer就没这么好了\\N{\\fs12}but photographer, not so much, right?\r\nDialogue: 0,0:22:09.74,0:22:12.41,yin,,0,0,0,,它只有NSManagedObject对应removePhotosObject\\N{\\fs12}It's got NS manage object for remove photos object.\r\nDialogue: 0,0:22:12.41,0:22:14.39,yin,,0,0,0,,这里应该是Photo\\N{\\fs12}This should really be photo star,\r\nDialogue: 0,0:22:14.39,0:22:17.39,yin,,0,0,0,,我打算再次生成这些东西\\N{\\fs12}so I'm just going to generate these things again.\r\nDialogue: 0,0:22:17.39,0:22:19.10,yin,,0,0,0,,实际上这很蹩脚\\N{\\fs12}Okay. And really, it's too bad\r\nDialogue: 0,0:22:19.10,0:22:22.39,yin,,0,0,0,,它不能一次给我把两次生成给办了\\N{\\fs12}that it doesn't automatically do this two pass generation,\r\nDialogue: 0,0:22:22.39,0:22:23.89,yin,,0,0,0,,不过手动就行了\\N{\\fs12}but you end up doing it yourself.\r\nDialogue: 0,0:22:23.89,0:22:26.68,yin,,0,0,0,,务必习惯这种生成 因为你会经常用到\\N{\\fs12}Get used to doing this generate, because you're going to do it a lot.\r\nDialogue: 0,0:22:26.68,0:22:28.79,yin,,0,0,0,,你会经常添加实体\\N{\\fs12}You're going to be constantly adding entities,\r\nDialogue: 0,0:22:28.79,0:22:31.11,yin,,0,0,0,,改变属性 等等\\N{\\fs12}changing attributes, like that, and you're just going\r\nDialogue: 0,0:22:31.11,0:22:33.77,yin,,0,0,0,,你将经常再生成这些东西\\N{\\fs12}to constantly be regenerating these things, and it's going\r\nDialogue: 0,0:22:33.77,0:22:35.94,yin,,0,0,0,,你会被要求替换它们\\N{\\fs12}to ask you to replace them, and so\r\nDialogue: 0,0:22:35.94,0:22:38.25,yin,,0,0,0,,不要不习惯这样再生成\\N{\\fs12}don't be uncomfortable about doing that regenerate.\r\nDialogue: 0,0:22:38.25,0:22:42.37,yin,,0,0,0,,这是很常用的东西 现在我们就胜利了\\N{\\fs12}It's a common thing to want to do, and so now we're winning here.\r\nDialogue: 0,0:22:43.54,0:22:45.86,yin,,0,0,0,,我们有了这些很好的类\\N{\\fs12}So we have these nice classes,\r\nDialogue: 0,0:22:45.86,0:22:51.03,yin,,0,0,0,,现在我们可以用点符号来访问它们所有的属性\\N{\\fs12}and now we can use properties to access all their attitudes.\r\nDialogue: 0,0:22:51.03,0:22:54.32,yin,,0,0,0,,例如用photo.title来获得标题\\N{\\fs12}Photo dot title to get at the title for example.\r\nDialogue: 0,0:22:54.32,0:22:57.89,yin,,0,0,0,,不过我之前就讲过 我们想要添加代码\\N{\\fs12}But, as I said before, we might want to add code, and I do want\r\nDialogue: 0,0:22:57.89,0:22:59.62,yin,,0,0,0,,例如这里是给Photo加\\N{\\fs12}to add code to photo here.\r\nDialogue: 0,0:22:59.62,0:23:02.52,yin,,0,0,0,,我想添加创建照片的代码\\N{\\fs12}I want to add code to create a photo.\r\nDialogue: 0,0:23:02.52,0:23:04.06,yin,,0,0,0,,让它能够添加\\N{\\fs12}Okay. To make so that I can add,\r\nDialogue: 0,0:23:04.06,0:23:07.66,yin,,0,0,0,,插入一个Photo对象到数据库中\\N{\\fs12}insert a photo object into the database.\r\nDialogue: 0,0:23:07.66,0:23:09.73,yin,,0,0,0,,我将使用category来做这个\\N{\\fs12}And so, I'm going to do that using categories.\r\nDialogue: 0,0:23:09.73,0:23:12.15,yin,,0,0,0,,category也就是我刚讲的新Objective-C特性\\N{\\fs12}Remember categories is that new objective C thing I was telling\r\nDialogue: 0,0:23:12.15,0:23:14.70,yin,,0,0,0,,记得吗 我们可以往一个类中添加代码\\N{\\fs12}you about, where we can add code to a class\r\nDialogue: 0,0:23:14.70,0:23:17.42,yin,,0,0,0,,又不创建它的子类 这里我打算把代码\\N{\\fs12}without sub-classing it, so I'm going to add code\r\nDialogue: 0,0:23:17.42,0:23:20.94,yin,,0,0,0,,加到Photo类 而不创建Photo的子类\\N{\\fs12}to this photo class, right here, without sub-classing photo.\r\nDialogue: 0,0:23:20.94,0:23:24.41,yin,,0,0,0,,做法是文件 新文件\\N{\\fs12}Okay, so I do that with file, new file,\r\nDialogue: 0,0:23:24.41,0:23:27.01,yin,,0,0,0,,这里不再选择Objective-C类\\N{\\fs12}and instead of picking objective C class,\r\nDialogue: 0,0:23:27.01,0:23:29.60,yin,,0,0,0,,而是选择Objective-C category\\N{\\fs12}I'm going to pick objective C category.\r\nDialogue: 0,0:23:29.60,0:23:33.33,yin,,0,0,0,,这时 它会问我要创建category的是哪个类\\N{\\fs12}And when I do, it's going to say, what class do you want to make a category on,\r\nDialogue: 0,0:23:33.33,0:23:36.01,yin,,0,0,0,,要创建category的是Photo类\\N{\\fs12}I'm going to make a category on the class photo,\r\nDialogue: 0,0:23:36.01,0:23:37.29,yin,,0,0,0,,我打算叫它Flickr\\N{\\fs12}and I'm going to call it Flickr\r\nDialogue: 0,0:23:37.29,0:23:41.51,yin,,0,0,0,,因为我要给Photo加的这些方法\\N{\\fs12}because that's what this method that I'm, these methods I'm going to add to photo\r\nDialogue: 0,0:23:41.51,0:23:44.61,yin,,0,0,0,,都是将Flickr同数据库关联起来\\N{\\fs12}are all kind of hooking Flickr up to the database,\r\nDialogue: 0,0:23:44.62,0:23:47.19,yin,,0,0,0,,因此 我认为Flickr用作这个category名很好\\N{\\fs12}so Flickr seems like a good name for that category.\r\nDialogue: 0,0:23:47.19,0:23:49.82,yin,,0,0,0,,它还问我要放在哪里\\N{\\fs12}And, it wants to know where I'm going to put them.\r\nDialogue: 0,0:23:50.92,0:23:53.71,yin,,0,0,0,,放在和其它东西一样的位置\\N{\\fs12}Put them in the same places everywhere as everything,\r\nDialogue: 0,0:23:53.71,0:23:56.10,yin,,0,0,0,,这是我的.h 这是我的.m\\N{\\fs12}and so here's my .H and here's my .M,\r\nDialogue: 0,0:23:56.10,0:23:58.82,yin,,0,0,0,,它问我想要做什么\\N{\\fs12}and it's asking me what do you want to do here.\r\nDialogue: 0,0:23:58.82,0:24:04.64,yin,,0,0,0,,这里我要实现的方法\\N{\\fs12}So, the method that I want to implement here is a method\r\nDialogue: 0,0:24:04.64,0:24:07.18,yin,,0,0,0,,是取一个Flickr字典\\N{\\fs12}that essentially takes a Flickr dictionary\r\nDialogue: 0,0:24:07.18,0:24:10.65,yin,,0,0,0,,将一个照片对象加到数据库\\N{\\fs12}and adds a photo object to the database,\r\nDialogue: 0,0:24:10.65,0:24:12.91,yin,,0,0,0,,并返回一个指向它的指针\\N{\\fs12}and returns the pointer to it to me.\r\nDialogue: 0,0:24:12.91,0:24:14.80,yin,,0,0,0,,都知道我这里要做什么吗\\N{\\fs12}Everyone understand what I'm going to do here?\r\nDialogue: 0,0:24:14.80,0:24:19.08,yin,,0,0,0,,我打算把这个叫作 Photo… 确定选的是相同名称\\N{\\fs12}So, I'm going to call this thing, photo, make sure I pick the same name,\r\nDialogue: 0,0:24:19.08,0:24:20.99,yin,,0,0,0,,免得后面出现问题\\N{\\fs12}so that I don't get sidetracked here.\r\nDialogue: 0,0:24:20.99,0:24:28.74,yin,,0,0,0,,photoWithFlickrInfo 这将是一个NSDictionary\\N{\\fs12}Photo with Flickr info and this is going be NS Dictionary,\r\nDialogue: 0,0:24:28.74,0:24:31.68,yin,,0,0,0,,照片字典 除了这个照片字典\\N{\\fs12}photo dictionary, and what else do I need beside\r\nDialogue: 0,0:24:31.68,0:24:34.76,yin,,0,0,0,,我还需要什么才能在数据库中创建一个对象\\N{\\fs12}that photo dictionary to create an object in the database?\r\nDialogue: 0,0:24:36.47,0:24:38.16,yin,,0,0,0,,同数据库的关联\\N{\\fs12}A hook to the database.\r\nDialogue: 0,0:24:38.16,0:24:40.83,yin,,0,0,0,,我需要知道 我要把这张照片加到哪个数据库中\\N{\\fs12}Okay, I got to know which database you want me to add this photo to.\r\nDialogue: 0,0:24:40.83,0:24:45.17,yin,,0,0,0,,因此 我还需要 inManagedObjectContext\\N{\\fs12}So, I also need in managed object context,\r\nDialogue: 0,0:24:45.17,0:24:48.90,yin,,0,0,0,,NSManagedObjectContext context\\N{\\fs12}NS managed object managed context context.\r\nDialogue: 0,0:24:48.90,0:24:49.91,yin,,0,0,0,,我只需要这些\\N{\\fs12}Okay, and that's all I need;\r\nDialogue: 0,0:24:49.91,0:24:52.05,yin,,0,0,0,,不过是Flickr信息和context\\N{\\fs12}just the Flickr information and the context.\r\nDialogue: 0,0:24:52.05,0:24:55.72,yin,,0,0,0,,这是你要我创建这张照片的地方 我会在这里创建\\N{\\fs12}That's the place you want me to create this photo, and I will.\r\nDialogue: 0,0:24:56.48,0:24:59.72,yin,,0,0,0,,这里我还会有一个方法\\N{\\fs12}And, I'm also going to have another one here; because I know\r\nDialogue: 0,0:24:59.72,0:25:03.11,yin,,0,0,0,,因为我知道Flickr照片会大批量下载\\N{\\fs12}that I'm going to be downloading these Flickr photos in big bunches.\r\nDialogue: 0,0:25:03.11,0:25:05.73,yin,,0,0,0,,每次我调用URLGeoreferencePhotos\\N{\\fs12}Every time I call URL, geo reference photos\r\nDialogue: 0,0:25:05.73,0:25:06.74,yin,,0,0,0,,大概是叫这个吧\\N{\\fs12}or whatever it's called,\r\nDialogue: 0,0:25:06.74,0:25:09.42,yin,,0,0,0,,它会给出很多 例如一两百个\\N{\\fs12}I'm going to get a whole bunch of them, like a hundred or 200 of them.\r\nDialogue: 0,0:25:09.42,0:25:11.62,yin,,0,0,0,,我要有一个批量加载方法 我称其为\\N{\\fs12}So, I'm going to have a bulk load one that I'm going to call\r\nDialogue: 0,0:25:11.62,0:25:19.60,yin,,0,0,0,,loadPhotosFromFlickrArray\\N{\\fs12}load photos from Flickr array,\r\nDialogue: 0,0:25:19.60,0:25:21.77,yin,,0,0,0,,NSArray\\N{\\fs12}NS-Array\r\nDialogue: 0,0:25:21.77,0:25:23.91,yin,,0,0,0,,photos\\N{\\fs12}photos\r\nDialogue: 0,0:25:23.91,0:25:26.72,yin,,0,0,0,,这是Flickr NSDictionary的\\N{\\fs12}of Flickr NS dictionary\r\nDialogue: 0,0:25:26.72,0:25:30.84,yin,,0,0,0,,inManagedObjectContext\\N{\\fs12}into managed object context.\r\nDialogue: 0,0:25:34.24,0:25:36.87,yin,,0,0,0,,NSManagedObjectContext\\N{\\fs12}NS managed object context.\r\nDialogue: 0,0:25:36.87,0:25:41.49,yin,,0,0,0,,这就是批量加载方法 我会反复调用这个\\N{\\fs12}Okay, so that's just going to bulk. It's going to call this basically repeatedly,\r\nDialogue: 0,0:25:41.49,0:25:43.83,yin,,0,0,0,,虽然这并不见得是最高效的做法\\N{\\fs12}although that might not be the most efficient way to do that,\r\nDialogue: 0,0:25:43.83,0:25:46.70,yin,,0,0,0,,后面我们还会稍微讲到\\N{\\fs12}and we'll talk about that in a little bit.\r\nDialogue: 0,0:25:46.70,0:25:48.97,yin,,0,0,0,,让我来实现这两个方法\\N{\\fs12}So, let me implement these two methods.\r\nDialogue: 0,0:25:48.97,0:25:51.60,yin,,0,0,0,,这是category的接口\\N{\\fs12}Okay, this is the interface of my category,\r\nDialogue: 0,0:25:51.60,0:25:53.66,yin,,0,0,0,,而这是category的实现\\N{\\fs12}and so here's the implementation of my category.\r\nDialogue: 0,0:25:53.66,0:25:57.29,yin,,0,0,0,,我可以做任何我想做的事情来实现这些\\N{\\fs12}Now, I can do whatever I want to implement these, except,\r\nDialogue: 0,0:25:57.29,0:26:00.71,yin,,0,0,0,,但我不能使用任何实例变量\\N{\\fs12}I can't use any instance variables,\r\nDialogue: 0,0:26:00.71,0:26:03.42,yin,,0,0,0,,这里不能有任何属性\\N{\\fs12}so I can't have any properties that are, you know, here,\r\nDialogue: 0,0:26:03.42,0:26:08.22,yin,,0,0,0,,我需要用photo来实现它们 这样应该就行了\\N{\\fs12}so I have to implement them basically in terms of photo, if that makes sense that way.\r\nDialogue: 0,0:26:08.22,0:26:10.86,yin,,0,0,0,,这个会返回一张照片 因此我说\\N{\\fs12}So, this is going to return a photo, so I'm going to say,\r\nDialogue: 0,0:26:10.86,0:26:13.25,yin,,0,0,0,,photo = nil\\N{\\fs12}photo equal nil,\r\nDialogue: 0,0:26:13.25,0:26:16.48,yin,,0,0,0,,下面这里则是return photo 而两者中间\\N{\\fs12}and down here, return photo, and in between,\r\nDialogue: 0,0:26:16.48,0:26:20.47,yin,,0,0,0,,我需要在数据库中找这张照片 或是创建它\\N{\\fs12}I got to go find this photo in the database, or create it, or\r\nDialogue: 0,0:26:20.47,0:26:22.15,yin,,0,0,0,,或是别的什么\\N{\\fs12}whatever it may be.\r\nDialogue: 0,0:26:22.15,0:26:28.70,yin,,0,0,0,,我们首先来问数据库 你是否已经有了这张照片\\N{\\fs12}So, let's start with asking the database, do you already have this photo?\r\nDialogue: 0,0:26:28.70,0:26:32.26,yin,,0,0,0,,如何问数据库是否已经有这张照片呢\\N{\\fs12}And, so how am I going to ask the database if the photo is already there,\r\nDialogue: 0,0:26:32.26,0:26:35.73,yin,,0,0,0,,答案是 我将尝试取回它\\N{\\fs12}and the answer is, I'm going to try and fetch it.\r\nDialogue: 0,0:26:35.75,0:26:39.00,yin,,0,0,0,,我将用一个FetchRequest\\N{\\fs12}So, I'm going to have a Fetch Request, and it's going\r\nDialogue: 0,0:26:39.00,0:26:48.93,yin,,0,0,0,,这是一个到照片表格中的FetchRequest\\N{\\fs12}to be a Fetch Request into the photo table, if you know anything about it, or into photos.\r\nDialogue: 0,0:26:48.93,0:26:52.74,yin,,0,0,0,,它会返回照片 因为我要找这张照片\\N{\\fs12}It's going to return photos, okay, because I'm trying to find this photo.\r\nDialogue: 0,0:26:52.74,0:26:56.97,yin,,0,0,0,,然后 请求需要一个谓词 什么谓词呢\\N{\\fs12}And then, the request needs a predicate, and what is the predicate.\r\nDialogue: 0,0:26:56.97,0:26:58.65,yin,,0,0,0,,我要找哪张照片\\N{\\fs12}Which photo am I looking for?\r\nDialogue: 0,0:26:58.65,0:27:05.31,yin,,0,0,0,,我要找的照片 其唯一标识符unique要等于\\N{\\fs12}Well, I'm looking for the photo whose unique equals the same\r\nDialogue: 0,0:27:05.31,0:27:10.77,yin,,0,0,0,,这个照片字典的unique\\N{\\fs12}unique that is photo dictionary right here,\r\nDialogue: 0,0:27:10.77,0:27:13.05,yin,,0,0,0,,让我们获取这个\\N{\\fs12}so let's go get that.\r\nDialogue: 0,0:27:13.05,0:27:16.43,yin,,0,0,0,,NSString *unique = …\\N{\\fs12}NS-string star unique equals, and we're going\r\nDialogue: 0,0:27:16.43,0:27:23.62,yin,,0,0,0,,这里我们需要import FlickrFetcher.h\\N{\\fs12}to need our Flickr Fetcher import, Flickr Fetcher .H,\r\nDialogue: 0,0:27:23.62,0:27:26.36,yin,,0,0,0,,我将抓取FlickrFetcher.h\\N{\\fs12}so I'm going to grab Flickr Fetcher .H\r\nDialogue: 0,0:27:26.36,0:27:30.64,yin,,0,0,0,,从之前我们所做的 也就是Shutterbug\\N{\\fs12}from the thing we did before, which was Shutterbug.\r\nDialogue: 0,0:27:30.64,0:27:33.07,yin,,0,0,0,,这是Shutterbug 这是FlickrFetcher\\N{\\fs12}So, here's Shutterbug, and here's Flickr Fetcher.\r\nDialogue: 0,0:27:33.07,0:27:36.41,yin,,0,0,0,,我要把这整个都拖到这里\\N{\\fs12}I'm just going to drag that whole thing right in here.\r\nDialogue: 0,0:27:36.41,0:27:40.29,yin,,0,0,0,,这样我就有了FlickrFetcher.h\\N{\\fs12}Alright, so now I have Flickr Fetcher .H,\r\nDialogue: 0,0:27:40.29,0:27:43.52,yin,,0,0,0,,而在FlickrFetcher.h内\\N{\\fs12}and inside Flickr Fletcher .H,\r\nDialogue: 0,0:27:43.52,0:27:46.54,yin,,0,0,0,,我们可以获得照片的唯一标识符\\N{\\fs12}we can get the photos unique ID\r\nDialogue: 0,0:27:46.54,0:27:48.92,yin,,0,0,0,,使用这个FLICKR_PHOTO_ID\\N{\\fs12}with this Flickr photo ID.\r\nDialogue: 0,0:27:48.93,0:27:51.78,yin,,0,0,0,,于是 我可以到这下面说\\N{\\fs12}So, I'm going to go down here and say,\r\nDialogue: 0,0:27:51.78,0:27:58.41,yin,,0,0,0,,photoDictionary[FLICKR_PHOTO_ID]\\N{\\fs12}photo dictionary, Flickr photo ID.\r\nDialogue: 0,0:27:58.41,0:28:01.24,yin,,0,0,0,,这里我可能要用valueForKeyPath\\N{\\fs12}Now, I might want to do value for key path here,\r\nDialogue: 0,0:28:01.24,0:28:07.42,yin,,0,0,0,,防止这张Flickr照片ID中间有点这些\\N{\\fs12}just in case this Flickr photo ID might have dots in it or whatever,\r\nDialogue: 0,0:28:07.42,0:28:09.14,yin,,0,0,0,,Flickr\\N{\\fs12}Flickr.\r\nDialogue: 0,0:28:09.14,0:28:12.42,yin,,0,0,0,,也许会有点 就像描述一样\\N{\\fs12}You know, it might have dots in it like the description has.\r\nDialogue: 0,0:28:12.42,0:28:15.89,yin,,0,0,0,,这里我就这样 不过valueForKeyPath或许更好\\N{\\fs12}Okay, I'll leave it this way here, but value for key might be a good idea.\r\nDialogue: 0,0:28:15.89,0:28:19.28,yin,,0,0,0,,这里我将尝试在数据库中\\N{\\fs12}So, I'm basically going to fetch into the database to try\r\nDialogue: 0,0:28:19.28,0:28:23.33,yin,,0,0,0,,找到这张独一无二的照片 看是否已经存在\\N{\\fs12}and find this unique photo; see if it's already there.\r\nDialogue: 0,0:28:23.33,0:28:26.08,yin,,0,0,0,,这里我需要一个NSError\\N{\\fs12}And, I do that by saying I need an NS error here,\r\nDialogue: 0,0:28:26.08,0:28:31.68,yin,,0,0,0,,我要说 NSArray *matches = [context …\\N{\\fs12}and then I'm going to say NS array matches equals context,\r\nDialogue: 0,0:28:31.68,0:28:34.37,yin,,0,0,0,,因为我们需要一个context来进行取回\\N{\\fs12}because we always have to ask a context to do a fetch.\r\nDialogue: 0,0:28:34.37,0:28:37.66,yin,,0,0,0,,executeFetchRequest 那个请求\\N{\\fs12}Execute Fetch Request, that request,\r\nDialogue: 0,0:28:37.66,0:28:40.44,yin,,0,0,0,,如果有错误 返回错误\\N{\\fs12}and if there's an error, return an error.\r\nDialogue: 0,0:28:40.44,0:28:43.43,yin,,0,0,0,,这样我就有了这些照片\\N{\\fs12}So, now I've got those photos.\r\nDialogue: 0,0:28:43.43,0:28:46.96,yin,,0,0,0,,这些照片 这里是一张匹配的照片\\N{\\fs12}Those photos hopefully, in this case a matching photo or maybe not,\r\nDialogue: 0,0:28:46.96,0:28:47.98,yin,,0,0,0,,被取出来了\\N{\\fs12}has been pulled out.\r\nDialogue: 0,0:28:47.98,0:28:50.56,yin,,0,0,0,,这个匹配可以有多种\\N{\\fs12}Now, this matches can have a number\r\nDialogue: 0,0:28:50.56,0:28:53.90,yin,,0,0,0,,不同的状态 或者不同的值\\N{\\fs12}of different states or different values.\r\nDialogue: 0,0:28:53.90,0:28:56.60,yin,,0,0,0,,这里有一点 它可能是nil\\N{\\fs12}One thing is, it might be nil.\r\nDialogue: 0,0:28:56.60,0:29:02.66,yin,,0,0,0,,如果它是nil 或者 如果这个错误不为nil\\N{\\fs12}If it's nil, okay, or if this error is not nil,\r\nDialogue: 0,0:29:05.87,0:29:08.25,yin,,0,0,0,,这里是或error\\N{\\fs12}let's say or error\r\nDialogue: 0,0:29:08.25,0:29:10.66,yin,,0,0,0,,或者 这里的另一个错误条件是\\N{\\fs12}or another error condition here is\r\nDialogue: 0,0:29:10.66,0:29:19.37,yin,,0,0,0,,匹配计数大于1\\N{\\fs12}that the matches, matches count is greater than one.\r\nDialogue: 0,0:29:19.37,0:29:22.34,yin,,0,0,0,,因为这些是唯一的\\N{\\fs12}Okay, because these are supposed to be unique,\r\nDialogue: 0,0:29:22.34,0:29:26.16,yin,,0,0,0,,如果我这样做得到了多张照片\\N{\\fs12}and so if I somehow got multiple photos by doing this,\r\nDialogue: 0,0:29:26.16,0:29:31.84,yin,,0,0,0,,这显然也是错误的 我需要处理这里的错误\\N{\\fs12}that would also be an error condition, so I have to handle error here.\r\nDialogue: 0,0:29:31.84,0:29:33.34,yin,,0,0,0,,处理错误\\N{\\fs12}Handle error.\r\nDialogue: 0,0:29:33.34,0:29:36.03,yin,,0,0,0,,今天我不打算做这个 不过你们可以想象的到\\N{\\fs12}I'm not going to do that today, but you can imagine.\r\nDialogue: 0,0:29:36.03,0:29:47.84,yin,,0,0,0,,否则 如果匹配找到了东西 我们可以直接返回它\\N{\\fs12}Okay, otherwise, if the matches found something, then we can just return it.\r\nDialogue: 0,0:29:47.84,0:29:49.42,yin,,0,0,0,,如何返回它呢\\N{\\fs12}So, how do we return it?\r\nDialogue: 0,0:29:49.42,0:29:54.28,yin,,0,0,0,,这是一个数组 但这个数组有且只有一个匹配项\\N{\\fs12}This is in array, but this array is going to have the one and only one match,\r\nDialogue: 0,0:29:54.28,0:29:58.42,yin,,0,0,0,,因此我可以说 匹配第一个对象\\N{\\fs12}so I'm going to say matches first object.\r\nDialogue: 0,0:29:58.42,0:30:00.91,yin,,0,0,0,,你也可以说最后一个对象\\N{\\fs12}Could also say last object.\r\nDialogue: 0,0:30:00.91,0:30:04.81,yin,,0,0,0,,否则 匹配计数如果是0\\N{\\fs12}Otherwise, this matches dot count is 0,\r\nDialogue: 0,0:30:04.81,0:30:06.96,yin,,0,0,0,,返回的是空数组\\N{\\fs12}so it returned an array, an empty array.\r\nDialogue: 0,0:30:06.96,0:30:09.65,yin,,0,0,0,,这意味着我要找的唯一标识符照片并不存在\\N{\\fs12}That means I looked for that photo that had that unique,\r\nDialogue: 0,0:30:09.65,0:30:11.74,yin,,0,0,0,,这意味着我要找的唯一标识符照片并不存在\\N{\\fs12}I couldn't find it, so that photo doesn't exist.\r\nDialogue: 0,0:30:11.74,0:30:13.69,yin,,0,0,0,,我现在需要创建它\\N{\\fs12}I now need to create it.\r\nDialogue: 0,0:30:13.69,0:30:16.31,yin,,0,0,0,,记得如何在数据库中创建对象吗\\N{\\fs12}Okay, everyone remember how to create an object in the database?\r\nDialogue: 0,0:30:16.31,0:30:19.31,yin,,0,0,0,,NSEntityDescription\\N{\\fs12}NS entity description,\r\nDialogue: 0,0:30:19.32,0:30:22.51,yin,,0,0,0,,insertNewObjectForEntityForName\\N{\\fs12}insert new object for entity for name,\r\nDialogue: 0,0:30:22.51,0:30:26.73,yin,,0,0,0,,我们插入一张照片 显然我们还需要指定context\\N{\\fs12}we're inserting a photo, and we obviously have to specify the context.\r\nDialogue: 0,0:30:26.73,0:30:28.75,yin,,0,0,0,,我们于是创建了一张照片\\N{\\fs12}So, we created a photo.\r\nDialogue: 0,0:30:28.75,0:30:29.93,yin,,0,0,0,,很好\\N{\\fs12}Excellent.\r\nDialogue: 0,0:30:29.93,0:30:34.44,yin,,0,0,0,,下面 我们进一步设置照片的属性\\N{\\fs12}And, now, let's go ahead and set the attributes of the photo.\r\nDialogue: 0,0:30:34.44,0:30:39.11,yin,,0,0,0,,我还要设置照片的unique\\N{\\fs12}I'm also going to set the photo's unique, go to unique.\r\nDialogue: 0,0:30:39.11,0:30:43.64,yin,,0,0,0,,这里我设置了照片的标题 副标题 图像URL\\N{\\fs12}Alright, so here I'm setting the photos title, subtitle, image URL.\r\nDialogue: 0,0:30:43.64,0:30:47.37,yin,,0,0,0,,这里我用valueForKeyPath 设置了标题\\N{\\fs12}So here I'm just setting the title using value for key path\r\nDialogue: 0,0:30:47.37,0:30:48.95,yin,,0,0,0,,从Flickr字典中\\N{\\fs12}out of the Flickr dictionary,\r\nDialogue: 0,0:30:48.95,0:30:51.37,yin,,0,0,0,,副标题 给定描述下 还有URL\\N{\\fs12}the subtitle, given the description, the URL.\r\nDialogue: 0,0:30:51.37,0:30:53.66,yin,,0,0,0,,我把这个URL用于照片格式这些\\N{\\fs12}I'm using this URL for photo format thing.\r\nDialogue: 0,0:30:53.66,0:30:57.27,yin,,0,0,0,,我要把它转换成字符串 因为数据库中不能放URL\\N{\\fs12}I have to turn it into a string, okay, because can't put URLs in the database,\r\nDialogue: 0,0:30:57.27,0:30:58.76,yin,,0,0,0,,但可以放字符串\\N{\\fs12}but we can put strings there,\r\nDialogue: 0,0:30:58.78,0:31:00.67,yin,,0,0,0,,然后我还有拍照者名字\\N{\\fs12}and then I also have the photographer name,\r\nDialogue: 0,0:31:00.67,0:31:03.21,yin,,0,0,0,,不过我有一个和拍照者实体之间的关系\\N{\\fs12}but I have a relationship to photographer entity,\r\nDialogue: 0,0:31:03.21,0:31:06.14,yin,,0,0,0,,因此 现在我还需要创建一个拍照者\\N{\\fs12}so now I need to create a photographer as well.\r\nDialogue: 0,0:31:06.14,0:31:09.59,yin,,0,0,0,,于是这里 从Flickr加载一张照片\\N{\\fs12}So here, loading a photo, right from Flickr,\r\nDialogue: 0,0:31:09.59,0:31:12.91,yin,,0,0,0,,会导致拍照者也被创建出来\\N{\\fs12}is causing a photographer also to be created.\r\nDialogue: 0,0:31:12.91,0:31:15.58,yin,,0,0,0,,这在作业中也会发生\\N{\\fs12}Okay, and this is happen in your homework too in spades.\r\nDialogue: 0,0:31:15.58,0:31:18.25,yin,,0,0,0,,你会从Flickr下载这些照片\\N{\\fs12}Okay, where you're going to download these photos from\r\nDialogue: 0,0:31:18.25,0:31:20.77,yin,,0,0,0,,你还要创建整个数据库\\N{\\fs12}Flickr, and you're going to build your entire database.\r\nDialogue: 0,0:31:20.77,0:31:23.23,yin,,0,0,0,,很多实体总在被创建\\N{\\fs12}Lots of entities are going to be created all the time,\r\nDialogue: 0,0:31:23.23,0:31:26.20,yin,,0,0,0,,每次有东西从Flickr回来都是如此\\N{\\fs12}every time things come back from Flickr.\r\nDialogue: 0,0:31:26.20,0:31:28.73,yin,,0,0,0,,那我们如何创建拍照者呢\\N{\\fs12}So, how do we create a photographer?\r\nDialogue: 0,0:31:28.73,0:31:31.24,yin,,0,0,0,,我会和这里做一样的事\\N{\\fs12}Well, I'm going to do the same thing I did here,\r\nDialogue: 0,0:31:31.24,0:31:33.97,yin,,0,0,0,,这里照片的category创建的是这个\\N{\\fs12}where I have this photo category that creates that,\r\nDialogue: 0,0:31:33.97,0:31:35.88,yin,,0,0,0,,我要对拍照者做相同的事\\N{\\fs12}I'm going to do the same thing for photographers.\r\nDialogue: 0,0:31:35.88,0:31:38.87,yin,,0,0,0,,新文件 创建另一个category\\N{\\fs12}I'm going to say new file, another category.\r\nDialogue: 0,0:31:38.87,0:31:41.61,yin,,0,0,0,,这将是拍照者的category\\N{\\fs12}This is going to be a category in photography, photographer.\r\nDialogue: 0,0:31:41.61,0:31:43.16,yin,,0,0,0,,这不是特别用于Flickr的\\N{\\fs12}This one's not Flickr specific,\r\nDialogue: 0,0:31:43.16,0:31:45.19,yin,,0,0,0,,因为拍照者只有一个名字\\N{\\fs12}because photographer only has a name, so I'm going\r\nDialogue: 0,0:31:45.19,0:31:49.43,yin,,0,0,0,,因此 我打算把这个category叫作Create 而非Flickr\\N{\\fs12}to call this category, just to be different, create, instead of Flickr.\r\nDialogue: 0,0:31:49.43,0:31:51.93,yin,,0,0,0,,还是放到相同的地方\\N{\\fs12}So, we'll put this in the same place.\r\nDialogue: 0,0:31:51.93,0:31:53.86,yin,,0,0,0,,这里\\N{\\fs12}Here it is right here.\r\nDialogue: 0,0:31:53.86,0:31:59.00,yin,,0,0,0,,上面这里 Photographer 对\\N{\\fs12}Put this up here, and Photographer, yeah.\r\nDialogue: 0,0:31:59.00,0:32:00.63,yin,,0,0,0,,它非常类似\\N{\\fs12}It's very similar.\r\nDialogue: 0,0:32:00.63,0:32:01.79,yin,,0,0,0,,几乎完全一样\\N{\\fs12}It looks almost exactly the same.\r\nDialogue: 0,0:32:01.79,0:32:02.95,yin,,0,0,0,,我们为它进行取回\\N{\\fs12}We're going to fetch for it.\r\nDialogue: 0,0:32:02.95,0:32:07.09,yin,,0,0,0,,我们要处理找不到的情况 设定名称 等等\\N{\\fs12}We'll handle, if we can't find it, set the name, all that business.\r\nDialogue: 0,0:32:07.09,0:32:09.75,yin,,0,0,0,,把这些放到头文件中\\N{\\fs12}So, we put that in the header file, okay.\r\nDialogue: 0,0:32:11.51,0:32:14.37,yin,,0,0,0,,尝试加速一些\\N{\\fs12}Just trying to speed it up a little bit here.\r\nDialogue: 0,0:32:14.37,0:32:16.76,yin,,0,0,0,,看我做这些 你们学不到新东西\\N{\\fs12}You wouldn't learn anything new by my doing this all again.\r\nDialogue: 0,0:32:16.76,0:32:22.00,yin,,0,0,0,,这样我就能创建一个拍照者 给定名字 给定context\\N{\\fs12}But, now I have a way to create a photographer, given a name in a given context.\r\nDialogue: 0,0:32:22.00,0:32:23.43,yin,,0,0,0,,把那个用到这里\\N{\\fs12}So, we'll use that over here,\r\nDialogue: 0,0:32:23.43,0:32:27.76,yin,,0,0,0,,我们说 photo.whoTook = …\\N{\\fs12}and we'll just say photo.whotook equals,\r\nDialogue: 0,0:32:27.76,0:32:30.59,yin,,0,0,0,,我们需要导入那个category\\N{\\fs12}and we've got to import that little category.\r\nDialogue: 0,0:32:30.59,0:32:35.72,yin,,0,0,0,,Photographer+Create\\N{\\fs12}Photographer create.\r\nDialogue: 0,0:32:35.72,0:32:39.79,yin,,0,0,0,,Photographer\\N{\\fs12}Photographer,\r\nDialogue: 0,0:32:39.79,0:32:41.38,yin,,0,0,0,,photographerWithName\\N{\\fs12}photographer with name\r\nDialogue: 0,0:32:41.38,0:32:45.57,yin,,0,0,0,,名字也就是我们从Flickr获得的拍照者名字\\N{\\fs12}and the name is the photographer name that we got out of the Flickr thing,\r\nDialogue: 0,0:32:45.57,0:32:47.58,yin,,0,0,0,,context一样\\N{\\fs12}and same context.\r\nDialogue: 0,0:32:50.99,0:32:53.60,yin,,0,0,0,,大家都理解了这个方法吧\\N{\\fs12}Everyone understand this method right here.\r\nDialogue: 0,0:32:53.60,0:32:55.51,yin,,0,0,0,,对于这个方法\\N{\\fs12}So, this method is going to,\r\nDialogue: 0,0:32:55.51,0:32:59.09,yin,,0,0,0,,如果我们从照片信息给它一个Flickr字典\\N{\\fs12}if we give it a Flickr dictionary from photo info,\r\nDialogue: 0,0:32:59.11,0:33:01.50,yin,,0,0,0,,它会返给我们一个数据库中的照片对象\\N{\\fs12}it's going to give us back a photo object in the database,\r\nDialogue: 0,0:33:01.51,0:33:02.81,yin,,0,0,0,,要么是创建一个\\N{\\fs12}either by creating it\r\nDialogue: 0,0:33:02.81,0:33:04.95,yin,,0,0,0,,要么是找一个已经有的\\N{\\fs12}or by finding one that's already there,\r\nDialogue: 0,0:33:04.95,0:33:09.01,yin,,0,0,0,,如果有问题 它也可以返回nil\\N{\\fs12}and it will return nil if it has a problem with it.\r\nDialogue: 0,0:33:09.01,0:33:11.75,yin,,0,0,0,,都理解了吗\\N{\\fs12}Everybody got that.\r\nDialogue: 0,0:33:11.75,0:33:15.41,yin,,0,0,0,,好 这样 我们就有了很好的访问方式\\N{\\fs12}Okay. So, now that we have this thing, we have these nice ways to access it.\r\nDialogue: 0,0:33:15.41,0:33:17.53,yin,,0,0,0,,下面再简单讲下TableView\\N{\\fs12}Let's talk a little bit about the TableView,\r\nDialogue: 0,0:33:17.53,0:33:20.52,yin,,0,0,0,,以及如何把这些东西显示在TableView中\\N{\\fs12}and how we're going to display this stuff in a TableView,\r\nDialogue: 0,0:33:20.52,0:33:22.47,yin,,0,0,0,,我们能很简单地\\N{\\fs12}and it's really a simple matter\r\nDialogue: 0,0:33:22.47,0:33:28.43,yin,,0,0,0,,创建一个新的TableView子类\\N{\\fs12}of creating a new TableView subclass\r\nDialogue: 0,0:33:28.43,0:33:31.83,yin,,0,0,0,,来实现那个FetchedResultsController\\N{\\fs12}that implements that Fetch Results Controller business.\r\nDialogue: 0,0:33:31.83,0:33:34.32,yin,,0,0,0,,我讲过 你们有这个Core Data的东西\\N{\\fs12}And I told you that you were going to have this Core Data thing\r\nDialogue: 0,0:33:34.32,0:33:36.48,yin,,0,0,0,,让这个更容易 我们现在要用它\\N{\\fs12}to make that easy, so we're going to use that.\r\nDialogue: 0,0:33:36.48,0:33:38.55,yin,,0,0,0,,这是CoreDataTableViewController\\N{\\fs12}Here is the Core Data TableView controller.\r\nDialogue: 0,0:33:38.55,0:33:39.31,yin,,0,0,0,,拖进来\\N{\\fs12}We'll drag it in.\r\nDialogue: 0,0:33:39.31,0:33:41.03,yin,,0,0,0,,这里我们来看看它\\N{\\fs12}We'll take a look at it here.\r\nDialogue: 0,0:33:41.03,0:33:44.27,yin,,0,0,0,,这是Core Data表格视图\\N{\\fs12}Alright, so here's the Core Data TableView.\r\nDialogue: 0,0:33:44.27,0:33:45.43,yin,,0,0,0,,这是它的头文件\\N{\\fs12}Here's its header file.\r\nDialogue: 0,0:33:45.43,0:33:48.41,yin,,0,0,0,,可以看到 它有这个FetchedResultsController的东西\\N{\\fs12}You can see, it just has this Fetch Results Controller thing.\r\nDialogue: 0,0:33:48.41,0:33:51.18,yin,,0,0,0,,它还有一个强制取回的方式 但你不需要这样做\\N{\\fs12}It also has a way to force it to Fetch, but you don't ever have to do that.\r\nDialogue: 0,0:33:51.18,0:33:52.54,yin,,0,0,0,,它会自动发生\\N{\\fs12}It will happen automatically.\r\nDialogue: 0,0:33:52.54,0:33:55.26,yin,,0,0,0,,它有这个属性 再看这个的实现\\N{\\fs12}So, it has this property, and if you look at this implementation of this thing.\r\nDialogue: 0,0:33:55.26,0:33:59.31,yin,,0,0,0,,除了设置FetchedResultsController…\\N{\\fs12}Besides setting the Fetcher Results Controller,\r\nDialogue: 0,0:33:59.31,0:34:02.59,yin,,0,0,0,,我放到这里的其实主要是一些日志\\N{\\fs12}which is mostly just a bunch of logs, okay, that I put in there.\r\nDialogue: 0,0:34:02.59,0:34:07.47,yin,,0,0,0,,它还实现UITableViewDataSource 看到了没\\N{\\fs12}It's implementing UI-TableView data source, you see,\r\nDialogue: 0,0:34:07.47,0:34:09.44,yin,,0,0,0,,用FetchedResultsController\\N{\\fs12}in terms of the Fetch Result Controller.\r\nDialogue: 0,0:34:09.44,0:34:11.74,yin,,0,0,0,,然后 它还做了这些委托的事情\\N{\\fs12}And then, it's also doing this delegate business,\r\nDialogue: 0,0:34:11.74,0:34:14.82,yin,,0,0,0,,监视数据库中的变化\\N{\\fs12}where it's watching for changes in the database.\r\nDialogue: 0,0:34:14.82,0:34:16.79,yin,,0,0,0,,就这些了\\N{\\fs12}Okay, and that's it. That's all it does.\r\nDialogue: 0,0:34:16.79,0:34:18.58,yin,,0,0,0,,这段代码实际上复制粘贴自\\N{\\fs12}And this code is actually copied and pasted\r\nDialogue: 0,0:34:18.58,0:34:21.14,yin,,0,0,0,,NSFetchedResultsController的说明文档\\N{\\fs12}from the documentation for NS Fetch Results Controller,\r\nDialogue: 0,0:34:21.14,0:34:24.60,yin,,0,0,0,,这里没有什么值得惊喜的\\N{\\fs12}so this is nothing exciting in here.\r\nDialogue: 0,0:34:24.60,0:34:28.89,yin,,0,0,0,,创建关联数据库的TableView时\\N{\\fs12}So, when we create a TableView that wants to look in the database,\r\nDialogue: 0,0:34:28.89,0:34:30.69,yin,,0,0,0,,我们创建了类\\N{\\fs12}okay, we've created objectives in class,\r\nDialogue: 0,0:34:30.69,0:34:33.81,yin,,0,0,0,,现在我们要创建CoreDataTableViewController的子类\\N{\\fs12}we're going to make it be a subclass of Core Data TableView Controller.\r\nDialogue: 0,0:34:33.81,0:34:34.98,yin,,0,0,0,,我要创建的这个\\N{\\fs12}So, I'm going to create one, and I'm going\r\nDialogue: 0,0:34:34.98,0:34:39.15,yin,,0,0,0,,叫作PhotographersCDTVC\\N{\\fs12}to call it photographers, I'm going to call it CDTVC,\r\nDialogue: 0,0:34:39.15,0:34:41.00,yin,,0,0,0,,CoreDataTableViewController的首字母\\N{\\fs12}Core Data TableView Controller.\r\nDialogue: 0,0:34:41.00,0:34:43.40,yin,,0,0,0,,有些人很喜欢这种命名惯例\\N{\\fs12}Okay, it's kind of a naming convention some people\r\nDialogue: 0,0:34:43.40,0:34:45.60,yin,,0,0,0,,我打算这样命名\\N{\\fs12}like to use, and so I'm going to do that.\r\nDialogue: 0,0:34:45.60,0:34:48.13,yin,,0,0,0,,因为它会显示拍照者 这就是它的作用\\N{\\fs12}Because it displays photographer; that's what it does.\r\nDialogue: 0,0:34:48.13,0:34:49.39,yin,,0,0,0,,创建这个\\N{\\fs12}So, let's create that.\r\nDialogue: 0,0:34:49.39,0:34:53.51,yin,,0,0,0,,还是放到顶层 同其它那些一样\\N{\\fs12}Let's put it top level; same place as everywhere else.\r\nDialogue: 0,0:34:53.51,0:34:55.13,yin,,0,0,0,,好了 创建成功\\N{\\fs12}Here it is. It's created it.\r\nDialogue: 0,0:34:55.13,0:34:57.73,yin,,0,0,0,,这些东西我都不需要\\N{\\fs12}I don't need any of this business for that.\r\nDialogue: 0,0:34:57.73,0:35:00.03,yin,,0,0,0,,我们来想想它的公共API\\N{\\fs12}And, let's think about its public API.\r\nDialogue: 0,0:35:00.03,0:35:01.71,yin,,0,0,0,,这个东西需要什么\\N{\\fs12}What does this thing need?\r\nDialogue: 0,0:35:01.71,0:35:05.55,yin,,0,0,0,,它和数据库中很多其它东西需要的一样\\N{\\fs12}Well, it needs what most things need that are doing database stuff.\r\nDialogue: 0,0:35:05.55,0:35:10.54,yin,,0,0,0,,它需要一个NSManagedObjectContext\\N{\\fs12}It needs an NS managed object context,\r\nDialogue: 0,0:35:10.55,0:35:12.14,yin,,0,0,0,,因此这个类\\N{\\fs12}and so, this class,\r\nDialogue: 0,0:35:12.14,0:35:15.96,yin,,0,0,0,,它的作用就是 给你展示所有拍照者\\N{\\fs12}its job in life is going to be, it will show you all the photographers\r\nDialogue: 0,0:35:15.96,0:35:18.43,yin,,0,0,0,,在给定context下 在给定数据库中\\N{\\fs12}in a given context, the given database.\r\nDialogue: 0,0:35:18.43,0:35:19.71,yin,,0,0,0,,你到数据库中\\N{\\fs12}You give it a point or two databases;\r\nDialogue: 0,0:35:19.71,0:35:21.55,yin,,0,0,0,,它会给你其中所有的拍照者\\N{\\fs12}it will look in there and show you all the photographers in it.\r\nDialogue: 0,0:35:21.55,0:35:24.27,yin,,0,0,0,,这就是它的作用\\N{\\fs12}That's what this thing is going to do.\r\nDialogue: 0,0:35:24.27,0:35:28.80,yin,,0,0,0,,要让这个发生 它只需要设置\\N{\\fs12}So, to make that happen, all it needs to do is set\r\nDialogue: 0,0:35:28.80,0:35:31.99,yin,,0,0,0,,FetchedResultsController那些 在它的超类中\\N{\\fs12}that Fetch Results Controller thing in its super class, right?\r\nDialogue: 0,0:35:31.99,0:35:35.41,yin,,0,0,0,,也就是CoreDataTableViewController 我来做这个\\N{\\fs12}Which is its Core Data TableView controller, so I'm going to do that.\r\nDialogue: 0,0:35:35.41,0:35:39.76,yin,,0,0,0,,只要有人设置了ManagedObjectContext\\N{\\fs12}As soon as someone sets the managed object context.\r\nDialogue: 0,0:35:39.76,0:35:46.18,yin,,0,0,0,,这个叫作managedObjectContext吧 这样更清楚一些\\N{\\fs12}Let's call this managed object context, so it's a little clearer.\r\nDialogue: 0,0:35:46.18,0:35:50.30,yin,,0,0,0,,只要有人设置了ManagedObjectContext\\N{\\fs12}As soon as someone sets this managed object context,\r\nDialogue: 0,0:35:50.30,0:35:54.76,yin,,0,0,0,,我就能设置我的FetchedResultsController\\N{\\fs12}I'm going to be able to set up my Fetch Results Controller.\r\nDialogue: 0,0:35:54.76,0:35:58.35,yin,,0,0,0,,只有有了context才能设置FetchedResultsController\\N{\\fs12}I can't set up my Fetch Results Controller until I have the context.\r\nDialogue: 0,0:35:58.35,0:36:01.70,yin,,0,0,0,,有时 context通过这样的公共API给到我\\N{\\fs12}Sometimes, the context comes to me via public API like this.\r\nDialogue: 0,0:36:01.70,0:36:06.54,yin,,0,0,0,,有些视图控制器会从其它对象获得它们的context\\N{\\fs12}Some view controllers will get their context from other objects.\r\nDialogue: 0,0:36:06.54,0:36:09.31,yin,,0,0,0,,最显著的是 作业中这一点要注意\\N{\\fs12}Most notably, and pay attention here for your homework,\r\nDialogue: 0,0:36:09.31,0:36:12.13,yin,,0,0,0,,如果有人给你一个ManagedObject 例如照片\\N{\\fs12}if someone gives you a managed object like a photo\r\nDialogue: 0,0:36:12.13,0:36:13.20,yin,,0,0,0,,或拍照者\\N{\\fs12}or a photographer,\r\nDialogue: 0,0:36:13.20,0:36:17.63,yin,,0,0,0,,你现在就有了context 因为NSManagedObject有一个方法\\N{\\fs12}you now have the context, because NS managed object has a method\r\nDialogue: 0,0:36:17.63,0:36:19.98,yin,,0,0,0,,叫作managedObjectContext\\N{\\fs12}in it called managed object context.\r\nDialogue: 0,0:36:19.98,0:36:23.07,yin,,0,0,0,,它会给你对象的context\\N{\\fs12}It will give you the context that that object came out of.\r\nDialogue: 0,0:36:23.07,0:36:24.51,yin,,0,0,0,,了解这个很重要\\N{\\fs12}So, it's really important to understand.\r\nDialogue: 0,0:36:24.51,0:36:27.93,yin,,0,0,0,,如果有人给你一个Photo 你就有了ManagedObjectContext\\N{\\fs12}If someone gives you a photo, you have a managed object context,\r\nDialogue: 0,0:36:27.93,0:36:29.68,yin,,0,0,0,,不过这个处在顶层\\N{\\fs12}but this thing is at the top level.\r\nDialogue: 0,0:36:29.68,0:36:31.38,yin,,0,0,0,,它展示所有的拍照者\\N{\\fs12}It's showing all the photographers.\r\nDialogue: 0,0:36:31.38,0:36:33.20,yin,,0,0,0,,我们还没从数据库中得到任何东西\\N{\\fs12}We don't have anything yet out of the database,\r\nDialogue: 0,0:36:33.20,0:36:34.45,yin,,0,0,0,,因此有人需要告诉我们context\\N{\\fs12}so someone has to tell us the context.\r\nDialogue: 0,0:36:34.45,0:36:37.03,yin,,0,0,0,,从哪个数据库取回这些东西\\N{\\fs12}Which database to fetch these things out of?\r\nDialogue: 0,0:36:37.03,0:36:38.74,yin,,0,0,0,,下面我只需要说\\N{\\fs12}So, now I just need to say,\r\nDialogue: 0,0:36:38.74,0:36:41.43,yin,,0,0,0,,fetchResultsController = 什么东西\\N{\\fs12}Fetch Results Controller equals something, and so I'm going\r\nDialogue: 0,0:36:41.43,0:36:44.84,yin,,0,0,0,,我要创建一个新的FetchResultsController\\N{\\fs12}to create a new Fetch Results Controller.\r\nDialogue: 0,0:36:44.84,0:36:49.29,yin,,0,0,0,,alloc init\\N{\\fs12}Alloc init,\r\nDialogue: 0,0:36:49.29,0:36:52.58,yin,,0,0,0,,init有所有这些参数\\N{\\fs12}and its init has all these arguments here.\r\nDialogue: 0,0:36:52.58,0:36:54.87,yin,,0,0,0,,它需要一个FetchRequest\\N{\\fs12}It needs a Fetch Request, okay.\r\nDialogue: 0,0:36:54.87,0:36:57.96,yin,,0,0,0,,这里不要弄得这么晦涩\\N{\\fs12}Actually, let's, so we don't get this kind of blackiness,\r\nDialogue: 0,0:36:57.96,0:37:00.70,yin,,0,0,0,,先来看这些参数\\N{\\fs12}let's go ahead and make all the arguments first.\r\nDialogue: 0,0:37:00.70,0:37:02.09,yin,,0,0,0,,它需要一个FetchRequest\\N{\\fs12}It needs a Fetch Request,\r\nDialogue: 0,0:37:02.09,0:37:04.88,yin,,0,0,0,,因为这就是它的作用 关联一个FetchRequest\\N{\\fs12}because that's what it does is hook up a Fetch Request\r\nDialogue: 0,0:37:04.88,0:37:09.33,yin,,0,0,0,,那么 这就是一个请求\\N{\\fs12}to something, and so, this is a request\r\nDialogue: 0,0:37:09.33,0:37:14.68,yin,,0,0,0,,请求的是拍照者表格 我们想要一个拍照者\\N{\\fs12}into the photographer table, right, so we want photographer.\r\nDialogue: 0,0:37:14.68,0:37:17.20,yin,,0,0,0,,我们要展示所有的拍照者\\N{\\fs12}We're going to show all the photographers.\r\nDialogue: 0,0:37:17.20,0:37:19.70,yin,,0,0,0,,这个的谓词是nil\\N{\\fs12}The predicate for this thing is nil.\r\nDialogue: 0,0:37:19.70,0:37:22.47,yin,,0,0,0,,谓词为nil是什么意思\\N{\\fs12}What does that mean predicate nil?\r\nDialogue: 0,0:37:22.47,0:37:25.77,yin,,0,0,0,,谓词为nil是说 所有都要\\N{\\fs12}Predicate nil means all of them.\r\nDialogue: 0,0:37:25.77,0:37:28.22,yin,,0,0,0,,如果你说谓词为nil\\N{\\fs12}So, if you say predicate nil,\r\nDialogue: 0,0:37:28.22,0:37:30.50,yin,,0,0,0,,这是说 我要所有的拍照者\\N{\\fs12}that means give me all the photographers.\r\nDialogue: 0,0:37:30.50,0:37:33.46,yin,,0,0,0,,排序描述器 没错 我们要排序\\N{\\fs12}And sort descriptor, yea, let's sort these things.\r\nDialogue: 0,0:37:33.46,0:37:39.55,yin,,0,0,0,,排序这样来 sortDescriptorWithKey\\N{\\fs12}Let's sort them by, let's see, sort descriptor with key, well,\r\nDialogue: 0,0:37:39.55,0:37:41.68,yin,,0,0,0,,我们根据拍照者名字来排序\\N{\\fs12}let's sort photographers by their name.\r\nDialogue: 0,0:37:41.68,0:37:46.92,yin,,0,0,0,,实际上很有趣的是 你还可以通过关系来排序\\N{\\fs12}Amazingly, you can actually sort things by things through relationships.\r\nDialogue: 0,0:37:46.92,0:37:49.14,yin,,0,0,0,,你还可以通过其它对象的属性来排序\\N{\\fs12}So, you can sort it be other objects properties if you want.\r\nDialogue: 0,0:37:49.14,0:37:51.54,yin,,0,0,0,,不过这里 拍照者的排序\\N{\\fs12}But here, photographer, we're going to have it sort\r\nDialogue: 0,0:37:51.54,0:37:54.57,yin,,0,0,0,,我们打算根据名字来 采用降序\\N{\\fs12}by its name, and yes, we're going to have it descending,\r\nDialogue: 0,0:37:54.57,0:38:01.90,yin,,0,0,0,,这里的选择器我们选用localizedStandardCompare\\N{\\fs12}and we're going to use the selector here called localized standard compare, okay.\r\nDialogue: 0,0:38:01.90,0:38:07.21,yin,,0,0,0,,对于字符串 我们一般都用这个\\N{\\fs12}Which is what we use mostly for strings that are going to appear when these interface.\r\nDialogue: 0,0:38:07.21,0:38:09.69,yin,,0,0,0,,数组要有闭括号\\N{\\fs12}We need to close our array there,\r\nDialogue: 0,0:38:09.69,0:38:12.12,yin,,0,0,0,,因为这是一个排序描述器的数组\\N{\\fs12}because this is an array of sort descriptors. We only need one,\r\nDialogue: 0,0:38:12.12,0:38:15.83,yin,,0,0,0,,我们还可以施加限制 例如只要一百个\\N{\\fs12}and we could limit like, for example we could say, only give us a hundred.\r\nDialogue: 0,0:38:15.83,0:38:20.04,yin,,0,0,0,,我们只要一百个拍照者 这当然有些傻\\N{\\fs12}We only want to see a hundred photographers, which would be kind of silly\r\nDialogue: 0,0:38:20.04,0:38:21.85,yin,,0,0,0,,因为这里是字母顺序排序\\N{\\fs12}because we are sorting alphabetically,\r\nDialogue: 0,0:38:21.85,0:38:23.56,yin,,0,0,0,,这没有意义 这样的话\\N{\\fs12}so this would not make sense, because we wouldn't get\r\nDialogue: 0,0:38:23.56,0:38:26.12,yin,,0,0,0,,名字字母序靠后的人就永远不会出现\\N{\\fs12}to see the people whose names unfortunately happen to be end\r\nDialogue: 0,0:38:26.12,0:38:27.55,yin,,0,0,0,,因此这里我们不会这样做\\N{\\fs12}of the alphabet, but we wouldn't do it here.\r\nDialogue: 0,0:38:27.55,0:38:28.70,yin,,0,0,0,,不过有些情况下需要这样\\N{\\fs12}But, in other cases you would.\r\nDialogue: 0,0:38:28.70,0:38:31.76,yin,,0,0,0,,作业中 你可能就会这样做\\N{\\fs12}In your homework, you very well might do that.\r\nDialogue: 0,0:38:31.76,0:38:36.65,yin,,0,0,0,,好 我们有了请求 有了ManagedObjectContext\\N{\\fs12}Alright, so now, we have the request, we have the managed object context.\r\nDialogue: 0,0:38:36.65,0:38:40.44,yin,,0,0,0,,这是这个方法的参数 我们也设置了\\N{\\fs12}That's an argument to this method is what we're setting actually.\r\nDialogue: 0,0:38:40.44,0:38:41.58,yin,,0,0,0,,这是section那些\\N{\\fs12}Here's the section thing.\r\nDialogue: 0,0:38:41.58,0:38:42.93,yin,,0,0,0,,我们可以在这里做\\N{\\fs12}We could make sections here,\r\nDialogue: 0,0:38:42.94,0:38:44.93,yin,,0,0,0,,不过Photographer中没有东西可以做到这个\\N{\\fs12}but there's really nothing in a photographer to do that,\r\nDialogue: 0,0:38:44.94,0:38:48.48,yin,,0,0,0,,因此这里我们不打算做 缓存也免了\\N{\\fs12}so we won't do that, and we're not going to cache.\r\nDialogue: 0,0:38:48.48,0:38:51.96,yin,,0,0,0,,就是这样了 就只需要这些了\\N{\\fs12}So, that's it. That's really all that's required\r\nDialogue: 0,0:38:51.96,0:38:55.25,yin,,0,0,0,,这样TableView就能工作了 不过还有一点\\N{\\fs12}to make this TableView work, except for one thing,\r\nDialogue: 0,0:38:55.25,0:38:57.45,yin,,0,0,0,,也就是 FetchResultsController\\N{\\fs12}which is that Fetch Results Controller,\r\nDialogue: 0,0:38:57.45,0:38:59.85,yin,,0,0,0,,我讲过 它实现了所有的UITableViewDataSource\\N{\\fs12}I told you it implemented all the UI-TableView data source\r\nDialogue: 0,0:38:59.85,0:39:02.68,yin,,0,0,0,,不过有一个它不能实现 也就是\\N{\\fs12}things, but there's one of them it can't implement which is\r\nDialogue: 0,0:39:02.68,0:39:04.84,yin,,0,0,0,,cellForRowAtIndexPath\\N{\\fs12}cell for row at index path.\r\nDialogue: 0,0:39:04.84,0:39:07.66,yin,,0,0,0,,它不知道对象的什么属性\\N{\\fs12}Okay, it doesn't really know what attributes\r\nDialogue: 0,0:39:07.66,0:39:11.43,yin,,0,0,0,,你想放到UITableViewCell的哪些部分\\N{\\fs12}of the object you want to put in which parts of the UI-TableView cell.\r\nDialogue: 0,0:39:11.43,0:39:14.32,yin,,0,0,0,,标题 副标题 它不知道这些\\N{\\fs12}The title, the subtitle, it doesn't know those things.\r\nDialogue: 0,0:39:14.32,0:39:16.43,yin,,0,0,0,,因此 我们需要自己来实现\\N{\\fs12}So, we have to implement that ourselves.\r\nDialogue: 0,0:39:16.43,0:39:20.68,yin,,0,0,0,,这是UITableViewCell\\N{\\fs12}So, that's UI-TableView cell,\r\nDialogue: 0,0:39:20.68,0:39:22.91,yin,,0,0,0,,cellForRowAtIndexPath\\N{\\fs12}cellForRowAtIndexPath.\r\nDialogue: 0,0:39:22.91,0:39:25.18,yin,,0,0,0,,这个东西你应该非常熟悉才行\\N{\\fs12}You should be very, very, very familiar with this thing.\r\nDialogue: 0,0:39:25.18,0:39:28.74,yin,,0,0,0,,它是这样的 cell =\\N{\\fs12}It just looks like this, cell equal,\r\nDialogue: 0,0:39:28.74,0:39:32.72,yin,,0,0,0,,self.tableView Dequeue…\\N{\\fs12}self.tableview DQ,\r\nDialogue: 0,0:39:32.74,0:39:35.87,yin,,0,0,0,,这些是拍照者 因此这里称作Photographer Cell\\N{\\fs12}and well, these are photographers, so we'll call this photographer cells.\r\nDialogue: 0,0:39:35.87,0:39:38.53,yin,,0,0,0,,你们要监督我的工作\\N{\\fs12}We got to make sure you guys are going to keep me honest.\r\nDialogue: 0,0:39:38.53,0:39:40.32,yin,,0,0,0,,确保我记得在故事板中设置这个\\N{\\fs12}Make sure I remember to set that in the story board\r\nDialogue: 0,0:39:40.32,0:39:42.52,yin,,0,0,0,,确保我记得在故事板中设置这个\\N{\\fs12}when we create one of these in the story board.\r\nDialogue: 0,0:39:42.52,0:39:50.11,yin,,0,0,0,,现在 我需要这个行和这个section处的拍照者\\N{\\fs12}And now, I need the photographer that is at this row and section.\r\nDialogue: 0,0:39:50.11,0:39:57.23,yin,,0,0,0,,我将首先导入Photographer.h\\N{\\fs12}So, I'm going to import photographer first of all, not create, .H.\r\nDialogue: 0,0:39:57.23,0:39:58.97,yin,,0,0,0,,好 这就是Photographer\\N{\\fs12}Okay, so there's the photographer.\r\nDialogue: 0,0:39:58.97,0:40:01.36,yin,,0,0,0,,然后我要说 photographer = …\\N{\\fs12}And, then I'm going to say photographer equals,\r\nDialogue: 0,0:40:01.36,0:40:06.31,yin,,0,0,0,,这个怎么做呢 photographer = self.\\N{\\fs12}and how do I do this, photographer equals self.\r\nDialogue: 0,0:40:06.31,0:40:10.73,yin,,0,0,0,,fetchedResultsController objectAtIndexPath:indexPath\\N{\\fs12}Fetched results controller, object at index path, index path.\r\nDialogue: 0,0:40:10.73,0:40:13.98,yin,,0,0,0,,这就得到了这一行处的拍照者\\N{\\fs12}Now I have the photographer that's in this row.\r\nDialogue: 0,0:40:13.98,0:40:15.84,yin,,0,0,0,,有了这个之后\\N{\\fs12}So, now that I have that, I can do things\r\nDialogue: 0,0:40:15.84,0:40:22.51,yin,,0,0,0,,我就可以说 textLabel.text = 拍照者的名字\\N{\\fs12}like text label.text equals let's say the photographers name of course.\r\nDialogue: 0,0:40:22.51,0:40:24.26,yin,,0,0,0,,再来点酷的\\N{\\fs12}Also, how about something cool like this,\r\nDialogue: 0,0:40:24.26,0:40:29.61,yin,,0,0,0,,cell.detailTextLabel = 一个带格式的字符串\\N{\\fs12}cell.detail text label equals a string with format.\r\nDialogue: 0,0:40:31.07,0:40:34.91,yin,,0,0,0,,如果我想要拍照者所拍的照片数量呢\\N{\\fs12}What if I wanted to put how many photos this photographer has taken,\r\nDialogue: 0,0:40:34.91,0:40:37.97,yin,,0,0,0,,这个信息很容易从数据库中获得\\N{\\fs12}well that information is readily available to me in the database,\r\nDialogue: 0,0:40:37.98,0:40:40.18,yin,,0,0,0,,%d photos\\N{\\fs12}percent D photos,\r\nDialogue: 0,0:40:40.18,0:40:45.66,yin,,0,0,0,,photographer.photos count\\N{\\fs12}photographer.photos count.\r\nDialogue: 0,0:40:45.66,0:40:50.65,yin,,0,0,0,,好 Xcode中 它是这样的\\N{\\fs12}Okay, X code, shoot, the way it does that.\r\nDialogue: 0,0:40:50.65,0:40:52.02,yin,,0,0,0,,好\\N{\\fs12}Okay.\r\nDialogue: 0,0:40:52.02,0:40:55.19,yin,,0,0,0,,我刚搞定了这个东西\\N{\\fs12}So, I just go through that thing that goes through that thing\r\nDialogue: 0,0:40:55.19,0:40:56.94,yin,,0,0,0,,whoTook photos关系\\N{\\fs12}that who took photos relationship.\r\nDialogue: 0,0:40:56.94,0:40:58.25,yin,,0,0,0,,我抓取了photos一侧\\N{\\fs12}I just grab the photos side.\r\nDialogue: 0,0:40:58.25,0:40:59.39,yin,,0,0,0,,它是一个NSSet\\N{\\fs12}It's an NS set.\r\nDialogue: 0,0:40:59.39,0:41:01.11,yin,,0,0,0,,NSSet实现count计数\\N{\\fs12}NS set implements count.\r\nDialogue: 0,0:41:01.11,0:41:03.82,yin,,0,0,0,,我就得到了我要的\\N{\\fs12}I got what I need.\r\nDialogue: 0,0:41:03.82,0:41:05.81,yin,,0,0,0,,然后返回cell\\N{\\fs12}And, then let's return this cell.\r\nDialogue: 0,0:41:07.81,0:41:10.41,yin,,0,0,0,,大家都理解这个cellForRowAtIndexPath了吗\\N{\\fs12}Okay, every one understand this cellForRowAtIndexPath.\r\nDialogue: 0,0:41:10.41,0:41:10.86,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:41:15.06,0:41:17.33,yin,,0,0,0,,对 这个属性 fetchedResultsController\\N{\\fs12}Yes, this property fetchedResultsController\r\nDialogue: 0,0:41:17.33,0:41:19.51,yin,,0,0,0,,继承自CoreDataTableView\\N{\\fs12}is inherited from Core Data TableView.\r\nDialogue: 0,0:41:19.51,0:41:22.19,yin,,0,0,0,,问得很好\\N{\\fs12}That's actually a good question.\r\nDialogue: 0,0:41:22.19,0:41:24.21,yin,,0,0,0,,好 我们继续\\N{\\fs12}Okay, so let's go ahead\r\nDialogue: 0,0:41:24.21,0:41:29.09,yin,,0,0,0,,来创建相关的故事板 毕竟我们现在在做这个\\N{\\fs12}and build our story board while we're at this, and while we have this fresh in our minds.\r\nDialogue: 0,0:41:29.09,0:41:29.85,yin,,0,0,0,,它是这样的\\N{\\fs12}So, here it is.\r\nDialogue: 0,0:41:29.85,0:41:31.95,yin,,0,0,0,,这是我们得到的默认情形\\N{\\fs12}This is the kind of default one that we got.\r\nDialogue: 0,0:41:31.95,0:41:33.87,yin,,0,0,0,,删掉它 我们不需要它\\N{\\fs12}Let's get rid this. We don't want this.\r\nDialogue: 0,0:41:33.87,0:41:38.75,yin,,0,0,0,,拖出一个TableView\\N{\\fs12}Let's go bring out a TableView. So, here I'm just going to drag a TableView out here.\r\nDialogue: 0,0:41:38.75,0:41:47.41,yin,,0,0,0,,将它设置为PhotographersCDTVC\\N{\\fs12}I'm going to set it to be a photographers Core Data TableView Controller, right,\r\nDialogue: 0,0:41:47.42,0:41:50.56,yin,,0,0,0,,然后按需求设置cell\\N{\\fs12}and then let's set up our cell the way we want.\r\nDialogue: 0,0:41:50.56,0:41:54.53,yin,,0,0,0,,我们需要它是带有标题的 因为它将拥有拍照者名字\\N{\\fs12}We want it to be subtitled, because it's going to have the photographer name\r\nDialogue: 0,0:41:54.53,0:41:56.39,yin,,0,0,0,,然后是他们拍了多少张照片\\N{\\fs12}and then how many photos they took.\r\nDialogue: 0,0:41:56.39,0:42:01.83,yin,,0,0,0,,我们需要Photographer Cell作为再利用标识符\\N{\\fs12}We need to make sure that its photographer cell is our reuse identifier.\r\nDialogue: 0,0:42:01.83,0:42:03.60,yin,,0,0,0,,这就做好准备了\\N{\\fs12}Otherwise, we're ready to go.\r\nDialogue: 0,0:42:03.60,0:42:05.44,yin,,0,0,0,,如果数据库中有东西\\N{\\fs12}So, if we had stuff in our database,\r\nDialogue: 0,0:42:05.44,0:42:08.65,yin,,0,0,0,,现在开始运行 这个将能工作\\N{\\fs12}and we hit run right now, this would work.\r\nDialogue: 0,0:42:08.65,0:42:10.16,yin,,0,0,0,,我们只需要这些\\N{\\fs12}That's all we needed to do.\r\nDialogue: 0,0:42:10.16,0:42:14.52,yin,,0,0,0,,很少量的代码 将TableView和Core Data关联了起来\\N{\\fs12}An incredibly small amount of code to hook up a table view to Core Data.\r\nDialogue: 0,0:42:14.52,0:42:16.67,yin,,0,0,0,,不过 数据库中还没有数据\\N{\\fs12}But, of course, we have no data in our databases.\r\nDialogue: 0,0:42:16.67,0:42:20.59,yin,,0,0,0,,代码中还没有从Flickr查询加载任何东西\\N{\\fs12}Nowhere in our code are we querying from Flickr or loading stuff in, and so\r\nDialogue: 0,0:42:20.59,0:42:24.72,yin,,0,0,0,,我将利用需要这个的机会\\N{\\fs12}I'm going to use the opportunity of our needing that\r\nDialogue: 0,0:42:24.72,0:42:29.26,yin,,0,0,0,,为你们首次介绍应用委托\\N{\\fs12}to introduce you for the first time to your application delegate.\r\nDialogue: 0,0:42:29.26,0:42:33.01,yin,,0,0,0,,我总喜欢把这些文件移动到支持文件\\N{\\fs12}So, I've always been moving these files down to supporting files.\r\nDialogue: 0,0:42:33.01,0:42:34.92,yin,,0,0,0,,不要看它们\\N{\\fs12}Don't look at them, you know,\r\nDialogue: 0,0:42:34.92,0:42:36.97,yin,,0,0,0,,我要展示一下这里面有些什么\\N{\\fs12}and so now I'm going show you a little bit what's in here.\r\nDialogue: 0,0:42:36.97,0:42:41.15,yin,,0,0,0,,应用委托所监视的是\\N{\\fs12}So, your application delegate is kind of like,\r\nDialogue: 0,0:42:41.15,0:42:45.61,yin,,0,0,0,,应用程序中最高层发生的情况\\N{\\fs12}it is watching what's going on at the highest level of your application.\r\nDialogue: 0,0:42:45.61,0:42:47.61,yin,,0,0,0,,它会看应用的启动\\N{\\fs12}It sees your application has launched.\r\nDialogue: 0,0:42:47.61,0:42:52.39,yin,,0,0,0,,它会看应用退出活动\\N{\\fs12}Okay. It sees that your application has resigned being the active application.\r\nDialogue: 0,0:42:52.39,0:42:55.23,yin,,0,0,0,,它会看应用进入后台\\N{\\fs12}It sees that your application is entering the background.\r\nDialogue: 0,0:42:55.23,0:42:57.53,yin,,0,0,0,,我们知道在iOS中 一个app\\N{\\fs12}Okay, we know then iOS, the apps,\r\nDialogue: 0,0:42:57.53,0:43:00.13,yin,,0,0,0,,在你进入另一个app时并不会退出\\N{\\fs12}when you go to another app, they don't quit, they just kind\r\nDialogue: 0,0:43:00.13,0:43:03.06,yin,,0,0,0,,它会进入后台运行 我们可以找到这个\\N{\\fs12}of move into this background state, right, so we can find that.\r\nDialogue: 0,0:43:03.06,0:43:05.18,yin,,0,0,0,,你可以知道它什么时候进入前台\\N{\\fs12}You can find it when you move back into the foreground.\r\nDialogue: 0,0:43:05.18,0:43:07.03,yin,,0,0,0,,应用是否成为活动应用\\N{\\fs12}If you become the active application.\r\nDialogue: 0,0:43:07.03,0:43:10.85,yin,,0,0,0,,是否退出应用 这些都可以知道\\N{\\fs12}If someone's quitting your application, you find that out as well.\r\nDialogue: 0,0:43:10.85,0:43:13.57,yin,,0,0,0,,所有这些它都能够弄清\\N{\\fs12}So, it finds out all these things, and we're going to learn\r\nDialogue: 0,0:43:13.57,0:43:15.41,yin,,0,0,0,,以后我们还会学到\\N{\\fs12}about those later in the quarter, so I'm going\r\nDialogue: 0,0:43:15.41,0:43:18.28,yin,,0,0,0,,现在先把它们都删掉 不过我们要看这个\\N{\\fs12}to delete all those now, but we are going to look at this one.\r\nDialogue: 0,0:43:18.28,0:43:20.13,yin,,0,0,0,,这个是didFinishLaunchingWithOptions\\N{\\fs12}This one is did finish launching with option,\r\nDialogue: 0,0:43:20.13,0:43:23.76,yin,,0,0,0,,这里它告诉你 你的应用结束了启动\\N{\\fs12}so here it's tell you your application finished launching.\r\nDialogue: 0,0:43:23.76,0:43:25.59,yin,,0,0,0,,这时 你就可以\\N{\\fs12}This is a great time to do things\r\nDialogue: 0,0:43:25.59,0:43:28.72,yin,,0,0,0,,开始一些Flickr取回了\\N{\\fs12}like kick off some Flickr fetching or something.\r\nDialogue: 0,0:43:28.72,0:43:33.55,yin,,0,0,0,,在应用委托中 如果我要在这时进行Flickr取回\\N{\\fs12}Now, if I'm going to be doing my Flickr fetching here in my application delegate,\r\nDialogue: 0,0:43:33.55,0:43:35.24,yin,,0,0,0,,我就需要context\\N{\\fs12}I need the context.\r\nDialogue: 0,0:43:35.24,0:43:36.95,yin,,0,0,0,,在你们的作业中\\N{\\fs12}Okay, now in your homework,\r\nDialogue: 0,0:43:36.95,0:43:40.45,yin,,0,0,0,,你们需要通过创建UIManagedDocument来做到\\N{\\fs12}you're going to do that by creating a UI managed document.\r\nDialogue: 0,0:43:40.45,0:43:46.90,yin,,0,0,0,,不过这里 我有一小段代码\\N{\\fs12}But, here, I have a little piece of code that I got\r\nDialogue: 0,0:43:46.90,0:43:49.81,yin,,0,0,0,,来自我告诉过你们的另一个模板\\N{\\fs12}from that other template that I was telling you about\r\nDialogue: 0,0:43:49.81,0:43:51.78,yin,,0,0,0,,把它复制过来\\N{\\fs12}that I'm going to bring in here.\r\nDialogue: 0,0:43:51.78,0:43:54.59,yin,,0,0,0,,像这样 它是一个category\\N{\\fs12}It looks like this. It's a little category,\r\nDialogue: 0,0:43:54.59,0:43:58.85,yin,,0,0,0,,它有这个方法 createMainQueueManagedObjectContext\\N{\\fs12}and it has this method, create main queue managed object context.\r\nDialogue: 0,0:43:58.85,0:44:00.71,yin,,0,0,0,,这是一个ManagedObjectContext\\N{\\fs12}So, that's a managed object context\r\nDialogue: 0,0:44:00.71,0:44:04.93,yin,,0,0,0,,连有一个数据库 这个app的数据库\\N{\\fs12}that attaches to a database, the database for this app.\r\nDialogue: 0,0:44:04.93,0:44:09.56,yin,,0,0,0,,这个只有一个 很幸运 而且是在主队列上\\N{\\fs12}This only has one luckily, and gives me; it's on the main queue,\r\nDialogue: 0,0:44:09.56,0:44:13.30,yin,,0,0,0,,就像UIDocument一样 因此代码会非常类似\\N{\\fs12}just like a UI document one is, so this code can be similar.\r\nDialogue: 0,0:44:13.30,0:44:14.76,yin,,0,0,0,,然后 我还可以保存\\N{\\fs12}And then also, I can save it. Now,\r\nDialogue: 0,0:44:14.78,0:44:17.61,yin,,0,0,0,,UIManagedDocument并不需要这个saveContext\\N{\\fs12}I don't need this save context message for UI managed document,\r\nDialogue: 0,0:44:17.61,0:44:18.66,yin,,0,0,0,,因为它有自动保存\\N{\\fs12}because it auto saves.\r\nDialogue: 0,0:44:18.66,0:44:21.49,yin,,0,0,0,,但这里 如果创建ManagedObjectContext时\\N{\\fs12}But, here if I create this manage object context not using\r\nDialogue: 0,0:44:21.49,0:44:23.66,yin,,0,0,0,,不使用Document 那就需要这样做了\\N{\\fs12}a document, then I have to do that.\r\nDialogue: 0,0:44:23.66,0:44:26.25,yin,,0,0,0,,我说了 这是另外一种做法\\N{\\fs12}So, this is, like I said, the other way to do it,\r\nDialogue: 0,0:44:26.25,0:44:29.71,yin,,0,0,0,,这不需要用到作业中 我只是希望展示给你们\\N{\\fs12}which you're not going to do for your homework, but I just wanted to show you,\r\nDialogue: 0,0:44:29.71,0:44:32.03,yin,,0,0,0,,我不打算展示UIManagedDocument\\N{\\fs12}I didn't really didn't want to show you the UI managed document,\r\nDialogue: 0,0:44:32.03,0:44:33.79,yin,,0,0,0,,因为我要你们自己去弄清楚\\N{\\fs12}because I wanted you to figure that out on your own,\r\nDialogue: 0,0:44:33.79,0:44:35.65,yin,,0,0,0,,因此 我在演示中用这个\\N{\\fs12}so we're going to manage this one.\r\nDialogue: 0,0:44:35.65,0:44:37.32,yin,,0,0,0,,好 我添加了这个\\N{\\fs12}Okay, so I've added this.\r\nDialogue: 0,0:44:37.32,0:44:41.30,yin,,0,0,0,,这里是PhotomaniaAppDelegate\\N{\\fs12}This is a, you can see that the photo mania app delegate\r\nDialogue: 0,0:44:41.30,0:44:42.70,yin,,0,0,0,,category\\N{\\fs12}category,\r\nDialogue: 0,0:44:42.70,0:44:48.16,yin,,0,0,0,,它将这两个方法添加到了我的app委托\\N{\\fs12}so it simply added these two methods to my app delegate.\r\nDialogue: 0,0:44:49.89,0:44:53.01,yin,,0,0,0,,下面 我将首先创建一些属性\\N{\\fs12}Now, what I'm going to do here is I am just going to,\r\nDialogue: 0,0:44:53.01,0:44:56.35,yin,,0,0,0,,下面 我将首先创建一些属性\\N{\\fs12}first of all, let me create some property.\r\nDialogue: 0,0:44:56.35,0:44:59.33,yin,,0,0,0,,这是我刚创建的一些属性\\N{\\fs12}So, this is some stuff that I just created, some properties\r\nDialogue: 0,0:44:59.33,0:45:00.68,yin,,0,0,0,,这是我刚创建的一些属性\\N{\\fs12}that I need and stuff like that.\r\nDialogue: 0,0:45:00.68,0:45:03.35,yin,,0,0,0,,先直接放到这里 使用的时候\\N{\\fs12}For time, I'm just going to put them in here, but as we use them,\r\nDialogue: 0,0:45:03.35,0:45:04.92,yin,,0,0,0,,我会提到它们\\N{\\fs12}I will refer to them.\r\nDialogue: 0,0:45:04.92,0:45:07.07,yin,,0,0,0,,这里我要用的一个\\N{\\fs12}But one of them I'm going to use right here\r\nDialogue: 0,0:45:07.07,0:45:08.90,yin,,0,0,0,,是这个photoDatabaseContext\\N{\\fs12}is this photo database context.\r\nDialogue: 0,0:45:08.90,0:45:11.36,yin,,0,0,0,,我要在app委托中记录一个属性\\N{\\fs12}So, I'm going to keep a property in my app delegate,\r\nDialogue: 0,0:45:11.36,0:45:14.46,yin,,0,0,0,,也就是我们要进行取回和读取操作的context\\N{\\fs12}which is the context that we're going to be fetching into\r\nDialogue: 0,0:45:14.46,0:45:15.81,yin,,0,0,0,,也就是我们要进行取回和读取操作的context\\N{\\fs12}and that we're going to be reading out of.\r\nDialogue: 0,0:45:15.81,0:45:17.85,yin,,0,0,0,,我打算在这里设置\\N{\\fs12}So, I'm going to set that right here,\r\nDialogue: 0,0:45:17.85,0:45:25.08,yin,,0,0,0,,photoDatabaseContext = self create …\\N{\\fs12}photo data with context equals self create, oops,\r\nDialogue: 0,0:45:25.08,0:45:32.23,yin,,0,0,0,,我要导入PhotomaniaAppDelegate+MOC\\N{\\fs12}got to import that, import photo mania MOC.\r\nDialogue: 0,0:45:32.23,0:45:36.11,yin,,0,0,0,,这里我导入的是category的头文件 其中有create\\N{\\fs12}I'm just importing the category header file that has that create\r\nDialogue: 0,0:45:36.11,0:45:39.39,yin,,0,0,0,,也就是createMainQueueManagedObjectContext\\N{\\fs12}in that, so create main queue managed object context.\r\nDialogue: 0,0:45:39.39,0:45:41.75,yin,,0,0,0,,你也需要设置这个\\N{\\fs12}So, again, you're going to set this as well, but you're going\r\nDialogue: 0,0:45:41.75,0:45:44.57,yin,,0,0,0,,不过是从UIManagedDocument进行设置\\N{\\fs12}to set it from your UI managed document.\r\nDialogue: 0,0:45:44.57,0:45:46.88,yin,,0,0,0,,我有一个context\\N{\\fs12}So, now, I have a context,\r\nDialogue: 0,0:45:46.88,0:45:49.98,yin,,0,0,0,,我想开始进行Flickr取回\\N{\\fs12}and I want to start doing some Flickr Fetches, so I'm going\r\nDialogue: 0,0:45:49.98,0:45:55.27,yin,,0,0,0,,我要调用另一个方法 start… 叫什么来着\\N{\\fs12}to call another method here, start, what did I call this,\r\nDialogue: 0,0:45:55.27,0:45:59.66,yin,,0,0,0,,应该是startFlickrFetch\\N{\\fs12}start Flickr fetch, I think.\r\nDialogue: 0,0:45:59.66,0:46:04.00,yin,,0,0,0,,这就会在启动时 立刻开始Flickr取回\\N{\\fs12}So, that's just going to fire off a Flickr fetch as soon as we launch.\r\nDialogue: 0,0:46:04.00,0:46:05.39,yin,,0,0,0,,我们刚启动程序\\N{\\fs12}Okay, we just launched.\r\nDialogue: 0,0:46:05.39,0:46:07.73,yin,,0,0,0,,这个消息发送给我们\\N{\\fs12}Get this message gets sent to us when we launch,\r\nDialogue: 0,0:46:07.73,0:46:09.81,yin,,0,0,0,,然后我将立刻开始Flickr取回\\N{\\fs12}and I'm just going to fire off a Flickr fetch.\r\nDialogue: 0,0:46:09.81,0:46:12.31,yin,,0,0,0,,这就是启动时立刻开始取回的一种情况\\N{\\fs12}So, that's one of the times we're going to fetch is as soon as we launch.\r\nDialogue: 0,0:46:12.31,0:46:15.36,yin,,0,0,0,,其它情况我们有时也会立刻开始取回\\N{\\fs12}We're going to fetch some other times, so we're going to fetch as soon as we launch.\r\nDialogue: 0,0:46:16.84,0:46:20.00,yin,,0,0,0,,我打算把这个放到这里\\N{\\fs12}So, I'm going to go ahead and put this in here\r\nDialogue: 0,0:46:20.00,0:46:23.73,yin,,0,0,0,,我们可以看一下 我不打算一行行输入\\N{\\fs12}so we can look it, instead of my typing it in line by line,\r\nDialogue: 0,0:46:23.73,0:46:27.57,yin,,0,0,0,,这里有一些东西\\N{\\fs12}and this is something where it's got some stuff\r\nDialogue: 0,0:46:27.57,0:46:31.73,yin,,0,0,0,,我在课上没有详细讲过\\N{\\fs12}that I didn't teach really in detail in lecture,\r\nDialogue: 0,0:46:31.73,0:46:33.66,yin,,0,0,0,,不过你们应该基本能理解\\N{\\fs12}but you should mostly be able to understand.\r\nDialogue: 0,0:46:33.66,0:46:36.89,yin,,0,0,0,,这里做的主要是创建了一个session\\N{\\fs12}Mostly what this is doing here is it creates a session,\r\nDialogue: 0,0:46:36.89,0:46:41.11,yin,,0,0,0,,你们知道URLSession 我创建了这个session\\N{\\fs12}so you know about URL sessions, so I'm creating this session.\r\nDialogue: 0,0:46:41.11,0:46:43.66,yin,,0,0,0,,这个session同我们之前创建的略有不同\\N{\\fs12}This session is a little different than the one we created before,\r\nDialogue: 0,0:46:43.66,0:46:45.79,yin,,0,0,0,,因为它有一个委托\\N{\\fs12}because look, it has a delegate.\r\nDialogue: 0,0:46:45.79,0:46:46.60,yin,,0,0,0,,看到了吗\\N{\\fs12}You see that.\r\nDialogue: 0,0:46:46.60,0:46:48.71,yin,,0,0,0,,之前我们没有指定委托\\N{\\fs12}We didn't specify a delegate before.\r\nDialogue: 0,0:46:48.71,0:46:50.41,yin,,0,0,0,,委托为nil\\N{\\fs12}Okay, we had delegate nil.\r\nDialogue: 0,0:46:50.41,0:46:53.24,yin,,0,0,0,,为什么要委托呢\\N{\\fs12}And, why do we want a delegate, and why are we making it so.\r\nDialogue: 0,0:46:53.24,0:46:55.95,yin,,0,0,0,,因为我们希望后台开始的这些Flickr取回\\N{\\fs12}Well, that's because we want these Flickr Fetches\r\nDialogue: 0,0:46:55.95,0:46:57.52,yin,,0,0,0,,因为我们希望后台开始的这些Flickr取回\\N{\\fs12}that we're starting off in the background.\r\nDialogue: 0,0:46:57.52,0:47:00.51,yin,,0,0,0,,如果它们在应用不再运行时结束\\N{\\fs12}If they finish while our application is no longer running,\r\nDialogue: 0,0:47:00.53,0:47:03.44,yin,,0,0,0,,我们希望它启动应用并告知我们\\N{\\fs12}we want it to launch our application and tell us.\r\nDialogue: 0,0:47:03.44,0:47:05.01,yin,,0,0,0,,或者 如果我们在后台\\N{\\fs12}Or, if we're in the background,\r\nDialogue: 0,0:47:05.01,0:47:07.11,yin,,0,0,0,,我们不是用户正在使用的应用\\N{\\fs12}we're not the application the user is using right now,\r\nDialogue: 0,0:47:07.11,0:47:10.02,yin,,0,0,0,,而这个URL Flickr返回了一些信息\\N{\\fs12}and this URL Flickr comes back with some information,\r\nDialogue: 0,0:47:10.02,0:47:14.59,yin,,0,0,0,,我们希望它唤醒一些 并让我们处理它\\N{\\fs12}we want it to you know, make us, wake us up a little bit and let us process it.\r\nDialogue: 0,0:47:14.59,0:47:16.95,yin,,0,0,0,,通过这个委托\\N{\\fs12}Okay, so by doing this delegate,\r\nDialogue: 0,0:47:16.95,0:47:21.63,yin,,0,0,0,,同某些后台session一起 我们可以做到这些\\N{\\fs12}along with a background session, we can do that.\r\nDialogue: 0,0:47:21.63,0:47:24.08,yin,,0,0,0,,因此 我打算讲讲这个委托实现\\N{\\fs12}So, I'm going to show you this delegate implementation.\r\nDialogue: 0,0:47:24.08,0:47:26.17,yin,,0,0,0,,我创建了这个session\\N{\\fs12}So, I create this session, and then I'm doing here\r\nDialogue: 0,0:47:26.17,0:47:30.26,yin,,0,0,0,,然后startFlickrFetch创建了一个任务 然后重新开始\\N{\\fs12}on start Flickr Fetch is creating a task and resuming it.\r\nDialogue: 0,0:47:30.26,0:47:32.69,yin,,0,0,0,,这同我们之前做的完全一样\\N{\\fs12}So, this is the exact same thing that we did before, right?\r\nDialogue: 0,0:47:32.69,0:47:33.84,yin,,0,0,0,,我们有一个URLSession\\N{\\fs12}We had a URL session.\r\nDialogue: 0,0:47:33.84,0:47:35.41,yin,,0,0,0,,我们创建一个下载任务\\N{\\fs12}We created a download task.\r\nDialogue: 0,0:47:35.41,0:47:38.65,yin,,0,0,0,,唯一的差别在于 上次我们用到了competionHandler\\N{\\fs12}The only difference is last time we did with completion handler,\r\nDialogue: 0,0:47:38.65,0:47:41.91,yin,,0,0,0,,我们还有一段代码发生在下载回来时\\N{\\fs12}and we had a little block that would happen when the download came back.\r\nDialogue: 0,0:47:41.91,0:47:44.68,yin,,0,0,0,,而现在 委托将会在URL加载返回时被调用\\N{\\fs12}Now instead, our delegate's going to get called\r\nDialogue: 0,0:47:44.68,0:47:48.00,yin,,0,0,0,,而现在 委托将会在URL加载返回时被调用\\N{\\fs12}when the URL gets loaded and comes back.\r\nDialogue: 0,0:47:48.00,0:47:49.55,yin,,0,0,0,,大家都理解了\\N{\\fs12}Does everyone understand the difference\r\nDialogue: 0,0:47:49.55,0:47:51.88,yin,,0,0,0,,之前和现在的差别了吗\\N{\\fs12}between what we did before and what we're doing here?\r\nDialogue: 0,0:47:51.88,0:47:53.29,yin,,0,0,0,,没有competionHandler\\N{\\fs12}Okay, no completion handler.\r\nDialogue: 0,0:47:53.29,0:47:54.78,yin,,0,0,0,,这里我们用的是委托\\N{\\fs12}Here, we're going to use a delegate.\r\nDialogue: 0,0:47:54.78,0:47:57.22,yin,,0,0,0,,我们看看这个委托是怎样的\\N{\\fs12}So, let's look at what that delegate looks like.\r\nDialogue: 0,0:47:57.22,0:47:58.90,yin,,0,0,0,,它是这样的\\N{\\fs12}It looks like this.\r\nDialogue: 0,0:47:58.90,0:48:00.82,yin,,0,0,0,,其中有三个方法\\N{\\fs12}Okay, there are three methods in it.\r\nDialogue: 0,0:48:00.82,0:48:03.04,yin,,0,0,0,,这三个方法\\N{\\fs12}These three methods right here.\r\nDialogue: 0,0:48:03.04,0:48:07.44,yin,,0,0,0,,一是文件刚完成下载时 在这里\\N{\\fs12}One is your file just finished downloading, and here it is\r\nDialogue: 0,0:48:07.44,0:48:09.08,yin,,0,0,0,,这里说是本地文件\\N{\\fs12}as a local file, so this looks a lot\r\nDialogue: 0,0:48:09.08,0:48:10.83,yin,,0,0,0,,这和competionHandler很像\\N{\\fs12}like that completion handler,\r\nDialogue: 0,0:48:10.84,0:48:13.83,yin,,0,0,0,,然后这里有一些我们不打算用\\N{\\fs12}and then, here's a couple that we're not going to use, like giving you,\r\nDialogue: 0,0:48:13.83,0:48:17.54,yin,,0,0,0,,这个给了你一些进度 已经读了多少字节\\N{\\fs12}this gives you some progress, how many bytes its read so far,\r\nDialogue: 0,0:48:17.54,0:48:19.22,yin,,0,0,0,,是否分块来读\\N{\\fs12}if it does it in chunks,\r\nDialogue: 0,0:48:19.23,0:48:22.98,yin,,0,0,0,,然后 下载session也可以被打断 然后继续\\N{\\fs12}and this also, download sessions can get interrupted and then resumed.\r\nDialogue: 0,0:48:22.98,0:48:26.39,yin,,0,0,0,,这个我们显然不打算细讲 无论如何\\N{\\fs12}We're definitely not going to talk about that, but anyway.\r\nDialogue: 0,0:48:26.39,0:48:29.08,yin,,0,0,0,,可以看到这里我有一个错误 怎么做呢\\N{\\fs12}Now, you can see I have an error here, okay, so what do we do.\r\nDialogue: 0,0:48:29.08,0:48:32.21,yin,,0,0,0,,这就是我们在competionHandler中做的\\N{\\fs12}So, this is what we would have done in our completion handler.\r\nDialogue: 0,0:48:32.21,0:48:35.18,yin,,0,0,0,,而这里我们要做的\\N{\\fs12}And, all we're going to do here is we are going\r\nDialogue: 0,0:48:35.18,0:48:36.99,yin,,0,0,0,,是获得context\\N{\\fs12}to get the context,\r\nDialogue: 0,0:48:36.99,0:48:39.63,yin,,0,0,0,,我们在程序已经完成启动方法里面\\N{\\fs12}our little photo database context that we set up there\r\nDialogue: 0,0:48:39.63,0:48:41.32,yin,,0,0,0,,设置的照片数据库context\\N{\\fs12}in application did finish launching.\r\nDialogue: 0,0:48:41.32,0:48:44.80,yin,,0,0,0,,我们打算从Flickr下载这些照片\\N{\\fs12}We are going to download those photos from Flickr,\r\nDialogue: 0,0:48:44.80,0:48:48.84,yin,,0,0,0,,Flickr照片是这个 你们很熟悉这个 对吧\\N{\\fs12}so Flickr photos is this, which you're very used to, right?\r\nDialogue: 0,0:48:48.84,0:48:50.81,yin,,0,0,0,,dataWithContentsOfURL\\N{\\fs12}Data with contents of URL,\r\nDialogue: 0,0:48:50.81,0:48:52.90,yin,,0,0,0,,JSON 去JSON化\\N{\\fs12}JSON, de-JSONize it,\r\nDialogue: 0,0:48:52.90,0:48:55.76,yin,,0,0,0,,从中抓取结果\\N{\\fs12}grab the results out of that.\r\nDialogue: 0,0:48:55.76,0:48:57.40,yin,,0,0,0,,我们打算做这些\\N{\\fs12}Okay. So, we're going to do that little thing.\r\nDialogue: 0,0:48:57.40,0:49:01.80,yin,,0,0,0,,这需要发生 这是一个本地URL\\N{\\fs12}This needs to be happening, you know, this is a local URL,\r\nDialogue: 0,0:49:01.80,0:49:04.39,yin,,0,0,0,,它可以发生在主线程 没问题\\N{\\fs12}so it can be happening on the main thread, no problem.\r\nDialogue: 0,0:49:04.39,0:49:06.74,yin,,0,0,0,,下面 我们要在这个context中做点什么\\N{\\fs12}Now, we're going to do something in this context,\r\nDialogue: 0,0:49:06.74,0:49:08.68,yin,,0,0,0,,注意 我用了performBlock\\N{\\fs12}and notice I'm doing perform block.\r\nDialogue: 0,0:49:08.68,0:49:11.74,yin,,0,0,0,,我在照片创建那个里面没有使用performBlock\\N{\\fs12}I didn't do perform block over in the photo creating one,\r\nDialogue: 0,0:49:11.74,0:49:13.60,yin,,0,0,0,,因为这是隐含的 我在创建一张照片\\N{\\fs12}because it's kind of implicit. I'm creating a photo.\r\nDialogue: 0,0:49:13.60,0:49:15.84,yin,,0,0,0,,很显然 我在那个context中那样做了\\N{\\fs12}Of course, I'm doing it on that context,\r\nDialogue: 0,0:49:15.84,0:49:18.50,yin,,0,0,0,,无论谁调用了那个 都希望在performBlock中做\\N{\\fs12}so whoever calls that would want to do that in perform block,\r\nDialogue: 0,0:49:18.50,0:49:20.35,yin,,0,0,0,,这就是我这里所做的\\N{\\fs12}and that's, in fact, what I'm doing here.\r\nDialogue: 0,0:49:20.35,0:49:25.12,yin,,0,0,0,,我调用了我们刚写的方法 loadPhotosWithFlickrData\\N{\\fs12}I'm calling that method we just wrote, load photos with Flickr data, okay.\r\nDialogue: 0,0:49:25.12,0:49:27.48,yin,,0,0,0,,我们还没有写这个方法 看看它\\N{\\fs12}We didn't actually write that method, so let's look at that.\r\nDialogue: 0,0:49:27.48,0:49:28.84,yin,,0,0,0,,它在这里\\N{\\fs12}So, that's over here.\r\nDialogue: 0,0:49:28.84,0:49:32.16,yin,,0,0,0,,我们有photoWithFlickrInfo 而这里是加载照片\\N{\\fs12}Okay, we have photo with Flickr info, and here's loading the photos.\r\nDialogue: 0,0:49:32.16,0:49:33.29,yin,,0,0,0,,如何加载照片呢\\N{\\fs12}So, how do we load the photos?\r\nDialogue: 0,0:49:33.29,0:49:38.85,yin,,0,0,0,,我只需要说 for (NSDictionary *photo in photos)\\N{\\fs12}I'm just going to say, for NS dictionary photo in photos,\r\nDialogue: 0,0:49:38.85,0:49:41.56,yin,,0,0,0,,一个个地给我每一张Flickr照片\\N{\\fs12}okay, so give me each Flickr photo one by one,\r\nDialogue: 0,0:49:41.56,0:49:44.78,yin,,0,0,0,,然后self photoWithFlickrInfo:\\N{\\fs12}and then self photo with Flickr info,\r\nDialogue: 0,0:49:44.78,0:49:48.63,yin,,0,0,0,,photo inManagedObjectContext:context\\N{\\fs12}photo in manage context, context.\r\nDialogue: 0,0:49:48.63,0:49:52.22,yin,,0,0,0,,这其实是一种很低效的方式\\N{\\fs12}Now, this turns out to be really an inefficient way\r\nDialogue: 0,0:49:52.22,0:49:54.98,yin,,0,0,0,,来加载这一百张Flickr照片\\N{\\fs12}of loading those hundred Flickr photos,\r\nDialogue: 0,0:49:54.98,0:50:02.68,yin,,0,0,0,,因为每次调用这个时 我都在进行取回操作\\N{\\fs12}because every time I call this, I am doing this Fetch.\r\nDialogue: 0,0:50:02.68,0:50:04.21,yin,,0,0,0,,如果我想加载一百张照片\\N{\\fs12}So, if I want to load a hundred photos,\r\nDialogue: 0,0:50:04.21,0:50:07.34,yin,,0,0,0,,我需要一百次取回看是否唯一\\N{\\fs12}I got to do a hundred fetches to see if those are unique.\r\nDialogue: 0,0:50:07.34,0:50:09.11,yin,,0,0,0,,这个显然有更好的做法\\N{\\fs12}Okay, there are much better ways to do this,\r\nDialogue: 0,0:50:09.11,0:50:11.02,yin,,0,0,0,,一个额外加分的条件就是\\N{\\fs12}and one of your extra credit items is for you to try\r\nDialogue: 0,0:50:11.02,0:50:13.05,yin,,0,0,0,,如果你能找到更好的做法\\N{\\fs12}and figure out a better way to do this.\r\nDialogue: 0,0:50:13.05,0:50:17.98,yin,,0,0,0,,一种方式是看所有一百张照片的唯一ID\\N{\\fs12}Okay, and one way is to look at the unique Id's of all hundred photos,\r\nDialogue: 0,0:50:17.98,0:50:21.17,yin,,0,0,0,,一次把它们都取回 看哪些在数据库中\\N{\\fs12}fetch them all at once, and see which ones are in the database,\r\nDialogue: 0,0:50:21.17,0:50:22.68,yin,,0,0,0,,因为你可以取回一个它们的列表\\N{\\fs12}because you can get a list of them back, right?\r\nDialogue: 0,0:50:22.68,0:50:25.87,yin,,0,0,0,,在其中的那些 然后你可以一个一个地\\N{\\fs12}The ones that are in there, and then one by one, you can go\r\nDialogue: 0,0:50:25.87,0:50:27.84,yin,,0,0,0,,创建没有的那些\\N{\\fs12}and create the ones that aren't there.\r\nDialogue: 0,0:50:27.84,0:50:29.81,yin,,0,0,0,,这是一种做法\\N{\\fs12}Okay, so that's one way to do it.\r\nDialogue: 0,0:50:29.81,0:50:33.37,yin,,0,0,0,,不过demo中我就用这个简单的方式\\N{\\fs12}Okay, but this cheap and simple way is good for a demo, okay.\r\nDialogue: 0,0:50:33.37,0:50:35.34,yin,,0,0,0,,回到app委托\\N{\\fs12}So, back to our app delegate\r\nDialogue: 0,0:50:35.34,0:50:37.38,yin,,0,0,0,,现在我们有这个loadPhotosWithFlickrArray\\N{\\fs12}and now we have this load photos with Flickr array.\r\nDialogue: 0,0:50:37.38,0:50:40.55,yin,,0,0,0,,让我们导入这个头文件\\N{\\fs12}Let's go ahead and import that header file, which I do, oh,\r\nDialogue: 0,0:50:40.55,0:50:42.33,yin,,0,0,0,,或许我该起个别的名字\\N{\\fs12}maybe I called it something different there.\r\nDialogue: 0,0:50:42.33,0:50:43.78,yin,,0,0,0,,问题在哪\\N{\\fs12}What's the problem?\r\nDialogue: 0,0:50:43.78,0:50:48.77,yin,,0,0,0,,看看 或许我该起个别的名字\\N{\\fs12}Let's see, yeah, I probably called it something different.\r\nDialogue: 0,0:50:48.77,0:50:52.23,yin,,0,0,0,,起相同的名字\\N{\\fs12}Call it the same thing.\r\nDialogue: 0,0:50:52.23,0:50:55.18,yin,,0,0,0,,这是我的委托 这里\\N{\\fs12}Here's my delegate, here it is.\r\nDialogue: 0,0:50:55.18,0:50:57.03,yin,,0,0,0,,称它为[声音不清]Flickr\\N{\\fs12}There we go, I called it [inaudible] Flickr, right?\r\nDialogue: 0,0:50:57.03,0:50:58.80,yin,,0,0,0,,这将加载所有这些照片\\N{\\fs12}So, that's going to load all these photos.\r\nDialogue: 0,0:50:58.80,0:51:01.04,yin,,0,0,0,,注意 这里我保存了我的context\\N{\\fs12}Notice, I'm saving my context here.\r\nDialogue: 0,0:51:01.06,0:51:03.74,yin,,0,0,0,,这里是一个方法 ManagedObjectContext被保存\\N{\\fs12}Okay this is a method, manage object context was saved.\r\nDialogue: 0,0:51:03.74,0:51:05.75,yin,,0,0,0,,这是一个错误 我忽略它\\N{\\fs12}This is an error, which I'm ignoring.\r\nDialogue: 0,0:51:05.75,0:51:07.32,yin,,0,0,0,,实际不需要做这个\\N{\\fs12}Don't really need to do this\r\nDialogue: 0,0:51:07.32,0:51:09.62,yin,,0,0,0,,用于UIManagedDocument 不过也无伤大雅\\N{\\fs12}for your UI managed document, but it doesn't hurt.\r\nDialogue: 0,0:51:09.62,0:51:10.74,yin,,0,0,0,,想这样也行\\N{\\fs12}You can do it if you want.\r\nDialogue: 0,0:51:10.74,0:51:12.32,yin,,0,0,0,,这不会破坏任何东西\\N{\\fs12}This would not break anything\r\nDialogue: 0,0:51:12.32,0:51:14.64,yin,,0,0,0,,如果你有一个context来自UIManagedDocument\\N{\\fs12}if you had a context from UI managed document,\r\nDialogue: 0,0:51:14.65,0:51:15.38,yin,,0,0,0,,但我的没有\\N{\\fs12}but mine's not,\r\nDialogue: 0,0:51:15.38,0:51:19.38,yin,,0,0,0,,因此我这里明文要求在加载一些照片后进行保存\\N{\\fs12}so that's why I'm explicitly saving here after I load some photos in.\r\nDialogue: 0,0:51:21.69,0:51:23.35,yin,,0,0,0,,好 这很酷\\N{\\fs12}Okay, so that's cool.\r\nDialogue: 0,0:51:23.35,0:51:26.70,yin,,0,0,0,,再来看看我们的表格\\N{\\fs12}So, let's go look at our tables.\r\nDialogue: 0,0:51:26.70,0:51:30.26,yin,,0,0,0,,我们表格的公共API是什么\\N{\\fs12}What is our tables, public API,\r\nDialogue: 0,0:51:30.27,0:51:31.93,yin,,0,0,0,,ManagedObjectContext\\N{\\fs12}managed object context?\r\nDialogue: 0,0:51:31.93,0:51:33.17,yin,,0,0,0,,我们从没设置过\\N{\\fs12}We never set that.\r\nDialogue: 0,0:51:33.17,0:51:36.89,yin,,0,0,0,,我们需要设置这个表格的ManagedObjectContext\\N{\\fs12}Okay. We need to set this tables managed object context.\r\nDialogue: 0,0:51:36.89,0:51:39.99,yin,,0,0,0,,我们什么时候做 怎么做呢\\N{\\fs12}Okay. When and how are we going to do that?\r\nDialogue: 0,0:51:39.99,0:51:41.50,yin,,0,0,0,,我们有这个应用委托\\N{\\fs12}We have this application delegate.\r\nDialogue: 0,0:51:41.50,0:51:43.39,yin,,0,0,0,,这个全局的东西\\N{\\fs12}It's kind of this global thing,\r\nDialogue: 0,0:51:43.39,0:51:45.88,yin,,0,0,0,,它在管理这个全局数据库\\N{\\fs12}and it is managing this global database, but it needs\r\nDialogue: 0,0:51:45.88,0:51:50.52,yin,,0,0,0,,不过这个东西需要同其他需要它的人进行通信\\N{\\fs12}to be able to communicate this thing out to anyone who needs to use it,\r\nDialogue: 0,0:51:50.54,0:51:52.75,yin,,0,0,0,,做法如下\\N{\\fs12}and the way we're going to that is,\r\nDialogue: 0,0:51:52.75,0:51:56.74,yin,,0,0,0,,任何设置照片数据库context的时候\\N{\\fs12}whenever we set this photo database context, we are going\r\nDialogue: 0,0:51:56.74,0:52:00.29,yin,,0,0,0,,我们都将发布一个通知 广播站那些东西\\N{\\fs12}to post a notification, the radio station thing.\r\nDialogue: 0,0:52:00.29,0:52:03.04,yin,,0,0,0,,这是你们第一次看到如何发布一个通知\\N{\\fs12}So, this is the first time you're going to see how to post an notification,\r\nDialogue: 0,0:52:03.04,0:52:05.39,yin,,0,0,0,,而不只是观测监听\\N{\\fs12}not just listen with that observer,\r\nDialogue: 0,0:52:05.39,0:52:07.87,yin,,0,0,0,,这里你要发布 我们来做这个\\N{\\fs12}you're going to actually post it right here, so let's do that,\r\nDialogue: 0,0:52:07.87,0:52:11.29,yin,,0,0,0,,发布通知 你几乎100%的时候\\N{\\fs12}and when you post a notification you almost always 100%\r\nDialogue: 0,0:52:11.29,0:52:15.44,yin,,0,0,0,,希望创建一个头文件 这里我来创建头文件\\N{\\fs12}of the time, want to create a header file, so I'm going to create a header file.\r\nDialogue: 0,0:52:15.44,0:52:18.75,yin,,0,0,0,,到头文件 C和C++头文件\\N{\\fs12}Just go here to header file, C, C++ header file,\r\nDialogue: 0,0:52:18.75,0:52:22.39,yin,,0,0,0,,头文件将包含通知名\\N{\\fs12}and that header file is going to contain the name of the notification,\r\nDialogue: 0,0:52:22.39,0:52:26.41,yin,,0,0,0,,还有用户信息中那些东西的名称 用于通知\\N{\\fs12}and also the name of anything that's in the user info, for the notification.\r\nDialogue: 0,0:52:26.41,0:52:30.72,yin,,0,0,0,,保证这是在正确的地方\\N{\\fs12}So, let's go ahead and make sure it's in the right place.\r\nDialogue: 0,0:52:30.72,0:52:35.66,yin,,0,0,0,,我将把这称作PhotoDatabaseAvailability\\N{\\fs12}It is. I'm going to call this photo database availability,\r\nDialogue: 0,0:52:35.66,0:52:37.81,yin,,0,0,0,,这个通知就是关于这个的\\N{\\fs12}because that's what this notification is about.\r\nDialogue: 0,0:52:37.81,0:52:38.82,yin,,0,0,0,,广播站\\N{\\fs12}This radio station talks\r\nDialogue: 0,0:52:38.82,0:52:41.21,yin,,0,0,0,,讨论了照片数据库是否可用\\N{\\fs12}about whether the photo database is available, so I'm going\r\nDialogue: 0,0:52:41.21,0:52:44.40,yin,,0,0,0,,于是我创建了这个头文件 在它中间\\N{\\fs12}to create this header file, and inside this header file,\r\nDialogue: 0,0:52:44.40,0:52:46.10,yin,,0,0,0,,我要给出两个#定义\\N{\\fs12}I'm just going to put 2 pound defines.\r\nDialogue: 0,0:52:46.10,0:52:51.99,yin,,0,0,0,,一个是PhotoDatabaseAvailabilityNotification\\N{\\fs12}One is photo database availability notification.\r\nDialogue: 0,0:52:51.99,0:52:53.89,yin,,0,0,0,,这是通知名\\N{\\fs12}That's the name of the notification.\r\nDialogue: 0,0:52:53.89,0:52:55.92,yin,,0,0,0,,我把它叫作这个\\N{\\fs12}I'm going to call it this.\r\nDialogue: 0,0:52:55.92,0:52:58.07,yin,,0,0,0,,什么都行 不过我把它叫作这个\\N{\\fs12}I can call it anything I want, but I'm going to call it that,\r\nDialogue: 0,0:52:58.07,0:53:01.52,yin,,0,0,0,,然后 通知发出之后\\N{\\fs12}and then also when the notification goes out,\r\nDialogue: 0,0:53:01.52,0:53:05.64,yin,,0,0,0,,我们会把context包含在广播站广播中\\N{\\fs12}I'm going to include the context in the radio station broadcast,\r\nDialogue: 0,0:53:05.64,0:53:08.38,yin,,0,0,0,,获得通知的人也可以同时获得这个\\N{\\fs12}so the person can just get it when they get the notification.\r\nDialogue: 0,0:53:08.38,0:53:14.45,yin,,0,0,0,,这个用PhotoDatabaseAvailabilityContext\\N{\\fs12}I'll do that with photo database availability context.\r\nDialogue: 0,0:53:14.45,0:53:16.84,yin,,0,0,0,,名字中使用的是Context\\N{\\fs12}And, I'll use the same, well, just say context.\r\nDialogue: 0,0:53:16.84,0:53:18.37,yin,,0,0,0,,叫什么其实都行\\N{\\fs12}It can be anything you want it to.\r\nDialogue: 0,0:53:18.37,0:53:20.70,yin,,0,0,0,,这是通知名\\N{\\fs12}Okay, so this is going to be the name of the notification.\r\nDialogue: 0,0:53:20.70,0:53:23.63,yin,,0,0,0,,这是同通知一同的信息字典中的键\\N{\\fs12}This is going to be the key into the dictionary of information\r\nDialogue: 0,0:53:23.63,0:53:25.49,yin,,0,0,0,,这是同通知一同的信息字典中的键\\N{\\fs12}that comes along with the notification, alright?\r\nDialogue: 0,0:53:26.63,0:53:29.56,yin,,0,0,0,,下面 发送这个通知\\N{\\fs12}So, now, let's send that notification, and I'm going\r\nDialogue: 0,0:53:29.56,0:53:35.03,yin,,0,0,0,,每次设置这个照片数据库context时 我都会这样做\\N{\\fs12}to do that every time we set this photo database context.\r\nDialogue: 0,0:53:35.03,0:53:35.86,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:53:42.65,0:53:44.01,yin,,0,0,0,,哦 或许吧\\N{\\fs12}Oh, yeah, probably.\r\nDialogue: 0,0:53:44.01,0:53:45.11,yin,,0,0,0,,提得很好\\N{\\fs12}Good point.\r\nDialogue: 0,0:53:45.11,0:53:46.37,yin,,0,0,0,,对 这里没有等于\\N{\\fs12}Yeah, no equals there.\r\nDialogue: 0,0:53:48.08,0:53:49.05,yin,,0,0,0,,谢谢 很好\\N{\\fs12}Thanks, very good.\r\nDialogue: 0,0:53:49.05,0:53:50.52,yin,,0,0,0,,这里只不过是#定义\\N{\\fs12}This is just a pound sign defined.\r\nDialogue: 0,0:53:50.52,0:53:53.34,yin,,0,0,0,,这是常数 我们不应该这样做\\N{\\fs12}If it was a constant, we wouldn't do that.\r\nDialogue: 0,0:53:53.87,0:54:03.06,yin,,0,0,0,,好 让我们来设置这个照片数据库context\\N{\\fs12}Okay, alright, so let's set this photo database context,\r\nDialogue: 0,0:54:03.06,0:54:05.89,yin,,0,0,0,,在set… 这个应该有\\N{\\fs12}so in the set; I think I might have a thing for that actually.\r\nDialogue: 0,0:54:05.89,0:54:06.82,yin,,0,0,0,,setPhotoData…\\N{\\fs12}Set photo data.\r\nDialogue: 0,0:54:06.82,0:54:07.62,yin,,0,0,0,,确实有\\N{\\fs12}Yeah, I do.\r\nDialogue: 0,0:54:07.62,0:54:10.61,yin,,0,0,0,,设置这个照片数据库context时\\N{\\fs12}So, here when we set this photo database context,\r\nDialogue: 0,0:54:10.61,0:54:14.68,yin,,0,0,0,,我们会公布这个通知\\N{\\fs12}we are going to post this notification.\r\nDialogue: 0,0:54:14.68,0:54:18.70,yin,,0,0,0,,做法是使用NSNotificationCenter defaultCenter\\N{\\fs12}And we do that using the NS Notification Center default center,\r\nDialogue: 0,0:54:18.70,0:54:20.10,yin,,0,0,0,,postNotificationName\\N{\\fs12}post notification name.\r\nDialogue: 0,0:54:20.10,0:54:21.95,yin,,0,0,0,,我们指定名称 也就是这个\\N{\\fs12}We just specify the name, which is this.\r\nDialogue: 0,0:54:21.95,0:54:24.82,yin,,0,0,0,,要想让这个正常工作 我们需要导入\\N{\\fs12}For this to work, we need to import\r\nDialogue: 0,0:54:24.82,0:54:29.99,yin,,0,0,0,,PhotoDatabaseAvailability头文件\\N{\\fs12}that photo availability, photo database availability header.\r\nDialogue: 0,0:54:29.99,0:54:31.88,yin,,0,0,0,,我们要发布这个通知\\N{\\fs12}So, we're just going to post this notification,\r\nDialogue: 0,0:54:31.88,0:54:34.40,yin,,0,0,0,,我们同时还会给出这个用户信息\\N{\\fs12}and we're going to give this user info along with it,\r\nDialogue: 0,0:54:34.40,0:54:38.54,yin,,0,0,0,,用户信息只是一个字典 它有一个键\\N{\\fs12}and user info, it's just a dictionary that has one key,\r\nDialogue: 0,0:54:38.54,0:54:40.03,yin,,0,0,0,,也就是那个context\\N{\\fs12}which is that context,\r\nDialogue: 0,0:54:40.03,0:54:44.29,yin,,0,0,0,,而键的值是context\\N{\\fs12}and the value of that key is the context.\r\nDialogue: 0,0:54:45.94,0:54:49.64,yin,,0,0,0,,这就是广播站模型中发布的方式\\N{\\fs12}So, this is how you post in the radio station model.\r\nDialogue: 0,0:54:49.64,0:54:52.79,yin,,0,0,0,,有问题吗\\N{\\fs12}Any questions about that?\r\nDialogue: 0,0:54:52.79,0:54:56.41,yin,,0,0,0,,下面我要讲监听到广播站\\N{\\fs12}And now, I'm going to show you listening to a radio station\r\nDialogue: 0,0:54:56.41,0:55:00.36,yin,,0,0,0,,而不用创建另一个方法\\N{\\fs12}without having to create another method and all this stuff,\r\nDialogue: 0,0:55:00.36,0:55:04.10,yin,,0,0,0,,只是很简单的监听 谁需要监听这个\\N{\\fs12}basically really straightforward listening, and who needs to listen to this?\r\nDialogue: 0,0:55:04.10,0:55:09.54,yin,,0,0,0,,这个需要 这个拍照者的东西 它需要监听它\\N{\\fs12}Well, this guy does, this photographer guy, he needs to listen to it.\r\nDialogue: 0,0:55:09.54,0:55:12.93,yin,,0,0,0,,这个唤醒之后\\N{\\fs12}So, basically, as soon as this guy awakes,\r\nDialogue: 0,0:55:12.93,0:55:16.25,yin,,0,0,0,,我或许该用initWithStyle\\N{\\fs12}and I might do this init with style,\r\nDialogue: 0,0:55:16.25,0:55:18.25,yin,,0,0,0,,或是别的什么指定初始化器\\N{\\fs12}or whatever the designated initializer is\r\nDialogue: 0,0:55:18.25,0:55:20.38,yin,,0,0,0,,用于TableView 我要在awakeFromNib总这样做\\N{\\fs12}for TableView, but I'm just going to it in awakeFromNib\r\nDialogue: 0,0:55:20.38,0:55:23.31,yin,,0,0,0,,因为我们知道这个TableView出自于故事板\\N{\\fs12}for here, because we know this TableView is coming out of the story board.\r\nDialogue: 0,0:55:23.31,0:55:26.61,yin,,0,0,0,,我要说 通知中心\\N{\\fs12}I'm just going to say, notification center.\r\nDialogue: 0,0:55:26.61,0:55:30.82,yin,,0,0,0,,首先导入Availability那个\\N{\\fs12}First let's import that availability thing.\r\nDialogue: 0,0:55:30.82,0:55:36.55,yin,,0,0,0,,我要做的是NSNotificationCenter defaultCenter\\N{\\fs12}So, I'm going to do NS Notification Center, default center.\r\nDialogue: 0,0:55:36.55,0:55:37.10,yin,,0,0,0,,看这个\\N{\\fs12}Watch this.\r\nDialogue: 0,0:55:37.10,0:55:38.67,yin,,0,0,0,,addObserver\\N{\\fs12}Add observer.\r\nDialogue: 0,0:55:38.67,0:55:41.14,yin,,0,0,0,,通常我们会使用选择器这些\\N{\\fs12}Normally, we do it with a selector and all this stuff.\r\nDialogue: 0,0:55:41.14,0:55:42.98,yin,,0,0,0,,我打算使用基于block的这个\\N{\\fs12}I'm going to do a block-based one.\r\nDialogue: 0,0:55:42.98,0:55:45.79,yin,,0,0,0,,之前你们不知道block 所以我没展示 也就是这个\\N{\\fs12}I couldn't show you this before, because you didn't know block, but it's this one.\r\nDialogue: 0,0:55:45.79,0:55:48.28,yin,,0,0,0,,addObserverForName 我们给出名字\\N{\\fs12}Add observer for name, and we give the name,\r\nDialogue: 0,0:55:48.28,0:55:52.47,yin,,0,0,0,,也就是PhotoDatabaseAvailabilityNotification\\N{\\fs12}which is photo database availability notification.\r\nDialogue: 0,0:55:52.47,0:55:57.13,yin,,0,0,0,,对象是谁能发送 我将其设为任何人\\N{\\fs12}The object is who can send it, and I'll let anyone send this to me.\r\nDialogue: 0,0:55:57.13,0:55:59.65,yin,,0,0,0,,这是app委托 不过也可以是任何人\\N{\\fs12}It's going to be the app delegate, but it could be anybody.\r\nDialogue: 0,0:55:59.65,0:56:03.08,yin,,0,0,0,,队列 我打算在我现在正处在的队列上做\\N{\\fs12}The queue, I'm going to do it on the queue that I'm on now.\r\nDialogue: 0,0:56:03.08,0:56:04.15,yin,,0,0,0,,这就是nil的意思\\N{\\fs12}That's what nil means,\r\nDialogue: 0,0:56:04.15,0:56:06.56,yin,,0,0,0,,不过我也可以说 NSOperation主队列\\N{\\fs12}but I could say NS Operation main queue,\r\nDialogue: 0,0:56:06.56,0:56:09.22,yin,,0,0,0,,或是其它某个队列 不过这里我将其设为nil\\N{\\fs12}or some other queue even, but I'm going to say nil,\r\nDialogue: 0,0:56:09.22,0:56:12.49,yin,,0,0,0,,也就是说执行这个时我现在所处的队列\\N{\\fs12}which means whatever queue I'm on right now when this is being executed,\r\nDialogue: 0,0:56:12.50,0:56:14.10,yin,,0,0,0,,使用block\\N{\\fs12}using block,\r\nDialogue: 0,0:56:14.11,0:56:17.02,yin,,0,0,0,,我双击这里添加一个代码块\\N{\\fs12}so I'm going to double click here to put a block.\r\nDialogue: 0,0:56:17.02,0:56:21.00,yin,,0,0,0,,这是末尾 其中有些什么呢\\N{\\fs12}Okay, and then that's the end of that, and what's going to be in this block?\r\nDialogue: 0,0:56:21.00,0:56:24.02,yin,,0,0,0,,只有一行代码\\N{\\fs12}This is one line of code.\r\nDialogue: 0,0:56:24.02,0:56:30.58,yin,,0,0,0,,self.managedObjectContext = 这个通知\\N{\\fs12}Self.manage object context equals this notification,\r\nDialogue: 0,0:56:30.58,0:56:33.67,yin,,0,0,0,,它的用户信息\\N{\\fs12}its user info,\r\nDialogue: 0,0:56:33.67,0:56:36.48,yin,,0,0,0,,PhotoDatabaseAvailabilityContext\\N{\\fs12}photo database context.\r\nDialogue: 0,0:56:40.48,0:56:42.50,yin,,0,0,0,,抱歉 这一行有点长\\N{\\fs12}Okay. Sorry for the very, very long line there.\r\nDialogue: 0,0:56:42.50,0:56:44.11,yin,,0,0,0,,应该能够容纳进来 确实能\\N{\\fs12}I think it will fit, yeah it will.\r\nDialogue: 0,0:56:44.97,0:56:46.77,yin,,0,0,0,,我获得了这个block\\N{\\fs12}So, I'm getting this block.\r\nDialogue: 0,0:56:46.77,0:56:49.90,yin,,0,0,0,,它在广播站广播时会被执行\\N{\\fs12}It's executed whenever this radio station broadcasts,\r\nDialogue: 0,0:56:49.90,0:56:54.08,yin,,0,0,0,,因为加入了context的用户信息 现在我就有了context\\N{\\fs12}and because I put this user info of the context, now I have the context,\r\nDialogue: 0,0:56:54.08,0:56:56.42,yin,,0,0,0,,我只需设置我的ManagedObjectContext\\N{\\fs12}and I just set my own managed object context,\r\nDialogue: 0,0:56:56.42,0:56:59.61,yin,,0,0,0,,它就会加载这个表格\\N{\\fs12}and voila, it's going to load this table.\r\nDialogue: 0,0:56:59.61,0:57:01.60,yin,,0,0,0,,这方面有问题吗\\N{\\fs12}Questions about that?\r\nDialogue: 0,0:57:01.60,0:57:04.76,yin,,0,0,0,,这是在发布和接收上的通知\\N{\\fs12}So, that's notifying both on posting and receiving.\r\nDialogue: 0,0:57:04.76,0:57:06.69,yin,,0,0,0,,现在它就应该能够工作了\\N{\\fs12}Alright, so now hopefully it will work.\r\nDialogue: 0,0:57:06.71,0:57:09.70,yin,,0,0,0,,我们来看看 这就是了\\N{\\fs12}Let's go take a look at this, and there it is.\r\nDialogue: 0,0:57:09.70,0:57:12.40,yin,,0,0,0,,它运行得非常快\\N{\\fs12}Okay, now it went really fast there,\r\nDialogue: 0,0:57:12.40,0:57:15.16,yin,,0,0,0,,因为它上次进行过加载\\N{\\fs12}because it actually did the load last time,\r\nDialogue: 0,0:57:15.16,0:57:17.28,yin,,0,0,0,,只是我们没有看到 数据库已经加载\\N{\\fs12}but we just didn't see it, so the database was loaded.\r\nDialogue: 0,0:57:17.28,0:57:19.62,yin,,0,0,0,,我要展示加载是怎样的\\N{\\fs12}So, I'm going to show it what it looked like to load up.\r\nDialogue: 0,0:57:19.62,0:57:21.67,yin,,0,0,0,,我如何把这个清掉呢\\N{\\fs12}So, how do I clean this out?\r\nDialogue: 0,0:57:21.67,0:57:23.70,yin,,0,0,0,,如何把数据库清掉\\N{\\fs12}Okay, how do I clean my database out?\r\nDialogue: 0,0:57:23.70,0:57:26.58,yin,,0,0,0,,知道这个很重要 看好了\\N{\\fs12}You're really going to want to know this. So, really watch this.\r\nDialogue: 0,0:57:26.58,0:57:28.67,yin,,0,0,0,,如果你想清掉数据库\\N{\\fs12}If you want to get rid of your database,\r\nDialogue: 0,0:57:28.67,0:57:30.83,yin,,0,0,0,,尤其是想改变其schema的时候\\N{\\fs12}especially if you want to change its schema.\r\nDialogue: 0,0:57:30.83,0:57:33.42,yin,,0,0,0,,因为如果你要改变其schema 你会重启\\N{\\fs12}Because if you change its schema, and then you relaunch,\r\nDialogue: 0,0:57:33.42,0:57:35.60,yin,,0,0,0,,它会说不兼容数据库类型\\N{\\fs12}it's going to say incompatible database type.\r\nDialogue: 0,0:57:35.60,0:57:38.77,yin,,0,0,0,,如果你想清掉它 你只需按Home键\\N{\\fs12}So, if you want to get rid of it, just press the home key.\r\nDialogue: 0,0:57:38.77,0:57:42.47,yin,,0,0,0,,我还建议先退出Xcode\\N{\\fs12}I also recommend quitting in X code first.\r\nDialogue: 0,0:57:45.85,0:57:50.18,yin,,0,0,0,,然后按Home键 按住图标\\N{\\fs12}Then press the home key, hold down, press to hold,\r\nDialogue: 0,0:57:50.18,0:57:52.40,yin,,0,0,0,,你也可以在设备上这样做\\N{\\fs12}you can do this on your device too, and then,\r\nDialogue: 0,0:57:52.40,0:57:53.79,yin,,0,0,0,,图标会抖动\\N{\\fs12}you get these jigglies,\r\nDialogue: 0,0:57:53.79,0:57:56.97,yin,,0,0,0,,然后点X删除应用\\N{\\fs12}and then press the X to delete that application.\r\nDialogue: 0,0:57:56.97,0:57:58.90,yin,,0,0,0,,这会删除整个应用\\N{\\fs12}That will delete the entire application,\r\nDialogue: 0,0:57:58.90,0:58:06.08,yin,,0,0,0,,包括数据库 之后重新在Xcode中启动\\N{\\fs12}including the database, and now, when I launch again in X code,\r\nDialogue: 0,0:58:06.08,0:58:08.33,yin,,0,0,0,,它最开始会是空白的\\N{\\fs12}it is going to start up blank,\r\nDialogue: 0,0:58:08.33,0:58:10.63,yin,,0,0,0,,在后台进行Flickr取回\\N{\\fs12}doing the Flickr Fetch in the background.\r\nDialogue: 0,0:58:10.63,0:58:13.75,yin,,0,0,0,,ManagedObjectContext填满数据后\\N{\\fs12}When that manage object context is filled up with data,\r\nDialogue: 0,0:58:13.75,0:58:17.68,yin,,0,0,0,,它就会神奇地自动出现在TableView中\\N{\\fs12}it magically automatically appears in the TableView.\r\nDialogue: 0,0:58:17.68,0:58:21.97,yin,,0,0,0,,这就是FetchedResultsController正在监视context\\N{\\fs12}That's because that Fetch Results Controller is watching the context.\r\nDialogue: 0,0:58:21.97,0:58:23.07,yin,,0,0,0,,有问题\\N{\\fs12}Questions.\r\nDialogue: 0,0:58:28.82,0:58:30.87,yin,,0,0,0,,好 我们回头看看这个\\N{\\fs12}Yeah, let's go back and look at that.\r\nDialogue: 0,0:58:30.87,0:58:33.26,yin,,0,0,0,,问题是 我在哪设置的用户信息\\N{\\fs12}The question is where did I set this user info,\r\nDialogue: 0,0:58:33.26,0:58:36.32,yin,,0,0,0,,这一小段用户信息 我在哪设的\\N{\\fs12}this little user info right here, where did I set that,\r\nDialogue: 0,0:58:36.32,0:58:41.18,yin,,0,0,0,,这是我发布通知的时候 这里\\N{\\fs12}and that was when I posted the notification here\r\nDialogue: 0,0:58:41.18,0:58:42.52,yin,,0,0,0,,在app委托中\\N{\\fs12}in my app delegate,\r\nDialogue: 0,0:58:42.52,0:58:46.89,yin,,0,0,0,,这是我在设置context时 在我启动时\\N{\\fs12}which I did when I set the context, which I did when I launched.\r\nDialogue: 0,0:58:46.89,0:58:48.30,yin,,0,0,0,,我启动\\N{\\fs12}Right, so I launch.\r\nDialogue: 0,0:58:48.30,0:58:49.86,yin,,0,0,0,,这是启动\\N{\\fs12}Here's launching.\r\nDialogue: 0,0:58:49.88,0:58:52.18,yin,,0,0,0,,启动时 我创建了context\\N{\\fs12}When I launch, I create the context,\r\nDialogue: 0,0:58:52.18,0:58:54.26,yin,,0,0,0,,你会和UIManagedDocument一起创建\\N{\\fs12}you're going to create it with UI managed document.\r\nDialogue: 0,0:58:54.26,0:58:55.86,yin,,0,0,0,,我在这里设置了它\\N{\\fs12}I set it right here.\r\nDialogue: 0,0:58:55.86,0:58:58.11,yin,,0,0,0,,这是那个的setter\\N{\\fs12}This is the setter for that.\r\nDialogue: 0,0:58:58.11,0:58:59.28,yin,,0,0,0,,我设置了它\\N{\\fs12}Okay, I set it.\r\nDialogue: 0,0:58:59.28,0:59:02.74,yin,,0,0,0,,然后我把它发布 对其他所有人可用\\N{\\fs12}Then I post it to available to everybody else.\r\nDialogue: 0,0:59:04.65,0:59:05.80,yin,,0,0,0,,有问题\\N{\\fs12}Question.\r\nDialogue: 0,0:59:11.46,0:59:14.21,yin,,0,0,0,,问题是我如何确保\\N{\\fs12}Yeah, so the question is, how can I make sure\r\nDialogue: 0,0:59:14.21,0:59:19.38,yin,,0,0,0,,视图控制器存在 而且在即时监听这个\\N{\\fs12}that the view controller exists, and is listening in time\r\nDialogue: 0,0:59:19.38,0:59:22.36,yin,,0,0,0,,毕竟应用委托发布会很早\\N{\\fs12}to hear this, because the application delegate is posting\r\nDialogue: 0,0:59:22.36,0:59:24.00,yin,,0,0,0,,就在启动之后\\N{\\fs12}this pretty early, right after launch.\r\nDialogue: 0,0:59:24.00,0:59:26.08,yin,,0,0,0,,它发送了这个通知\\N{\\fs12}It's sending out this notification,\r\nDialogue: 0,0:59:26.08,0:59:30.91,yin,,0,0,0,,答案是 这就是我在awakeFromNib中做这个的原因\\N{\\fs12}and the answer to that is that's why I do this in awake from nib,\r\nDialogue: 0,0:59:30.91,0:59:33.83,yin,,0,0,0,,处在视图控制器生命周期的很早时期\\N{\\fs12}really early in the view controller's life cycle, right?\r\nDialogue: 0,0:59:33.83,0:59:36.88,yin,,0,0,0,,当它刚创建时 这样它就有最大的获得机会\\N{\\fs12}When it's first created, so it has the maximum chance of getting it,\r\nDialogue: 0,0:59:36.88,0:59:39.12,yin,,0,0,0,,不过也有可能\\N{\\fs12}but it's possible.\r\nDialogue: 0,0:59:39.12,0:59:40.70,yin,,0,0,0,,不大可能 不过有可能\\N{\\fs12}It's unlikely, but it's possible\r\nDialogue: 0,0:59:40.70,0:59:43.54,yin,,0,0,0,,后面创建的视图控制器可能会适时需要它\\N{\\fs12}that some view controller you might create later in time might need it,\r\nDialogue: 0,0:59:43.55,0:59:45.64,yin,,0,0,0,,这时 你可能需要另外一种机制\\N{\\fs12}and in that case, you might need a different mechanism, or you might need\r\nDialogue: 0,0:59:45.64,0:59:48.71,yin,,0,0,0,,你可能需要再发布 或是往下传递\\N{\\fs12}to repost it or you might need to pass it along.\r\nDialogue: 0,0:59:48.71,0:59:51.82,yin,,0,0,0,,很多时候 我们都不想用这个机制\\N{\\fs12}Okay, a lot of times, we don't want to use this mechanism\r\nDialogue: 0,0:59:51.82,0:59:54.28,yin,,0,0,0,,将context给到视图控制器\\N{\\fs12}to give the context to view controllers,\r\nDialogue: 0,0:59:54.28,0:59:56.96,yin,,0,0,0,,原因正是视图控制器还不存在\\N{\\fs12}exactly because the view controller doesn't exist yet,\r\nDialogue: 0,0:59:56.96,1:00:00.24,yin,,0,0,0,,在这个availability发生之前 它甚至都没有\\N{\\fs12}until when this availability happens, it's not even there.\r\nDialogue: 0,1:00:00.24,1:00:04.22,yin,,0,0,0,,还有其它方式能传递ManagedObjectContext\\N{\\fs12}So, there are other ways to pass you managed object context around, and you always want\r\nDialogue: 0,1:00:04.22,1:00:07.18,yin,,0,0,0,,那些总需要用到这样的做法之前\\N{\\fs12}to use those before a way like this.\r\nDialogue: 0,1:00:07.18,1:00:09.75,yin,,0,0,0,,我讲这个对作业是个提示\\N{\\fs12}Okay, and I mentioned that in the hints, so the homework is,\r\nDialogue: 0,1:00:09.75,1:00:12.63,yin,,0,0,0,,传递ManagedObjectContext\\N{\\fs12}pass the manage object context\r\nDialogue: 0,1:00:12.63,1:00:17.15,yin,,0,0,0,,给视图控制器 受控于FetchedResultsController\\N{\\fs12}to a view controller that's NS Fetch results controller controlled\r\nDialogue: 0,1:00:17.15,1:00:19.27,yin,,0,0,0,,以一种有意义的方式\\N{\\fs12}in a sensible way in a way that makes sense.\r\nDialogue: 0,1:00:19.27,1:00:24.06,yin,,0,0,0,,如果你segue到它 传递给它 通过准备它\\N{\\fs12}If you're segueing to it, pass it to it by preparing it, right?\r\nDialogue: 0,1:00:24.06,1:00:27.55,yin,,0,0,0,,你不会希望指望这里的这些东西\\N{\\fs12}You wouldn't want to rely on something like this.\r\nDialogue: 0,1:00:27.55,1:00:31.67,yin,,0,0,0,,好 再来讨论更多地加载数据库\\N{\\fs12}Okay. Alright, now let's talk about loading our database some more.\r\nDialogue: 0,1:00:31.67,1:00:35.45,yin,,0,0,0,,现在 我们只在启动时加载了数据库\\N{\\fs12}Okay, right now, we only loaded our database on launch.\r\nDialogue: 0,1:00:35.45,1:00:37.92,yin,,0,0,0,,这是didFinishLaunchingWithOptions\\N{\\fs12}Here's the application that did finish loading with options.\r\nDialogue: 0,1:00:37.92,1:00:41.82,yin,,0,0,0,,我们加载了数据库 然后开始Flickr取回 这就完了\\N{\\fs12}We load our database right here and start Flickr fetch that's it.\r\nDialogue: 0,1:00:41.82,1:00:44.01,yin,,0,0,0,,这还不是很好\\N{\\fs12}Well, that's not very good,\r\nDialogue: 0,1:00:44.01,1:00:46.42,yin,,0,0,0,,这意味着我们永远就这一批数据\\N{\\fs12}that just means we only get one batch of data ever,\r\nDialogue: 0,1:00:46.42,1:00:49.29,yin,,0,0,0,,我们需要一直退出重启来获得新数据\\N{\\fs12}when we launch our app, we have to quit, or have to relaunch it all the time.\r\nDialogue: 0,1:00:49.29,1:00:52.33,yin,,0,0,0,,我们希望能够在后台加载这些Flickr信息\\N{\\fs12}So, what about kind of loading this Flickr information\r\nDialogue: 0,1:00:52.33,1:00:55.16,yin,,0,0,0,,我们希望能够在后台加载这些Flickr信息\\N{\\fs12}in the background, and we can do that,\r\nDialogue: 0,1:00:55.16,1:00:58.47,yin,,0,0,0,,不过有两种不同的后台条件需要考虑\\N{\\fs12}but there's really two different background conditions to consider.\r\nDialogue: 0,1:00:58.47,1:01:02.03,yin,,0,0,0,,一个 我们的app处在后台\\N{\\fs12}One is background, and our app is in the background.\r\nDialogue: 0,1:01:02.03,1:01:04.96,yin,,0,0,0,,换言之 用户当前并没有用我们的app\\N{\\fs12}In other words, the user is not currently using our app, okay.\r\nDialogue: 0,1:01:04.96,1:01:07.60,yin,,0,0,0,,他们用过 但现在程序在后台\\N{\\fs12}They were using it, but now it's in the background.\r\nDialogue: 0,1:01:07.60,1:01:09.34,yin,,0,0,0,,这时如何取回呢\\N{\\fs12}Okay, how do I fetch when that happens.\r\nDialogue: 0,1:01:09.34,1:01:12.44,yin,,0,0,0,,这时的取回受系统限制\\N{\\fs12}Well, fetching there is kind of limited by the system.\r\nDialogue: 0,1:01:12.44,1:01:15.75,yin,,0,0,0,,这时系统不会让你疯狂地取回数据\\N{\\fs12}The system is not going let you just go hog wild fetching things\r\nDialogue: 0,1:01:15.75,1:01:17.88,yin,,0,0,0,,毕竟你不是用户使用的app\\N{\\fs12}when you're not the app that the user is using,\r\nDialogue: 0,1:01:17.88,1:01:20.51,yin,,0,0,0,,不过有时 它会让你这样做\\N{\\fs12}but it will let you do it sometimes.\r\nDialogue: 0,1:01:20.51,1:01:24.02,yin,,0,0,0,,系统有时可以将你从背景唤醒\\N{\\fs12}And, the way you can get the system to kind of wake you up\r\nDialogue: 0,1:01:24.02,1:01:26.61,yin,,0,0,0,,并让你取回一些信息\\N{\\fs12}and let you fetch sometimes in the background,\r\nDialogue: 0,1:01:26.61,1:01:28.95,yin,,0,0,0,,或许一天几次\\N{\\fs12}every once in awhile, I don't know, a few times a day,\r\nDialogue: 0,1:01:28.95,1:01:32.51,yin,,0,0,0,,具体的没人知道 不过有时 它会使用后台取回\\N{\\fs12}who knows what, but sometimes, it's using background fetching,\r\nDialogue: 0,1:01:32.51,1:01:36.86,yin,,0,0,0,,这是一个多任务处理API 这是iOS7的新特性\\N{\\fs12}which is a multitasking API, new for iOS 7.\r\nDialogue: 0,1:01:36.87,1:01:40.06,yin,,0,0,0,,我将把这当作一个例子\\N{\\fs12}So, I'm just going to show you this as an example of what some\r\nDialogue: 0,1:01:40.06,1:01:43.16,yin,,0,0,0,,告诉你们多任务处理API是怎样的\\N{\\fs12}of the multitasking APIs look like.\r\nDialogue: 0,1:01:43.16,1:01:45.75,yin,,0,0,0,,打开这个的做法如下 编辑你的项目\\N{\\fs12}Now, the way you turn this is on, is you edit your project.\r\nDialogue: 0,1:01:45.75,1:01:48.25,yin,,0,0,0,,这是我的项目 我点了上面这里\\N{\\fs12}You see this is my project I clicked on up here,\r\nDialogue: 0,1:01:48.25,1:01:51.52,yin,,0,0,0,,然后到这个选项卡 Capabilities(能力)\\N{\\fs12}and now you're going to go to this tab right here, capabilities.\r\nDialogue: 0,1:01:51.52,1:01:54.63,yin,,0,0,0,,来到capabilities 这里有很多\\N{\\fs12}So, I go to capabilities, and there's a lot of capabilities.\r\nDialogue: 0,1:01:54.63,1:01:58.39,yin,,0,0,0,,从这里就能感受到 我们对iOS的接触有多粗浅\\N{\\fs12}This really kind of gives you a feeling of how we're only skimming the surface of iOS,\r\nDialogue: 0,1:01:58.39,1:02:00.58,yin,,0,0,0,,看看这里你可以做多少事情\\N{\\fs12}when you look at all these things you can do.\r\nDialogue: 0,1:02:00.58,1:02:02.21,yin,,0,0,0,,无论如何 我们要的在这里\\N{\\fs12}But, anyway, we're going to do this one right here,\r\nDialogue: 0,1:02:02.21,1:02:05.17,yin,,0,0,0,,后台模式 我要把这个打开\\N{\\fs12}background modes, and I'm going to turn this on.\r\nDialogue: 0,1:02:05.17,1:02:07.76,yin,,0,0,0,,打开时 这里有各种后台模式\\N{\\fs12}When I turn it on, there's all kinds of background modes,\r\nDialogue: 0,1:02:07.76,1:02:10.51,yin,,0,0,0,,这些在后台都可以做到\\N{\\fs12}things that I can be allowed to do in the background.\r\nDialogue: 0,1:02:10.51,1:02:13.81,yin,,0,0,0,,也就是说 我的app当前没有被用户使用\\N{\\fs12}That is to say when my app is not currently being used by the user,\r\nDialogue: 0,1:02:13.83,1:02:15.39,yin,,0,0,0,,我要的是下面这个\\N{\\fs12}and I'm going to pick this one down here,\r\nDialogue: 0,1:02:15.39,1:02:16.81,yin,,0,0,0,,后台取回\\N{\\fs12}background fetch,\r\nDialogue: 0,1:02:16.81,1:02:19.91,yin,,0,0,0,,如果我打开这个后台取回\\N{\\fs12}and if I turn this on, okay, background fetch,\r\nDialogue: 0,1:02:19.91,1:02:24.14,yin,,0,0,0,,那么 我就会偶尔在系统的允许下\\N{\\fs12}then I will occasionally by the system at its discretion,\r\nDialogue: 0,1:02:24.14,1:02:29.31,yin,,0,0,0,,发送一条消息给我的app委托 甚至启动去做这个\\N{\\fs12}send a message to my app delegate, perhaps even launching me to do it.\r\nDialogue: 0,1:02:29.31,1:02:32.23,yin,,0,0,0,,发送的消息是什么呢\\N{\\fs12}And what is that message that gets sent.\r\nDialogue: 0,1:02:32.23,1:02:33.90,yin,,0,0,0,,我展示一下\\N{\\fs12}I'll show it to you right here.\r\nDialogue: 0,1:02:33.91,1:02:36.74,yin,,0,0,0,,它叫… 我们将键入它\\N{\\fs12}It is called, we're going to type it in.\r\nDialogue: 0,1:02:36.74,1:02:39.93,yin,,0,0,0,,application… 你可以看看能从应用中接收的所有东西\\N{\\fs12}Application, so you can look at all the things you can receive from your application.\r\nDialogue: 0,1:02:39.93,1:02:41.91,yin,,0,0,0,,这里有好多东西\\N{\\fs12}There is just a billion of them here.\r\nDialogue: 0,1:02:41.91,1:02:43.29,yin,,0,0,0,,看到了吗\\N{\\fs12}See them.\r\nDialogue: 0,1:02:43.29,1:02:45.70,yin,,0,0,0,,我们会谈到有些 不过肯定不是全部\\N{\\fs12}So, we'll cover some of those, but not all of them,\r\nDialogue: 0,1:02:45.70,1:02:47.95,yin,,0,0,0,,总之 这里有很多\\N{\\fs12}but there's quite a few of them in here.\r\nDialogue: 0,1:02:47.95,1:02:51.71,yin,,0,0,0,,这里我们要的是这个\\N{\\fs12}But, the one you get when you do this is this one right here,\r\nDialogue: 0,1:02:51.71,1:02:55.19,yin,,0,0,0,,performFetchWithCompletionHandler\\N{\\fs12}perform fetch with completion handler, okay,\r\nDialogue: 0,1:02:55.20,1:02:58.94,yin,,0,0,0,,这个被发给你 它会说 好\\N{\\fs12}so this gets sent to you, and it's basically saying, okay,\r\nDialogue: 0,1:02:58.94,1:03:01.32,yin,,0,0,0,,我给你一个在后台做事的机会\\N{\\fs12}I'm giving you an opportunity to go do something in the background,\r\nDialogue: 0,1:03:01.34,1:03:02.92,yin,,0,0,0,,取回或是别的什么\\N{\\fs12}a fetch or whatever you want to do.\r\nDialogue: 0,1:03:02.92,1:03:06.15,yin,,0,0,0,,通常是取回 不过这里想做什么都可以\\N{\\fs12}Usually it's a fetch, but you can kind of do whatever you want here,\r\nDialogue: 0,1:03:06.15,1:03:10.23,yin,,0,0,0,,你在做这个时的唯一责任是\\N{\\fs12}and the only responsibility you have in doing this is\r\nDialogue: 0,1:03:10.23,1:03:12.88,yin,,0,0,0,,完成时调用这个completionHandler\\N{\\fs12}to call this completion handler when you're done.\r\nDialogue: 0,1:03:12.88,1:03:14.69,yin,,0,0,0,,你只需要做这个就行了\\N{\\fs12}That's the only thing you absolutely have to do.\r\nDialogue: 0,1:03:14.69,1:03:16.70,yin,,0,0,0,,如果你不及时调用这个\\N{\\fs12}If you don't call that in a timely manner,\r\nDialogue: 0,1:03:16.70,1:03:19.91,yin,,0,0,0,,系统会对你产生厌烦 它会停止取回\\N{\\fs12}the system will grow tired of you, and it will stop fetching.\r\nDialogue: 0,1:03:19.91,1:03:22.06,yin,,0,0,0,,会停止发送这条消息给你\\N{\\fs12}It will stop sending you this message.\r\nDialogue: 0,1:03:22.06,1:03:25.25,yin,,0,0,0,,我们对这个的反应越及时 系统就越有可能\\N{\\fs12}So, more timely we respond to this, the more likely it's going\r\nDialogue: 0,1:03:25.25,1:03:27.54,yin,,0,0,0,,许我们在后台取回\\N{\\fs12}to let you fetch in the background.\r\nDialogue: 0,1:03:27.54,1:03:29.71,yin,,0,0,0,,这里我们怎么做呢\\N{\\fs12}Okay, so what are we going to do here?\r\nDialogue: 0,1:03:29.71,1:03:36.00,yin,,0,0,0,,我们这里只需要开始一个Flickr取回\\N{\\fs12}Well, it turns out, all we're going to do in here is start a Flickr fetch,\r\nDialogue: 0,1:03:36.01,1:03:40.42,yin,,0,0,0,,然后我们立刻调用这个CompletionHandler\\N{\\fs12}and then we're immediately going to call this completion handler.\r\nDialogue: 0,1:03:40.42,1:03:41.90,yin,,0,0,0,,这还没完\\N{\\fs12}We're not done.\r\nDialogue: 0,1:03:41.90,1:03:43.56,yin,,0,0,0,,这个取回我们才开始\\N{\\fs12}This fetch, we just started it.\r\nDialogue: 0,1:03:43.56,1:03:46.24,yin,,0,0,0,,它需要一会才能完成 但是\\N{\\fs12}It's going to take awhile to come back later, but\r\nDialogue: 0,1:03:46.24,1:03:48.94,yin,,0,0,0,,只要这个后台取回的东西在继续就行了\\N{\\fs12}we're done, as far as this background fetch thing is continued.\r\nDialogue: 0,1:03:48.94,1:03:52.86,yin,,0,0,0,,获得结果这些会在别的时候发生\\N{\\fs12}Okay, getting the result and doing all that, that's going to happen at some other time,\r\nDialogue: 0,1:03:52.86,1:03:55.28,yin,,0,0,0,,但这里我们完成了\\N{\\fs12}but here, we're done, and we have to,\r\nDialogue: 0,1:03:55.28,1:03:58.08,yin,,0,0,0,,这个CompletionHandler的参数\\N{\\fs12}the argument to this completion handler\r\nDialogue: 0,1:03:58.08,1:04:00.68,yin,,0,0,0,,是一个UIBackgroundFetchResult\\N{\\fs12}is a UI background fetch result,\r\nDialogue: 0,1:04:00.68,1:04:05.23,yin,,0,0,0,,也就是 无论这里做了什么 改变你的UI\\N{\\fs12}which is whether whatever you did in here changed your UI.\r\nDialogue: 0,1:04:05.23,1:04:09.11,yin,,0,0,0,,因为如果它这样做了 我们就需要更新任务切换器\\N{\\fs12}Because if it did, we need to update the little task switcher.\r\nDialogue: 0,1:04:09.11,1:04:11.76,yin,,0,0,0,,iOS7中任务切换器是什么知道吗\\N{\\fs12}Okay, does everyone know what the task switcher is in iOS 7?\r\nDialogue: 0,1:04:11.76,1:04:14.81,yin,,0,0,0,,它是这样的 这就是任务切换器\\N{\\fs12}It looks like this, okay, here's the task switcher.\r\nDialogue: 0,1:04:14.81,1:04:18.77,yin,,0,0,0,,它让你能观看各种app 看app有没有做任何事\\N{\\fs12}It lets you go through and look at various apps, if my apps are doing anything here.\r\nDialogue: 0,1:04:18.77,1:04:19.99,yin,,0,0,0,,让我们启动一个app\\N{\\fs12}Let's launch an app.\r\nDialogue: 0,1:04:19.99,1:04:21.76,yin,,0,0,0,,启动Safari\\N{\\fs12}Let's launch safari here.\r\nDialogue: 0,1:04:21.76,1:04:24.51,yin,,0,0,0,,现在进入任务切换器 这是Safari\\N{\\fs12}Okay, so now I go into task switcher, and here's Safari.\r\nDialogue: 0,1:04:24.51,1:04:27.95,yin,,0,0,0,,它给我展示了Safari中显示的内容\\N{\\fs12}See how it's showing me what's actually in Safari?\r\nDialogue: 0,1:04:27.95,1:04:30.85,yin,,0,0,0,,它展示的并不是现在Safari中的内容\\N{\\fs12}It's not really showing me what's in Safari right now.\r\nDialogue: 0,1:04:30.85,1:04:35.75,yin,,0,0,0,,而是上次我离开Safari时显示的内容\\N{\\fs12}It's kind of showing me Safari the last time I left Safari.\r\nDialogue: 0,1:04:35.75,1:04:37.83,yin,,0,0,0,,或者 如果我有这种后台取回\\N{\\fs12}Or, if I get this background fetch\r\nDialogue: 0,1:04:37.83,1:04:40.31,yin,,0,0,0,,和这个完成处理器\\N{\\fs12}and this completion handler,\r\nDialogue: 0,1:04:40.31,1:04:44.61,yin,,0,0,0,,我说UIBackgroundFetchNewData\\N{\\fs12}I say UI background fetch, new data,\r\nDialogue: 0,1:04:44.62,1:04:46.89,yin,,0,0,0,,这时 它就会为我重新绘制这个\\N{\\fs12}then it would redraw that thing for me.\r\nDialogue: 0,1:04:46.89,1:04:49.26,yin,,0,0,0,,它会给我一个重新绘制的机会\\N{\\fs12}It would give me a chance to redraw it.\r\nDialogue: 0,1:04:49.26,1:04:51.29,yin,,0,0,0,,但我没有任何新数据\\N{\\fs12}But, I don't actually have any new data.\r\nDialogue: 0,1:04:51.29,1:04:55.17,yin,,0,0,0,,这里我没有数据 因为我还没有从这里获得数据\\N{\\fs12}I have no data here, because I haven't gotten the data from this yet.\r\nDialogue: 0,1:04:55.17,1:05:00.63,yin,,0,0,0,,这个Flickr取回还没有返回 因此它什么都不会做\\N{\\fs12}This Flickr fetch has not come back yet, so it's not going to do anything.\r\nDialogue: 0,1:05:00.63,1:05:02.28,yin,,0,0,0,,这很棒\\N{\\fs12}So, this is great.\r\nDialogue: 0,1:05:02.28,1:05:05.62,yin,,0,0,0,,这让我偶尔能够进行后台取回\\N{\\fs12}This lets me occasionally fire off a background fetch,\r\nDialogue: 0,1:05:05.62,1:05:09.97,yin,,0,0,0,,但当数据返回时 我该怎么做呢\\N{\\fs12}but when the data comes back in, then what do I do.\r\nDialogue: 0,1:05:09.97,1:05:11.93,yin,,0,0,0,,如果我在后台\\N{\\fs12}Well, if I'm in the background,\r\nDialogue: 0,1:05:11.93,1:05:17.54,yin,,0,0,0,,这些URL东西都不会被调用\\N{\\fs12}none of these URL things are going to get called.\r\nDialogue: 0,1:05:17.54,1:05:21.60,yin,,0,0,0,,因为我在后台\\N{\\fs12}Because I'm back-grounded.\r\nDialogue: 0,1:05:21.60,1:05:25.78,yin,,0,0,0,,这些不会被调用并不严格成立\\N{\\fs12}Now, it's not strictly true that these won't get called,\r\nDialogue: 0,1:05:25.78,1:05:29.93,yin,,0,0,0,,因为如果URL在我在后台时返回\\N{\\fs12}because what will happen is if the URL returns while I'm\r\nDialogue: 0,1:05:29.93,1:05:32.09,yin,,0,0,0,,我最开始是在后台中\\N{\\fs12}in the background, so I started it in the background,\r\nDialogue: 0,1:05:32.09,1:05:35.40,yin,,0,0,0,,如果它返回 我会得到另一个application的东西\\N{\\fs12}if it returns, I'll get another application thing called\r\nDialogue: 0,1:05:35.40,1:05:40.54,yin,,0,0,0,,叫application handleEventsForBackgroundURLSession\\N{\\fs12}application handle events for background URL session.\r\nDialogue: 0,1:05:40.54,1:05:44.30,yin,,0,0,0,,它也有一个完成处理器 和之前不同\\N{\\fs12}And, it also has a completion handler, a little different one.\r\nDialogue: 0,1:05:44.30,1:05:47.64,yin,,0,0,0,,事情在后台中发生时 这个就会被调用\\N{\\fs12}Okay, so this is called whenever things happen in the background.\r\nDialogue: 0,1:05:47.64,1:05:49.48,yin,,0,0,0,,这个有一点很有趣\\N{\\fs12}Now, what's interesting about this one is,\r\nDialogue: 0,1:05:49.48,1:05:52.06,yin,,0,0,0,,这个里面我也不需要做任何事\\N{\\fs12}I don't actually need to do anything in this one either.\r\nDialogue: 0,1:05:52.06,1:05:54.39,yin,,0,0,0,,因为如果我实现这个方法\\N{\\fs12}Because if I implement this method,\r\nDialogue: 0,1:05:54.40,1:05:58.37,yin,,0,0,0,,那么下面这里的委托方法 就会自动被调用\\N{\\fs12}then these delegate methods down here will automatically get called,\r\nDialogue: 0,1:05:58.37,1:06:04.39,yin,,0,0,0,,它们已经知道如何从Flickr解包数据 并放入我的数据库\\N{\\fs12}and they already know how to unpackage the data from Flickr and put it in my database.\r\nDialogue: 0,1:06:04.39,1:06:07.52,yin,,0,0,0,,它们已经知道怎么做 不过我还有这个责任\\N{\\fs12}They already know how to do all that, but I still do have this responsibility\r\nDialogue: 0,1:06:07.52,1:06:09.83,yin,,0,0,0,,对于这个的完成处理器\\N{\\fs12}for the completion handler on this one too.\r\nDialogue: 0,1:06:11.71,1:06:15.62,yin,,0,0,0,,这个完成处理器的调用需要等到\\N{\\fs12}Now, this completion handler, we really do want to wait to call\r\nDialogue: 0,1:06:15.62,1:06:19.39,yin,,0,0,0,,我们已经处理了这个返回自Flickr的URL\\N{\\fs12}until we've actually handled this URL coming back from Flickr.\r\nDialogue: 0,1:06:19.39,1:06:22.18,yin,,0,0,0,,这个在处理返回自Flickr的URL\\N{\\fs12}Okay, this is handling a URL coming back from Flickr.\r\nDialogue: 0,1:06:22.18,1:06:24.72,yin,,0,0,0,,现在我们要等待\\N{\\fs12}So, now we're going to wait. So, I'm going to have to hold onto it.\r\nDialogue: 0,1:06:24.72,1:06:28.10,yin,,0,0,0,,我这里有一个实例变量\\N{\\fs12}So, I'm going to. I have an instance variable here,\r\nDialogue: 0,1:06:28.10,1:06:31.13,yin,,0,0,0,,我要保持住这个完成处理器\\N{\\fs12}where I'm going to hold onto this completion handler,\r\nDialogue: 0,1:06:31.13,1:06:33.77,yin,,0,0,0,,这里就是那个实例变量\\N{\\fs12}and here's the instance variable right here.\r\nDialogue: 0,1:06:33.77,1:06:35.88,yin,,0,0,0,,它是void\\N{\\fs12}Okay. It's a void.\r\nDialogue: 0,1:06:35.88,1:06:39.10,yin,,0,0,0,,没有参数 只是属性\\N{\\fs12}It takes no arguments, just properties.\r\nDialogue: 0,1:06:39.10,1:06:42.35,yin,,0,0,0,,顺便说下 所有的block 都是copy属性\\N{\\fs12}All blocks by the way, want to be copy properties.\r\nDialogue: 0,1:06:42.35,1:06:46.10,yin,,0,0,0,,在保持处理时 block需要被复制到堆\\N{\\fs12}Blocks want to be copied into the heap when you keep a handle to them.\r\nDialogue: 0,1:06:46.10,1:06:47.70,yin,,0,0,0,,这需要大家知道\\N{\\fs12}Something to know.\r\nDialogue: 0,1:06:47.70,1:06:52.58,yin,,0,0,0,,无论如何 我要保持这个东西\\N{\\fs12}So, anyway, all I need to do is keep this thing, and then I need\r\nDialogue: 0,1:06:52.58,1:06:55.17,yin,,0,0,0,,然后我要在完成时调用这个\\N{\\fs12}to call this when I'm done,\r\nDialogue: 0,1:06:55.17,1:06:58.48,yin,,0,0,0,,下面有个方法是做这个的\\N{\\fs12}so I have a method down here that I use to do that with.\r\nDialogue: 0,1:06:58.48,1:07:02.31,yin,,0,0,0,,叫作flickrDownloadTasksMightBeComplete\\N{\\fs12}It's called Flickr download tasks might be complete,\r\nDialogue: 0,1:07:02.31,1:07:05.05,yin,,0,0,0,,因为我可能有多个下载任务发生\\N{\\fs12}because I might have multiple download tasks happening,\r\nDialogue: 0,1:07:05.05,1:07:07.94,yin,,0,0,0,,于是这里我获得所有Flickr下载session所做的任务\\N{\\fs12}and so what I do here is, I get all the tasks\r\nDialogue: 0,1:07:07.94,1:07:10.20,yin,,0,0,0,,于是这里我获得所有Flickr下载session所做的任务\\N{\\fs12}that my Flickr download session is doing,\r\nDialogue: 0,1:07:10.20,1:07:12.84,yin,,0,0,0,,这就是这个方法的作用 它也有一个block\\N{\\fs12}that's what this method does, and it has a little block\r\nDialogue: 0,1:07:12.84,1:07:14.88,yin,,0,0,0,,这个会被调用 因为它无法立刻执行\\N{\\fs12}that gets called, because it can't do that immediately.\r\nDialogue: 0,1:07:14.88,1:07:17.57,yin,,0,0,0,,有时 它需要一些时间才能弄清\\N{\\fs12}Sometimes it takes a little time to figure that out,\r\nDialogue: 0,1:07:17.57,1:07:20.63,yin,,0,0,0,,如果没有下载任务剩余\\N{\\fs12}and then if there are no download tasks left, right?\r\nDialogue: 0,1:07:20.63,1:07:22.79,yin,,0,0,0,,![dowloadTasks count]\\N{\\fs12}Not download task count,\r\nDialogue: 0,1:07:22.79,1:07:25.48,yin,,0,0,0,,那么我就会调用这个完成处理器\\N{\\fs12}then I'm going to call this completion handler.\r\nDialogue: 0,1:07:25.48,1:07:30.06,yin,,0,0,0,,这个Flickr下载后台完成处理器 说我完成了\\N{\\fs12}This Flickr download background completion handler, and say that I'm done.\r\nDialogue: 0,1:07:30.06,1:07:32.34,yin,,0,0,0,,这时 我就完成了下载\\N{\\fs12}Okay, so now I've finished downloading it,\r\nDialogue: 0,1:07:32.34,1:07:35.84,yin,,0,0,0,,我重画了我的UI 我还调用了完成处理器\\N{\\fs12}I've redrawn my UI, and I'm calling the completion handler,\r\nDialogue: 0,1:07:35.84,1:07:40.73,yin,,0,0,0,,这个完成处理器没有UI无数据的东西\\N{\\fs12}and this completion handler doesn't have the little UI no data thing,\r\nDialogue: 0,1:07:40.73,1:07:44.60,yin,,0,0,0,,因为它总假设你会更新你的UI\\N{\\fs12}because it always assumes that you're going to update your UI.\r\nDialogue: 0,1:07:44.60,1:07:45.63,yin,,0,0,0,,总是假设\\N{\\fs12}So, it's always assuming.\r\nDialogue: 0,1:07:45.63,1:07:48.92,yin,,0,0,0,,它在你那样做时会总是重绘\\N{\\fs12}It's always going to redraw when you do that.\r\nDialogue: 0,1:07:48.92,1:07:51.75,yin,,0,0,0,,好 要看这是怎么样的\\N{\\fs12}Okay. So, let's see what this, okay, to see what this is going\r\nDialogue: 0,1:07:51.75,1:07:53.40,yin,,0,0,0,,有一个很酷的方式\\N{\\fs12}to look like, there's a really cool way.\r\nDialogue: 0,1:07:53.40,1:07:55.62,yin,,0,0,0,,我们这里分两步走\\N{\\fs12}Well let's, okay, let's do this two part here.\r\nDialogue: 0,1:07:55.62,1:07:57.00,yin,,0,0,0,,我打算运行这个\\N{\\fs12}I'm going to run this.\r\nDialogue: 0,1:07:57.00,1:07:58.12,yin,,0,0,0,,它在这里\\N{\\fs12}Here it is right here.\r\nDialogue: 0,1:07:58.12,1:08:02.44,yin,,0,0,0,,你可以在Xcode中模拟后台取回\\N{\\fs12}You can actually simulate fetching in the background in X code.\r\nDialogue: 0,1:08:02.44,1:08:03.98,yin,,0,0,0,,回到Xcode\\N{\\fs12}So, I'm going back to X code.\r\nDialogue: 0,1:08:03.98,1:08:05.46,yin,,0,0,0,,这是我的UI\\N{\\fs12}Here's my UI.\r\nDialogue: 0,1:08:05.48,1:08:08.99,yin,,0,0,0,,从Xcode中 在调试下 我要说\\N{\\fs12}Okay, I'm going to say, from X code, under debug,\r\nDialogue: 0,1:08:08.99,1:08:12.22,yin,,0,0,0,,模拟后台取回 看我的UI会发生什么\\N{\\fs12}simulate background fetch, and watch what's going to happen to my UI,\r\nDialogue: 0,1:08:12.23,1:08:14.51,yin,,0,0,0,,我被丢到了后台\\N{\\fs12}oop, I got put in the background.\r\nDialogue: 0,1:08:14.51,1:08:16.28,yin,,0,0,0,,它在进行取回\\N{\\fs12}Okay. And it's doing a fetch.\r\nDialogue: 0,1:08:16.28,1:08:20.12,yin,,0,0,0,,它到Flickr进行着那些下载\\N{\\fs12}It's going in Flickr. It's downloading to Flickr and doing all that stuff,\r\nDialogue: 0,1:08:20.12,1:08:22.26,yin,,0,0,0,,实际上 完成后到这里\\N{\\fs12}and actually if I went like this when it was done,\r\nDialogue: 0,1:08:22.26,1:08:24.72,yin,,0,0,0,,我可以看到结果\\N{\\fs12}I would see the results in here.\r\nDialogue: 0,1:08:24.72,1:08:27.08,yin,,0,0,0,,这个你们有些难于看到\\N{\\fs12}Okay, now that's hard for you to see here,\r\nDialogue: 0,1:08:27.08,1:08:30.81,yin,,0,0,0,,因此 我还打算展示另一个模拟后台取回的方式\\N{\\fs12}so I'm going to show you another way to simulate a background fetch besides this,\r\nDialogue: 0,1:08:30.81,1:08:33.88,yin,,0,0,0,,我们删除了Photomania 这样表格就空了\\N{\\fs12}so let's delete photo mania so that our tables are empty.\r\nDialogue: 0,1:08:33.88,1:08:36.30,yin,,0,0,0,,你们可以在这里很清楚地看到\\N{\\fs12}You'll really be able to see it clearly here, oops,\r\nDialogue: 0,1:08:36.30,1:08:39.27,yin,,0,0,0,,我应该先退出Xcode\\N{\\fs12}I should have quit X code first.\r\nDialogue: 0,1:08:39.27,1:08:40.68,yin,,0,0,0,,这里我来退出\\N{\\fs12}Put that in the step.\r\nDialogue: 0,1:08:41.72,1:08:45.07,yin,,0,0,0,,我下面要做的是这样 有一种方式\\N{\\fs12}And, so what I'm going to do here is there's a way\r\nDialogue: 0,1:08:45.07,1:08:47.31,yin,,0,0,0,,来启动你的应用\\N{\\fs12}to launch your application\r\nDialogue: 0,1:08:47.31,1:08:51.09,yin,,0,0,0,,就像它刚从后台取回中得到启动\\N{\\fs12}as if it just got launched from a background fetch,\r\nDialogue: 0,1:08:51.09,1:08:54.71,yin,,0,0,0,,做法是编辑scheme\\N{\\fs12}and the way to do that is edit scheme.\r\nDialogue: 0,1:08:54.71,1:08:58.23,yin,,0,0,0,,编辑scheme scheme也就是它如何启动你\\N{\\fs12}If you edit this little scheme, the scheme is how it's launching you.\r\nDialogue: 0,1:08:58.23,1:09:00.44,yin,,0,0,0,,这里它是在模拟器中启动我们\\N{\\fs12}In this case, it's launching us in a simulator.\r\nDialogue: 0,1:09:00.44,1:09:04.65,yin,,0,0,0,,编辑scheme 到选项 这里有个小选框\\N{\\fs12}So, if you edit scheme, and you go over to options, there's this little switch here,\r\nDialogue: 0,1:09:04.65,1:09:06.94,yin,,0,0,0,,由于后台取回的启动\\N{\\fs12}launch due to a background fetch.\r\nDialogue: 0,1:09:06.94,1:09:10.14,yin,,0,0,0,,换言之 我点击运行时 假装我刚启动\\N{\\fs12}In other words, when I hit run, pretend I just got launched,\r\nDialogue: 0,1:09:10.14,1:09:14.23,yin,,0,0,0,,因为一个后台取回被发送给我 这就是这个\\N{\\fs12}because a background fetch got sent to me, okay, so that's what that means.\r\nDialogue: 0,1:09:14.23,1:09:17.85,yin,,0,0,0,,通常 我们不会那样设置\\N{\\fs12}Now, normally, we're not going to set that switch and leave it set like that.\r\nDialogue: 0,1:09:17.85,1:09:21.46,yin,,0,0,0,,你可以复制这个scheme 这里我来复制一下\\N{\\fs12}You can actually duplicate this scheme, so I have the schema; I'm going to duplicate it.\r\nDialogue: 0,1:09:21.46,1:09:23.79,yin,,0,0,0,,称它为我的BFF scheme\\N{\\fs12}I'm going to call it my BFF scheme.\r\nDialogue: 0,1:09:23.79,1:09:27.66,yin,,0,0,0,,意思是后台Flickr取回器\\N{\\fs12}That means background Flickr fetcher.\r\nDialogue: 0,1:09:27.66,1:09:34.75,yin,,0,0,0,,我的BFF scheme中 我将勾选这个\\N{\\fs12}It's my BFF scheme, and in my BFF scheme, I'm going to have that switch set, okay.\r\nDialogue: 0,1:09:34.75,1:09:38.66,yin,,0,0,0,,在其它scheme 例如回到这个scheme 编辑它\\N{\\fs12}In my other scheme, if I go back to this scheme and edit it,\r\nDialogue: 0,1:09:38.66,1:09:41.20,yin,,0,0,0,,这个就没有勾选\\N{\\fs12}that switch is not set, okay.\r\nDialogue: 0,1:09:41.20,1:09:44.32,yin,,0,0,0,,要假装这个正在发生\\N{\\fs12}So, if I want to pretend that's happening,\r\nDialogue: 0,1:09:44.32,1:09:48.36,yin,,0,0,0,,我到BFF scheme 点运行\\N{\\fs12}I go to my BFF scheme, and I press run.\r\nDialogue: 0,1:09:48.36,1:09:51.91,yin,,0,0,0,,运行时 可以看到 我是在后台运行\\N{\\fs12}Now, when I run, see it ran me in the background.\r\nDialogue: 0,1:09:51.91,1:09:55.23,yin,,0,0,0,,另外还有一点我想展示给大家\\N{\\fs12}So, the other two things -- the other thing I really wanted\r\nDialogue: 0,1:09:55.23,1:09:57.57,yin,,0,0,0,,只是时间有点不够了\\N{\\fs12}to show you here, which I don't really have time to do.\r\nDialogue: 0,1:09:57.57,1:09:59.24,yin,,0,0,0,,我快点展示吧 也就是\\N{\\fs12}Oh, actually I'll do it real quick is,\r\nDialogue: 0,1:09:59.24,1:10:02.23,yin,,0,0,0,,我如果是前台app 取回是怎样的\\N{\\fs12}how about fetching when I'm the foreground app.\r\nDialogue: 0,1:10:02.23,1:10:06.77,yin,,0,0,0,,如果用户正在用我 我想周期性取回\\N{\\fs12}What happens if the user is currently using me, and I want to fetch periodically.\r\nDialogue: 0,1:10:06.77,1:10:08.57,yin,,0,0,0,,这是完全不同的内容\\N{\\fs12}Okay, that's a totally different thing.\r\nDialogue: 0,1:10:08.57,1:10:11.78,yin,,0,0,0,,要做到这个 我们需要一个类 叫NSTimer\\N{\\fs12}To do that, we're going to use a class called NS timer.\r\nDialogue: 0,1:10:11.78,1:10:13.57,yin,,0,0,0,,我要写到这里\\N{\\fs12}Okay, so I'm going to put this here.\r\nDialogue: 0,1:10:13.57,1:10:16.39,yin,,0,0,0,,一旦数据库context可用\\N{\\fs12}Once the database context is available, then I'm going\r\nDialogue: 0,1:10:16.39,1:10:20.07,yin,,0,0,0,,我就要开启一个Timer 使用NSTimer方法\\N{\\fs12}to fire off a timer using this NS timer method,\r\nDialogue: 0,1:10:20.07,1:10:21.80,yin,,0,0,0,,scheduleTimerWithTimeInterval\\N{\\fs12}schedule timer with time interval.\r\nDialogue: 0,1:10:21.80,1:10:23.20,yin,,0,0,0,,我要做这个\\N{\\fs12}I want to do this one.\r\nDialogue: 0,1:10:23.20,1:10:26.10,yin,,0,0,0,,Flickr取回要多频繁呢\\N{\\fs12}How often should we do our Flickr fetch?\r\nDialogue: 0,1:10:26.10,1:10:30.16,yin,,0,0,0,,Flickr大概每十到十五分钟才会更新一次\\N{\\fs12}Well, it doesn't seem like Flickr updates it more than once every 10 or 15 minutes,\r\nDialogue: 0,1:10:30.16,1:10:33.24,yin,,0,0,0,,我们这里就每二十分钟取回一次吧\\N{\\fs12}so let's do it every 20 minutes.\r\nDialogue: 0,1:10:33.24,1:10:34.83,yin,,0,0,0,,这是以秒计的\\N{\\fs12}So, this is in seconds.\r\nDialogue: 0,1:10:34.83,1:10:38.49,yin,,0,0,0,,我们用二十分钟 目标是我的self\\N{\\fs12}So, I'll do 20 minutes, and the target is going to be myself.\r\nDialogue: 0,1:10:38.49,1:10:41.25,yin,,0,0,0,,换言之 每隔二十分钟 发给我一个方法\\N{\\fs12}In other words, every 20 minutes, send me a method,\r\nDialogue: 0,1:10:41.25,1:10:49.63,yin,,0,0,0,,而发送给我的方法是 startFlickrFetch 还有参数\\N{\\fs12}and the method to send me is start Flickr fetch, and the argument.\r\nDialogue: 0,1:10:49.63,1:10:51.63,yin,,0,0,0,,没有用户信息\\N{\\fs12}And, no user info.\r\nDialogue: 0,1:10:51.63,1:10:55.56,yin,,0,0,0,,抱歉 这里应该是个冒号\\N{\\fs12}Sorry, this has to be a colon.\r\nDialogue: 0,1:10:55.56,1:10:57.59,yin,,0,0,0,,等下我就会解释为什么\\N{\\fs12}I'll show you why in a second.\r\nDialogue: 0,1:10:57.59,1:10:59.63,yin,,0,0,0,,然后重复\\N{\\fs12}And repeat, yes,\r\nDialogue: 0,1:10:59.63,1:11:04.05,yin,,0,0,0,,我希望这个是每二十分钟 发送这个Timer\\N{\\fs12}so I want this to just be every 20 minutes at sending this timer.\r\nDialogue: 0,1:11:04.05,1:11:09.41,yin,,0,0,0,,这个startFlickrFetch为什么需要有一个冒号呢\\N{\\fs12}Okay. So, why is this start Flickr fetch here have to have colon?\r\nDialogue: 0,1:11:09.41,1:11:12.07,yin,,0,0,0,,这是因为这个Timer在发送它的消息时\\N{\\fs12}That's because this timer when it sends its message,\r\nDialogue: 0,1:11:12.07,1:11:16.76,yin,,0,0,0,,总有一个参数 如果我说startFlickrFetch\\N{\\fs12}it always has an argument, and if I do start Flickr fetch\r\nDialogue: 0,1:11:16.76,1:11:21.33,yin,,0,0,0,,带有那个参数 发送给你的是NSTimer\\N{\\fs12}with the argument, it's the NS timer that sent it to you.\r\nDialogue: 0,1:11:21.33,1:11:23.89,yin,,0,0,0,,不过这里 我不关心\\N{\\fs12}But, in this case, I don't care.\r\nDialogue: 0,1:11:23.89,1:11:25.92,yin,,0,0,0,,我只要startFlickrFetch\\N{\\fs12}I'm just going to start Flickr fetch.\r\nDialogue: 0,1:11:25.92,1:11:29.86,yin,,0,0,0,,每二十分钟 我都会发送这个Flickr取回\\N{\\fs12}So, every 20 minutes, I'm going to fire off this Flickr fetch.\r\nDialogue: 0,1:11:29.86,1:11:31.78,yin,,0,0,0,,这很简单\\N{\\fs12}Okay, so that's easy.\r\nDialogue: 0,1:11:31.78,1:11:33.17,yin,,0,0,0,,这时你在前台\\N{\\fs12}So, if you're in the foreground,\r\nDialogue: 0,1:11:33.17,1:11:36.07,yin,,0,0,0,,在后台时 这个Timer不会发送\\N{\\fs12}now this timer will not fire when you're in the background.\r\nDialogue: 0,1:11:36.07,1:11:38.37,yin,,0,0,0,,它不会发送 不过这没问题\\N{\\fs12}It just will not fire, but that's okay, because we have\r\nDialogue: 0,1:11:38.37,1:11:42.32,yin,,0,0,0,,因为有后台取回那些在发送 不这么频繁 不过偶尔会\\N{\\fs12}that background fetching thing firing it, not as often, but occasionally.\r\nDialogue: 0,1:11:42.32,1:11:47.15,yin,,0,0,0,,而现在 我们的app会一直获取新Flickr\\N{\\fs12}Okay, but now all the time, our app is getting new Flickr information all the time.\r\nDialogue: 0,1:11:48.34,1:11:49.32,yin,,0,0,0,,理解吗\\N{\\fs12}Make sense?\r\nDialogue: 0,1:11:50.75,1:11:53.40,yin,,0,0,0,,好 这就是我要演示的全部\\N{\\fs12}Okay, so that's all I wanted to show you. Hopefully.\r\nDialogue: 0,1:11:53.40,1:11:55.22,yin,,0,0,0,,这里有很多信息\\N{\\fs12}There's a lot of information there I know.\r\nDialogue: 0,1:11:55.22,1:11:56.08,yin,,0,0,0,,包括后台取回\\N{\\fs12}We have background fetching.\r\nDialogue: 0,1:11:56.08,1:11:56.94,yin,,0,0,0,,前台取回\\N{\\fs12}We have foreground fetching.\r\nDialogue: 0,1:11:56.94,1:11:58.98,yin,,0,0,0,,创建数据库模型\\N{\\fs12}You've got creating the database model.\r\nDialogue: 0,1:11:58.98,1:12:01.59,yin,,0,0,0,,使用category来创建添加\\N{\\fs12}You got doing the categories to create the adding things.\r\nDialogue: 0,1:12:01.59,1:12:04.01,yin,,0,0,0,,有TableView 带NSFetchResultsController\\N{\\fs12}We got the TableView with NS Fetch Results Controller.\r\nDialogue: 0,1:12:04.01,1:12:05.52,yin,,0,0,0,,所有代码我都会贴出\\N{\\fs12}I'm going to post all this code.\r\nDialogue: 0,1:12:05.52,1:12:07.20,yin,,0,0,0,,今晚我会加一些评论\\N{\\fs12}I'll throw some comments in there tonight,\r\nDialogue: 0,1:12:07.20,1:12:13.13,yin,,0,0,0,,让你们记得所有这些东西 方便你们掌握\\N{\\fs12}so you can remember what all these things do, and you'll be good to go.\r\nDialogue: 0,1:12:14.26,1:12:18.63,yin,,0,0,0,,作业好运 我们周一见\\N{\\fs12}Good luck with your homework, and I'll see you on Monday.\r\nDialogue: 0,1:12:18.63,1:12:22.37,yin,,0,0,0,,更多内容 请访问我校官网stanford.edu\\N{\\fs12}> For more, please visit us at Stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/14. UIApplication, Network Activity Indicator, and Maps.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.2.0\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage]\r\nActive Line: 7\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:04.89,0:00:07.99,yin,,0,0,0,,斯坦福大学\\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:07.99,0:00:16.00,yin,,0,0,0,,欢迎来到CS193P课程 2013-14秋季第14讲\\N{\\fs12}Welcome to the lecture 14 of CS193P for Fall of 2013 and 14.\r\nDialogue: 0,0:00:16.00,0:00:20.14,yin,,0,0,0,,今天我将讲到一些比较杂的主题\\N{\\fs12}Today I'm going to talk a little bit about miscellaneous topics,\r\nDialogue: 0,0:00:20.14,0:00:24.18,yin,,0,0,0,,UIApplication和网络活动指示器\\N{\\fs12}UI application and network activity indicator,\r\nDialogue: 0,0:00:24.18,0:00:28.70,yin,,0,0,0,,然后我打算继续上次的demo\\N{\\fs12}and then I'm going to follow up a little bit on the demo we did last time,\r\nDialogue: 0,0:00:28.70,0:00:32.38,yin,,0,0,0,,我要接着上周创建的Photomania程序\\N{\\fs12}then I'm going to continue that demo, and we're going to take Photo Mania\r\nDialogue: 0,0:00:32.38,0:00:35.20,yin,,0,0,0,,让它运行到iPad上\\N{\\fs12}that we built last week and we're going to make it work on the iPad,\r\nDialogue: 0,0:00:35.20,0:00:38.57,yin,,0,0,0,,我还要给它加个弹窗segue\\N{\\fs12}and we're going to add a popover segue to it,\r\nDialogue: 0,0:00:38.57,0:00:40.56,yin,,0,0,0,,因为几周前我讲过弹窗\\N{\\fs12}because I talked about popovers a couple weeks ago,\r\nDialogue: 0,0:00:40.56,0:00:43.23,yin,,0,0,0,,但我从来就没演示过\\N{\\fs12}but I never showed you how to do it, and you know, all this stuff\r\nDialogue: 0,0:00:43.23,0:00:46.18,yin,,0,0,0,,要知道 我不能只是讲而不演示\\N{\\fs12}if I just tell you about it, it's really not real probably\r\nDialogue: 0,0:00:46.18,0:00:49.03,yin,,0,0,0,,否则你们会一头雾水 这里我要演示弹窗\\N{\\fs12}for you until I show you how to do it, so we'll do a popover.\r\nDialogue: 0,0:00:49.04,0:00:51.31,yin,,0,0,0,,然后我们将开始讨论地图\\N{\\fs12}And then we're going to dive into maps,\r\nDialogue: 0,0:00:51.31,0:00:53.33,yin,,0,0,0,,今天的课将开始讨论地图\\N{\\fs12}so I'll be doing the lecture today on maps.\r\nDialogue: 0,0:00:53.33,0:00:55.07,yin,,0,0,0,,但愿我能讲完\\N{\\fs12}Hopefully, I'll get all the way through it.\r\nDialogue: 0,0:00:55.07,0:00:58.04,yin,,0,0,0,,然后周三 我会做一个地图的demo\\N{\\fs12}And then on Wednesday, I will do a demo with the maps,\r\nDialogue: 0,0:00:58.04,0:01:03.46,yin,,0,0,0,,周三我还将演示更多segue 特别是embed segue\\N{\\fs12}and also then on Wednesday, I will demo some more segues, especially the embed segue.\r\nDialogue: 0,0:01:03.48,0:01:05.57,yin,,0,0,0,,这就是我们的安排\\N{\\fs12}So that's what we're talking about today.\r\nDialogue: 0,0:01:05.57,0:01:08.06,yin,,0,0,0,,首先讲一些比较杂的主题\\N{\\fs12}So let's talk about a couple of miscellaneous topics.\r\nDialogue: 0,0:01:08.06,0:01:11.36,yin,,0,0,0,,第一个是UIApplication\\N{\\fs12}So UI application is my first one.\r\nDialogue: 0,0:01:11.36,0:01:12.86,yin,,0,0,0,,什么是UIApplication\\N{\\fs12}What is UI application?\r\nDialogue: 0,0:01:12.86,0:01:14.43,yin,,0,0,0,,听起来很重要\\N{\\fs12}It sounds important.\r\nDialogue: 0,0:01:14.43,0:01:18.37,yin,,0,0,0,,其实并没有那么重要\\N{\\fs12}It's not really that important, we dive right\r\nDialogue: 0,0:01:18.37,0:01:21.73,yin,,0,0,0,,上周我们使用了应用委托\\N{\\fs12}into using the application delegate last week, where we did things like application,\r\nDialogue: 0,0:01:21.73,0:01:24.04,yin,,0,0,0,,包括didFinishLaunchingWithOptions\\N{\\fs12}did finish launching with options and,\r\nDialogue: 0,0:01:24.05,0:01:27.02,yin,,0,0,0,,处理后台进入的URL\\N{\\fs12}you know, handling background URLs coming in,\r\nDialogue: 0,0:01:27.02,0:01:29.20,yin,,0,0,0,,后台取回 等等\\N{\\fs12}and background fetching and all that.\r\nDialogue: 0,0:01:29.20,0:01:30.84,yin,,0,0,0,,这些都是应用委托\\N{\\fs12}That was all in the applications delegate.\r\nDialogue: 0,0:01:30.84,0:01:34.75,yin,,0,0,0,,应用委托实际上是由另一个对象上的属性所设置\\N{\\fs12}So the applications delegate is actually set by a property on another\r\nDialogue: 0,0:01:34.77,0:01:37.05,yin,,0,0,0,,这就是UIApplication\\N{\\fs12}object called UI application.\r\nDialogue: 0,0:01:37.05,0:01:38.77,yin,,0,0,0,,UIApplication这个类\\N{\\fs12}So UI application, this class,\r\nDialogue: 0,0:01:38.77,0:01:41.40,yin,,0,0,0,,在整个应用中只有一个实例\\N{\\fs12}it only has one instance in your entire application.\r\nDialogue: 0,0:01:41.40,0:01:44.97,yin,,0,0,0,,通过这个调用 UIApplication sharedApplication\\N{\\fs12}You get it by calling this UI application shared application,\r\nDialogue: 0,0:01:44.97,0:01:48.11,yin,,0,0,0,,这个里面没有太多有趣的东西\\N{\\fs12}and there's really not a lot of really interesting stuff\r\nDialogue: 0,0:01:48.11,0:01:51.74,yin,,0,0,0,,你可以自己去看说明文档\\N{\\fs12}in this thing, you can go check out the documentation,\r\nDialogue: 0,0:01:51.74,0:01:54.84,yin,,0,0,0,,实际的东西都在应用委托中\\N{\\fs12}but all the real stuff is in applications delegate.\r\nDialogue: 0,0:01:54.84,0:01:57.56,yin,,0,0,0,,应用上有一个属性 叫委托\\N{\\fs12}Alright? So it has a property on your application called delegate,\r\nDialogue: 0,0:01:57.56,0:01:59.31,yin,,0,0,0,,它会自动为你设置\\N{\\fs12}that gets automatically set for you,\r\nDialogue: 0,0:01:59.31,0:02:03.92,yin,,0,0,0,,然后是你的应用委托对象 上周三我们详细看过\\N{\\fs12}and then your application delegate object, which we did a lot in last Wednesday,\r\nDialogue: 0,0:02:03.92,0:02:05.74,yin,,0,0,0,,所有动作都在这里\\N{\\fs12}that's where all the action is.\r\nDialogue: 0,0:02:05.74,0:02:08.93,yin,,0,0,0,,你可以自己去看UIApplication\\N{\\fs12}So you can check out UI application if you want.\r\nDialogue: 0,0:02:08.93,0:02:13.18,yin,,0,0,0,,不过我想指出UIApplication上的一个特定属性\\N{\\fs12}I did want to point out one particular property on UI application, however,\r\nDialogue: 0,0:02:13.18,0:02:16.12,yin,,0,0,0,,也就是networkActivityIndicatorVisible属性\\N{\\fs12}which is the network activity indicator visible property.\r\nDialogue: 0,0:02:16.12,0:02:17.45,yin,,0,0,0,,这是一个布尔型属性\\N{\\fs12}This is a Boolean property.\r\nDialogue: 0,0:02:17.45,0:02:21.72,yin,,0,0,0,,如果设为YES 那么状态栏上的那个小转轮就会转\\N{\\fs12}If you set it to yes, then the little spinner that shows\r\nDialogue: 0,0:02:21.72,0:02:23.57,yin,,0,0,0,,见过吗\\N{\\fs12}up on the status bar, have you ever seen that?\r\nDialogue: 0,0:02:23.57,0:02:27.04,yin,,0,0,0,,进行网络活动时 有个小转轮在转\\N{\\fs12}When you're doing network stuff, there's a little spinner that's spinning,\r\nDialogue: 0,0:02:27.05,0:02:30.98,yin,,0,0,0,,应用是活动应用时 这个会开启\\N{\\fs12}that turns that on when your application is the active application.\r\nDialogue: 0,0:02:30.98,0:02:37.26,yin,,0,0,0,,这个是布尔型的 YES或NO 转轮对应开或关\\N{\\fs12}And this thing, you know, it's Boolean, yes or no, that spinner is either on or it's off,\r\nDialogue: 0,0:02:37.26,0:02:40.41,yin,,0,0,0,,它的开关完全取决于你\\N{\\fs12}it's totally your responsibility to turn this thing on and off.\r\nDialogue: 0,0:02:40.41,0:02:43.35,yin,,0,0,0,,这有点难于处理 因为\\N{\\fs12}It's a little bit difficult to deal with because\r\nDialogue: 0,0:02:43.35,0:02:46.36,yin,,0,0,0,,一 它是全局的 它在UIApplication中\\N{\\fs12}A, it's global, it's in UI application,\r\nDialogue: 0,0:02:46.36,0:02:51.02,yin,,0,0,0,,你的应用中的所有线程都在使用这个转轮\\N{\\fs12}so all the threads in your application are all using this same spinner,\r\nDialogue: 0,0:02:51.02,0:02:56.45,yin,,0,0,0,,二是 它是一个布尔型 而不是压入弹出 或是计数\\N{\\fs12}and number two, it's a Boolean, it's not like a push and pop or a count,\r\nDialogue: 0,0:02:56.46,0:03:01.68,yin,,0,0,0,,假设你开始了一个很大的Flickr取回 需要10秒\\N{\\fs12}and so imagine that you fire off a big Flickr fetch that's going to take ten seconds.\r\nDialogue: 0,0:03:01.68,0:03:02.69,yin,,0,0,0,,你开始app\\N{\\fs12}And you start the app,\r\nDialogue: 0,0:03:02.69,0:03:05.44,yin,,0,0,0,,这个网络活动指示器 打开为YES\\N{\\fs12}this network activity indicator, turn it to yes.\r\nDialogue: 0,0:03:05.44,0:03:08.44,yin,,0,0,0,,然后在另一个线程中 你发起了一个小的Flickr取回\\N{\\fs12}Then, in another thread, you fire off a little Flickr fetch,\r\nDialogue: 0,0:03:08.44,0:03:10.52,yin,,0,0,0,,只需要1秒钟\\N{\\fs12}it's only going to take one second.\r\nDialogue: 0,0:03:10.52,0:03:14.14,yin,,0,0,0,,它发起了 打开了这个 1秒钟过去\\N{\\fs12}So it fires off, it turns this on, one second goes on,\r\nDialogue: 0,0:03:14.14,0:03:16.10,yin,,0,0,0,,它完成了 然后关掉\\N{\\fs12}it finishes, it turns it back off.\r\nDialogue: 0,0:03:16.10,0:03:19.22,yin,,0,0,0,,现在它关掉了 但10秒那个还在运行\\N{\\fs12}Now it's off, but the ten second one is still running.\r\nDialogue: 0,0:03:19.22,0:03:20.93,yin,,0,0,0,,这就糟糕了\\N{\\fs12}So that's bad.\r\nDialogue: 0,0:03:20.93,0:03:26.24,yin,,0,0,0,,很不幸 你需要在app中添加一些机制\\N{\\fs12}So it's totally up to you, unfortunately, to put mechanism in your app for dealing\r\nDialogue: 0,0:03:26.24,0:03:30.20,yin,,0,0,0,,来处理这里API的过分简单化\\N{\\fs12}with that unfortunate simplicity of API.\r\nDialogue: 0,0:03:30.20,0:03:32.66,yin,,0,0,0,,我不确定 不过我猜\\N{\\fs12}I'm sure, I mean, I don't know, but I'm guessing\r\nDialogue: 0,0:03:32.66,0:03:35.93,yin,,0,0,0,,苹果试过在这上面加一些复杂的API\\N{\\fs12}that Apple tried to put more complicated API on top of this,\r\nDialogue: 0,0:03:35.93,0:03:39.26,yin,,0,0,0,,但这并不适用于人们在不同线程\\N{\\fs12}and it just didn't work for all different kinds of ways people,\r\nDialogue: 0,0:03:39.26,0:03:41.46,yin,,0,0,0,,进行各种网络活动的不同需要\\N{\\fs12}you know, are doing network activity in different threads,\r\nDialogue: 0,0:03:41.46,0:03:44.76,yin,,0,0,0,,最后他们只能说 这个还是留给你们自己吧\\N{\\fs12}so they just kind of said, okay we'll give you this and we'll leave it to you.\r\nDialogue: 0,0:03:44.76,0:03:46.62,yin,,0,0,0,,不过 你应该开启这个\\N{\\fs12}But you should turn this on.\r\nDialogue: 0,0:03:46.62,0:03:49.45,yin,,0,0,0,,我不确定苹果会不会因为某个程序没有开启这个\\N{\\fs12}I'm not sure if Apple would reject an application submitted\r\nDialogue: 0,0:03:49.45,0:03:51.02,yin,,0,0,0,,而拒绝它在App商店中的提交\\N{\\fs12}to the App Store that didn't turn this on,\r\nDialogue: 0,0:03:51.02,0:03:52.95,yin,,0,0,0,,不过他们很有可能这么做\\N{\\fs12}and did do network activity, but they might.\r\nDialogue: 0,0:03:53.61,0:03:55.84,yin,,0,0,0,,而且这样做在他们的权利范围之内\\N{\\fs12}And they'd probably be within their rights to doing it.\r\nDialogue: 0,0:03:55.84,0:03:57.21,yin,,0,0,0,,为什么要这个呢\\N{\\fs12}Why do we have this thing?\r\nDialogue: 0,0:03:57.21,0:04:00.25,yin,,0,0,0,,因为很多用户都在使用移动电话\\N{\\fs12}Because a lot of users might be on cellular,\r\nDialogue: 0,0:04:00.25,0:04:02.87,yin,,0,0,0,,他们可能一个月只有300兆流量\\N{\\fs12}and they only have 300 megabytes a month or something,\r\nDialogue: 0,0:04:02.87,0:04:06.04,yin,,0,0,0,,他们希望知道应用什么时候在耗流量\\N{\\fs12}and they want to know when apps are using that up, right?\r\nDialogue: 0,0:04:06.04,0:04:08.14,yin,,0,0,0,,他们希望看到那个旋转\\N{\\fs12}So they want to see that little thing spinning.\r\nDialogue: 0,0:04:08.14,0:04:10.09,yin,,0,0,0,,因此 开启这个非常重要\\N{\\fs12}So that's why it's important to turn this thing on.\r\nDialogue: 0,0:04:10.09,0:04:14.42,yin,,0,0,0,,这是网络活动的转轮 而不是请等待的转轮\\N{\\fs12}Only when you're doing network activity, this is not a spinner for please wait, okay.\r\nDialogue: 0,0:04:14.42,0:04:16.74,yin,,0,0,0,,首先 app不应该总让用户等\\N{\\fs12}Your app first of all should never be doing please wait,\r\nDialogue: 0,0:04:16.74,0:04:18.84,yin,,0,0,0,,因为一切都可以不在主线程上进行\\N{\\fs12}because as we know, we do everything off the main thread,\r\nDialogue: 0,0:04:18.84,0:04:21.78,yin,,0,0,0,,不过这里是告诉用户 网络活动正在发生\\N{\\fs12}but this is just to tell them network activity is happening,\r\nDialogue: 0,0:04:21.78,0:04:23.53,yin,,0,0,0,,哪怕是在app的后台\\N{\\fs12}even in the background in my app.\r\nDialogue: 0,0:04:23.53,0:04:24.26,yin,,0,0,0,,有问题\\N{\\fs12}Question back there?\r\nDialogue: 0,0:04:30.46,0:04:33.40,yin,,0,0,0,,问题是iOS难道不能知道\\N{\\fs12}Yeah, so the question is can't iOS know\r\nDialogue: 0,0:04:33.40,0:04:36.81,yin,,0,0,0,,我的app在进行网络活动 然后为我开启吗\\N{\\fs12}that I'm doing network activity in my app and turn it on for me?\r\nDialogue: 0,0:04:36.81,0:04:39.85,yin,,0,0,0,,答案它大多数时候都能知道\\N{\\fs12}And the answer is, I'll be it could figure it out most of the time,\r\nDialogue: 0,0:04:39.85,0:04:41.53,yin,,0,0,0,,但并非100%的时候\\N{\\fs12}but not 100 percent of the time,\r\nDialogue: 0,0:04:41.53,0:04:43.03,yin,,0,0,0,,因为你在网络活动时\\N{\\fs12}because when you do a network activity,\r\nDialogue: 0,0:04:43.03,0:04:46.23,yin,,0,0,0,,你会发起什么东西 或许是URLSession\\N{\\fs12}you fire something off, maybe you're doing that URL session,\r\nDialogue: 0,0:04:46.23,0:04:49.09,yin,,0,0,0,,等等 如果是URLSession\\N{\\fs12}things like that, I think if you do the URL session\r\nDialogue: 0,0:04:49.09,0:04:52.85,yin,,0,0,0,,这个发生时 iOS应该会开启它\\N{\\fs12}where it's actually happening I bet they do turn it on, or they might.\r\nDialogue: 0,0:04:52.85,0:04:54.13,yin,,0,0,0,,具体我不知道\\N{\\fs12}I really don't know what they do,\r\nDialogue: 0,0:04:54.13,0:04:57.03,yin,,0,0,0,,不过可以肯定的是 这不是100%可靠的\\N{\\fs12}but then the bottom line is they can't reliably 100 percent do\r\nDialogue: 0,0:04:57.03,0:04:59.17,yin,,0,0,0,,因此他们要求你来做\\N{\\fs12}it, so they're asking you, you can do it here.\r\nDialogue: 0,0:04:59.70,0:05:02.31,yin,,0,0,0,,据我所知 情况就是这样的\\N{\\fs12}This is the best to my knowledge, that's the answer.\r\nDialogue: 0,0:05:03.04,0:05:04.91,yin,,0,0,0,,以上只是一些离题的话\\N{\\fs12}Um, okay so that was just a little aside.\r\nDialogue: 0,0:05:04.91,0:05:08.84,yin,,0,0,0,,下面 我们将接着上周三的demo来\\N{\\fs12}So now, a little follow up on our demo that we did last Wednesday.\r\nDialogue: 0,0:05:08.84,0:05:12.04,yin,,0,0,0,,有两点我要澄清 我也确实澄清了\\N{\\fs12}Two things that I want to clarify and that I did clarify\r\nDialogue: 0,0:05:12.04,0:05:15.30,yin,,0,0,0,,下载了已发布代码 读了评论的人知道\\N{\\fs12}if you downloaded the posted code and read the comments,\r\nDialogue: 0,0:05:15.30,0:05:17.55,yin,,0,0,0,,一点是 有时我在demo中途\\N{\\fs12}one is, as I was going through my demo,\r\nDialogue: 0,0:05:17.55,0:05:20.99,yin,,0,0,0,,忘记了一些东西 例如我忘了这一段代码\\N{\\fs12}sometimes I forget things, and I did forget this one line of code,\r\nDialogue: 0,0:05:20.99,0:05:24.63,yin,,0,0,0,,也就是如果你想让这些后台取回发生\\N{\\fs12}which is you have to send a message if you want to get these background\r\nDialogue: 0,0:05:24.65,0:05:28.41,yin,,0,0,0,,你就需要发送一条消息给你的共享应用\\N{\\fs12}fetches to happen, to your shared application,\r\nDialogue: 0,0:05:28.41,0:05:31.96,yin,,0,0,0,,消息叫作setMinimumBackgroundFetchInterval\\N{\\fs12}you shared your application called set minimum background fetch interval.\r\nDialogue: 0,0:05:31.96,0:05:34.39,yin,,0,0,0,,这个区间是NSTimeInterval\\N{\\fs12}So that interval, and it's NS time interval,\r\nDialogue: 0,0:05:34.39,0:05:35.92,yin,,0,0,0,,以秒数计\\N{\\fs12}it's the number of seconds\r\nDialogue: 0,0:05:35.92,0:05:42.06,yin,,0,0,0,,是iOS给你机会进行后台取回的最小时间间隔\\N{\\fs12}that is the minimum between the times that iOS will send you the opportunity\r\nDialogue: 0,0:05:42.06,0:05:43.47,yin,,0,0,0,,是iOS给你机会进行后台取回的最小时间间隔\\N{\\fs12}to do a background fetch, right?\r\nDialogue: 0,0:05:43.47,0:05:44.86,yin,,0,0,0,,这时你在后台\\N{\\fs12}So you're in the background, remember,\r\nDialogue: 0,0:05:44.86,0:05:47.36,yin,,0,0,0,,iOS会发个消息给你说 嘿 醒醒\\N{\\fs12}the iOS can send you a thing, it says \"Hey, wake up,\r\nDialogue: 0,0:05:47.36,0:05:50.96,yin,,0,0,0,,你现在可以进行后台取回 而这里是最小值\\N{\\fs12}you can do a background fetch if you want,\" and this says the minimum.\r\nDialogue: 0,0:05:50.96,0:05:55.28,yin,,0,0,0,,这个最小值 你甚至可以设为1秒 每秒都唤醒\\N{\\fs12}Now, this minimum, you can't set it to one second, it's going to wake you up every second\r\nDialogue: 0,0:05:55.28,0:05:58.33,yin,,0,0,0,,因为有一个UIApplicationBackgroundFetchIntervalMinimum\\N{\\fs12}because there's a UI application background fetch interval\r\nDialogue: 0,0:05:58.33,0:06:01.00,yin,,0,0,0,,这就是你可以设置的最小值\\N{\\fs12}minimum and that's the minimum you can set it to,\r\nDialogue: 0,0:06:01.00,0:06:03.38,yin,,0,0,0,,如果设置为这个\\N{\\fs12}and so if you want to set it to that,\r\nDialogue: 0,0:06:03.38,0:06:07.83,yin,,0,0,0,,系统就会尽可能多地将你唤醒\\N{\\fs12}then you'll get woken up as much as the system is willing to wake you up,\r\nDialogue: 0,0:06:07.83,0:06:09.77,yin,,0,0,0,,记住 这只是最小值\\N{\\fs12}remember that only the minimum.\r\nDialogue: 0,0:06:09.77,0:06:13.38,yin,,0,0,0,,唤醒你可能会需要更久 取决于发生了什么\\N{\\fs12}It could take much longer to wake you up, depending on what's happening.\r\nDialogue: 0,0:06:13.38,0:06:14.99,yin,,0,0,0,,关于这些后台取回有一点要讲\\N{\\fs12}One thing about these background fetches,\r\nDialogue: 0,0:06:14.99,0:06:18.62,yin,,0,0,0,,系统在何时唤醒你进行后台取回方面非常聪明\\N{\\fs12}the system is quite smart about when it wakes you up to do a background fetch,\r\nDialogue: 0,0:06:18.62,0:06:21.31,yin,,0,0,0,,它可能也会唤醒其它一些程序 进行后台取回\\N{\\fs12}it's probably waking up a whole bunch of other apps doing background fetches too,\r\nDialogue: 0,0:06:21.31,0:06:23.67,yin,,0,0,0,,一次性做所有这些事 因为\\N{\\fs12}and doing it all at one time because all\r\nDialogue: 0,0:06:23.67,0:06:27.95,yin,,0,0,0,,iOS中的所有这些多任务处理 都是为了节约电量\\N{\\fs12}of this multi-tasking in iOS is all about saving the battery.\r\nDialogue: 0,0:06:27.95,0:06:29.82,yin,,0,0,0,,为什么 也许你会问\\N{\\fs12}Why, you might ask?\r\nDialogue: 0,0:06:29.82,0:06:31.99,yin,,0,0,0,,屏幕上不能同时有四个app吗\\N{\\fs12}Can't I have four apps on the screen at the same time?\r\nDialogue: 0,0:06:31.99,0:06:33.55,yin,,0,0,0,,这会需要很多处理器\\N{\\fs12}Well that would be a lot of processor,\r\nDialogue: 0,0:06:33.55,0:06:36.30,yin,,0,0,0,,很多网络活动 很多电量消耗\\N{\\fs12}a lot of network activity, a lot of battery drain.\r\nDialogue: 0,0:06:36.30,0:06:38.52,yin,,0,0,0,,因此 当应用在后台时\\N{\\fs12}And so when an application is in the background\r\nDialogue: 0,0:06:38.52,0:06:42.45,yin,,0,0,0,,它没在运行 我们希望它消耗的电量最小\\N{\\fs12}and it's not running, we want minimum battery drain going on,\r\nDialogue: 0,0:06:42.45,0:06:43.85,yin,,0,0,0,,如果要唤醒它\\N{\\fs12}so if it's going to wake,\r\nDialogue: 0,0:06:43.85,0:06:46.83,yin,,0,0,0,,很多时候电量消耗都不是来自于你的app\\N{\\fs12}and a lot of the battery drain is not necessarily what your app is doing,\r\nDialogue: 0,0:06:46.83,0:06:50.64,yin,,0,0,0,,而只是手机或iPad醒着的状态\\N{\\fs12}it's just the fact that the phone or the iPad is awake, right?\r\nDialogue: 0,0:06:50.64,0:06:52.95,yin,,0,0,0,,它在运行 OS在运行\\N{\\fs12}It's up and running, it's OS is running.\r\nDialogue: 0,0:06:52.95,0:06:56.58,yin,,0,0,0,,不过大多数时候 手机或iPad不用时都处于睡眠状态\\N{\\fs12}So mostly the phone and iPad are sleeping when you're not using it.\r\nDialogue: 0,0:06:56.58,0:06:58.02,yin,,0,0,0,,你希望它保持这样\\N{\\fs12}So you want it to stay that way.\r\nDialogue: 0,0:06:58.02,0:06:59.85,yin,,0,0,0,,如果你要把它唤醒\\N{\\fs12}So if you are going to wake it up from sleep\r\nDialogue: 0,0:06:59.85,0:07:02.42,yin,,0,0,0,,开始消耗电量 你需要让尽量多的app\\N{\\fs12}and start using battery, you want to get as many apps going\r\nDialogue: 0,0:07:02.42,0:07:04.64,yin,,0,0,0,,同时进行后台取回这些操作\\N{\\fs12}with their background fetches and all at once.\r\nDialogue: 0,0:07:04.64,0:07:08.59,yin,,0,0,0,,而且 还有很多电量消耗很多的东西 例如无线电天线\\N{\\fs12}Plus, there's a lot of very battery intensive things like the radio antennas, right?\r\nDialogue: 0,0:07:08.59,0:07:12.01,yin,,0,0,0,,wifi 电话功能 这些会消耗电量\\N{\\fs12}The wi-fi and the cellular, those things use power.\r\nDialogue: 0,0:07:12.01,0:07:14.01,yin,,0,0,0,,因此 如果你要进行后台取回\\N{\\fs12}So if you're going to do a background fetch,\r\nDialogue: 0,0:07:14.01,0:07:17.10,yin,,0,0,0,,这有可能会用到wifi 这会消耗电量\\N{\\fs12}you're probably going to fire up the wi-fi, that's going to use power,\r\nDialogue: 0,0:07:17.11,0:07:20.42,yin,,0,0,0,,这时最好是让所有需要后台取回的人都一起取回了\\N{\\fs12}we'd better get everybody who wants to do a background fetch doing it all at once.\r\nDialogue: 0,0:07:20.42,0:07:21.86,yin,,0,0,0,,这只是一个最小值\\N{\\fs12}So this is just a minimum.\r\nDialogue: 0,0:07:21.86,0:07:24.45,yin,,0,0,0,,提到这个的原因在于\\N{\\fs12}Now, the reason I'm mentioning this is\r\nDialogue: 0,0:07:24.45,0:07:25.78,yin,,0,0,0,,默认值是\\N{\\fs12}because the default is\r\nDialogue: 0,0:07:25.78,0:07:29.53,yin,,0,0,0,,UIApplicationBackgroundFetchIntervalNever\\N{\\fs12}UIApplicationBackgroundFetchIntervalNever\r\nDialogue: 0,0:07:29.53,0:07:32.03,yin,,0,0,0,,也就是说从不进行后台取回\\N{\\fs12}which means you'll never get background fetch,\r\nDialogue: 0,0:07:32.03,0:07:33.88,yin,,0,0,0,,因此 这个肯定需要调用\\N{\\fs12}so you definitely need to call this.\r\nDialogue: 0,0:07:33.88,0:07:35.11,yin,,0,0,0,,注意 这还意味着\\N{\\fs12}It also, notice, means\r\nDialogue: 0,0:07:35.12,0:07:37.40,yin,,0,0,0,,用户至少需要运行一次你的应用\\N{\\fs12}you have to run your application at least once.\r\nDialogue: 0,0:07:37.40,0:07:39.15,yin,,0,0,0,,用户至少需要运行一次你的应用\\N{\\fs12}Your user has to run your application at least once,\r\nDialogue: 0,0:07:39.15,0:07:42.63,yin,,0,0,0,,如果你想要后台取回发生 这个需要被调用\\N{\\fs12}and this gets called if you want background fetching to happen.\r\nDialogue: 0,0:07:42.63,0:07:45.69,yin,,0,0,0,,调用了这个后 系统知道你要做这个\\N{\\fs12}Once you've called this, system knows you want to do that,\r\nDialogue: 0,0:07:45.69,0:07:50.35,yin,,0,0,0,,你到后台之后 然后是启动\\N{\\fs12}you know, once you go to the background, then after that, the launch,\r\nDialogue: 0,0:07:50.35,0:07:52.75,yin,,0,0,0,,然后它就不只是唤醒你\\N{\\fs12}then it will not only wake you up,\r\nDialogue: 0,0:07:52.75,0:07:54.97,yin,,0,0,0,,如果你退出或是崩溃\\N{\\fs12}but if you were to exit or crash,\r\nDialogue: 0,0:07:54.97,0:08:00.73,yin,,0,0,0,,只要是进入了后台取回的世界 它还会重新开启你\\N{\\fs12}it will fire you back up once it kind of gets you into the background fetch world.\r\nDialogue: 0,0:08:00.73,0:08:03.77,yin,,0,0,0,,用户不大喜欢应用在后台运行\\N{\\fs12}Users might find that they don't like your application running\r\nDialogue: 0,0:08:03.77,0:08:05.78,yin,,0,0,0,,因为这会用掉很多资源\\N{\\fs12}in the background because you use a lot of resources,\r\nDialogue: 0,0:08:05.78,0:08:09.04,yin,,0,0,0,,让你在后台取回 电量会被消耗\\N{\\fs12}their battery gets drained when they let you fetch\r\nDialogue: 0,0:08:09.04,0:08:11.90,yin,,0,0,0,,或许你是一个很糟糕的后台公民\\N{\\fs12}in the background, because you're a bad background citizen, maybe.\r\nDialogue: 0,0:08:11.90,0:08:17.68,yin,,0,0,0,,他们可以到设置里 把处于后台的你关闭掉\\N{\\fs12}They can actually go into settings and turn you off when it comes to background.\r\nDialogue: 0,0:08:17.68,0:08:21.22,yin,,0,0,0,,有一个选项会说 不要让Photomania\\N{\\fs12}Okay, there's actually a switch, it says \"don't let Photo Mania\r\nDialogue: 0,0:08:21.22,0:08:24.17,yin,,0,0,0,,或Shutterbug在后台取回\\N{\\fs12}or Shutterbug fetch in the background.\" Don't do it.\r\nDialogue: 0,0:08:24.17,0:08:26.44,yin,,0,0,0,,把这个设置为关闭 后台取回就做不到了\\N{\\fs12}And if you set that off, then you won't be able to do it.\r\nDialogue: 0,0:08:26.44,0:08:30.05,yin,,0,0,0,,你可以通过这个属性看用户有没这样做\\N{\\fs12}And you can find out if the user has done that, using this property\r\nDialogue: 0,0:08:30.05,0:08:33.02,yin,,0,0,0,,在UIApplication中 它叫BackgroundRefreshStatus\\N{\\fs12}in UI application called background refresh status,\r\nDialogue: 0,0:08:33.02,0:08:34.67,yin,,0,0,0,,它会返回刷新状态\\N{\\fs12}and it will return the refresh status.\r\nDialogue: 0,0:08:34.67,0:08:36.06,yin,,0,0,0,,状态有三种\\N{\\fs12}It actually has three different states.\r\nDialogue: 0,0:08:36.06,0:08:38.16,yin,,0,0,0,,一个一切良好\\N{\\fs12}One can be you're good to go,\r\nDialogue: 0,0:08:38.16,0:08:42.50,yin,,0,0,0,,二是用户关了你 三是受限\\N{\\fs12}two can be the user turned you off, third can be restricted.\r\nDialogue: 0,0:08:42.50,0:08:45.13,yin,,0,0,0,,受限是什么 这在很多东西里面都有\\N{\\fs12}What restricted means, and you're going to see this in various things.\r\nDialogue: 0,0:08:45.13,0:08:46.77,yin,,0,0,0,,例如在地图里面就有\\N{\\fs12}You'll see this with the map stuff,\r\nDialogue: 0,0:08:46.77,0:08:52.10,yin,,0,0,0,,受限是说 你不能这样做 它被关了 但不是用户关的\\N{\\fs12}restricted means you can't do it, it's off, but your user didn't turn it off,\r\nDialogue: 0,0:08:52.10,0:08:54.86,yin,,0,0,0,,他们也不能把它打开\\N{\\fs12}and they can't turn it back on.\r\nDialogue: 0,0:08:54.86,0:08:57.08,yin,,0,0,0,,因为这在某方面受限了\\N{\\fs12}Because they're restricted in some way.\r\nDialogue: 0,0:08:57.08,0:08:58.32,yin,,0,0,0,,为什么会这样呢\\N{\\fs12}How would this happen?\r\nDialogue: 0,0:08:58.32,0:09:00.64,yin,,0,0,0,,例如家长控制\\N{\\fs12}Parental controls, for example.\r\nDialogue: 0,0:09:00.64,0:09:05.57,yin,,0,0,0,,在家长控制中 某个程序很有可能不被允许\\N{\\fs12}It's possible in parental controls to make it so this app is not allowed to run\r\nDialogue: 0,0:09:05.57,0:09:08.05,yin,,0,0,0,,在后台模式下运行\\N{\\fs12}in background mode in parental controls.\r\nDialogue: 0,0:09:08.05,0:09:09.35,yin,,0,0,0,,再例如企业环境\\N{\\fs12}Corporate environment.\r\nDialogue: 0,0:09:09.35,0:09:12.69,yin,,0,0,0,,一个企业有可能不允许程序运行在后台\\N{\\fs12}A corporation might not want to allow a certain app to run in the background\r\nDialogue: 0,0:09:12.70,0:09:14.44,yin,,0,0,0,,因为取回的内容或是别的什么\\N{\\fs12}because of what it fetches or whatever.\r\nDialogue: 0,0:09:14.44,0:09:17.36,yin,,0,0,0,,你需要检查所有这三种状态\\N{\\fs12}So you've got to check all three of those states,\r\nDialogue: 0,0:09:17.36,0:09:20.15,yin,,0,0,0,,如果它处在受限状态 而不只是这个\\N{\\fs12}and if it's in that restricted state, not just this thing,\r\nDialogue: 0,0:09:20.15,0:09:23.45,yin,,0,0,0,,如果它处在受限状态 你不要给用户说\\N{\\fs12}but anything that's in a restricted state like that, you don't want to say to the user,\r\nDialogue: 0,0:09:23.45,0:09:25.05,yin,,0,0,0,,我想后台取回\\N{\\fs12}\"I want to do background fetches,\r\nDialogue: 0,0:09:25.05,0:09:26.29,yin,,0,0,0,,但你没有开启\\N{\\fs12}but you haven't turned me on,\"\r\nDialogue: 0,0:09:26.29,0:09:28.03,yin,,0,0,0,,因为这时他们根本没能力打开\\N{\\fs12}because then they won't be able to go turn you on,\r\nDialogue: 0,0:09:28.03,0:09:30.92,yin,,0,0,0,,他们会说 什么 他们会很困惑\\N{\\fs12}and they'll be like, \"What?\" Okay, they'll be confused, so\r\nDialogue: 0,0:09:30.92,0:09:34.90,yin,,0,0,0,,我只是想借这个机会讲讲这三种状态\\N{\\fs12}I just want to make-- this is a good opportunity to talk about those three states.\r\nDialogue: 0,0:09:34.90,0:09:37.55,yin,,0,0,0,,一是开启 一是用户关闭\\N{\\fs12}Okay, it's on, it got turned off by the user,\r\nDialogue: 0,0:09:37.55,0:09:40.36,yin,,0,0,0,,一是受限 意思是你无法开启它\\N{\\fs12}and it's restricted, meaning it can't be turned on.\r\nDialogue: 0,0:09:40.36,0:09:41.14,yin,,0,0,0,,有问题\\N{\\fs12}Go ahead. Question.\r\nDialogue: 0,0:09:46.26,0:09:49.34,yin,,0,0,0,,问题是 如果我想在后台做点取回外的别的什么呢\\N{\\fs12}So the question is what if I want to do something in the background, but not a fetch?\r\nDialogue: 0,0:09:49.34,0:09:50.63,yin,,0,0,0,,答案是 你可以这样做\\N{\\fs12}And the answer is, you can do that.\r\nDialogue: 0,0:09:50.63,0:09:53.70,yin,,0,0,0,,这个后台取回机制并没说你只能取回\\N{\\fs12}This background fetch mechanism doesn't mean you can only fetch\r\nDialogue: 0,0:09:53.70,0:09:55.39,yin,,0,0,0,,你可以在网络上做别的事\\N{\\fs12}on the network, you can do other things.\r\nDialogue: 0,0:09:55.39,0:09:57.44,yin,,0,0,0,,不过它叫作后台取回\\N{\\fs12}But it's called background fetch and all that, I think,\r\nDialogue: 0,0:09:57.44,0:10:00.52,yin,,0,0,0,,苹果这样做是有原因的 他们可能想说\\N{\\fs12}for a reason by Apple, is that they're kind of implying\r\nDialogue: 0,0:10:00.52,0:10:02.80,yin,,0,0,0,,这就是我们希望你用这个做的事\\N{\\fs12}\"this is kind of what we imagine you're doing with this,\"\r\nDialogue: 0,0:10:02.80,0:10:05.75,yin,,0,0,0,,他们可能不希望你把程序唤醒\\N{\\fs12}so they don't really want you to wake up and then just use a lot\r\nDialogue: 0,0:10:05.75,0:10:08.38,yin,,0,0,0,,使用很多资源做别的事\\N{\\fs12}of resources somehow doing something else,\r\nDialogue: 0,0:10:08.38,0:10:10.29,yin,,0,0,0,,不过做别的事也是允许的\\N{\\fs12}but you are allowed to do something else.\r\nDialogue: 0,0:10:10.29,0:10:11.52,yin,,0,0,0,,没有一条规则说\\N{\\fs12}There's no law that says\r\nDialogue: 0,0:10:11.52,0:10:13.22,yin,,0,0,0,,后台取回被调用时\\N{\\fs12}when the background fetch is called you couldn't make some\r\nDialogue: 0,0:10:13.22,0:10:16.84,yin,,0,0,0,,你不能进行任何数学运算 或是别的什么\\N{\\fs12}mathematical calculation or something like that.\r\nDialogue: 0,0:10:16.84,0:10:19.78,yin,,0,0,0,,想想 有什么需要进行数学计算的\\N{\\fs12}As you can imagine, what really would you be calculating mathematically?\r\nDialogue: 0,0:10:19.78,0:10:21.35,yin,,0,0,0,,从后台被唤醒后\\N{\\fs12}Kind of, when you wake up in the background it's kind\r\nDialogue: 0,0:10:21.35,0:10:23.59,yin,,0,0,0,,你会希望检查正在发生什么\\N{\\fs12}of like you want to check what's going on in the world.\r\nDialogue: 0,0:10:23.59,0:10:25.56,yin,,0,0,0,,我们会讲到如何检查诸如\\N{\\fs12}And we're going to talk about checking things like\r\nDialogue: 0,0:10:25.56,0:10:27.03,yin,,0,0,0,,我在哪\\N{\\fs12}\"where am I in the world?\"\r\nDialogue: 0,0:10:27.03,0:10:28.03,yin,,0,0,0,,这是另一码事\\N{\\fs12}That's a different thing.\r\nDialogue: 0,0:10:28.03,0:10:30.95,yin,,0,0,0,,这方面有另一个机制 我会讲到这个\\N{\\fs12}There's another mechanism for that, and we're going to talk about that.\r\nDialogue: 0,0:10:30.95,0:10:31.59,yin,,0,0,0,,有问题\\N{\\fs12}Yeah. Question?\r\nDialogue: 0,0:10:37.65,0:10:43.67,yin,,0,0,0,,问题是 Facebook或是其它社交媒体app\\N{\\fs12}So the question is, is this what, you know, Facebook or some social media app,\r\nDialogue: 0,0:10:43.67,0:10:46.09,yin,,0,0,0,,在有人发你消息时\\N{\\fs12}that you know people are sending you messages,\r\nDialogue: 0,0:10:46.09,0:10:49.67,yin,,0,0,0,,是否就是用这个在说 有人给你发了消息\\N{\\fs12}is this what it's using to say \"someone sent you a message,\"\r\nDialogue: 0,0:10:50.61,0:10:53.77,yin,,0,0,0,,那个小通知行 答案是 不是用的这个\\N{\\fs12}Yeah, the little notification line, and the answer is no, this is not what it's doing.\r\nDialogue: 0,0:10:53.77,0:10:56.83,yin,,0,0,0,,那是另外一个机制 叫推送通知\\N{\\fs12}There's another mechanism for that called push notifications,\r\nDialogue: 0,0:10:56.83,0:10:59.25,yin,,0,0,0,,很不幸 我们可能不会讲到这个\\N{\\fs12}which we're probably not going to get to talk about, unfortunately.\r\nDialogue: 0,0:10:59.25,0:11:01.16,yin,,0,0,0,,这就是他们的做法\\N{\\fs12}So that's how they're doing it.\r\nDialogue: 0,0:11:01.16,0:11:05.25,yin,,0,0,0,,有一种方式能让app的用户\\N{\\fs12}There is a way to basically have a user of an app sign up\r\nDialogue: 0,0:11:05.25,0:11:07.80,yin,,0,0,0,,在服务器某处同意说\\N{\\fs12}and say, with the server somewhere, saying \"hey,\r\nDialogue: 0,0:11:07.80,0:11:10.48,yin,,0,0,0,,我愿意接受Facebook的推送通知\\N{\\fs12}I'm willing to accept push notifications from Facebook,\"\r\nDialogue: 0,0:11:10.48,0:11:14.03,yin,,0,0,0,,然后Facebook服务器就能发送通知\\N{\\fs12}and then the Facebook server can send notifications,\r\nDialogue: 0,0:11:14.03,0:11:17.51,yin,,0,0,0,,一个很小的JSON数据包 给手机说\\N{\\fs12}little tiny JSON packets, basically, to the phone saying\r\nDialogue: 0,0:11:17.51,0:11:19.50,yin,,0,0,0,,这里有条消息\\N{\\fs12}\"Oh, here's a message\" or something like that,\r\nDialogue: 0,0:11:19.50,0:11:23.40,yin,,0,0,0,,消息可以是这个人获得了一条消息\\N{\\fs12}and the message might be this guy's got a message.\r\nDialogue: 0,0:11:23.40,0:11:26.43,yin,,0,0,0,,你获得这些时 后台就有办法唤醒\\N{\\fs12}When you get those, there's a way to get woken up in the background.\r\nDialogue: 0,0:11:26.43,0:11:28.65,yin,,0,0,0,,这是后台唤醒的另外一种机制\\N{\\fs12}So it's a different mechanism for waking up in the background.\r\nDialogue: 0,0:11:28.65,0:11:33.43,yin,,0,0,0,,不过 如果你在Reddit或Facebook上\\N{\\fs12}However, if you're doing something, let's say you're in Reddit or in Facebook,\r\nDialogue: 0,0:11:33.43,0:11:36.40,yin,,0,0,0,,你的页面放到上面\\N{\\fs12}and you have your little page up,\r\nDialogue: 0,0:11:36.40,0:11:38.91,yin,,0,0,0,,上次你访问Facebook 你想要它更新\\N{\\fs12}the last time you were in Facebook and you want that to update.\r\nDialogue: 0,0:11:38.91,0:11:40.65,yin,,0,0,0,,没人发送消息给你\\N{\\fs12}No one is sending you a message, per se,\r\nDialogue: 0,0:11:40.65,0:11:42.78,yin,,0,0,0,,没有Facebook消息\\N{\\fs12}like not a Facebook messaging thing, but it's just\r\nDialogue: 0,0:11:42.78,0:11:45.08,yin,,0,0,0,,只是人们在发自己的东西\\N{\\fs12}like people are posting on their wall, you're watching\r\nDialogue: 0,0:11:45.08,0:11:47.79,yin,,0,0,0,,你在看发生了什么\\N{\\fs12}or whatever is going on, and you want that to,\r\nDialogue: 0,0:11:47.79,0:11:51.55,yin,,0,0,0,,你到app切换器中时 希望看到发生了什么\\N{\\fs12}when you go to the app switcher, you want to see kind of what's happening there.\r\nDialogue: 0,0:11:51.55,0:11:55.26,yin,,0,0,0,,不是实时的 不过是… 这就是这个很好用的地方\\N{\\fs12}Not in real time, but kind of like...you know, that's what this would be great for.\r\nDialogue: 0,0:11:55.26,0:11:59.42,yin,,0,0,0,,在背景中唤醒 取回页面当前内容\\N{\\fs12}So wake up in the background, fetch the current contents of the page,\r\nDialogue: 0,0:11:59.42,0:12:01.63,yin,,0,0,0,,更新 这时有人看app切换器\\N{\\fs12}update it, now if someone looks in app switcher,\r\nDialogue: 0,0:12:01.63,0:12:05.37,yin,,0,0,0,,就能很快看到 哦 这里有新东西 他们可以点开看\\N{\\fs12}they can quickly see \"Oh, I've got new stuff there!\" and they can go click and look.\r\nDialogue: 0,0:12:05.37,0:12:07.76,yin,,0,0,0,,明白了吗 这是不同类型的东西\\N{\\fs12}You see? So it's different kinds of things,\r\nDialogue: 0,0:12:07.76,0:12:09.93,yin,,0,0,0,,发送消息后的通知\\N{\\fs12}but sending a message and notification,\r\nDialogue: 0,0:12:09.93,0:12:12.97,yin,,0,0,0,,是推送通知 这是我们不打算讲的\\N{\\fs12}that's push notifications, which we're not going to talk about.\r\nDialogue: 0,0:12:12.97,0:12:14.97,yin,,0,0,0,,问得很好\\N{\\fs12}Good question though.\r\nDialogue: 0,0:12:14.97,0:12:18.48,yin,,0,0,0,,好 关于demo还有一点要讲明\\N{\\fs12}Okay one other follow up from that demo is,\r\nDialogue: 0,0:12:18.48,0:12:20.98,yin,,0,0,0,,我用了一个小的demo工具\\N{\\fs12}I kind of use a little demo ware in that,\r\nDialogue: 0,0:12:20.98,0:12:25.18,yin,,0,0,0,,在我们有机会进行后台取回时我用了它\\N{\\fs12}when we got the background fetch, when we got a chance to do a background fetch,\r\nDialogue: 0,0:12:25.18,0:12:27.58,yin,,0,0,0,,我把它叫作startFLickrFetch\\N{\\fs12}I called start FLickr fetch, okay,\r\nDialogue: 0,0:12:27.58,0:12:29.55,yin,,0,0,0,,为了让这里只有一行\\N{\\fs12}just to make it a one-liner there,\r\nDialogue: 0,0:12:29.55,0:12:32.41,yin,,0,0,0,,我做的是很概念性的东西 也就是\\N{\\fs12}that was almost a conceptual thing I was doing, just to kind\r\nDialogue: 0,0:12:32.41,0:12:34.98,yin,,0,0,0,,好 我们有机会取回 让我们取回吧\\N{\\fs12}of say \"Okay, we can have a chance to do a fetch, let's do it.\"\r\nDialogue: 0,0:12:34.98,0:12:37.90,yin,,0,0,0,,但实际上 调用startFLickrFetch并不好\\N{\\fs12}But actually calling start FLickr fetch there would not be\r\nDialogue: 0,0:12:37.90,0:12:40.22,yin,,0,0,0,,甚至有可能无法工作\\N{\\fs12}good, and probably would not work.\r\nDialogue: 0,0:12:40.22,0:12:41.35,yin,,0,0,0,,为什么呢\\N{\\fs12}And why was that?\r\nDialogue: 0,0:12:41.35,0:12:43.25,yin,,0,0,0,,这是因为startFLickrFetch\\N{\\fs12}That's because start FLickr fetch\r\nDialogue: 0,0:12:43.25,0:12:46.63,yin,,0,0,0,,开始了一个后台URLSession\\N{\\fs12}starts a background session, URL session.\r\nDialogue: 0,0:12:46.63,0:12:49.20,yin,,0,0,0,,后台session是说 这是一个URLSession\\N{\\fs12}Background session meaning it's the kind of URL session\r\nDialogue: 0,0:12:49.20,0:12:54.25,yin,,0,0,0,,如果URL返回 而你没在运行 你将有机会处理它\\N{\\fs12}that if the URL comes back and you're not running, you get a chance to handle it.\r\nDialogue: 0,0:12:54.25,0:12:58.81,yin,,0,0,0,,那整个处理URL后台session 我们看过的\\N{\\fs12}Right? That whole handle URL background session other one we looked at.\r\nDialogue: 0,0:12:58.81,0:13:03.15,yin,,0,0,0,,这些后台URLSession取回都是自由裁量的\\N{\\fs12}Those kind of background session URL fetches are discretionary.\r\nDialogue: 0,0:13:03.15,0:13:05.94,yin,,0,0,0,,也就是说系统可以决定\\N{\\fs12}Meaning that the system can determine, can decide,\r\nDialogue: 0,0:13:05.94,0:13:08.57,yin,,0,0,0,,如果你在后台 我不打算进行取回\\N{\\fs12}if you're in the background, I'm not even going to do that fetch.\r\nDialogue: 0,0:13:08.57,0:13:12.01,yin,,0,0,0,,这些取回 你通常是在前台发送\\N{\\fs12}So those are fetches that generally you issue them in the foreground,\r\nDialogue: 0,0:13:12.01,0:13:14.47,yin,,0,0,0,,它们可能在后台完成\\N{\\fs12}they might complete in the background.\r\nDialogue: 0,0:13:14.47,0:13:16.83,yin,,0,0,0,,当你有机会取回时\\N{\\fs12}When you get a chance to fetch.\r\nDialogue: 0,0:13:16.83,0:13:17.92,yin,,0,0,0,,因为这个fetch东西\\N{\\fs12}Because of this fetch thing?\r\nDialogue: 0,0:13:17.92,0:13:21.16,yin,,0,0,0,,你希望就在那里进行取回 使用临时session\\N{\\fs12}You want to do that fetch right there, using ephemeral session\r\nDialogue: 0,0:13:21.16,0:13:24.06,yin,,0,0,0,,就像我们在Shutterbug很多其它地方做的那样\\N{\\fs12}like we did everywhere else in Shutterbug and stuff,\r\nDialogue: 0,0:13:24.06,0:13:25.98,yin,,0,0,0,,临时的常规session\\N{\\fs12}ephemeral normal session.\r\nDialogue: 0,0:13:25.98,0:13:27.01,yin,,0,0,0,,而不是后台session\\N{\\fs12}Not a background session.\r\nDialogue: 0,0:13:27.01,0:13:30.49,yin,,0,0,0,,这样就不是自由裁量的了 它会实际进行取回\\N{\\fs12}That way, it won't be discretionary and it will actually do the fetch.\r\nDialogue: 0,0:13:30.49,0:13:32.93,yin,,0,0,0,,通过发送这个消息给你 系统在说\\N{\\fs12}And since the system is saying, by sending you this message,\r\nDialogue: 0,0:13:32.93,0:13:34.21,yin,,0,0,0,,好 现在该你取回了\\N{\\fs12}\"Okay it's your turn to do a fetch,\r\nDialogue: 0,0:13:34.21,0:13:36.06,yin,,0,0,0,,我开启了所有的广播\\N{\\fs12}I've fired up all the radios,\r\nDialogue: 0,0:13:36.06,0:13:39.00,yin,,0,0,0,,我准备好进行一些网络活动 开始做吧\\N{\\fs12}I'm ready to do some network activity, go ahead and do it.\"\r\nDialogue: 0,0:13:39.00,0:13:43.94,yin,,0,0,0,,我上次课后发布的代码做了正确的事\\N{\\fs12}So the code that I posted after lecture last time is doing the right thing,\r\nDialogue: 0,0:13:43.94,0:13:46.31,yin,,0,0,0,,它进行了实际取回 你可以去看看\\N{\\fs12}it's doing actual fetch, so you can go take a look\r\nDialogue: 0,0:13:46.31,0:13:50.22,yin,,0,0,0,,iOS发送的后台取回消息\\N{\\fs12}at the background fetch message that gets sent by iOS\r\nDialogue: 0,0:13:50.22,0:13:52.20,yin,,0,0,0,,你会看到我做的是实际的临时取回\\N{\\fs12}and you'll see that I'm doing an actual ephemeral fetch,\r\nDialogue: 0,0:13:52.20,0:13:53.49,yin,,0,0,0,,我没调用startFLickrFetch\\N{\\fs12}I'm not calling start FLickr fetch.\r\nDialogue: 0,0:13:53.49,0:13:56.26,yin,,0,0,0,,我只是想说清楚 为什么代码发生了变化\\N{\\fs12}I just want to make it clear why that code was different there.\r\nDialogue: 0,0:13:56.26,0:13:56.94,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:14:08.37,0:14:10.05,yin,,0,0,0,,问得很好\\N{\\fs12}Great. Great question.\r\nDialogue: 0,0:14:10.05,0:14:13.84,yin,,0,0,0,,问题是 有些事情在发生\\N{\\fs12}Okay, so the question is something's happening and I'm\r\nDialogue: 0,0:14:13.84,0:14:16.05,yin,,0,0,0,,我在后台 我的UI需要更新\\N{\\fs12}in the background, and my UI needs to get updated.\r\nDialogue: 0,0:14:16.05,0:14:19.22,yin,,0,0,0,,例如 URL返回 或是我得到机会进行后台取回\\N{\\fs12}Like, a URL comes back or I get offered to do a background fetch,\r\nDialogue: 0,0:14:19.22,0:14:20.34,yin,,0,0,0,,我在做所有的事\\N{\\fs12}I'm doing all these things,\r\nDialogue: 0,0:14:20.34,0:14:22.37,yin,,0,0,0,,这里难道不会有问题吗\\N{\\fs12}and isn't there a problem there\r\nDialogue: 0,0:14:22.37,0:14:25.03,yin,,0,0,0,,毕竟我需要在主队列处理所有UI\\N{\\fs12}because I need to do all my UI in the main queue?\r\nDialogue: 0,0:14:25.03,0:14:26.73,yin,,0,0,0,,这是一个很好的问题\\N{\\fs12}That's the question, and that's a great question.\r\nDialogue: 0,0:14:26.73,0:14:29.96,yin,,0,0,0,,答案是 当你在后台运行时\\N{\\fs12}But the answer is, when you're running in the background,\r\nDialogue: 0,0:14:29.96,0:14:31.57,yin,,0,0,0,,你并不在别的队列上\\N{\\fs12}you're not on a different queue.\r\nDialogue: 0,0:14:31.57,0:14:36.71,yin,,0,0,0,,后台意味着 你不是用户正在看的app\\N{\\fs12}That background just means that you are not the app that the people are looking at.\r\nDialogue: 0,0:14:36.71,0:14:39.90,yin,,0,0,0,,不过其它方面 它和在前台运行无异\\N{\\fs12}But every otherwise, it's just like you're running in the foreground.\r\nDialogue: 0,0:14:39.90,0:14:41.61,yin,,0,0,0,,你可以绘制 你可以做任何事\\N{\\fs12}You can draw, you can do everything.\r\nDialogue: 0,0:14:41.61,0:14:43.52,yin,,0,0,0,,你的主队列在运行\\N{\\fs12}Your main queue is running.\r\nDialogue: 0,0:14:43.52,0:14:45.60,yin,,0,0,0,,当你有这样运行的机会时\\N{\\fs12}When you get the opportunity to run like this,\r\nDialogue: 0,0:14:45.60,0:14:48.39,yin,,0,0,0,,运行的是你的主队列 你可以进行图像处理\\N{\\fs12}it's your main queue that's running, so you can do graphics,\r\nDialogue: 0,0:14:48.41,0:14:50.61,yin,,0,0,0,,你可以绘图 做什么都行\\N{\\fs12}you can do drawing, anything you want, right?\r\nDialogue: 0,0:14:50.61,0:14:52.33,yin,,0,0,0,,前台和后台之间的差别\\N{\\fs12}So the difference between foreground\r\nDialogue: 0,0:14:52.33,0:14:55.07,yin,,0,0,0,,并不是主队列和非主队列之间的差别\\N{\\fs12}and background is not main queue/some other queue,\r\nDialogue: 0,0:14:55.07,0:14:57.97,yin,,0,0,0,,而是app活动与非活动之间的差别\\N{\\fs12}it's am I the active app? Am I not the active app?\r\nDialogue: 0,0:14:57.97,0:14:59.69,yin,,0,0,0,,这就是前台和后台之间的差别\\N{\\fs12}That's the difference between foreground and background.\r\nDialogue: 0,0:14:59.69,0:15:02.54,yin,,0,0,0,,通常在后台时 你不会运行\\N{\\fs12}Normally, when you're in the background, you don't get to run.\r\nDialogue: 0,0:15:02.54,0:15:06.25,yin,,0,0,0,,你的主队列没有任何周期 你的app没有任何周期\\N{\\fs12}Your main queue gets no cycles, because none of your app gets any cycles,\r\nDialogue: 0,0:15:06.25,0:15:07.67,yin,,0,0,0,,一般都是如此\\N{\\fs12}okay, normally,\r\nDialogue: 0,0:15:07.67,0:15:09.70,yin,,0,0,0,,不过偶尔 你会得到后台取回\\N{\\fs12}but then occasionally you'll get the background fetch\r\nDialogue: 0,0:15:09.70,0:15:12.94,yin,,0,0,0,,或是URL会返回 或者你是一个location的东西\\N{\\fs12}or URL will come back, or if you're a location thing,\r\nDialogue: 0,0:15:12.94,0:15:14.22,yin,,0,0,0,,就像我们今天要讲的\\N{\\fs12}like I was saying we were talking about today,\r\nDialogue: 0,0:15:14.22,0:15:18.15,yin,,0,0,0,,你可以得到消息说 嘿 手机移动到了新位置\\N{\\fs12}you can get messages that \"Hey the phone has moved to a new location,\"\r\nDialogue: 0,0:15:18.16,0:15:21.52,yin,,0,0,0,,你得到了一个我刚说的推送通知\\N{\\fs12}um, you get a push notification that I was talking about earlier.\r\nDialogue: 0,0:15:21.52,0:15:22.85,yin,,0,0,0,,Facebook发了个消息给你\\N{\\fs12}You know, Facebook sent you a message.\r\nDialogue: 0,0:15:22.85,0:15:24.41,yin,,0,0,0,,这些都会把你从后台中唤醒\\N{\\fs12}Those things will wake you up in the background,\r\nDialogue: 0,0:15:24.41,0:15:26.24,yin,,0,0,0,,你会有一点时间来处理\\N{\\fs12}and you can get a little time to process.\r\nDialogue: 0,0:15:26.24,0:15:29.15,yin,,0,0,0,,每次你得到机会在后台运行时\\N{\\fs12}Any time you're given an opportunity to run in the background a little,\r\nDialogue: 0,0:15:29.15,0:15:30.97,yin,,0,0,0,,你都只有一点时间\\N{\\fs12}you only get a little bit of time.\r\nDialogue: 0,0:15:30.97,0:15:31.87,yin,,0,0,0,,很好理解\\N{\\fs12}Understandably.\r\nDialogue: 0,0:15:31.87,0:15:33.99,yin,,0,0,0,,你不能在那运行十分钟\\N{\\fs12}You can't sit there and run for ten minutes.\r\nDialogue: 0,0:15:33.99,0:15:37.80,yin,,0,0,0,,这是为了让用户没用你的程序时\\N{\\fs12}The whole point is to kind of keep you when you're not the app the user is using,\r\nDialogue: 0,0:15:37.80,0:15:42.38,yin,,0,0,0,,你不会用太多资源 免得浪费电量\\N{\\fs12}we want to keep you not using a lot of resources so the battery doesn't drain.\r\nDialogue: 0,0:15:43.38,0:15:45.02,yin,,0,0,0,,问得很好 请讲\\N{\\fs12}So good question. Yeah?\r\nDialogue: 0,0:15:52.36,0:15:55.17,yin,,0,0,0,,问题是 如果我获得了机会\\N{\\fs12}So the question is, what if I get an opportunity to run\r\nDialogue: 0,0:15:55.17,0:15:57.80,yin,,0,0,0,,在后台运行这些机制\\N{\\fs12}in the background here from one of these many mechanisms,\r\nDialogue: 0,0:15:57.80,0:16:00.05,yin,,0,0,0,,而且我确实要花十分钟\\N{\\fs12}and I do start doing something that takes ten minutes.\r\nDialogue: 0,0:16:00.05,0:16:01.33,yin,,0,0,0,,这时会发生什么\\N{\\fs12}What's going to happen?\r\nDialogue: 0,0:16:01.33,0:16:03.89,yin,,0,0,0,,答案是 系统会让你停止\\N{\\fs12}And the answer is, the system is going to just stop you,\r\nDialogue: 0,0:16:03.89,0:16:06.05,yin,,0,0,0,,你的过程会停止\\N{\\fs12}your process is going to stop,\r\nDialogue: 0,0:16:06.05,0:16:07.96,yin,,0,0,0,,你将无法完成\\N{\\fs12}you're not going to get to finish,\r\nDialogue: 0,0:16:07.96,0:16:10.42,yin,,0,0,0,,而且这会导致很多糟糕事情发生\\N{\\fs12}and that will create all kinds of bad things,\r\nDialogue: 0,0:16:10.42,0:16:12.15,yin,,0,0,0,,你的用户会说 怎么回事\\N{\\fs12}your user will be like \"what's going on?\"\r\nDialogue: 0,0:16:12.15,0:16:14.79,yin,,0,0,0,,这对你也很糟糕 时间会超时\\N{\\fs12}you know? And that's bad for you if things will timeout,\r\nDialogue: 0,0:16:14.79,0:16:18.55,yin,,0,0,0,,如果你在访问网络 各种糟糕事情会发生\\N{\\fs12}if you're accessing the network, all kinds of bad things,\r\nDialogue: 0,0:16:18.55,0:16:21.82,yin,,0,0,0,,答案是 别那样做\\N{\\fs12}so the answer is you don't want to do that, and the answer is,\r\nDialogue: 0,0:16:21.82,0:16:24.12,yin,,0,0,0,,系统不会让你这样\\N{\\fs12}the system will not let you do it.\r\nDialogue: 0,0:16:24.12,0:16:25.36,yin,,0,0,0,,问得很好\\N{\\fs12}Good question.\r\nDialogue: 0,0:16:25.36,0:16:26.43,yin,,0,0,0,,还有吗\\N{\\fs12}Alright, anything else?\r\nDialogue: 0,0:16:26.43,0:16:28.68,yin,,0,0,0,,问得很好 这里的幻灯片很好\\N{\\fs12}Great question, this is a great slide, because we basically got\r\nDialogue: 0,0:16:28.68,0:16:31.52,yin,,0,0,0,,这里我们基本是在考虑多任务处理\\N{\\fs12}to talk about multi-tasking here.\r\nDialogue: 0,0:16:31.52,0:16:36.76,yin,,0,0,0,,下面 我们来继续Photomania演示demo\\N{\\fs12}Alright, so let's talk about, continuing our Photo Mania demo here,\r\nDialogue: 0,0:16:36.76,0:16:40.51,yin,,0,0,0,,我说了 我要把它做成iPad程序\\N{\\fs12}and like I said, I'm going to make it into an iPad app, actually I'm going\r\nDialogue: 0,0:16:40.51,0:16:42.63,yin,,0,0,0,,我要把它做成通用程序\\N{\\fs12}to make it a universal app.\r\nDialogue: 0,0:16:42.63,0:16:45.38,yin,,0,0,0,,这将是一个很短的demo\\N{\\fs12}Believe it or not, and this is going to be a fairly short demo.\r\nDialogue: 0,0:16:45.38,0:16:49.67,yin,,0,0,0,,我们这里创建了很多可再利用的部分\\N{\\fs12}And we've kind of built so much reusable parts here\r\nDialogue: 0,0:16:49.67,0:16:51.44,yin,,0,0,0,,我们也有了很多知识\\N{\\fs12}and so much knowledge that you have\r\nDialogue: 0,0:16:51.44,0:16:56.04,yin,,0,0,0,,我们现在可以很快用这些来做更复杂的事\\N{\\fs12}that we can really quickly now make these apps do much more sophisticated things,\r\nDialogue: 0,0:16:56.04,0:16:59.31,yin,,0,0,0,,然后我还要演示一个你们没看过的东西\\N{\\fs12}and then I'm going to demo a new thing that you've never seen before,\r\nDialogue: 0,0:16:59.31,0:17:02.15,yin,,0,0,0,,也就是如何创建弹窗segue\\N{\\fs12}which is how to make a popover segue.\r\nDialogue: 0,0:17:02.15,0:17:06.73,yin,,0,0,0,,这是一类新的segue 几堂课前我们在课堂上讲过\\N{\\fs12}This is a new kind of segue, we talked about it in lecture, a few lectures ago,\r\nDialogue: 0,0:17:06.73,0:17:10.46,yin,,0,0,0,,不过我没要求你们在作业中做过 也没进行过demo演示\\N{\\fs12}but I never asked you to do it on homework, and I never demoed it,\r\nDialogue: 0,0:17:10.46,0:17:12.83,yin,,0,0,0,,现在就让我来demo演示一下\\N{\\fs12}so I'm going to demo it here.\r\nDialogue: 0,0:17:12.83,0:17:17.50,yin,,0,0,0,,好 退出这个\\N{\\fs12}Oh yes, okay, let's quit that.\r\nDialogue: 0,0:17:17.50,0:17:20.68,yin,,0,0,0,,让我们来运行Photomania\\N{\\fs12}Alright, so, let's go run Photo Mania.\r\nDialogue: 0,0:17:20.68,0:17:24.57,yin,,0,0,0,,这就是我发布时的样子\\N{\\fs12}This is exactly the way it was when I posted it.\r\nDialogue: 0,0:17:24.57,0:17:27.56,yin,,0,0,0,,看这里 这就是执行取回\\N{\\fs12}So this is the posting, and you can see here, this is the perform fetch,\r\nDialogue: 0,0:17:27.56,0:17:31.37,yin,,0,0,0,,这里我做的是一个常规的临时URL取回\\N{\\fs12}and you can see how I'm just doing a normal ephemeral URL\r\nDialogue: 0,0:17:31.37,0:17:34.56,yin,,0,0,0,,我们没有调用startFlickrFetch\\N{\\fs12}fetch, I'm not calling start FLickr fetch here.\r\nDialogue: 0,0:17:34.56,0:17:37.55,yin,,0,0,0,,这个东西在跳动\\N{\\fs12}And this guy is not...how, okay, I know how it is,\r\nDialogue: 0,0:17:37.55,0:17:41.02,yin,,0,0,0,,到时候我们会处理iTunes的\\N{\\fs12}okay we'll deal with iTunes when we get there.\r\nDialogue: 0,0:17:41.02,0:17:42.95,yin,,0,0,0,,无论如何\\N{\\fs12}Alright, so um, so anyway,\r\nDialogue: 0,0:17:42.95,0:17:45.56,yin,,0,0,0,,这就是我上周发布的东西\\N{\\fs12}so this is exactly what I posted last week.\r\nDialogue: 0,0:17:45.56,0:17:47.61,yin,,0,0,0,,上周四\\N{\\fs12}Last Thursday or whatever.\r\nDialogue: 0,0:17:47.61,0:17:48.91,yin,,0,0,0,,这个做了什么呢\\N{\\fs12}So what did this do?\r\nDialogue: 0,0:17:48.91,0:17:52.88,yin,,0,0,0,,我们运行一下 回顾一下Photomania是干嘛的\\N{\\fs12}Let's run this, just so we can remind ourselves what Photo Mania does,\r\nDialogue: 0,0:17:52.88,0:17:55.25,yin,,0,0,0,,它已经有半个星期久远了\\N{\\fs12}it's been more than half a week, and there it is,\r\nDialogue: 0,0:17:55.25,0:17:57.56,yin,,0,0,0,,它在后台中进行取回\\N{\\fs12}it just fetches in the background,\r\nDialogue: 0,0:17:57.56,0:18:03.52,yin,,0,0,0,,还有在启动时 取回了一系列最新的照片\\N{\\fs12}and also when it launches, kind of a bunch of recent photos\r\nDialogue: 0,0:18:03.52,0:18:05.14,yin,,0,0,0,,从Flickr\\N{\\fs12}from Flickr,\r\nDialogue: 0,0:18:05.14,0:18:08.16,yin,,0,0,0,,然后它给了一张表\\N{\\fs12}then it basically makes a table\r\nDialogue: 0,0:18:08.16,0:18:12.17,yin,,0,0,0,,表中有很多拍照者\\N{\\fs12}of all the photographers who took the photos,\r\nDialogue: 0,0:18:12.17,0:18:15.19,yin,,0,0,0,,这些都是拍照者 不是照片 而是拍照者\\N{\\fs12}so these are all photographers, not photos, photographers.\r\nDialogue: 0,0:18:15.19,0:18:17.28,yin,,0,0,0,,不过我们希望能够点这些\\N{\\fs12}But we'd love to be able to click on these\r\nDialogue: 0,0:18:17.28,0:18:19.93,yin,,0,0,0,,并看到某个拍照者的照片\\N{\\fs12}and see the photos by that photographer, right?\r\nDialogue: 0,0:18:19.93,0:18:22.05,yin,,0,0,0,,但这里还不行 因为还没有segue\\N{\\fs12}But we can't because we never put any segues in here,\r\nDialogue: 0,0:18:22.05,0:18:23.19,yin,,0,0,0,,我们什么都没做\\N{\\fs12}we never did anything,\r\nDialogue: 0,0:18:23.20,0:18:26.74,yin,,0,0,0,,而且 我们的app在iPad上什么都做不了\\N{\\fs12}and plus our app doesn't work at all on iPad,\r\nDialogue: 0,0:18:26.74,0:18:29.19,yin,,0,0,0,,让我们看看iPad故事板\\N{\\fs12}in fact, let's go look at our iPad storyboard,\r\nDialogue: 0,0:18:29.19,0:18:31.70,yin,,0,0,0,,可以在这里看到 它只是这个空白屏幕\\N{\\fs12}you can see it right here, it's just this big blank screen.\r\nDialogue: 0,0:18:31.70,0:18:34.27,yin,,0,0,0,,如果在iPad上运行 它将是一大块白屏\\N{\\fs12}So if I ran this on the iPad, it would be a big, blank screen.\r\nDialogue: 0,0:18:34.27,0:18:35.71,yin,,0,0,0,,我们删掉这个\\N{\\fs12}So let's get rid of that.\r\nDialogue: 0,0:18:35.71,0:18:38.12,yin,,0,0,0,,我想在这里创建我的iPad UI\\N{\\fs12}Now, I want to build my iPad UI here,\r\nDialogue: 0,0:18:38.12,0:18:40.90,yin,,0,0,0,,做法我之前跟大家展示过\\N{\\fs12}but I'm going to do it in a way that I showed you a little bit before,\r\nDialogue: 0,0:18:40.90,0:18:45.56,yin,,0,0,0,,这个很强大 我要复制粘贴自另一个app\\N{\\fs12}but it's really powerful, which I'm just going to copy and paste it from another app,\r\nDialogue: 0,0:18:45.56,0:18:51.23,yin,,0,0,0,,记得吧 Shutterbug有一个iPad上很类似的UI\\N{\\fs12}because Shutterbug, if you remember, had a UI on the iPad that's very similar\r\nDialogue: 0,0:18:51.23,0:18:53.70,yin,,0,0,0,,我们可以将它用到Photomania 来到Shutterbug\\N{\\fs12}to what we want in Photo Mania, so I'm going to go over to Shutterbug.\r\nDialogue: 0,0:18:53.70,0:18:55.63,yin,,0,0,0,,这是最后编辑的Shutterbug\\N{\\fs12}This is Shutterbug as we last left it.\r\nDialogue: 0,0:18:55.63,0:19:02.28,yin,,0,0,0,,看Shutterbug的iPad UI 这基本上就是我们要的了\\N{\\fs12}And if you look at Shutterbug's iPad UI, this, it's kind of almost what we want.\r\nDialogue: 0,0:19:02.28,0:19:04.70,yin,,0,0,0,,Shutterbug展示的是照片列表\\N{\\fs12}Shutterbug just shows the list of photos here,\r\nDialogue: 0,0:19:04.70,0:19:08.24,yin,,0,0,0,,如果我们能把拍照者列表插入到这中间\\N{\\fs12}if we could just insert the list of photographers here in the middle,\r\nDialogue: 0,0:19:08.24,0:19:10.60,yin,,0,0,0,,我们几乎就得到了iPad上我们要的一切\\N{\\fs12}we'd have pretty much what we want on the iPad,\r\nDialogue: 0,0:19:10.60,0:19:13.88,yin,,0,0,0,,下面我要复制所有这些\\N{\\fs12}so I'm just going to copy all of this.\r\nDialogue: 0,0:19:13.88,0:19:16.19,yin,,0,0,0,,回到Photomania这里\\N{\\fs12}Go back over here to Photo Mania,\r\nDialogue: 0,0:19:16.19,0:19:19.73,yin,,0,0,0,,我在我的iPad故事板中 粘贴\\N{\\fs12}and I'm in my iPad storyboard here, and paste.\r\nDialogue: 0,0:19:19.73,0:19:21.95,yin,,0,0,0,,我需要全选这些\\N{\\fs12}Oops, I guess maybe select all over here?\r\nDialogue: 0,0:19:21.95,0:19:27.61,yin,,0,0,0,,全选 复制 到这里 粘贴\\N{\\fs12}Okay, select all, copy, over here, and paste.\r\nDialogue: 0,0:19:27.61,0:19:29.57,yin,,0,0,0,,放到了这里\\N{\\fs12}So put it in here.\r\nDialogue: 0,0:19:29.57,0:19:34.68,yin,,0,0,0,,还是一样 我们需要找一下 哦 就在这里\\N{\\fs12}As usual it's a little bit of a search party to find anything, oh, there it is!\r\nDialogue: 0,0:19:34.68,0:19:40.75,yin,,0,0,0,,这就是那个Shutterbug iPad UI\\N{\\fs12}So here is that Shutterbug iPad UI.\r\nDialogue: 0,0:19:40.77,0:19:43.35,yin,,0,0,0,,我说了 我想要往其中插入\\N{\\fs12}And like I said, basically I want to insert\r\nDialogue: 0,0:19:43.35,0:19:45.41,yin,,0,0,0,,一个照片列表\\N{\\fs12}in between the list of photos\r\nDialogue: 0,0:19:45.41,0:19:48.10,yin,,0,0,0,,放到这里 让我能选拍照者\\N{\\fs12}a thing here where I can choose the photographer.\r\nDialogue: 0,0:19:48.10,0:19:51.83,yin,,0,0,0,,也就是我刚在Photomania中展示的东西\\N{\\fs12}The same thing, the thing I just showed you, that we were running in Photo Mania.\r\nDialogue: 0,0:19:51.83,0:19:55.36,yin,,0,0,0,,既然在Shutterbug中 就让我来抓取图像视图控制器吧\\N{\\fs12}While I'm here in Shutterbug, let's grab the image view controller.\r\nDialogue: 0,0:19:55.36,0:19:56.63,yin,,0,0,0,,我们显然需要这个\\N{\\fs12}We're going to need that obviously,\r\nDialogue: 0,0:19:56.63,0:19:59.60,yin,,0,0,0,,故事板需要用到它 把它放到这里\\N{\\fs12}our storyboard uses that, so we'll put that over here.\r\nDialogue: 0,0:19:59.60,0:20:00.48,yin,,0,0,0,,复制进来\\N{\\fs12}Copy that in.\r\nDialogue: 0,0:20:00.48,0:20:03.11,yin,,0,0,0,,这就是Shutterbug中我们需要的一切\\N{\\fs12}And that's all we need from Shutterbug. So\r\nDialogue: 0,0:20:03.13,0:20:08.88,yin,,0,0,0,,这个故事板基本上就是我们要的了\\N{\\fs12}this storyboard is pretty much exactly what we want,\r\nDialogue: 0,0:20:08.88,0:20:11.61,yin,,0,0,0,,只有少量东西需要修正\\N{\\fs12}there's a couple of minor things we need to fix here.\r\nDialogue: 0,0:20:11.61,0:20:15.14,yin,,0,0,0,,一是 我们不想要这个照片列表\\N{\\fs12}One thing is we don't want this list of photos\r\nDialogue: 0,0:20:15.14,0:20:18.38,yin,,0,0,0,,为我们的拆分视图的根视图控制器\\N{\\fs12}to be the root view controller of our split view,\r\nDialogue: 0,0:20:18.38,0:20:21.39,yin,,0,0,0,,我们希望这里是拍照者\\N{\\fs12}we want the photographer thing to be that.\r\nDialogue: 0,0:20:21.39,0:20:23.26,yin,,0,0,0,,在哪获得拍照者的表格呢\\N{\\fs12}So where can we get our photographer's table?\r\nDialogue: 0,0:20:23.26,0:20:26.98,yin,,0,0,0,,这个我们也有 在iPhone的故事板中\\N{\\fs12}Well, we actually have that too, that's here in our iPhone storyboard.\r\nDialogue: 0,0:20:26.98,0:20:28.89,yin,,0,0,0,,这就是我刚运行展示的\\N{\\fs12}That's what I just ran and showed you, right?\r\nDialogue: 0,0:20:28.89,0:20:30.71,yin,,0,0,0,,这是列表 这张表\\N{\\fs12}This is the list, this table\r\nDialogue: 0,0:20:30.71,0:20:32.96,yin,,0,0,0,,到检查器中看\\N{\\fs12}if you inspect its identity\r\nDialogue: 0,0:20:32.96,0:20:35.69,yin,,0,0,0,,这是拍照者的Core Data表格视图控制器\\N{\\fs12}is this photographer's core data table view controller.\r\nDialogue: 0,0:20:35.69,0:20:38.03,yin,,0,0,0,,这里展示的是拍照者的列表\\N{\\fs12}So this is showing that list of photographers.\r\nDialogue: 0,0:20:38.03,0:20:40.19,yin,,0,0,0,,我们只需要复制这个\\N{\\fs12}So let's just copy this.\r\nDialogue: 0,0:20:40.19,0:20:44.75,yin,,0,0,0,,把这个放到我们的… 哦 到哪去了\\N{\\fs12}Put this in our...oops, and where did it go?\r\nDialogue: 0,0:20:46.96,0:20:50.95,yin,,0,0,0,,抱歉 有时很难找 在这里\\N{\\fs12}Sorry. Sometimes hard to find all this, there it is.\r\nDialogue: 0,0:20:50.95,0:20:52.88,yin,,0,0,0,,注意到 它看起来很大\\N{\\fs12}Notice that it looks really big.\r\nDialogue: 0,0:20:52.88,0:20:55.71,yin,,0,0,0,,这是因为我还没有segue到它 它还不知道\\N{\\fs12}That's because I haven't segued to it yet, so it doesn't know\r\nDialogue: 0,0:20:55.71,0:20:59.69,yin,,0,0,0,,它会处在一个拆分视频的master中\\N{\\fs12}that it's going to be in a master of a split view\r\nDialogue: 0,0:20:59.69,0:21:06.05,yin,,0,0,0,,并处在一个这样的导航控制器中\\N{\\fs12}and be inside of a navigation controller like that.\r\nDialogue: 0,0:21:06.05,0:21:08.79,yin,,0,0,0,,让我们把那个根视图控制器放到这里\\N{\\fs12}So let's go ahead and put that root view controller in there.\r\nDialogue: 0,0:21:08.79,0:21:09.22,yin,,0,0,0,,在哪\\N{\\fs12}Where is it?\r\nDialogue: 0,0:21:09.22,0:21:11.67,yin,,0,0,0,,这是我们的导航控制器的根\\N{\\fs12}Okay so here's the root of our navigation controller.\r\nDialogue: 0,0:21:11.67,0:21:14.10,yin,,0,0,0,,这个或许也叫作Shutterbug\\N{\\fs12}This thing is also probably called Shutterbug,\r\nDialogue: 0,0:21:14.10,0:21:18.01,yin,,0,0,0,,把这个改成Photomania或是Photographers\\N{\\fs12}let's change this to Photo Mania or maybe photographers,\r\nDialogue: 0,0:21:18.01,0:21:21.00,yin,,0,0,0,,因为出现在我们根视图控制器中的就是这个\\N{\\fs12}because that's what's going to show up in our root view controller.\r\nDialogue: 0,0:21:21.00,0:21:25.16,yin,,0,0,0,,我要control拖动到拍照者那个\\N{\\fs12}So I'm just going to control drag to the photographer's one,\r\nDialogue: 0,0:21:25.16,0:21:28.14,yin,,0,0,0,,并把这个重设为根视图控制器\\N{\\fs12}and reset that to be the root view controller.\r\nDialogue: 0,0:21:28.14,0:21:31.48,yin,,0,0,0,,下面… 这里腾点空间出来\\N{\\fs12}So now, let's get more space here.\r\nDialogue: 0,0:21:33.88,0:21:42.56,yin,,0,0,0,,现在我们的UI就更接近于我们想要的了\\N{\\fs12}So now our API or our UI is a little more what we want.\r\nDialogue: 0,0:21:42.56,0:21:46.73,yin,,0,0,0,,我们这里有这个拍照者的东西 我们希望\\N{\\fs12}We have this photographer's thing here, and now we want,\r\nDialogue: 0,0:21:46.73,0:21:49.84,yin,,0,0,0,,每次点击拍照者其中一行时\\N{\\fs12}if each time we click on a photographer, one of these rows,\r\nDialogue: 0,0:21:49.84,0:21:53.12,yin,,0,0,0,,都会跳到一个照片列表\\N{\\fs12}then we want to go to a list of photos.\r\nDialogue: 0,0:21:53.12,0:21:54.89,yin,,0,0,0,,让我们来做这个\\N{\\fs12}Alright? So let's do that.\r\nDialogue: 0,0:21:54.91,0:21:57.52,yin,,0,0,0,,从这里control拖动到这里\\N{\\fs12}I'm just going to control drag from here to here.\r\nDialogue: 0,0:21:57.52,0:22:00.80,yin,,0,0,0,,这处在导航控制器中 我要选push\\N{\\fs12}And this is inside our navigation control, so I'm going to push.\r\nDialogue: 0,0:22:00.80,0:22:04.12,yin,,0,0,0,,现在就很接近于我们要的了\\N{\\fs12}Now we're really getting close to what we want.\r\nDialogue: 0,0:22:04.12,0:22:06.63,yin,,0,0,0,,这是Shutterbug 不过这没问题\\N{\\fs12}This is Shutterbug, but that's okay, that's going\r\nDialogue: 0,0:22:06.63,0:22:09.60,yin,,0,0,0,,这是标题 我们会重置标题\\N{\\fs12}to be the title, we're going to reset that title anyway.\r\nDialogue: 0,0:22:09.60,0:22:11.71,yin,,0,0,0,,这个UI的问题是什么\\N{\\fs12}And what is the problem with this UI?\r\nDialogue: 0,0:22:11.71,0:22:15.80,yin,,0,0,0,,这个UI几乎就是我们要的了 除了一点\\N{\\fs12}This UI is actually exactly what we want except for one thing,\r\nDialogue: 0,0:22:15.80,0:22:21.18,yin,,0,0,0,,也就是 到检查器中看这个\\N{\\fs12}which is that if we inspect this guy right here,\r\nDialogue: 0,0:22:21.18,0:22:24.99,yin,,0,0,0,,它是一个JustPostedFlickrPhotoCDTVC\\N{\\fs12}it is a just posted Flickr photo CDTVC, right?\r\nDialogue: 0,0:22:24.99,0:22:26.20,yin,,0,0,0,,因为这是从Shutterbug复制来的\\N{\\fs12}Because I copied it from Shutterbug,\r\nDialogue: 0,0:22:26.20,0:22:27.76,yin,,0,0,0,,Shutterbug显示的就是这个\\N{\\fs12}and that's what Shutterbug shows, right?\r\nDialogue: 0,0:22:27.76,0:22:29.37,yin,,0,0,0,,刚发布的照片\\N{\\fs12}The just posted photos.\r\nDialogue: 0,0:22:29.37,0:22:35.02,yin,,0,0,0,,而这里 我们希望它是PhotosByPhotographerCDTVC\\N{\\fs12}So really we want this to be something like photos by photographer CDTVC, right?\r\nDialogue: 0,0:22:35.02,0:22:37.09,yin,,0,0,0,,因为我们会点击这里的拍照者\\N{\\fs12}Because we're going to click on a photographer here,\r\nDialogue: 0,0:22:37.09,0:22:39.55,yin,,0,0,0,,我们希望显示的是他拍的照片\\N{\\fs12}and we want this to show the photos by that photographer.\r\nDialogue: 0,0:22:39.55,0:22:42.07,yin,,0,0,0,,大家都理解我说的话了吗\\N{\\fs12}Does everybody understand why I'm saying that?\r\nDialogue: 0,0:22:42.07,0:22:43.83,yin,,0,0,0,,让我们把它设置为这个\\N{\\fs12}So let's just set it to be that, and\r\nDialogue: 0,0:22:43.83,0:22:47.84,yin,,0,0,0,,我们将要创建这个视图控制器 让我们来做这个\\N{\\fs12}we're going to have to create this view controller right here, so let's just do that.\r\nDialogue: 0,0:22:47.84,0:22:51.66,yin,,0,0,0,,文件 新文件 类\\N{\\fs12}File, new file, the class,\r\nDialogue: 0,0:22:51.66,0:22:54.47,yin,,0,0,0,,这就是一个CoreDataTableViewController\\N{\\fs12}it's going to be a core data table view controller.\r\nDialogue: 0,0:22:54.49,0:22:59.87,yin,,0,0,0,,我们将称其为PhotosByPhotographerCDTVC\\N{\\fs12}We're going to call it photos by photographer CDTVC,\r\nDialogue: 0,0:22:59.87,0:23:02.06,yin,,0,0,0,,我们需要确保这个等于这个\\N{\\fs12}we've got to make sure this equals this, because\r\nDialogue: 0,0:23:02.06,0:23:05.45,yin,,0,0,0,,因为我刚把那个设置为了这里的类\\N{\\fs12}I just set that to be the class in here.\r\nDialogue: 0,0:23:05.45,0:23:12.34,yin,,0,0,0,,把这个放到Photomania中\\N{\\fs12}So let's put this -- I'll bring that, let's put this in Photo Mania.\r\nDialogue: 0,0:23:12.34,0:23:16.31,yin,,0,0,0,,有点怪 好 放到这里\\N{\\fs12}Huh, that's kind of weird, okay...alright put in there.\r\nDialogue: 0,0:23:16.31,0:23:22.01,yin,,0,0,0,,好 这是我们的新PhotosByPhotographerCDTVC\\N{\\fs12}Alright. So here's our new photos by photographer core data table view controller.\r\nDialogue: 0,0:23:22.01,0:23:27.01,yin,,0,0,0,,我不想被这些垃圾弄得分心 删掉它们\\N{\\fs12}I'm going to not have you distracted by all this junk, let's get rid of all that.\r\nDialogue: 0,0:23:27.01,0:23:30.21,yin,,0,0,0,,创建了新的视图控制器后再怎么做呢\\N{\\fs12}When we create a new view controller, what do we do?\r\nDialogue: 0,0:23:30.21,0:23:33.64,yin,,0,0,0,,我们总需要想 这个东西的API是什么\\N{\\fs12}We always kind of think of what is this thing's API?\r\nDialogue: 0,0:23:33.64,0:23:35.58,yin,,0,0,0,,它的公共接口是什么\\N{\\fs12}What's its public interface?\r\nDialogue: 0,0:23:35.58,0:23:38.87,yin,,0,0,0,,我们来看PhotosByPhotographer的公共接口\\N{\\fs12}So let's look at the public interface of photos by photographer,\r\nDialogue: 0,0:23:38.87,0:23:41.49,yin,,0,0,0,,也许你们有些人会想到\\N{\\fs12}and probably some of you are imagining\r\nDialogue: 0,0:23:41.49,0:23:45.51,yin,,0,0,0,,这个很简单 它为非原子 强\\N{\\fs12}that what this is, it's really simple, it's just going to be non-atomic strong.\r\nDialogue: 0,0:23:45.51,0:23:50.32,yin,,0,0,0,,我们需要传入我们要显示的照片的拍照者\\N{\\fs12}We need to pass the photographer in that we want to show the photos of.\r\nDialogue: 0,0:23:50.32,0:23:52.86,yin,,0,0,0,,因此 我需要导入\\N{\\fs12}So I'd better import,\r\nDialogue: 0,0:23:53.69,0:23:59.69,yin,,0,0,0,,导入Photographer 然后我可以有一个拍照者\\N{\\fs12}import photographer, and then I can have a photographer.\r\nDialogue: 0,0:24:02.00,0:24:05.60,yin,,0,0,0,,这就是我们的公共模型 这就是我们的模型\\N{\\fs12}Okay so this is basically our public model, this is our model\r\nDialogue: 0,0:24:05.60,0:24:09.29,yin,,0,0,0,,它是公共的 如果有人设置了这个拍照者\\N{\\fs12}and it's public, so if someone sets this photographer,\r\nDialogue: 0,0:24:09.29,0:24:12.45,yin,,0,0,0,,我们需要显示这个拍照者的照片\\N{\\fs12}we'd better show the photos by that photographer.\r\nDialogue: 0,0:24:12.45,0:24:14.47,yin,,0,0,0,,这是一张显示照片的表格\\N{\\fs12}So this is a table that shows photos,\r\nDialogue: 0,0:24:14.47,0:24:18.24,yin,,0,0,0,,拍照者决定了显示哪些照片\\N{\\fs12}photographer determines which photos we show.\r\nDialogue: 0,0:24:18.24,0:24:20.49,yin,,0,0,0,,在我们实现这个之前\\N{\\fs12}Now before we go off and implement this,\r\nDialogue: 0,0:24:20.49,0:24:24.84,yin,,0,0,0,,我要先到拍照者的Core Data表格视图控制器\\N{\\fs12}I'm actually going to go down to our photographer's core data table view controller.\r\nDialogue: 0,0:24:24.84,0:24:27.40,yin,,0,0,0,,这是显示拍照者列表的东西\\N{\\fs12}This is the thing that shows the list of photographers.\r\nDialogue: 0,0:24:27.40,0:24:29.99,yin,,0,0,0,,这是我这一讲最开始展示的\\N{\\fs12}That I started off this lecture showing you.\r\nDialogue: 0,0:24:29.99,0:24:32.69,yin,,0,0,0,,但愿你们记得上周三的代码\\N{\\fs12}Hopefully you remember this code from last Wednesday,\r\nDialogue: 0,0:24:32.69,0:24:35.16,yin,,0,0,0,,它正在从拍照者中取回信息\\N{\\fs12}you can see that it's doing a fetch to the photographer,\r\nDialogue: 0,0:24:35.16,0:24:37.75,yin,,0,0,0,,按名字显示 取回所有这些\\N{\\fs12}showing them by name, it's fetching all of them right?\r\nDialogue: 0,0:24:37.75,0:24:41.94,yin,,0,0,0,,我要加入导航代码来导航\\N{\\fs12}I'm going to put in the navigation code to navigate\r\nDialogue: 0,0:24:41.94,0:24:48.04,yin,,0,0,0,,从这个照片列表…\\N{\\fs12}from this photos one right here, this is the list of photos,\r\nDialogue: 0,0:24:48.04,0:24:50.45,yin,,0,0,0,,抱歉 这是拍照者列表\\N{\\fs12}sorry, list of photographers.\r\nDialogue: 0,0:24:50.45,0:24:53.37,yin,,0,0,0,,这里这个segue\\N{\\fs12}This little segue right here.\r\nDialogue: 0,0:24:53.37,0:24:56.60,yin,,0,0,0,,给这个segue起个名字\\N{\\fs12}So let's give that little segue a name,\r\nDialogue: 0,0:24:56.60,0:25:01.37,yin,,0,0,0,,叫它Show Photos by Photographer segue\\N{\\fs12}we'll call it the show photos by photographer segue,\r\nDialogue: 0,0:25:01.37,0:25:02.97,yin,,0,0,0,,因为这就是它的作用\\N{\\fs12}because that's what it does, right?\r\nDialogue: 0,0:25:02.97,0:25:05.87,yin,,0,0,0,,点击这里的拍照者 它就会显示照片\\N{\\fs12}When we click on a photographer here, it's going to show the photos.\r\nDialogue: 0,0:25:05.87,0:25:10.29,yin,,0,0,0,,然后我要回到拍照者的Core Data表格视图控制器\\N{\\fs12}And then let's go back to our photographer's core data table view controller\r\nDialogue: 0,0:25:10.29,0:25:13.31,yin,,0,0,0,,然后做导航\\N{\\fs12}and let's do the navigation.\r\nDialogue: 0,0:25:13.31,0:25:15.31,yin,,0,0,0,,下面我要展示\\N{\\fs12}Now, I'm going to show you something\r\nDialogue: 0,0:25:15.31,0:25:19.50,yin,,0,0,0,,你们在开发过程中可能要用的东西\\N{\\fs12}that I think you should probably do for your development process,\r\nDialogue: 0,0:25:19.50,0:25:21.14,yin,,0,0,0,,也就是使用代码片段\\N{\\fs12}which is to start use code snippets.\r\nDialogue: 0,0:25:21.14,0:25:24.23,yin,,0,0,0,,我们在一个周五辅导课上讲过\\N{\\fs12}Now we talked about this in one of the Friday sections,\r\nDialogue: 0,0:25:24.23,0:25:25.91,yin,,0,0,0,,我不打算重复讲它\\N{\\fs12}so I'm not going to go over it again,\r\nDialogue: 0,0:25:25.91,0:25:29.56,yin,,0,0,0,,不过这里我有一段我创建的代码片段\\N{\\fs12}but I have a code snippet that I've created, for example, which is a kind\r\nDialogue: 0,0:25:29.56,0:25:32.71,yin,,0,0,0,,这是一段通用表格视图导航代码片段\\N{\\fs12}of generic table view navigation code snippet.\r\nDialogue: 0,0:25:32.71,0:25:36.29,yin,,0,0,0,,开始键入它的名字 表格视图导航\\N{\\fs12}So I start typing what I called it, table view navigation,\r\nDialogue: 0,0:25:36.29,0:25:40.07,yin,,0,0,0,,然后点回车 这就插入了进来\\N{\\fs12}and I'm going to hit return, and it's going to put it in. So put this code in here\r\nDialogue: 0,0:25:40.07,0:25:43.59,yin,,0,0,0,,这是很通用的 它是做什么的呢\\N{\\fs12}for me, and this is fairly generic okay? And what does it do?\r\nDialogue: 0,0:25:43.59,0:25:45.81,yin,,0,0,0,,它能为segue做准备\\N{\\fs12}Well, it does prepare for segue\r\nDialogue: 0,0:25:45.83,0:25:49.80,yin,,0,0,0,,而且它还能做到didSelectRowAtIndexPath\\N{\\fs12}and it also does did select row at index path.\r\nDialogue: 0,0:25:49.80,0:25:52.93,yin,,0,0,0,,这个能为一个表格视图工作\\N{\\fs12}So this can work for a table view\r\nDialogue: 0,0:25:52.93,0:25:54.98,yin,,0,0,0,,也就是拆分视图的master\\N{\\fs12}that is the master of a split view,\r\nDialogue: 0,0:25:54.98,0:25:56.66,yin,,0,0,0,,它还会为如下情况工作\\N{\\fs12}and it will also work for something\r\nDialogue: 0,0:25:56.67,0:26:00.28,yin,,0,0,0,,也就是通过导航控制来segue\\N{\\fs12}that it's just going to segue via navigation control or whatever.\r\nDialogue: 0,0:26:00.28,0:26:01.67,yin,,0,0,0,,它是如何工作的呢\\N{\\fs12}So how does it work?\r\nDialogue: 0,0:26:01.67,0:26:03.26,yin,,0,0,0,,如果我们prepareForSegue\\N{\\fs12}Well if we prepare for segue,\r\nDialogue: 0,0:26:03.26,0:26:05.63,yin,,0,0,0,,它会从sender获得索引路径\\N{\\fs12}it just gets the index path from the sender,\r\nDialogue: 0,0:26:05.63,0:26:07.48,yin,,0,0,0,,这是一个UITableViewCell\\N{\\fs12}which is a UI table view cell.\r\nDialogue: 0,0:26:07.48,0:26:10.13,yin,,0,0,0,,你们见过这个 没有什么新东西\\N{\\fs12}You've already seen this code before, so it's nothing new.\r\nDialogue: 0,0:26:10.13,0:26:12.45,yin,,0,0,0,,然后它会调用这个准备\\N{\\fs12}And then it calls this prepare up here, and we'll talk\r\nDialogue: 0,0:26:12.45,0:26:14.28,yin,,0,0,0,,马上我们会讲到这个\\N{\\fs12}about what the prepare does in a second.\r\nDialogue: 0,0:26:14.28,0:26:16.81,yin,,0,0,0,,然后didSelectRowAtIndexPath\\N{\\fs12}And then the did select row at index path, it does the trick\r\nDialogue: 0,0:26:16.81,0:26:20.15,yin,,0,0,0,,能够观察拆分视图的detail控制\\N{\\fs12}where it's looking at the detail control of the split view,\r\nDialogue: 0,0:26:20.15,0:26:21.79,yin,,0,0,0,,如果是导航控制器\\N{\\fs12}if it's a navigation controller\r\nDialogue: 0,0:26:21.79,0:26:26.17,yin,,0,0,0,,它会到里面找根视图控制器 然后做好准备\\N{\\fs12}it looks inside for its root view controller, and then is preparing that.\r\nDialogue: 0,0:26:26.17,0:26:30.50,yin,,0,0,0,,大家都理解这两个方法是做什么的了吗\\N{\\fs12}Everyone understand what these two methods do?\r\nDialogue: 0,0:26:30.50,0:26:32.97,yin,,0,0,0,,下面来看这个准备\\N{\\fs12}Okay. So now we've got to look at this prepare,\r\nDialogue: 0,0:26:32.97,0:26:35.03,yin,,0,0,0,,因为这是实际做准备的东西\\N{\\fs12}because this is the thing that's actually doing the prepare.\r\nDialogue: 0,0:26:35.03,0:26:36.34,yin,,0,0,0,,这是这个\\N{\\fs12}So here's that.\r\nDialogue: 0,0:26:36.34,0:26:37.76,yin,,0,0,0,,这个的作用\\N{\\fs12}And what this is going to do,\r\nDialogue: 0,0:26:37.76,0:26:42.58,yin,,0,0,0,,是把ManagedObject放到我们正在讨论的表格的行中\\N{\\fs12}it's going to get the managed object in the row on the table that we're talking about,\r\nDialogue: 0,0:26:42.58,0:26:48.75,yin,,0,0,0,,它会检查我们segue到的视图控制器的类\\N{\\fs12}okay, and then it's going to check the class of the view controller we're segueing to,\r\nDialogue: 0,0:26:48.75,0:26:52.40,yin,,0,0,0,,也许还会检查segue标识符\\N{\\fs12}maybe it's going to check the segue identifiers as well, that's not going to be--\r\nDialogue: 0,0:26:52.40,0:26:54.61,yin,,0,0,0,,didSelectRowAtIndexPath并不是一个segue\\N{\\fs12}you know, did select row at index path is not a segue,\r\nDialogue: 0,0:26:54.61,0:26:56.51,yin,,0,0,0,,因此这里并不适用\\N{\\fs12}so it's not going to be applicable there,\r\nDialogue: 0,0:26:56.51,0:26:59.69,yin,,0,0,0,,不过我在这里检查 看是否有segue标识符\\N{\\fs12}but I check here and see if there is a segue identifier,\r\nDialogue: 0,0:26:59.69,0:27:01.51,yin,,0,0,0,,如果没有 我就忽视这一部分\\N{\\fs12}and if there's not, then I'd ignore this part.\r\nDialogue: 0,0:27:01.51,0:27:05.02,yin,,0,0,0,,然后我要准备那个视图控制器 用于被segue到\\N{\\fs12}And then I'd prepare that view controller for being segued to\r\nDialogue: 0,0:27:05.02,0:27:07.80,yin,,0,0,0,,或者说 如果它是拆分控制器的detail\\N{\\fs12}or if it's the detail of the split view controller.\r\nDialogue: 0,0:27:07.80,0:27:11.63,yin,,0,0,0,,这里 我们有拍照者segue到照片\\N{\\fs12}So this case, we have photographers segueing\r\nDialogue: 0,0:27:11.63,0:27:13.28,yin,,0,0,0,,看看这是怎样的\\N{\\fs12}to photos, so let's see what this looks like.\r\nDialogue: 0,0:27:13.28,0:27:15.95,yin,,0,0,0,,这里我们要找的NSManagedObject\\N{\\fs12}Well, the NS managed object we have here that we're going\r\nDialogue: 0,0:27:15.95,0:27:17.70,yin,,0,0,0,,是一个拍照者\\N{\\fs12}to be looking for is a photographer,\r\nDialogue: 0,0:27:17.70,0:27:21.20,yin,,0,0,0,,因此我要把这个换成Photographer\\N{\\fs12}so I'm just going to replace this with photographer.\r\nDialogue: 0,0:27:21.20,0:27:22.67,yin,,0,0,0,,photographer\\N{\\fs12}Photographer.\r\nDialogue: 0,0:27:22.67,0:27:27.17,yin,,0,0,0,,从取回结果控制器中 将对象获得到索引路径中\\N{\\fs12}Just getting my object in index path out of my fetched results controller,\r\nDialogue: 0,0:27:27.17,0:27:28.35,yin,,0,0,0,,你们知道这是什么\\N{\\fs12}you know what that is,\r\nDialogue: 0,0:27:28.35,0:27:31.89,yin,,0,0,0,,然后我们segue到的是哪类视图控制器呢\\N{\\fs12}and then what kind of view controller are we segueing to?\r\nDialogue: 0,0:27:31.89,0:27:33.68,yin,,0,0,0,,我们将segue到这里的一个\\N{\\fs12}Well, we're going to be segueing to one of these\r\nDialogue: 0,0:27:33.69,0:27:37.69,yin,,0,0,0,,我们刚创建的PhotosByPhotographerCDTVC\\N{\\fs12}photos by photographer core data view controllers that we just created.\r\nDialogue: 0,0:27:37.69,0:27:39.19,yin,,0,0,0,,这个的实现我们还没做\\N{\\fs12}We haven't done the implementation of this yet,\r\nDialogue: 0,0:27:39.19,0:27:42.86,yin,,0,0,0,,不过我们知道要设置拍照者 它的公共API是什么\\N{\\fs12}but we know what its public API is, to set the photographer,\r\nDialogue: 0,0:27:42.86,0:27:44.81,yin,,0,0,0,,同我们想的一样\\N{\\fs12}which is exactly what we would want.\r\nDialogue: 0,0:27:44.81,0:27:47.79,yin,,0,0,0,,让我们导入这个\\N{\\fs12}So let's go ahead and import that.\r\nDialogue: 0,0:27:47.79,0:27:54.20,yin,,0,0,0,,导入 PhotosByPhotographer\\N{\\fs12}Import, m, import photos by photographer,\r\nDialogue: 0,0:27:54.20,0:27:56.73,yin,,0,0,0,,然后到下面这里\\N{\\fs12}and then let's go down here and\r\nDialogue: 0,0:27:56.73,0:27:59.72,yin,,0,0,0,,检查这就是那个类 PhotosByPhotographer\\N{\\fs12}check that that's the class, photos by photographer.\r\nDialogue: 0,0:27:59.72,0:28:03.24,yin,,0,0,0,,现在我们知道 这就是我们要的类\\N{\\fs12}Okay, so now we know that that's the class that we want.\r\nDialogue: 0,0:28:03.24,0:28:06.51,yin,,0,0,0,,这里 这个segue标识符 我们可以在这里检验\\N{\\fs12}Here, this segue identifier we can check that here,\r\nDialogue: 0,0:28:06.51,0:28:11.35,yin,,0,0,0,,记得吧 我把它设为了Show Photos by Photographer\\N{\\fs12}and if you remember, I set it to be show photos by photographer, right?\r\nDialogue: 0,0:28:11.35,0:28:13.48,yin,,0,0,0,,大家都知道这是什么\\N{\\fs12}That's, everyone know what that is, right?\r\nDialogue: 0,0:28:13.48,0:28:16.39,yin,,0,0,0,,也就是这里这个\\N{\\fs12}That is this thing right here.\r\nDialogue: 0,0:28:16.39,0:28:18.19,yin,,0,0,0,,这个小segue\\N{\\fs12}This little segue.\r\nDialogue: 0,0:28:18.19,0:28:20.75,yin,,0,0,0,,它的标识符是这个\\N{\\fs12}Okay. Its identifier is this.\r\nDialogue: 0,0:28:20.75,0:28:23.94,yin,,0,0,0,,这需要匹配我们这里所做的事情\\N{\\fs12}That's got to match what we're doing in here.\r\nDialogue: 0,0:28:23.94,0:28:26.35,yin,,0,0,0,,好 我们检验这个\\N{\\fs12}Alright, so we're checking that, and again,\r\nDialogue: 0,0:28:26.35,0:28:29.22,yin,,0,0,0,,如果我们考虑didSelectRowAtIndexPath的情形\\N{\\fs12}if we're doing the did select row at index path case\r\nDialogue: 0,0:28:29.22,0:28:30.34,yin,,0,0,0,,这里只是detail视图\\N{\\fs12}where it's just the detail view,\r\nDialogue: 0,0:28:30.34,0:28:34.59,yin,,0,0,0,,那么 segue标识符就是nil 其长度将为nil\\N{\\fs12}then the segue identifiers can be nil, so its length is going to be nil,\r\nDialogue: 0,0:28:34.59,0:28:37.33,yin,,0,0,0,,这里我用长度是为了\\N{\\fs12}and so I use length there just in case to check\r\nDialogue: 0,0:28:37.33,0:28:40.18,yin,,0,0,0,,同等地检查空字符串和nil\\N{\\fs12}for empty string and nil equally, either of them,\r\nDialogue: 0,0:28:40.18,0:28:43.63,yin,,0,0,0,,我用了非 如果没有segue标识符\\N{\\fs12}and I'm doing not, so if there's no segue identifier,\r\nDialogue: 0,0:28:43.63,0:28:49.19,yin,,0,0,0,,那么只要我们要到PhotosByPhotographerCDTVC\\N{\\fs12}then as long as we're going to a photos by photographer CDTVC,\r\nDialogue: 0,0:28:49.21,0:28:51.76,yin,,0,0,0,,我们就知道我们要怎么做\\N{\\fs12}then we know we're going to, what we're going to do.\r\nDialogue: 0,0:28:51.76,0:28:55.12,yin,,0,0,0,,有些人会认为 检查这个segue标识符\\N{\\fs12}Now, some people would argue the checking this segue identifier\r\nDialogue: 0,0:28:55.12,0:28:57.76,yin,,0,0,0,,根本就不应该做\\N{\\fs12}that you should almost never do that.\r\nDialogue: 0,0:28:57.76,0:29:02.36,yin,,0,0,0,,如果你要segue到PhotosByPhotographerCDTVC\\N{\\fs12}Because if you're segueing to photos by photographer CDTVC\r\nDialogue: 0,0:29:02.36,0:29:05.65,yin,,0,0,0,,从一个拍照者的CDTVC 你知道你在做什么\\N{\\fs12}from a photographer's CDTVC, you know what you're doing,\r\nDialogue: 0,0:29:05.65,0:29:07.83,yin,,0,0,0,,你不需要一个segue标识符告诉你 你在做什么\\N{\\fs12}you don't need a segue identifier to tell you what you're doing.\r\nDialogue: 0,0:29:07.83,0:29:09.30,yin,,0,0,0,,有些人会这样说\\N{\\fs12}That's what some people would say.\r\nDialogue: 0,0:29:09.30,0:29:11.88,yin,,0,0,0,,我认为这种说法并不错\\N{\\fs12}And I see that argument, it's not a bad argument,\r\nDialogue: 0,0:29:11.88,0:29:16.10,yin,,0,0,0,,我甚至赞同其观点 检查segue标识符\\N{\\fs12}I even buy that argument that really you only when you segue identifiers\r\nDialogue: 0,0:29:16.10,0:29:18.60,yin,,0,0,0,,只应该用到有两个不同segue的情况下\\N{\\fs12}if for some reason you had two different segues,\r\nDialogue: 0,0:29:18.60,0:29:20.94,yin,,0,0,0,,demo后面将有一个例子\\N{\\fs12}and we'll talk a little bit later in this demo an example\r\nDialogue: 0,0:29:20.94,0:29:22.97,yin,,0,0,0,,你会碰到这种情况\\N{\\fs12}of where you might actually have that.\r\nDialogue: 0,0:29:22.97,0:29:25.39,yin,,0,0,0,,你可以说 删掉这个\\N{\\fs12}So one could argue just delete that, okay,\r\nDialogue: 0,0:29:25.39,0:29:27.85,yin,,0,0,0,,把这个完全删掉 不要检查\\N{\\fs12}just get rid of that entirely, don't even check that.\r\nDialogue: 0,0:29:27.85,0:29:32.65,yin,,0,0,0,,这里我们知道 如果它是PhotosByPhotographerCDTVC\\N{\\fs12}And here we know that this is a, if it's photos by photographer CDTVC,\r\nDialogue: 0,0:29:32.65,0:29:35.49,yin,,0,0,0,,pbpcdtvc =\\N{\\fs12}photos by photographer CDTVC equals\r\nDialogue: 0,0:29:35.49,0:29:40.81,yin,,0,0,0,,(PhotosByPhotographerCDTVC *)vc\\N{\\fs12}PhotosByPhotographerCDTVC by photographer CDTVC, star, VC,\r\nDialogue: 0,0:29:40.81,0:29:42.15,yin,,0,0,0,,我们有了这个\\N{\\fs12}alright, so we have that.\r\nDialogue: 0,0:29:42.15,0:29:44.98,yin,,0,0,0,,下面我们将要准备视图控制器\\N{\\fs12}So now we're going to prepare this view controller.\r\nDialogue: 0,0:29:44.98,0:29:48.08,yin,,0,0,0,,pbpcdtvc.photographer =\\N{\\fs12}Photos by photographer dot photographer equals the\r\nDialogue: 0,0:29:48.08,0:29:51.46,yin,,0,0,0,,我们在行中选择的拍照者\\N{\\fs12}photographer that was selected in our row.\r\nDialogue: 0,0:29:56.53,0:29:58.44,yin,,0,0,0,,我们会讲到这个\\N{\\fs12}Uh, yeah, we'll talk about that.\r\nDialogue: 0,0:29:58.44,0:29:59.58,yin,,0,0,0,,问题是\\N{\\fs12}So the question is,\r\nDialogue: 0,0:29:59.58,0:30:04.00,yin,,0,0,0,,我不需要将context传给这个新控制器吗\\N{\\fs12}don't I have to pass the context to this new controller?\r\nDialogue: 0,0:30:04.00,0:30:08.99,yin,,0,0,0,,答案是需要 我在这行代码中这样做了\\N{\\fs12}And the answer is yes, and I'm doing that in this line of code right here.\r\nDialogue: 0,0:30:08.99,0:30:12.46,yin,,0,0,0,,我们来看看PhotosByPhotographer\\N{\\fs12}So let's go look at photos by photographer.\r\nDialogue: 0,0:30:12.46,0:30:15.27,yin,,0,0,0,,PhotosByPhotographer会获得这个拍照者\\N{\\fs12}So photos by photographer, it's going to get this photographer.\r\nDialogue: 0,0:30:15.27,0:30:17.03,yin,,0,0,0,,我们在PhotosByPhotographer中需要做什么\\N{\\fs12}What do we need to do in photos by photographer.\r\nDialogue: 0,0:30:17.03,0:30:18.49,yin,,0,0,0,,我们主要要做的\\N{\\fs12}Well, really the main thing we need\r\nDialogue: 0,0:30:18.49,0:30:20.96,yin,,0,0,0,,是取回该拍照者拍摄的照片\\N{\\fs12}to do is fetch the photos by that photographer.\r\nDialogue: 0,0:30:20.96,0:30:24.11,yin,,0,0,0,,我们来看看这个\\N{\\fs12}So let's go ahead and look at that.\r\nDialogue: 0,0:30:24.11,0:30:29.21,yin,,0,0,0,,每次我设置拍照者 顺便说下 你们会注意到\\N{\\fs12}Every time I set the photographer, and you're noticing, by the way,\r\nDialogue: 0,0:30:29.21,0:30:31.85,yin,,0,0,0,,每次设置公共模型时\\N{\\fs12}any time you have a public model set, you almost always are going\r\nDialogue: 0,0:30:31.85,0:30:37.27,yin,,0,0,0,,你几乎总需要setter来更新你的视图\\N{\\fs12}to use the setter to update your view when someone sets your model.\r\nDialogue: 0,0:30:37.27,0:30:38.87,yin,,0,0,0,,这是很显然的\\N{\\fs12}That's kind of an obvious thing.\r\nDialogue: 0,0:30:38.87,0:30:43.67,yin,,0,0,0,,这里我还要将标题设置为拍照者的名字\\N{\\fs12}One thing I might do here, by the way, is set my title to be the photographer's name.\r\nDialogue: 0,0:30:43.67,0:30:45.36,yin,,0,0,0,,这是一个很好的做法\\N{\\fs12}That would be a good thing, right?\r\nDialogue: 0,0:30:45.36,0:30:48.52,yin,,0,0,0,,我是一个控制器 显示一系列该拍照者拍的照片\\N{\\fs12}I'm a controller that's showing a bunch of photos by photographer,\r\nDialogue: 0,0:30:48.52,0:30:50.40,yin,,0,0,0,,我的标题显然应该是这个\\N{\\fs12}so my title might want to be that.\r\nDialogue: 0,0:30:50.40,0:30:52.71,yin,,0,0,0,,不过这里我真正需要做的是 .\\N{\\fs12}But the real thing I need to do here is\r\nDialogue: 0,0:30:52.71,0:30:55.97,yin,,0,0,0,,setupFetchedResultsController\\N{\\fs12}set up my fetched results controller.\r\nDialogue: 0,0:30:55.97,0:30:59.63,yin,,0,0,0,,这是CDTVC需要做的主要事情\\N{\\fs12}That's the main thing that CDTVCs need to do,\r\nDialogue: 0,0:30:59.63,0:31:01.72,yin,,0,0,0,,setupFetchedResultsController\\N{\\fs12}is set up their fetched results controller,\r\nDialogue: 0,0:31:01.72,0:31:03.74,yin,,0,0,0,,然后这个会自动工作\\N{\\fs12}and then they just kind of work automatically right?\r\nDialogue: 0,0:31:03.74,0:31:08.85,yin,,0,0,0,,为了节省时间 我提前准备好了 它是这样的\\N{\\fs12}So to save some time, I have that ready to go here, this is what it looks like.\r\nDialogue: 0,0:31:08.85,0:31:12.34,yin,,0,0,0,,我会一行行讲 别担心\\N{\\fs12}Let me, I'm going to go through every line of this, don't worry.\r\nDialogue: 0,0:31:12.34,0:31:15.46,yin,,0,0,0,,首先 回答你的问题 我如何得到context\\N{\\fs12}So first is answering your question, how do I get my context?\r\nDialogue: 0,0:31:15.46,0:31:18.02,yin,,0,0,0,,我需要context 没有context就无法取回\\N{\\fs12}I need a context, I can't fetch without a context.\r\nDialogue: 0,0:31:18.02,0:31:22.54,yin,,0,0,0,,答案是 我会问拍照者 你处在什么context中\\N{\\fs12}And the answer is, I'm just going to ask the photographer what context it's in.\r\nDialogue: 0,0:31:22.54,0:31:24.93,yin,,0,0,0,,有人给了我一个拍照者\\N{\\fs12}Someone gave me a photographer, and I'm going\r\nDialogue: 0,0:31:24.93,0:31:27.15,yin,,0,0,0,,我要弄清它来自什么context\\N{\\fs12}to go find out what the context is from it.\r\nDialogue: 0,0:31:27.15,0:31:28.72,yin,,0,0,0,,这个拍照者来自某个数据库\\N{\\fs12}That photographer came from some database,\r\nDialogue: 0,0:31:28.72,0:31:30.88,yin,,0,0,0,,我希望从相同数据库中获得照片\\N{\\fs12}I want to get the photos in the same database.\r\nDialogue: 0,0:31:30.88,0:31:33.40,yin,,0,0,0,,我不需要单独传递context\\N{\\fs12}So I don't need to pass the context separately,\r\nDialogue: 0,0:31:33.40,0:31:35.25,yin,,0,0,0,,它会和拍照者一同过来\\N{\\fs12}it comes along with the photographer.\r\nDialogue: 0,0:31:35.25,0:31:38.71,yin,,0,0,0,,如果context为nil 要么拍照者为nil\\N{\\fs12}If the context is nil, so either the photographer is nil,\r\nDialogue: 0,0:31:38.71,0:31:42.24,yin,,0,0,0,,要么拍照者不来自这个context 这是不可能的\\N{\\fs12}or for some weird reason the photographer didn't come from a context, that's impossible,\r\nDialogue: 0,0:31:42.24,0:31:44.92,yin,,0,0,0,,大多数时候 拍照者为nil\\N{\\fs12}but mostly this will be the photographer is nil,\r\nDialogue: 0,0:31:44.92,0:31:47.56,yin,,0,0,0,,这时 我会将FetchedResultsController设为nil\\N{\\fs12}then I'm going to set my fetch controller results to nil, that\r\nDialogue: 0,0:31:47.56,0:31:48.86,yin,,0,0,0,,我的表格会为空\\N{\\fs12}blanks out my table.\r\nDialogue: 0,0:31:48.86,0:31:51.84,yin,,0,0,0,,FetchedResultsController为nil 表格就会是空的\\N{\\fs12}If you set your FetchedResultsController to nil, then your table's going to be blank.\r\nDialogue: 0,0:31:51.84,0:31:54.09,yin,,0,0,0,,这就是我要的 你给我一个拍照者\\N{\\fs12}Which I want in this case, if someone gives me a photographer\r\nDialogue: 0,0:31:54.09,0:31:56.94,yin,,0,0,0,,没有context 或是给我nil拍照者\\N{\\fs12}with no context, or gives me nil photographer.\r\nDialogue: 0,0:31:56.94,0:32:01.76,yin,,0,0,0,,不过其它情况下 我会为所有照片设置取回请求\\N{\\fs12}But otherwise, I'm going to set up a fetch request for all the photos\r\nDialogue: 0,0:32:01.76,0:32:07.68,yin,,0,0,0,,我的谓词是 whoTook = 那个拍照者\\N{\\fs12}where my predicate is who took equals that photographer.\r\nDialogue: 0,0:32:07.69,0:32:10.32,yin,,0,0,0,,大家应该懂这一行代码吧\\N{\\fs12}Everyone understand that line of code, hopefully?\r\nDialogue: 0,0:32:10.32,0:32:12.52,yin,,0,0,0,,如果你开始了作业 你肯定能懂\\N{\\fs12}If you started on your homework, then you understand it.\r\nDialogue: 0,0:32:12.52,0:32:17.17,yin,,0,0,0,,然后我将通过照片标题对照片进行排序\\N{\\fs12}And then I'm going to show sort the photos by the photos title.\r\nDialogue: 0,0:32:17.17,0:32:19.64,yin,,0,0,0,,也就是通过照片的字典序来排序\\N{\\fs12}So they're going to be in alphabetical order by the title of the photo.\r\nDialogue: 0,0:32:19.64,0:32:24.00,yin,,0,0,0,,这是照片上的一个属性 我们会用这个排序\\N{\\fs12}So this is a property on photo, if you'll recall, and we're going to sort by that.\r\nDialogue: 0,0:32:24.00,0:32:28.10,yin,,0,0,0,,使用这种类似于finder中的排序\\N{\\fs12}Use this kind of finder like sorting order, and then that's it.\r\nDialogue: 0,0:32:28.10,0:32:30.99,yin,,0,0,0,,我创建了这个self.fetchedResultsController\\N{\\fs12}I just create this fetch, self dot fetch results controller,\r\nDialogue: 0,0:32:30.99,0:32:33.66,yin,,0,0,0,,它有这个我刚创建的请求\\N{\\fs12}it's got the request right here that I just created,\r\nDialogue: 0,0:32:33.66,0:32:35.83,yin,,0,0,0,,这是我从拍照者得到的context\\N{\\fs12}and the context, which I got from the photographer,\r\nDialogue: 0,0:32:35.83,0:32:38.77,yin,,0,0,0,,我没有做section那些 这里也没有缓存\\N{\\fs12}and I'm not doing any sections, and there's no cache.\r\nDialogue: 0,0:32:40.14,0:32:41.44,yin,,0,0,0,,这里有问题吗\\N{\\fs12}Any questions about that?\r\nDialogue: 0,0:32:41.44,0:32:44.28,yin,,0,0,0,,根据上次讲的 但愿大家都理解这个\\N{\\fs12}Hopefully everyone understands that from last time.\r\nDialogue: 0,0:32:44.28,0:32:47.89,yin,,0,0,0,,这个PhotosByPhotographer表格还需要做什么\\N{\\fs12}Now, what else does this photos by photographer table need to do?\r\nDialogue: 0,0:32:47.89,0:32:49.25,yin,,0,0,0,,没有太多东西了\\N{\\fs12}Well, not much else, okay,\r\nDialogue: 0,0:32:49.25,0:32:50.70,yin,,0,0,0,,通过发送FetchedResultsController\\N{\\fs12}by sending the fetch results controller,\r\nDialogue: 0,0:32:50.70,0:32:53.91,yin,,0,0,0,,它获得了结果 但它还需要显示这些结果\\N{\\fs12}it's getting the results, but it has to display those results,\r\nDialogue: 0,0:32:53.91,0:32:56.08,yin,,0,0,0,,因此它还需要做cellForRowAtIndexPath\\N{\\fs12}so it has to do cell for row at index path.\r\nDialogue: 0,0:32:56.08,0:32:59.81,yin,,0,0,0,,这是Core Data表格视图控制器能为你做的一件事\\N{\\fs12}That's the one thing that core data table view controller cannot do for you,\r\nDialogue: 0,0:32:59.81,0:33:01.65,yin,,0,0,0,,因为它不知道对象的什么属性\\N{\\fs12}because it doesn't know what attributes\r\nDialogue: 0,0:33:01.65,0:33:04.74,yin,,0,0,0,,你想显示在行中 我们需要这样做\\N{\\fs12}of the object you want to show in the row, so we've got to do that.\r\nDialogue: 0,0:33:04.76,0:33:07.55,yin,,0,0,0,,它需要做的另外一件事是导航\\N{\\fs12}The other thing it needs to do is navigation.\r\nDialogue: 0,0:33:07.55,0:33:09.51,yin,,0,0,0,,因为当我点击一张照片时\\N{\\fs12}Because when I click on a photo, I want to have\r\nDialogue: 0,0:33:09.51,0:33:12.13,yin,,0,0,0,,我希望图像视图控制器显示它的图像\\N{\\fs12}that image view controller show its image, right?\r\nDialogue: 0,0:33:12.13,0:33:13.41,yin,,0,0,0,,它需要做这两件事\\N{\\fs12}So it needs to do those two things.\r\nDialogue: 0,0:33:13.41,0:33:17.14,yin,,0,0,0,,但我不打算把那些放到这个类中\\N{\\fs12}But I'm not going to put those in this class.\r\nDialogue: 0,0:33:17.14,0:33:18.61,yin,,0,0,0,,为什么呢\\N{\\fs12}Why am I not going to put these in the class?\r\nDialogue: 0,0:33:18.61,0:33:21.86,yin,,0,0,0,,因为这两件事是每个显示照片的\\N{\\fs12}Because those two things every core data table view controller\r\nDialogue: 0,0:33:21.86,0:33:25.24,yin,,0,0,0,,Core Data表格视图控制器都想做的\\N{\\fs12}that shows photos wants to do. Every single one of them.\r\nDialogue: 0,0:33:25.24,0:33:27.23,yin,,0,0,0,,因此 我要创建一个通用的\\N{\\fs12}So I'm going to create a generic\r\nDialogue: 0,0:33:27.23,0:33:31.64,yin,,0,0,0,,照片Core Data表格视图控制器 它知道怎么做\\N{\\fs12}photos core data table view controller that knows how to do that.\r\nDialogue: 0,0:33:31.64,0:33:34.46,yin,,0,0,0,,然后我打算让这个类继承它\\N{\\fs12}Alright? And then I'm going to have this class inherit from it.\r\nDialogue: 0,0:33:34.46,0:33:36.66,yin,,0,0,0,,我需要强调这个\\N{\\fs12}So I'm doing this to really emphasize because a couple\r\nDialogue: 0,0:33:36.66,0:33:39.01,yin,,0,0,0,,因为有些人还不擅于\\N{\\fs12}of you, a few of you, are still struggling a little bit\r\nDialogue: 0,0:33:39.01,0:33:43.63,yin,,0,0,0,,使用面向对象的设计方式来创建控制器\\N{\\fs12}with this concept of using object oriented design to build your controllers.\r\nDialogue: 0,0:33:43.63,0:33:45.37,yin,,0,0,0,,因此我这里重复了一下\\N{\\fs12}Okay, so we're going to do it again right here.\r\nDialogue: 0,0:33:45.37,0:33:49.96,yin,,0,0,0,,我要创建一个新控制器\\N{\\fs12}So I'm going to create a new controller.\r\nDialogue: 0,0:33:49.96,0:33:53.10,yin,,0,0,0,,这将是一个新的Core Data视图控制器\\N{\\fs12}It's going to be a new core data view control,\r\nDialogue: 0,0:33:53.10,0:33:57.23,yin,,0,0,0,,名字叫PhotosCDTVC\\N{\\fs12}it's going to be called photos, core data table view controller,\r\nDialogue: 0,0:33:57.23,0:34:01.33,yin,,0,0,0,,它的全部作用就是显示一些照片\\N{\\fs12}and its job in life is to show a bunch of photos.\r\nDialogue: 0,0:34:01.33,0:34:03.93,yin,,0,0,0,,让我们这样做\\N{\\fs12}So let's do that.\r\nDialogue: 0,0:34:03.93,0:34:07.87,yin,,0,0,0,,我们来看看它的公共API是怎样的 这里\\N{\\fs12}Let's find out what its public API is, okay, here's its public API.\r\nDialogue: 0,0:34:07.87,0:34:11.61,yin,,0,0,0,,这个其实没有公共API 原因在于\\N{\\fs12}This turns out to have no public API because all you need to do\r\nDialogue: 0,0:34:11.61,0:34:17.93,yin,,0,0,0,,它只需要关联fetchedResultsController\\N{\\fs12}to make this thing work is hook up fetched results controller\r\nDialogue: 0,0:34:17.93,0:34:21.69,yin,,0,0,0,,到任何照片取回请求\\N{\\fs12}to any photo fetch request.\r\nDialogue: 0,0:34:21.69,0:34:24.89,yin,,0,0,0,,这是一个Core Data视图控制器\\N{\\fs12}This thing is a core data table view controller,\r\nDialogue: 0,0:34:24.89,0:34:27.36,yin,,0,0,0,,因此它有这个fetchedResultsController的东西\\N{\\fs12}so it has this fetched results controller thing.\r\nDialogue: 0,0:34:27.36,0:34:29.66,yin,,0,0,0,,只要你将这个fetchedResultsController\\N{\\fs12}As long as you set that fetch results controller\r\nDialogue: 0,0:34:29.66,0:34:34.02,yin,,0,0,0,,设置到任何照片取回请求 那么这个类就会\\N{\\fs12}to any photo request, then the job of this class is going to be\r\nDialogue: 0,0:34:34.02,0:34:37.06,yin,,0,0,0,,显示它并让你从它开始进行导航\\N{\\fs12}to display it and let you navigate from it as well.\r\nDialogue: 0,0:34:37.06,0:34:38.14,yin,,0,0,0,,通用\\N{\\fs12}Generic.\r\nDialogue: 0,0:34:38.14,0:34:41.95,yin,,0,0,0,,对于任何照片都适用 你什么都不需要设置\\N{\\fs12}Work for any photos, you don't even have to set anything except\r\nDialogue: 0,0:34:41.95,0:34:44.29,yin,,0,0,0,,除了fetchedResultsController\\N{\\fs12}for the fetch results controller.\r\nDialogue: 0,0:34:44.29,0:34:48.64,yin,,0,0,0,,好 来看看这个的实现 很简单\\N{\\fs12}Alright, so let's look at this guy's implementation, pretty straightforward here.\r\nDialogue: 0,0:34:48.64,0:34:50.62,yin,,0,0,0,,这些都不需要\\N{\\fs12}Don't need any of this,\r\nDialogue: 0,0:34:51.86,0:34:55.81,yin,,0,0,0,,这里 我们只需要实现两个东西\\N{\\fs12}so here we got to just implement those two things,\r\nDialogue: 0,0:34:55.81,0:34:57.73,yin,,0,0,0,,cellForRowAtIndexPath和导航\\N{\\fs12}cellForRowAtIndexPath and navigation.\r\nDialogue: 0,0:34:57.73,0:35:01.91,yin,,0,0,0,,我们来看cellForRowAtIndexPath\\N{\\fs12}So let's look at cellForRowAtIndexPath.\r\nDialogue: 0,0:35:01.91,0:35:05.42,yin,,0,0,0,,像这样 表格视图 cellForRowAtIndexPath\\N{\\fs12}Looks like this, table view, cellForRowAtIndexPath,\r\nDialogue: 0,0:35:05.42,0:35:08.27,yin,,0,0,0,,当然 我们只需要获取单元格\\N{\\fs12}and of course, we'll just get the cell.\r\nDialogue: 0,0:35:08.27,0:35:10.91,yin,,0,0,0,,这段代码 你们应该非常熟悉了\\N{\\fs12}Okay this code should be very, very familiar to you.\r\nDialogue: 0,0:35:10.91,0:35:13.80,yin,,0,0,0,,到表格视图 dequeue…\\N{\\fs12}Go to the table view, we dequeue, okay,\r\nDialogue: 0,0:35:13.82,0:35:16.67,yin,,0,0,0,,这个我叫作Photo Cell\\N{\\fs12}I'm going to call this photo cell.\r\nDialogue: 0,0:35:16.67,0:35:19.51,yin,,0,0,0,,很有趣 这是一个通用类\\N{\\fs12}Now it's interesting, this is a generic class,\r\nDialogue: 0,0:35:19.51,0:35:23.02,yin,,0,0,0,,它使用Photo Cell来再利用\\N{\\fs12}and it's using photo cell as it's reuse thing,\r\nDialogue: 0,0:35:23.02,0:35:26.98,yin,,0,0,0,,我需要将这个信息放入到它的公共头文件\\N{\\fs12}so I probably want to put that information into its public header file.\r\nDialogue: 0,0:35:26.98,0:35:28.72,yin,,0,0,0,,这里我说\\N{\\fs12}So I'm probably here going to say\r\nDialogue: 0,0:35:28.73,0:35:36.86,yin,,0,0,0,,使用Photo Cell作为表格视图单元格再利用id\\N{\\fs12}use photo cell as your table view cells reuse ID.\r\nDialogue: 0,0:35:36.86,0:35:38.95,yin,,0,0,0,,这样任何使用这个类的人\\N{\\fs12}That way anyone who is using my class\r\nDialogue: 0,0:35:38.96,0:35:40.63,yin,,0,0,0,,就无需看它的实现\\N{\\fs12}doesn't have to go look at its implementation,\r\nDialogue: 0,0:35:40.63,0:35:43.41,yin,,0,0,0,,他们可以从头文件获得这个信息\\N{\\fs12}they can just get this information from the header file and do it.\r\nDialogue: 0,0:35:43.41,0:35:44.88,yin,,0,0,0,,确保我们做了这个\\N{\\fs12}So let's make sure we do that.\r\nDialogue: 0,0:35:44.88,0:35:49.16,yin,,0,0,0,,回到这里 这是我们的PhotosByPhotographer单元格\\N{\\fs12}Let's go back here, here's our photos by photographer cell.\r\nDialogue: 0,0:35:49.16,0:35:53.28,yin,,0,0,0,,我们看看它的单元格再利用标识符是什么\\N{\\fs12}Let's see what its cells reuse identifier is,\r\nDialogue: 0,0:35:53.28,0:35:56.04,yin,,0,0,0,,答案是 哦 Flickr Photo Cell\\N{\\fs12}and the answer is, oooh, Flickr photo cell.\r\nDialogue: 0,0:35:56.04,0:35:59.10,yin,,0,0,0,,因为这是从Shutterbug借用的 那里是Flickr\\N{\\fs12}Because we stole this from Shutterbug, and Shutterbug is a Flickr thing,\r\nDialogue: 0,0:35:59.10,0:36:00.46,yin,,0,0,0,,我们这里是Core Data数据库\\N{\\fs12}whereas we are a core database thing.\r\nDialogue: 0,0:36:00.46,0:36:02.90,yin,,0,0,0,,把Flickr这个词删掉\\N{\\fs12}So I'm going to get rid of that word Flickr, and make sure\r\nDialogue: 0,0:36:02.90,0:36:06.43,yin,,0,0,0,,这就行了 Photo Cell\\N{\\fs12}that this is what it's supposed to be, photo cell.\r\nDialogue: 0,0:36:06.43,0:36:09.65,yin,,0,0,0,,大家都理解了吗\\N{\\fs12}Everyone understand that?\r\nDialogue: 0,0:36:09.65,0:36:10.52,yin,,0,0,0,,回到这里\\N{\\fs12}So back to here.\r\nDialogue: 0,0:36:10.52,0:36:15.55,yin,,0,0,0,,有了这个Photo Cell 然后怎么做呢\\N{\\fs12}So now I've got this photo cell, okay, what am I going to do with it?\r\nDialogue: 0,0:36:15.55,0:36:19.94,yin,,0,0,0,,我需要获得这个单元格中显示的照片\\N{\\fs12}Well, I need to get the photo that I'm supposed to show in this cell.\r\nDialogue: 0,0:36:19.94,0:36:26.97,yin,,0,0,0,,这是Photo * 显然 我们需要导入Photo\\N{\\fs12}So that's photo star and of course we need to import photo.\r\nDialogue: 0,0:36:26.97,0:36:30.27,yin,,0,0,0,,photo = [self.fetchedResultsController\\N{\\fs12}Photo equals self dot fetch results controller,\r\nDialogue: 0,0:36:30.27,0:36:34.10,yin,,0,0,0,,objectAtIndexPath:indexPath]\\N{\\fs12}object at index path, the index path.\r\nDialogue: 0,0:36:34.10,0:36:35.71,yin,,0,0,0,,也就是这个参数\\N{\\fs12}This argument right here.\r\nDialogue: 0,0:36:35.71,0:36:39.34,yin,,0,0,0,,你们应该能够完全理解这个\\N{\\fs12}This, hopefully, is completely you understand this.\r\nDialogue: 0,0:36:39.34,0:36:41.80,yin,,0,0,0,,然后我需要设置textLabel\\N{\\fs12}Now, I just need to set the text label.\r\nDialogue: 0,0:36:41.80,0:36:45.02,yin,,0,0,0,,其文本设为照片的标题\\N{\\fs12}I'm going to set it's text to be the photo's title,\r\nDialogue: 0,0:36:45.02,0:36:50.85,yin,,0,0,0,,然后设置detail 设为照片的副标题\\N{\\fs12}and let's set the detail, the subtext, the subtitle thing, to the photo's subtitle.\r\nDialogue: 0,0:36:50.85,0:36:52.46,yin,,0,0,0,,然后返回单元格\\N{\\fs12}And return the cell.\r\nDialogue: 0,0:36:52.46,0:36:55.54,yin,,0,0,0,,可见 写cellForRowAtIndexPath\\N{\\fs12}So you can see that writing cell for row index path\r\nDialogue: 0,0:36:55.54,0:36:57.86,yin,,0,0,0,,在Core Data表格视图单元格中很简单\\N{\\fs12}is pretty easy when it's a core data table view cell,\r\nDialogue: 0,0:36:57.86,0:37:02.07,yin,,0,0,0,,因为通常对于行中的对象 你可以得到一行代码\\N{\\fs12}because usually the object in the row which you can get one line of code\r\nDialogue: 0,0:37:02.07,0:37:04.32,yin,,0,0,0,,里面有你要的 你只需要展示它\\N{\\fs12}has what you want, you just display it.\r\nDialogue: 0,0:37:04.32,0:37:07.03,yin,,0,0,0,,下面 我们来讨论导航\\N{\\fs12}Now, let's talk about the navigation.\r\nDialogue: 0,0:37:07.03,0:37:10.29,yin,,0,0,0,,我说了我有这个通用表格视图导航的东西\\N{\\fs12}I told you I have this generic table view navigation thing,\r\nDialogue: 0,0:37:10.29,0:37:12.23,yin,,0,0,0,,这里我重新使用了它\\N{\\fs12}I'm going to use it again right here.\r\nDialogue: 0,0:37:12.25,0:37:15.31,yin,,0,0,0,,同之前那个里面完全相同\\N{\\fs12}So it's the exact same thing that I put in the other\r\nDialogue: 0,0:37:15.31,0:37:19.02,yin,,0,0,0,,我只需要确保 这个同我们这里相匹配\\N{\\fs12}one, I just have to make sure this is appropriate to what we're doing here.\r\nDialogue: 0,0:37:19.02,0:37:23.98,yin,,0,0,0,,这是照片 ManagedObject还是Photo *photo\\N{\\fs12}So this is photos, again, so the managed objects are going to be photo star photo, okay,\r\nDialogue: 0,0:37:23.98,0:37:25.88,yin,,0,0,0,,这样我就从行中得到了照片\\N{\\fs12}so now I got the photo out of the row.\r\nDialogue: 0,0:37:25.88,0:37:28.12,yin,,0,0,0,,这个在导航中做了什么\\N{\\fs12}What does this thing do in terms of navigation?\r\nDialogue: 0,0:37:28.12,0:37:29.50,yin,,0,0,0,,它会导航\\N{\\fs12}Well, it will navigate\r\nDialogue: 0,0:37:29.50,0:37:32.47,yin,,0,0,0,,到一个图像视图控制器 并展示照片\\N{\\fs12}to an image view controller and show the image.\r\nDialogue: 0,0:37:32.47,0:37:35.61,yin,,0,0,0,,让我们导入ImageViewController\\N{\\fs12}Alright? So let's import image view controller,\r\nDialogue: 0,0:37:35.61,0:37:38.42,yin,,0,0,0,,因为这就是我们要导航到的\\N{\\fs12}because that's what we're going to be navigating to.\r\nDialogue: 0,0:37:38.42,0:37:42.32,yin,,0,0,0,,到下面这里 isKindOfClass ImageViewController\\N{\\fs12}Get down here, kind of class image view controller,\r\nDialogue: 0,0:37:42.32,0:37:44.68,yin,,0,0,0,,还是一样 这里我可以跳过segue这些\\N{\\fs12}again I could probably skip the segue thing here,\r\nDialogue: 0,0:37:44.68,0:37:47.01,yin,,0,0,0,,因为如果我要导航到一个ImageViewController\\N{\\fs12}because if I'm navigating to an image view controller\r\nDialogue: 0,0:37:47.01,0:37:48.52,yin,,0,0,0,,从这个照片的视图控制器\\N{\\fs12}from this photos view controller,\r\nDialogue: 0,0:37:48.52,0:37:50.41,yin,,0,0,0,,我显然需要展示我的图像\\N{\\fs12}I almost certainly want to show my image.\r\nDialogue: 0,0:37:50.41,0:37:52.27,yin,,0,0,0,,这就是我要做的\\N{\\fs12}There's really nothing else I might want to do.\r\nDialogue: 0,0:37:52.27,0:37:53.68,yin,,0,0,0,,我来做这个\\N{\\fs12}So we'll just do that.\r\nDialogue: 0,0:37:53.68,0:37:56.24,yin,,0,0,0,,ImageViewController *ivc =\\N{\\fs12}So image view controller IVC equals\r\nDialogue: 0,0:37:56.24,0:37:59.18,yin,,0,0,0,,(ImageViewController *)vc\\N{\\fs12}image view controller VC,\r\nDialogue: 0,0:37:59.19,0:38:03.73,yin,,0,0,0,,然后我们只需要设置ivc的imageURL\\N{\\fs12}and we just need to set the IVC's image URL\r\nDialogue: 0,0:38:03.73,0:38:06.24,yin,,0,0,0,,等于一个NSURL\\N{\\fs12}equal to an NSURL\r\nDialogue: 0,0:38:06.24,0:38:09.68,yin,,0,0,0,,使用photo.imageURL\\N{\\fs12}with the photos image URL.\r\nDialogue: 0,0:38:09.68,0:38:11.23,yin,,0,0,0,,我这样做显然是因为\\N{\\fs12}The reason I have to do this, of course,\r\nDialogue: 0,0:38:11.23,0:38:13.99,yin,,0,0,0,,图像URL无法存储在数据库中\\N{\\fs12}is because you can't store an image URL in the database,\r\nDialogue: 0,0:38:13.99,0:38:15.74,yin,,0,0,0,,它只能以字符串形式存储\\N{\\fs12}we stored it as a string,\r\nDialogue: 0,0:38:15.75,0:38:17.91,yin,,0,0,0,,这会将它转化为URL\\N{\\fs12}so this converts it into a URL\r\nDialogue: 0,0:38:17.91,0:38:21.66,yin,,0,0,0,,因为图像视图控制器公共API用的是URL\\N{\\fs12}because image view controller takes a URL as it's public API.\r\nDialogue: 0,0:38:21.66,0:38:26.90,yin,,0,0,0,,我这里还可以写 title等于照片标题\\N{\\fs12}I could also do something here, title equals the photo's title.\r\nDialogue: 0,0:38:26.90,0:38:31.24,yin,,0,0,0,,因为图像视图控制器只有一个imageURL\\N{\\fs12}Because really the image view controller, since it only has an image URL,\r\nDialogue: 0,0:38:31.24,0:38:32.58,yin,,0,0,0,,它没有足够信息\\N{\\fs12}it doesn't have enough information\r\nDialogue: 0,0:38:32.58,0:38:36.60,yin,,0,0,0,,设置自身标题 同另一个一样 也就是拍照者\\N{\\fs12}to set its own title, like the other one did, the photographer,\r\nDialogue: 0,0:38:36.60,0:38:41.43,yin,,0,0,0,,我们创建的这个的子类\\N{\\fs12}this one-- this guy's subclass that we created,\r\nDialogue: 0,0:38:41.43,0:38:45.60,yin,,0,0,0,,这个无法做到 因此我们帮它设置标题\\N{\\fs12}it knew how to do it, but this one really can't so we'll help it out and set its title.\r\nDialogue: 0,0:38:45.60,0:38:48.18,yin,,0,0,0,,大家都理解了吗\\N{\\fs12}Everyone understand that?\r\nDialogue: 0,0:38:48.18,0:38:51.55,yin,,0,0,0,,现在我们有了这个很好的通用照片显示\\N{\\fs12}So now we have this nice generic photos showing thing.\r\nDialogue: 0,0:38:51.55,0:38:57.24,yin,,0,0,0,,下面再让PhotosByPhotographer继承它\\N{\\fs12}Let's go ahead and make our photos by photographer inherit from it, instead.\r\nDialogue: 0,0:38:57.24,0:39:03.33,yin,,0,0,0,,PhotosCDTVC PhotosCDTVC\\N{\\fs12}Photos CDTVC, photos CDTVC.\r\nDialogue: 0,0:39:03.33,0:39:08.34,yin,,0,0,0,,它会继承cellForRowAtIndexPath和导航的能力\\N{\\fs12}So now it just inherited the ability to do cellForRowAtIndexPath and navigation.\r\nDialogue: 0,0:39:08.34,0:39:11.61,yin,,0,0,0,,而且它仍然会自己去进行取回\\N{\\fs12}Okay, and it still does the fetch itself.\r\nDialogue: 0,0:39:11.61,0:39:14.14,yin,,0,0,0,,它决定了显示什么照片\\N{\\fs12}So it's the one determining what photos show up,\r\nDialogue: 0,0:39:14.14,0:39:16.50,yin,,0,0,0,,它的超类则将它们放到行中\\N{\\fs12}it super classes the one, putting them in the rows.\r\nDialogue: 0,0:39:16.50,0:39:19.13,yin,,0,0,0,,都理解了这里是在做什么吗\\N{\\fs12}Everyone understand what I'm doing there?\r\nDialogue: 0,0:39:20.30,0:39:22.38,yin,,0,0,0,,好 这很棒\\N{\\fs12}Okay, so that's awesome.\r\nDialogue: 0,0:39:22.38,0:39:26.46,yin,,0,0,0,,大家都知道如何导航 都知道\\N{\\fs12}Everybody kind of knows how to navigate, everyone knows how\r\nDialogue: 0,0:39:26.46,0:39:30.72,yin,,0,0,0,,如何加载自身 也许我们就只需要做这么多了\\N{\\fs12}to load themselves up, and might be that's all we need to do?\r\nDialogue: 0,0:39:30.72,0:39:32.27,yin,,0,0,0,,看看还有没有别的什么\\N{\\fs12}Let's see if I can remember anything else.\r\nDialogue: 0,0:39:32.27,0:39:34.34,yin,,0,0,0,,应该就这些了 看看能否工作\\N{\\fs12}I think that's it. So let's go see if we're working.\r\nDialogue: 0,0:39:34.34,0:39:38.18,yin,,0,0,0,,我们在iPad上试试 在真正的iPad上试\\N{\\fs12}Let's try this on the iPad, because we just built...whoops, let's do it on the real iPad.\r\nDialogue: 0,0:39:38.18,0:39:43.32,yin,,0,0,0,,我们刚创建了这个 让我们来试试\\N{\\fs12}We just built this, so let's go ahead and do that and see\r\nDialogue: 0,0:39:43.32,0:39:46.76,yin,,0,0,0,,看有没有bug 能否正常工作\\N{\\fs12}if we have any bugs, things not working.\r\nDialogue: 0,0:39:46.76,0:39:51.58,yin,,0,0,0,,或许我们忘记了什么 或许有些segue没设对\\N{\\fs12}Maybe we didn't forget, we didn't set some of our segues right or something like that,\r\nDialogue: 0,0:39:51.58,0:39:53.33,yin,,0,0,0,,看看结果怎样\\N{\\fs12}so we can see what's going on here.\r\nDialogue: 0,0:39:53.33,0:39:55.42,yin,,0,0,0,,这是Photomania\\N{\\fs12}So here it's Photo Mania,\r\nDialogue: 0,0:39:55.42,0:39:59.61,yin,,0,0,0,,但愿它在从Flickr取回数据并放入到拍照者表格\\N{\\fs12}so hopefully it's fetching from Flickr right now into this photographer table,\r\nDialogue: 0,0:39:59.61,0:40:01.13,yin,,0,0,0,,它这样做了 很好\\N{\\fs12}and it is, that's very good.\r\nDialogue: 0,0:40:01.13,0:40:02.91,yin,,0,0,0,,这里 我们得到了拍照者\\N{\\fs12}So here, we have photographers, right?\r\nDialogue: 0,0:40:02.91,0:40:04.64,yin,,0,0,0,,这就是Photomania的作用\\N{\\fs12}That's what Photo Mania does.\r\nDialogue: 0,0:40:04.64,0:40:07.32,yin,,0,0,0,,Shutterbug取回的是照片 显示的是照片标题\\N{\\fs12}Shutterbug fetched the photos and showed you the photos titles,\r\nDialogue: 0,0:40:07.32,0:40:10.75,yin,,0,0,0,,而Photomania取回照片 显示的则是拍照者\\N{\\fs12}Photo Mania fetches the photos and then shows you the photographer.\r\nDialogue: 0,0:40:10.75,0:40:12.23,yin,,0,0,0,,我们可以看\\N{\\fs12}And we can look and see, some\r\nDialogue: 0,0:40:12.23,0:40:14.72,yin,,0,0,0,,有些拍照者有三张照片 有些有九张\\N{\\fs12}of our photographers have three photos, some nine,\r\nDialogue: 0,0:40:14.72,0:40:16.78,yin,,0,0,0,,让我们来选这个九张的\\N{\\fs12}so let's pick this guy, he has nine.\r\nDialogue: 0,0:40:16.78,0:40:18.74,yin,,0,0,0,,再选这个拍了三张的\\N{\\fs12}Let's pick this guy, he has three.\r\nDialogue: 0,0:40:18.74,0:40:20.32,yin,,0,0,0,,我们可以点选其中一张\\N{\\fs12}And we can click on one of these.\r\nDialogue: 0,0:40:20.32,0:40:24.21,yin,,0,0,0,,但愿没什么… 这是里约热内卢 或许我们该选点别的\\N{\\fs12}Again, hopefully nothing, this is Rio De Janeiro, maybe we'll pick somewhere else.\r\nDialogue: 0,0:40:24.21,0:40:26.38,yin,,0,0,0,,这里没有标题\\N{\\fs12}No, there's no titles.\r\nDialogue: 0,0:40:26.38,0:40:27.37,yin,,0,0,0,,这个呢\\N{\\fs12}Uh, how about this one?\r\nDialogue: 0,0:40:27.37,0:40:28.78,yin,,0,0,0,,也没有标题\\N{\\fs12}Nah, there's no titles.\r\nDialogue: 0,0:40:28.78,0:40:30.14,yin,,0,0,0,,还是来看里约\\N{\\fs12}Okay, we'll do Rio.\r\nDialogue: 0,0:40:30.14,0:40:32.35,yin,,0,0,0,,但愿里约没有什么糟糕的东西\\N{\\fs12}Hopefully Rio is not going to do anything bad.\r\nDialogue: 0,0:40:32.35,0:40:33.61,yin,,0,0,0,,就点它吧\\N{\\fs12}Here we go.\r\nDialogue: 0,0:40:33.61,0:40:35.80,yin,,0,0,0,,这是里约 很棒嘛\\N{\\fs12}There's Rio. Oh, good! Not bad.\r\nDialogue: 0,0:40:35.80,0:40:39.30,yin,,0,0,0,,这就是我们的图像视图控制器 它工作得很好\\N{\\fs12}Okay, so there's our image view controller, so this all worked great.\r\nDialogue: 0,0:40:39.30,0:40:42.83,yin,,0,0,0,,但愿在竖屏模式下也能正常工作\\N{\\fs12}So hopefully it works here in portrait mode too\r\nDialogue: 0,0:40:42.83,0:40:44.84,yin,,0,0,0,,好像也能正常工作\\N{\\fs12}and it does seem to be working there too.\r\nDialogue: 0,0:40:46.98,0:40:51.46,yin,,0,0,0,,好 这是这个\\N{\\fs12}Okay, There we go. So that's that.\r\nDialogue: 0,0:40:51.48,0:40:54.56,yin,,0,0,0,,你们都了解了 它工作得很好\\N{\\fs12}You guys all got that? It worked perfectly.\r\nDialogue: 0,0:40:54.56,0:40:58.32,yin,,0,0,0,,下面我们就可以进入到下一个内容了\\N{\\fs12}So now we can quickly move on to the next thing we're going to show,\r\nDialogue: 0,0:40:58.32,0:41:03.77,yin,,0,0,0,,下面我们要展示的是…\\N{\\fs12}which is we're going to show how to put a little--\r\nDialogue: 0,0:41:03.78,0:41:07.45,yin,,0,0,0,,这里用横屏模式\\N{\\fs12}put it in landscape mode just to show here--\r\nDialogue: 0,0:41:07.45,0:41:10.81,yin,,0,0,0,,在这只鸭子的鼻子上面\\N{\\fs12}so right above where this duck's nose is, okay,\r\nDialogue: 0,0:41:10.81,0:41:14.32,yin,,0,0,0,,我想放一个小按钮 叫URL 点击它时\\N{\\fs12}I'm going to put a little button called URL, and when I click\r\nDialogue: 0,0:41:14.32,0:41:16.96,yin,,0,0,0,,它会弹窗 然后在弹窗中\\N{\\fs12}on it, it's going to do a popover, and in that popover,\r\nDialogue: 0,0:41:16.96,0:41:19.79,yin,,0,0,0,,它会展示这里显示的URL\\N{\\fs12}it's going to show me the URL that's showing here,\r\nDialogue: 0,0:41:19.79,0:41:22.25,yin,,0,0,0,,文本 也就是http://那些\\N{\\fs12}the text of it, you know, http slash something.\r\nDialogue: 0,0:41:22.25,0:41:25.55,yin,,0,0,0,,这里主要是要给你们演示如何弹窗\\N{\\fs12}Okay, so this is mostly to show you how to do popovers.\r\nDialogue: 0,0:41:25.55,0:41:28.84,yin,,0,0,0,,回头看看怎么做这个\\N{\\fs12}So let's go back and see how we would do that.\r\nDialogue: 0,0:41:28.84,0:41:31.94,yin,,0,0,0,,其实很简单\\N{\\fs12}This turns out to be quite straightforward.\r\nDialogue: 0,0:41:31.94,0:41:35.62,yin,,0,0,0,,这是我们的UI 我们希望做的是\\N{\\fs12}So here we are, here's our UI, and what we want\r\nDialogue: 0,0:41:35.62,0:41:39.98,yin,,0,0,0,,在这里加一个小按钮 显示URL\\N{\\fs12}to do is add a little button here that does URL.\r\nDialogue: 0,0:41:40.00,0:41:43.92,yin,,0,0,0,,我只需要把这个栏按钮项目拖到栏上这里\\N{\\fs12}Okay. So we're going to drag this bar button item into the bar here,\r\nDialogue: 0,0:41:43.92,0:41:45.55,yin,,0,0,0,,我把它称作URL\\N{\\fs12}and we're going to call it URL.\r\nDialogue: 0,0:41:45.55,0:41:47.48,yin,,0,0,0,,这将是一个栏按钮项目\\N{\\fs12}Okay, so this is going to be a bar button item\r\nDialogue: 0,0:41:47.48,0:41:51.74,yin,,0,0,0,,点击它时会出现一个弹窗在这里\\N{\\fs12}that when you click on it, it's going to bring up a popover here,\r\nDialogue: 0,0:41:51.74,0:41:54.27,yin,,0,0,0,,一个小的视图控制器会出现\\N{\\fs12}a little view or view controller that's going\r\nDialogue: 0,0:41:54.27,0:41:56.62,yin,,0,0,0,,覆盖到其它东西之上\\N{\\fs12}to appear, overlapping everything else.\r\nDialogue: 0,0:41:56.62,0:41:59.09,yin,,0,0,0,,怎么做到呢\\N{\\fs12}So how do we do that?\r\nDialogue: 0,0:41:59.09,0:42:01.09,yin,,0,0,0,,答案是这样的\\N{\\fs12}And the answer for that is\r\nDialogue: 0,0:42:01.09,0:42:05.67,yin,,0,0,0,,我们创建一个全新的视图控制器\\N{\\fs12}that we create an entirely new view controller.\r\nDialogue: 0,0:42:05.67,0:42:09.24,yin,,0,0,0,,弹窗segue是常规segue\\N{\\fs12}A popup, a popover segue is a normal segue.\r\nDialogue: 0,0:42:09.24,0:42:11.14,yin,,0,0,0,,segue到一个新的视图控制器\\N{\\fs12}You segue to a new view controller.\r\nDialogue: 0,0:42:11.14,0:42:13.31,yin,,0,0,0,,我们将创建一个新视图控制器用于显示这里的URL\\N{\\fs12}So we're going to create a new view controller that's going\r\nDialogue: 0,0:42:13.31,0:42:17.00,yin,,0,0,0,,我们将创建一个新视图控制器用于显示这里的URL\\N{\\fs12}to display the URL that's showing here in image view controller.\r\nDialogue: 0,0:42:17.00,0:42:20.50,yin,,0,0,0,,如何创建一个新视图控制器呢 你们都知道怎么做\\N{\\fs12}Alright? So how do we create a new view controller, you all know how to do that.\r\nDialogue: 0,0:42:20.50,0:42:23.28,yin,,0,0,0,,到这里 到最上面\\N{\\fs12}We go into here, we go up to the top,\r\nDialogue: 0,0:42:23.28,0:42:25.75,yin,,0,0,0,,将一个视图控制器拖出来\\N{\\fs12}we grab a view controller and we drag it out.\r\nDialogue: 0,0:42:25.75,0:42:29.09,yin,,0,0,0,,这个控制器太大了\\N{\\fs12}Now this view controller is quite big,\r\nDialogue: 0,0:42:29.09,0:42:32.06,yin,,0,0,0,,把它弄好看一些 这是我们的视图控制器\\N{\\fs12}let's make it so we can see a little better. So here's our view controller.\r\nDialogue: 0,0:42:32.06,0:42:34.23,yin,,0,0,0,,这就是弹窗的视图控制器\\N{\\fs12}So this is the view controller, it's going to pop over.\r\nDialogue: 0,0:42:34.23,0:42:39.72,yin,,0,0,0,,我们下面将通过control拖动创建一个segue\\N{\\fs12}And we then just create a segue by control dragging,\r\nDialogue: 0,0:42:39.72,0:42:42.20,yin,,0,0,0,,按住control 然后拖动\\N{\\fs12}so I'm holding down control, and dragging,\r\nDialogue: 0,0:42:42.20,0:42:46.27,yin,,0,0,0,,同其它segue一样 这将是一个弹窗segue\\N{\\fs12}just like any other segue, and this is going to be a popover segue.\r\nDialogue: 0,0:42:46.27,0:42:48.85,yin,,0,0,0,,这是我们第一次选popover\\N{\\fs12}So this is the first time we've ever done popover.\r\nDialogue: 0,0:42:48.85,0:42:54.34,yin,,0,0,0,,创建了弹窗segue之后 你就可以\\N{\\fs12}So now once you create a popover segue, you can now kind\r\nDialogue: 0,0:42:54.34,0:42:58.60,yin,,0,0,0,,以任何你想要的方式创建这个视图控制器\\N{\\fs12}of create this view controller how ever you want, it's a look, to pop over.\r\nDialogue: 0,0:42:58.60,0:43:01.65,yin,,0,0,0,,你需要设置它的大小\\N{\\fs12}And one of the things you might want to set it its size.\r\nDialogue: 0,0:43:01.65,0:43:04.97,yin,,0,0,0,,毕竟弹窗不能这么大\\N{\\fs12}Because if this is our popover size, that's not going\r\nDialogue: 0,0:43:04.97,0:43:07.73,yin,,0,0,0,,否则整个屏幕都被盖住就太糟糕了\\N{\\fs12}to be good. It's going to cover our whole screen, that's going to be horrendous.\r\nDialogue: 0,0:43:07.73,0:43:11.55,yin,,0,0,0,,显示URL只需要很小的弹窗\\N{\\fs12}So display URL, we only need it to be small.\r\nDialogue: 0,0:43:11.55,0:43:14.37,yin,,0,0,0,,一行就行了 不换行\\N{\\fs12}And it's nice to have URL on one line so it's not wrapping\r\nDialogue: 0,0:43:14.37,0:43:15.93,yin,,0,0,0,,URL有很多斜杠\\N{\\fs12}because URLs have all those slashes.\r\nDialogue: 0,0:43:15.95,0:43:19.39,yin,,0,0,0,,我们试试一个很宽的 让它能容纳在一行内\\N{\\fs12}So let's try to make a really wide one that will hopefully fit in one line.\r\nDialogue: 0,0:43:19.39,0:43:22.84,yin,,0,0,0,,如何改变视图控制器的大小呢\\N{\\fs12}So how do we change the size of a view controller?\r\nDialogue: 0,0:43:22.84,0:43:24.58,yin,,0,0,0,,一般的视图控制器\\N{\\fs12}Because all our other view controllers have kind\r\nDialogue: 0,0:43:24.58,0:43:27.99,yin,,0,0,0,,都可以用这些模拟衡量来推测大小\\N{\\fs12}of inferred their size using these simulated metrics right\r\nDialogue: 0,0:43:27.99,0:43:30.50,yin,,0,0,0,,这里看到推断大小了吗\\N{\\fs12}here, you see this inferred size?\r\nDialogue: 0,0:43:30.50,0:43:34.02,yin,,0,0,0,,但弹窗控制器很特殊\\N{\\fs12}But a pop up view, a popover's controller is\r\nDialogue: 0,0:43:34.02,0:43:36.53,yin,,0,0,0,,你可以改变它的大小\\N{\\fs12}special in that you can change its size,\r\nDialogue: 0,0:43:36.53,0:43:41.11,yin,,0,0,0,,要想这样做 Xcode必须先知道它是弹窗视图\\N{\\fs12}notice that you won't be able to do this until X code knows that this is a pop up view,\r\nDialogue: 0,0:43:41.11,0:43:42.76,yin,,0,0,0,,弹窗视图控制器 或者至少\\N{\\fs12}popover view controller, or at least knows\r\nDialogue: 0,0:43:42.76,0:43:46.08,yin,,0,0,0,,这个视图控制器处在弹窗环境中\\N{\\fs12}that this view controller is going to be in a popover context\r\nDialogue: 0,0:43:46.08,0:43:49.01,yin,,0,0,0,,因为这个弹窗segue\\N{\\fs12}because of this segue right here, this popover segue.\r\nDialogue: 0,0:43:49.01,0:43:52.84,yin,,0,0,0,,这样做之后 进入视图控制器\\N{\\fs12}Once you do that, if you go to your view controller\r\nDialogue: 0,0:43:52.84,0:43:56.71,yin,,0,0,0,,选择它的视图 self.view 你就可以到尺度这里\\N{\\fs12}and select its view, self dot view, then you can go dimensions\r\nDialogue: 0,0:43:56.71,0:43:58.80,yin,,0,0,0,,编辑这些东西\\N{\\fs12}and these will be editable.\r\nDialogue: 0,0:43:58.80,0:43:59.93,yin,,0,0,0,,宽和高\\N{\\fs12}The width and height.\r\nDialogue: 0,0:43:59.93,0:44:04.62,yin,,0,0,0,,例如这里可以设为600像素宽 40像素高\\N{\\fs12}So, for example, we could make this 600 wide, and maybe 40 pixels high.\r\nDialogue: 0,0:44:04.62,0:44:07.76,yin,,0,0,0,,或许看起来会不错\\N{\\fs12}Which is probably a pretty good looking thing.\r\nDialogue: 0,0:44:07.76,0:44:10.63,yin,,0,0,0,,这就意味着 点击URL按钮时\\N{\\fs12}So that means when we press this URL button it's going to pop\r\nDialogue: 0,0:44:10.63,0:44:13.79,yin,,0,0,0,,这个弹窗会出现 大小很合适\\N{\\fs12}over and be something like that, that's pretty good size,\r\nDialogue: 0,0:44:13.79,0:44:18.95,yin,,0,0,0,,600是弹窗最大的允许值\\N{\\fs12}600 is the widest they will allow you to make a popover.\r\nDialogue: 0,0:44:18.95,0:44:24.35,yin,,0,0,0,,如果指定数值大于600 它这里估计只会显示600\\N{\\fs12}So I think if you specify more than 600, it's only going to show up 600.\r\nDialogue: 0,0:44:24.35,0:44:26.75,yin,,0,0,0,,高度可以任意设置\\N{\\fs12}Alright, and you can make it any height you want,\r\nDialogue: 0,0:44:26.75,0:44:30.73,yin,,0,0,0,,不过显然 你不希望它太大 否则所有内容都会被覆盖\\N{\\fs12}although obviously you wouldn't want it too big, cover up all content underneath.\r\nDialogue: 0,0:44:30.73,0:44:33.58,yin,,0,0,0,,弹窗会覆盖它下面的一切东西\\N{\\fs12}It doesn't really make a-- a popover that would cover up everything, you would want\r\nDialogue: 0,0:44:33.58,0:44:36.79,yin,,0,0,0,,你也可以使用别的segue 例如modal segue\\N{\\fs12}to use a different kind of segue, a modal segue in that case.\r\nDialogue: 0,0:44:36.79,0:44:41.45,yin,,0,0,0,,我们有了这个 这是一个普通的视图控制器\\N{\\fs12}So we have this, and then this is just a normal view controller\r\nDialogue: 0,0:44:41.45,0:44:43.65,yin,,0,0,0,,我们有了这个 这是一个普通的视图控制器\\N{\\fs12}otherwise, this little view controller thing.\r\nDialogue: 0,0:44:43.65,0:44:47.87,yin,,0,0,0,,我们需要创建一个视图控制器的子类 成为它的子类\\N{\\fs12}So we need to create a subclass of view controller to be its subclass.\r\nDialogue: 0,0:44:47.87,0:44:49.92,yin,,0,0,0,,我们这样做\\N{\\fs12}So let's do that.\r\nDialogue: 0,0:44:49.92,0:44:52.68,yin,,0,0,0,,这个视图控制器做什么呢\\N{\\fs12}And what does this view controller do?\r\nDialogue: 0,0:44:52.68,0:44:56.35,yin,,0,0,0,,这是一个普通的UIViewController\\N{\\fs12}Well, it's a normal UI view controller.\r\nDialogue: 0,0:44:59.80,0:45:02.13,yin,,0,0,0,,它的作用不过是显示URL\\N{\\fs12}And it displays a URL,\r\nDialogue: 0,0:45:02.13,0:45:04.33,yin,,0,0,0,,我将称之为URLViewController\\N{\\fs12}that's all it does, so I'm going to call it URL view controller,\r\nDialogue: 0,0:45:04.33,0:45:07.04,yin,,0,0,0,,这就是它的作用 显示URL\\N{\\fs12}because that's what it does, displays the URL.\r\nDialogue: 0,0:45:07.04,0:45:09.74,yin,,0,0,0,,放到通常放的位置\\N{\\fs12}We'll put it in the place we usually put it.\r\nDialogue: 0,0:45:09.74,0:45:13.64,yin,,0,0,0,,放到下面这里 放到这附近\\N{\\fs12}Actually let's put it down here, eh, somewhere like here.\r\nDialogue: 0,0:45:13.64,0:45:15.77,yin,,0,0,0,,它的公共API是什么\\N{\\fs12}What's its public API?\r\nDialogue: 0,0:45:15.77,0:45:22.14,yin,,0,0,0,,很简单 属性 非原子 强 NSURL url\\N{\\fs12}Very simple, property, non-atomic strong, NSURL, URL.\r\nDialogue: 0,0:45:22.16,0:45:24.19,yin,,0,0,0,,这就是它要显示的URL\\N{\\fs12}That's the URL it's going to display.\r\nDialogue: 0,0:45:24.19,0:45:26.61,yin,,0,0,0,,它的实现是什么\\N{\\fs12}What's its implementation?\r\nDialogue: 0,0:45:26.61,0:45:28.97,yin,,0,0,0,,也很简单\\N{\\fs12}Also really, really easy.\r\nDialogue: 0,0:45:28.97,0:45:30.42,yin,,0,0,0,,删掉这个\\N{\\fs12}Let's get rid of this.\r\nDialogue: 0,0:45:30.42,0:45:37.27,yin,,0,0,0,,设置它的URL时 它会更新它的UI\\N{\\fs12}It's going, when you set its URL, it's going to update its UI,\r\nDialogue: 0,0:45:37.27,0:45:41.18,yin,,0,0,0,,这不是表格视图控制器 我们需要更新UI\\N{\\fs12}now this is not a table view controller, so we're going to have to write the update UI,\r\nDialogue: 0,0:45:41.18,0:45:44.79,yin,,0,0,0,,当视图确实发生加载\\N{\\fs12}also when it's view did load happens,\r\nDialogue: 0,0:45:47.79,0:45:51.26,yin,,0,0,0,,也要更新它的UI 别忘了这部分\\N{\\fs12}also wants to update its UI, don't forget this part.\r\nDialogue: 0,0:45:51.26,0:45:54.65,yin,,0,0,0,,当这是表格视图控制器时\\N{\\fs12}Okay, when you have non-table view, table view controllers,\r\nDialogue: 0,0:45:54.65,0:45:58.68,yin,,0,0,0,,这个setURL可以在outlet设置之前调用\\N{\\fs12}this set URL might be called before your outlets are set.\r\nDialogue: 0,0:45:58.68,0:46:02.42,yin,,0,0,0,,updateUI什么都不会做 因为你没有outlet\\N{\\fs12}So update UI might do nothing because you have no outlets.\r\nDialogue: 0,0:46:02.42,0:46:04.73,yin,,0,0,0,,你要再做一次 viewDidLoad\\N{\\fs12}So you want to do it again, view did load.\r\nDialogue: 0,0:46:04.73,0:46:07.46,yin,,0,0,0,,这个代价并不大 因此我打算这样做\\N{\\fs12}This is very inexpensive to do, so I'm just going to do it,\r\nDialogue: 0,0:46:07.46,0:46:09.96,yin,,0,0,0,,也许是两次 如果有人要设置这个\\N{\\fs12}possibly twice, if someone were to set this\r\nDialogue: 0,0:46:09.96,0:46:12.29,yin,,0,0,0,,而我的outlet已经设置 然后viewDidLoad发生\\N{\\fs12}and my outlets were set, and view did load happened\r\nDialogue: 0,0:46:12.29,0:46:14.57,yin,,0,0,0,,这之后 它可能发生两次\\N{\\fs12}after that, it might happen twice, but it's very inexpensive\r\nDialogue: 0,0:46:14.57,0:46:17.25,yin,,0,0,0,,但更新UI代价不大 我可以这样做\\N{\\fs12}to update my UI, so I can do that.\r\nDialogue: 0,0:46:17.25,0:46:19.65,yin,,0,0,0,,我们需要写updateUI\\N{\\fs12}So we need to write update UI.\r\nDialogue: 0,0:46:19.67,0:46:21.58,yin,,0,0,0,,要updateUI 我们需要一个UI\\N{\\fs12}To update UI, we need a UI,\r\nDialogue: 0,0:46:21.58,0:46:24.58,yin,,0,0,0,,我们回到故事板 给这个一个UI\\N{\\fs12}so let's go back to our storyboard and give this thing a UI.\r\nDialogue: 0,0:46:24.60,0:46:28.36,yin,,0,0,0,,对于这个UI 我只需要拖出一个文本视图\\N{\\fs12}And what I'm going to do for this UI is just drag out a text view,\r\nDialogue: 0,0:46:28.36,0:46:29.90,yin,,0,0,0,,到下面这里\\N{\\fs12}so I'm going to go down here,\r\nDialogue: 0,0:46:29.90,0:46:34.16,yin,,0,0,0,,找到文本视图 这里 之前我们用过\\N{\\fs12}find a text view right here, we saw a text view from before,\r\nDialogue: 0,0:46:34.16,0:46:36.32,yin,,0,0,0,,文本视图放到这里\\N{\\fs12}so I'm going to put the text view in here.\r\nDialogue: 0,0:46:36.32,0:46:38.59,yin,,0,0,0,,对齐一下\\N{\\fs12}I'm going to line it up,\r\nDialogue: 0,0:46:38.59,0:46:42.64,yin,,0,0,0,,然后让它自动布局\\N{\\fs12}let's go ahead and get its auto layout going,\r\nDialogue: 0,0:46:42.65,0:46:44.78,yin,,0,0,0,,我要重置 给出约束条件\\N{\\fs12}so I'm going to reset to suggest the constraints,\r\nDialogue: 0,0:46:44.78,0:46:47.57,yin,,0,0,0,,我要检验它有没有做好的事情\\N{\\fs12}I'm going to check to see if it did something good,\r\nDialogue: 0,0:46:47.57,0:46:48.81,yin,,0,0,0,,它显然做了\\N{\\fs12}which, it definitely did.\r\nDialogue: 0,0:46:48.81,0:46:52.56,yin,,0,0,0,,它会紧跟超视图的大小 我很喜欢这样\\N{\\fs12}You see that it's going to stick to the size of its super view, I like that.\r\nDialogue: 0,0:46:52.56,0:46:55.61,yin,,0,0,0,,我们再来检视文本视图 我不要这些代码\\N{\\fs12}Let's inspect the text view, I don't want all this code,\r\nDialogue: 0,0:46:55.61,0:47:03.48,yin,,0,0,0,,这里我只要http://www.stanford.edu\\N{\\fs12}I'm going to put like http slash, slash, www dot Stanford dot edu, okay, in there,\r\nDialogue: 0,0:47:03.48,0:47:07.61,yin,,0,0,0,,这看起来很糟 把它弄大一些\\N{\\fs12}that looks terrible, let's make it a little bigger.\r\nDialogue: 0,0:47:07.61,0:47:09.61,yin,,0,0,0,,18点 这样就更好了\\N{\\fs12}18 point, that looks better.\r\nDialogue: 0,0:47:09.61,0:47:15.64,yin,,0,0,0,,再让它居中 让它可选择\\N{\\fs12}Let's make it be centered, let's make it be selectable\r\nDialogue: 0,0:47:15.64,0:47:18.08,yin,,0,0,0,,但不可编辑 用户可以选择这个\\N{\\fs12}but not editable, so someone could select this and then copy\r\nDialogue: 0,0:47:18.08,0:47:20.71,yin,,0,0,0,,然后复制粘贴到浏览器\\N{\\fs12}and paste it into their browser and look at it that way,\r\nDialogue: 0,0:47:20.71,0:47:22.91,yin,,0,0,0,,这很好 你显然希望它能这样\\N{\\fs12}so that's good, we definitely like that.\r\nDialogue: 0,0:47:22.91,0:47:24.04,yin,,0,0,0,,这看起来很棒\\N{\\fs12}So that looks pretty good.\r\nDialogue: 0,0:47:24.04,0:47:27.87,yin,,0,0,0,,这是样子很不错的URL\\N{\\fs12}That's a pretty good looking view of URL,\r\nDialogue: 0,0:47:27.87,0:47:31.05,yin,,0,0,0,,然后再把这个和outlet关联起来\\N{\\fs12}and so now let's go ahead and wire this up to an outlet.\r\nDialogue: 0,0:47:31.05,0:47:32.57,yin,,0,0,0,,注意到我这样做时\\N{\\fs12}Notice that when I do that,\r\nDialogue: 0,0:47:32.57,0:47:35.10,yin,,0,0,0,,它会尝试UIViewController 为什么这样呢\\N{\\fs12}it's trying to do UI view controller, why is that?\r\nDialogue: 0,0:47:35.10,0:47:38.35,yin,,0,0,0,,这是因为我们需要设置这个的id\\N{\\fs12}That's because we need to set the identity of this thing\r\nDialogue: 0,0:47:38.35,0:47:41.07,yin,,0,0,0,,这是UIViewController\\N{\\fs12}to be a URL view controller, right?\r\nDialogue: 0,0:47:41.07,0:47:42.90,yin,,0,0,0,,一个普通的视图控制器\\N{\\fs12}This thought it was a general view controller,\r\nDialogue: 0,0:47:42.90,0:47:46.04,yin,,0,0,0,,这样做之后 它就理解了\\N{\\fs12}as soon as I do that, you can see that now it understands\r\nDialogue: 0,0:47:46.04,0:47:48.12,yin,,0,0,0,,这是一个URL视图控制器\\N{\\fs12}that this is a URL view controller.\r\nDialogue: 0,0:47:48.14,0:47:51.90,yin,,0,0,0,,下面我要拖动创建outlet到这个文本视图\\N{\\fs12}So I'm going to go ahead and drag to create an outlet to that text view.\r\nDialogue: 0,0:47:51.90,0:47:56.13,yin,,0,0,0,,称其为urlTextView\\N{\\fs12}I'll call it URL text view.\r\nDialogue: 0,0:47:56.13,0:47:57.14,yin,,0,0,0,,就是这个\\N{\\fs12}There it is.\r\nDialogue: 0,0:47:57.14,0:47:59.11,yin,,0,0,0,,常规IBOutlet\\N{\\fs12}Normal IB outlet.\r\nDialogue: 0,0:47:59.11,0:48:05.83,yin,,0,0,0,,下面我们采用代码全屏 像这样\\N{\\fs12}Let's go ahead and go full screen on the code here, like that.\r\nDialogue: 0,0:48:05.83,0:48:08.70,yin,,0,0,0,,然后是updateUI 也就是\\N{\\fs12}And now we can do our update UI, which is that,\r\nDialogue: 0,0:48:08.70,0:48:15.13,yin,,0,0,0,,将urlTextView设为URL\\N{\\fs12}let's just have our URL text view's text be the URLs,\r\nDialogue: 0,0:48:15.13,0:48:17.50,yin,,0,0,0,,其路径\\N{\\fs12}its path basically\r\nDialogue: 0,0:48:17.50,0:48:20.35,yin,,0,0,0,,URL中有个方法叫absoluteString\\N{\\fs12}and there's a method in URL called absolute string,\r\nDialogue: 0,0:48:20.35,0:48:24.27,yin,,0,0,0,,这会返回URL的绝对路径\\N{\\fs12}which will return the absolute path of that URL.\r\nDialogue: 0,0:48:24.27,0:48:26.36,yin,,0,0,0,,抱歉 self.url\\N{\\fs12}Sorry, self dot URL.\r\nDialogue: 0,0:48:26.36,0:48:30.62,yin,,0,0,0,,绝对路径作为字符串 这就是我们要的 文本是字符串\\N{\\fs12}The absolute path as a string, which is what we want, because text is a string.\r\nDialogue: 0,0:48:30.62,0:48:32.19,yin,,0,0,0,,我们可以做很多有趣的事\\N{\\fs12}And we can do a lot more fun things,\r\nDialogue: 0,0:48:32.19,0:48:35.20,yin,,0,0,0,,带属性文本视图 设置字体 颜色等等\\N{\\fs12}attribute a text view, you can set fonts, colors, whatever,\r\nDialogue: 0,0:48:35.20,0:48:37.65,yin,,0,0,0,,这里我们只打算写一个很简单的updateUI\\N{\\fs12}but we're just going to do a very, very simple update UI.\r\nDialogue: 0,0:48:37.65,0:48:41.59,yin,,0,0,0,,现在有了这个URL视图控制器 我们将segue到它\\N{\\fs12}So now we have this URL view controller, okay, that we're going to segue to.\r\nDialogue: 0,0:48:41.59,0:48:44.38,yin,,0,0,0,,这是一个segue 我们正在segue…\\N{\\fs12}Right? This is a segue. We are segueing...\r\nDialogue: 0,0:48:44.38,0:48:46.82,yin,,0,0,0,,汗 我应该把doc放到别处\\N{\\fs12}man, I should put my doc somewhere else.\r\nDialogue: 0,0:48:46.82,0:48:49.96,yin,,0,0,0,,我们正从这个视图控制器segue\\N{\\fs12}We are segueing from this view controller,\r\nDialogue: 0,0:48:49.96,0:48:52.98,yin,,0,0,0,,这是一个图像视图控制器\\N{\\fs12}which is an image view controller, right,\r\nDialogue: 0,0:48:52.98,0:48:56.60,yin,,0,0,0,,到这个 这是一个URL视图控制器\\N{\\fs12}to this which is a URL view controller,\r\nDialogue: 0,0:48:56.60,0:48:59.38,yin,,0,0,0,,通过这里的这个segue\\N{\\fs12}via this segue right here.\r\nDialogue: 0,0:48:59.38,0:49:04.11,yin,,0,0,0,,让我们给这个segue起个名字\\N{\\fs12}So let's go ahead and give that segue a name.\r\nDialogue: 0,0:49:04.11,0:49:07.87,yin,,0,0,0,,叫作Show URL 这个名字不错\\N{\\fs12}We'll call it show URL, that's probably a good name for it.\r\nDialogue: 0,0:49:07.87,0:49:10.76,yin,,0,0,0,,然后对它进行prepareForSegue\\N{\\fs12}And let's do the prepare for segue for this.\r\nDialogue: 0,0:49:10.76,0:49:12.21,yin,,0,0,0,,这是我们要做的最后一件事\\N{\\fs12}That's the last piece we have to do.\r\nDialogue: 0,0:49:12.21,0:49:13.71,yin,,0,0,0,,如何为这个segue做准备呢\\N{\\fs12}So how are we going to prepare for this segue?\r\nDialogue: 0,0:49:13.71,0:49:15.14,yin,,0,0,0,,这是一个普通的segue\\N{\\fs12}It's a normal segue.\r\nDialogue: 0,0:49:15.14,0:49:18.45,yin,,0,0,0,,这个图像视图控制器就是它发生的地方\\N{\\fs12}This image view controller is where it happens, right?\r\nDialogue: 0,0:49:18.45,0:49:23.55,yin,,0,0,0,,UI就在这里 因此我们需要把prepareForSegue放到这里\\N{\\fs12}That's where the UI is, so that's where we have to put the prepare for segue.\r\nDialogue: 0,0:49:23.55,0:49:27.59,yin,,0,0,0,,让我们这样做 把它放到下面这里\\N{\\fs12}So we're going to do that. Let's put it right down here.\r\nDialogue: 0,0:49:27.59,0:49:33.61,yin,,0,0,0,,这里我要放一个#pragma mark - Navigation\\N{\\fs12}So I'm going to put a nice pragma mark navigation,\r\nDialogue: 0,0:49:33.61,0:49:37.67,yin,,0,0,0,,然后我要写 (void)prepareForSegue\\N{\\fs12}and I'm just going to do void prepare for segue.\r\nDialogue: 0,0:49:37.67,0:49:39.62,yin,,0,0,0,,这里 我只打算写\\N{\\fs12}And so here, I'm just going to say\r\nDialogue: 0,0:49:39.62,0:49:43.99,yin,,0,0,0,,如果segue的目标视图控制器\\N{\\fs12}if the segue's destination view controller\r\nDialogue: 0,0:49:43.99,0:49:48.50,yin,,0,0,0,,是URLViewController这类\\N{\\fs12}is kind of class a URL view controller,\r\nDialogue: 0,0:49:52.63,0:49:57.81,yin,,0,0,0,,那么 我就将segue到它\\N{\\fs12}then I'm going to segue to it.\r\nDialogue: 0,0:49:57.81,0:50:01.29,yin,,0,0,0,,没错 我还可以说 如果标识符等于Show URL\\N{\\fs12}And yeah, I could also say if the identifier equals show URL,\r\nDialogue: 0,0:50:01.29,0:50:06.29,yin,,0,0,0,,不过为了更快一些 这里我们就不那样做了\\N{\\fs12}but for speed here, we're just going to go ahead and not do that.\r\nDialogue: 0,0:50:06.29,0:50:08.53,yin,,0,0,0,,视图 控制器 类\\N{\\fs12}View, controller, class.\r\nDialogue: 0,0:50:08.53,0:50:12.26,yin,,0,0,0,,这样我就有了URLViewController\\N{\\fs12}Okay. So now I have the URL view controller.\r\nDialogue: 0,0:50:12.26,0:50:17.65,yin,,0,0,0,,urlvc = (URLViewController *)\\N{\\fs12}URLVC equals URL view controller, uh,\r\nDialogue: 0,0:50:17.66,0:50:20.44,yin,,0,0,0,,segue.destinationViewController\\N{\\fs12}the segue dot destination view controller.\r\nDialogue: 0,0:50:20.44,0:50:22.07,yin,,0,0,0,,我有了URLViewController\\N{\\fs12}I've got the URL view controller,\r\nDialogue: 0,0:50:22.07,0:50:26.00,yin,,0,0,0,,我可以将这个URLViewController的URL\\N{\\fs12}and I can just set the URL view controller's image, or sorry, URL\r\nDialogue: 0,0:50:26.02,0:50:28.82,yin,,0,0,0,,设为我的imageURL\\N{\\fs12}to be my image URL.\r\nDialogue: 0,0:50:28.84,0:50:30.68,yin,,0,0,0,,我是一个图像视图控制器\\N{\\fs12}I am an image view controller,\r\nDialogue: 0,0:50:30.68,0:50:34.05,yin,,0,0,0,,imageURL是我的模型\\N{\\fs12}so image URL happens to be my model, right?\r\nDialogue: 0,0:50:34.05,0:50:38.87,yin,,0,0,0,,这样我就很好用它 我于是打算这样设\\N{\\fs12}So I have it handy dandy, and I'm just going to set that.\r\nDialogue: 0,0:50:38.87,0:50:42.56,yin,,0,0,0,,现在我准备好了segue到这个\\N{\\fs12}So now, I'm totally prepared to segue to this thing,\r\nDialogue: 0,0:50:42.56,0:50:47.51,yin,,0,0,0,,下面试一下这个 看它能否正常工作\\N{\\fs12}so let's go ahead and give this a try and see if it works.\r\nDialogue: 0,0:50:59.30,0:51:02.28,yin,,0,0,0,,让我们选一张照片\\N{\\fs12}Okay, so let's pick a photo here.\r\nDialogue: 0,0:51:02.28,0:51:06.35,yin,,0,0,0,,选一个更好的 回到里约热内卢\\N{\\fs12}Let's pick a better one than that, let's pick, okay, let's go back to Rio De Janeiro.\r\nDialogue: 0,0:51:06.35,0:51:06.98,yin,,0,0,0,,好\\N{\\fs12}Okay, there we go.\r\nDialogue: 0,0:51:06.98,0:51:08.83,yin,,0,0,0,,这个的URL是什么\\N{\\fs12}So what is the URL for this?\r\nDialogue: 0,0:51:08.83,0:51:10.58,yin,,0,0,0,,会是某个Flickr URL\\N{\\fs12}It's going to be something Flickr URL.\r\nDialogue: 0,0:51:10.58,0:51:13.15,yin,,0,0,0,,我们点URL 它展示的是这个\\N{\\fs12}So we click on URL and it shows it to us.\r\nDialogue: 0,0:51:13.15,0:51:15.98,yin,,0,0,0,,Flickr的某个服务器群\\N{\\fs12}Some farm, some server farm at Flickr.\r\nDialogue: 0,0:51:15.98,0:51:16.76,yin,,0,0,0,,很好\\N{\\fs12}Excellent.\r\nDialogue: 0,0:51:16.76,0:51:19.02,yin,,0,0,0,,看起来很好 一切正常运行\\N{\\fs12}Now, this looks like, oh, good, it's all working.\r\nDialogue: 0,0:51:19.02,0:51:20.60,yin,,0,0,0,,不过这里实际有个问题\\N{\\fs12}But actually there's a problem here.\r\nDialogue: 0,0:51:20.60,0:51:21.22,yin,,0,0,0,,看这个\\N{\\fs12}Watch this.\r\nDialogue: 0,0:51:21.22,0:51:23.50,yin,,0,0,0,,我打算再按一下URL按钮\\N{\\fs12}I'm going to press the UR button again.\r\nDialogue: 0,0:51:23.50,0:51:27.97,yin,,0,0,0,,里约越来越模糊 甚至有些看不到了\\N{\\fs12}Oh, the smog is building in Rio here, look at it, oh, it's getting so you can't even see.\r\nDialogue: 0,0:51:27.97,0:51:29.07,yin,,0,0,0,,这里发生了什么\\N{\\fs12}What's happening there?\r\nDialogue: 0,0:51:29.07,0:51:31.61,yin,,0,0,0,,实际上 这个segue一次又一次发生\\N{\\fs12}Actually, that segue is happening over and over,\r\nDialogue: 0,0:51:31.61,0:51:33.83,yin,,0,0,0,,弹窗越来越多\\N{\\fs12}it's putting up more and more popovers.\r\nDialogue: 0,0:51:33.83,0:51:36.61,yin,,0,0,0,,这里实际有四五个弹窗 一层层覆盖\\N{\\fs12}So there's actually four or five popovers over the top of each other,\r\nDialogue: 0,0:51:36.61,0:51:37.99,yin,,0,0,0,,于是图像越来越暗\\N{\\fs12}that's why it's getting darker and darker,\r\nDialogue: 0,0:51:37.99,0:51:40.67,yin,,0,0,0,,这是因为每次有弹窗时 屏幕其它地方都会变暗\\N{\\fs12}because the popover kind of darkens the rest of the screen when it puts it up.\r\nDialogue: 0,0:51:40.67,0:51:41.83,yin,,0,0,0,,我可以点别的地方\\N{\\fs12}So if I click somewhere else,\r\nDialogue: 0,0:51:41.83,0:51:45.78,yin,,0,0,0,,这是取消弹窗的方式 所有弹窗会慢慢消失\\N{\\fs12}which is how you dismiss a popover, it's slowly getting rid of them all,\r\nDialogue: 0,0:51:45.78,0:51:47.51,yin,,0,0,0,,直到最开始的那个\\N{\\fs12}all the way back to the other one.\r\nDialogue: 0,0:51:47.51,0:51:50.76,yin,,0,0,0,,毫无疑问 这对于用户而言不是很好的UI\\N{\\fs12}Needless to say, this is not a great UI, for the user,\r\nDialogue: 0,0:51:50.76,0:51:54.29,yin,,0,0,0,,我们不希望这样 如何避免这样呢\\N{\\fs12}so we don't want this. Okay, why is this? How are we going to stop this?\r\nDialogue: 0,0:51:54.29,0:51:56.13,yin,,0,0,0,,我们准备这样做\\N{\\fs12}Well, we're going to stop this when this\r\nDialogue: 0,0:51:56.13,0:51:59.64,yin,,0,0,0,,当有人点URL时 我们打算检查\\N{\\fs12}segue, when someone clicks on URL, we are going to check to see\r\nDialogue: 0,0:51:59.64,0:52:04.02,yin,,0,0,0,,是否已经有弹窗了 如果有 我们将不再segue\\N{\\fs12}if we already have a popover up, and if we do, we're not going to do that segue.\r\nDialogue: 0,0:52:04.30,0:52:06.28,yin,,0,0,0,,我来展示一下怎么做\\N{\\fs12}So let me show you how to do that.\r\nDialogue: 0,0:52:06.28,0:52:10.13,yin,,0,0,0,,首先 我们要跟踪这个弹窗是否已经弹出\\N{\\fs12}So first of all, we have to keep track of whether this popover is up.\r\nDialogue: 0,0:52:10.13,0:52:15.27,yin,,0,0,0,,做法是添加一个属性给我的图像视图控制器\\N{\\fs12}So I'm going to do that by adding a property here to my image view controller.\r\nDialogue: 0,0:52:15.27,0:52:18.05,yin,,0,0,0,,设为弱属性\\N{\\fs12}I'm going to make it weak.\r\nDialogue: 0,0:52:18.05,0:52:22.03,yin,,0,0,0,,除了outlet 我们很少使用弱属性\\N{\\fs12}Here's one of the first times we've used a weak property outside of outlets,\r\nDialogue: 0,0:52:22.03,0:52:24.83,yin,,0,0,0,,这里用于UIPopoverController\\N{\\fs12}but it's going to be UI popover controller,\r\nDialogue: 0,0:52:24.83,0:52:27.17,yin,,0,0,0,,urlPopoverController\\N{\\fs12}URL popover controller,\r\nDialogue: 0,0:52:27.17,0:52:31.91,yin,,0,0,0,,设为弱的原因在于 我希望使用弱的性质\\N{\\fs12}and the reason it's going to be weak is because I want to use the weakness\r\nDialogue: 0,0:52:31.91,0:52:34.82,yin,,0,0,0,,让弹窗控制器失去之后\\N{\\fs12}so that when the popover controller is gone,\r\nDialogue: 0,0:52:34.82,0:52:39.23,yin,,0,0,0,,没有其它强指针指向它 于是我的指针会被设为nil\\N{\\fs12}no one else will have a strong pointer to it, my pointer will get set to nil.\r\nDialogue: 0,0:52:40.43,0:52:42.65,yin,,0,0,0,,明白吗 现在我就总能知道\\N{\\fs12}Get it? So now I'm always going to know whether\r\nDialogue: 0,0:52:42.65,0:52:45.17,yin,,0,0,0,,弹窗控制器是否在作用\\N{\\fs12}that popover controller is up,\r\nDialogue: 0,0:52:45.17,0:52:47.37,yin,,0,0,0,,不过我需要初始设置它\\N{\\fs12}but I've got to set it initially, though.\r\nDialogue: 0,0:52:47.37,0:52:51.69,yin,,0,0,0,,segue发生时 我需要设置这个到弹窗\\N{\\fs12}I've got to set this thing to the popover when the segue happens.\r\nDialogue: 0,0:52:51.69,0:52:54.53,yin,,0,0,0,,我们来做一下 如何做到呢\\N{\\fs12}So let's do that. And how do we do that?\r\nDialogue: 0,0:52:54.53,0:52:58.55,yin,,0,0,0,,我在幻灯片中说过 但你们可能不记得了\\N{\\fs12}I said this in the slide, but you're probably like \"what?\"\r\nDialogue: 0,0:52:58.55,0:53:01.67,yin,,0,0,0,,现在我来讲下 也就是 这个segue\\N{\\fs12}but now you'll see it, which is this segue,\r\nDialogue: 0,0:53:01.68,0:53:03.71,yin,,0,0,0,,如果是弹窗segue\\N{\\fs12}if this is a popover segue,\r\nDialogue: 0,0:53:03.71,0:53:06.28,yin,,0,0,0,,它将是UIStoryboardSegue的子类\\N{\\fs12}will be a subclass of UI storyboard\r\nDialogue: 0,0:53:06.29,0:53:11.32,yin,,0,0,0,,也就是UIStoryboardPopoverSegue\\N{\\fs12}called UI storyboard popover segue.\r\nDialogue: 0,0:53:11.32,0:53:21.29,yin,,0,0,0,,popoverSegue = (UIStoryboardPopoverSegue *)segue\\N{\\fs12}Popover segue equals UI popover storyboard popover segue, segue.\r\nDialogue: 0,0:53:21.29,0:53:23.15,yin,,0,0,0,,我可以只这样做\\N{\\fs12}Now I could just do this,\r\nDialogue: 0,0:53:23.15,0:53:25.29,yin,,0,0,0,,不过我还可以更保险一些 我可以说\\N{\\fs12}but I'm going to be a little safe and say\r\nDialogue: 0,0:53:25.29,0:53:33.72,yin,,0,0,0,,如果我的segue是UIStoryboardPopoverSegue这一类\\N{\\fs12}if my segue is kind of class UI popover storyboard popover segue class,\r\nDialogue: 0,0:53:33.72,0:53:35.37,yin,,0,0,0,,那么我就要做所有这些\\N{\\fs12}then I'll get it, then I'll do this.\r\nDialogue: 0,0:53:35.37,0:53:39.22,yin,,0,0,0,,我喜欢在做这样的事情之前先检查一下\\N{\\fs12}I just don't like to do casts like that without, you know, checking first.\r\nDialogue: 0,0:53:39.22,0:53:43.09,yin,,0,0,0,,虽然这里很有可能是弹窗\\N{\\fs12}Although if I got to here, it probably is going to be a popover, but,\r\nDialogue: 0,0:53:43.10,0:53:45.85,yin,,0,0,0,,不过我这里还是检查一下\\N{\\fs12}you know, it should be a popover, but I'm going to check anyway.\r\nDialogue: 0,0:53:45.85,0:53:49.20,yin,,0,0,0,,然后我要将我的URL弹窗控制器设为\\N{\\fs12}And now I'm just going to set my URL popover controller equal\r\nDialogue: 0,0:53:49.20,0:53:53.38,yin,,0,0,0,,这个弹窗segue的popoverController属性\\N{\\fs12}to that popover segue's popover controller property.\r\nDialogue: 0,0:53:53.38,0:53:55.83,yin,,0,0,0,,看这个弹窗segue\\N{\\fs12}If you look at popover segue, here's popover segue,\r\nDialogue: 0,0:53:55.83,0:53:59.44,yin,,0,0,0,,去UIStoryboardPopoverSegue的说明文档\\N{\\fs12}I'm going to go to its documentation, okay, for UI storyboard popover,\r\nDialogue: 0,0:53:59.44,0:54:00.78,yin,,0,0,0,,你会看到\\N{\\fs12}and you'll see\r\nDialogue: 0,0:54:00.78,0:54:04.10,yin,,0,0,0,,UIStoryboardPopoverSegue只有一项属性\\N{\\fs12}that UI storyboard popover only has one property,\r\nDialogue: 0,0:54:04.10,0:54:06.11,yin,,0,0,0,,也就是popoverController\\N{\\fs12}which is the popover controller.\r\nDialogue: 0,0:54:06.11,0:54:11.83,yin,,0,0,0,,我们这里是从segue得到了popoverController\\N{\\fs12}So we're basically getting the popover controller from the segue.\r\nDialogue: 0,0:54:11.83,0:54:12.83,yin,,0,0,0,,很特殊\\N{\\fs12}It's a special kind.\r\nDialogue: 0,0:54:12.83,0:54:17.39,yin,,0,0,0,,但愿大家都理解了这个\\N{\\fs12}So it's a little-- hopefully you understand that-- everyone understand that?\r\nDialogue: 0,0:54:17.39,0:54:18.41,yin,,0,0,0,,有问题吗\\N{\\fs12}Question? No?\r\nDialogue: 0,0:54:20.99,0:54:25.77,yin,,0,0,0,,这不是目标视图控制器 这是segue本身\\N{\\fs12}Um, it's not, this is not the destination view controller, this is the segue itself.\r\nDialogue: 0,0:54:25.77,0:54:28.29,yin,,0,0,0,,这里我们没有说segue.destinationViewController\\N{\\fs12}We're not saying segue dot destination view controller here.\r\nDialogue: 0,0:54:29.83,0:54:31.28,yin,,0,0,0,,问得很好\\N{\\fs12}Okay, great question.\r\nDialogue: 0,0:54:31.28,0:54:33.91,yin,,0,0,0,,目标视图控制器 这个东西\\N{\\fs12}Is the destination view controller, this thing,\r\nDialogue: 0,0:54:33.92,0:54:35.30,yin,,0,0,0,,是弹窗控制器吗\\N{\\fs12}is that a popover controller?\r\nDialogue: 0,0:54:35.30,0:54:37.17,yin,,0,0,0,,答案是 不是\\N{\\fs12}And the answer is, it is not.\r\nDialogue: 0,0:54:37.17,0:54:39.51,yin,,0,0,0,,它是一个URL视图控制器\\N{\\fs12}It is a URL view controller.\r\nDialogue: 0,0:54:39.51,0:54:42.05,yin,,0,0,0,,弹窗控制器是另一个类\\N{\\fs12}Popover view controller is another class,\r\nDialogue: 0,0:54:42.05,0:54:46.71,yin,,0,0,0,,不是控制那个弹窗的UIViewController\\N{\\fs12}not a UI view controller, that controls that popover.\r\nDialogue: 0,0:54:46.71,0:54:47.55,yin,,0,0,0,,它不是\\N{\\fs12}So it is not.\r\nDialogue: 0,0:54:47.55,0:54:50.66,yin,,0,0,0,,segue是一个StoryboardPopoverSegue\\N{\\fs12}So the segue is a storyboard popover segue,\r\nDialogue: 0,0:54:50.66,0:54:53.92,yin,,0,0,0,,从这里面我们得到弹窗控制器\\N{\\fs12}out of which we get the popover controller,\r\nDialogue: 0,0:54:53.92,0:54:57.96,yin,,0,0,0,,而目标视图控制器是一个URL视图控制器\\N{\\fs12}and the destination view controller is a URL view controller.\r\nDialogue: 0,0:54:57.96,0:54:59.95,yin,,0,0,0,,大家都明白吗\\N{\\fs12}Everyone got all that?\r\nDialogue: 0,0:54:59.95,0:55:01.35,yin,,0,0,0,,好 现在我们有一个指针\\N{\\fs12}Alright, so now we have a pointer\r\nDialogue: 0,0:55:01.35,0:55:03.21,yin,,0,0,0,,指向这个URL弹窗控制器\\N{\\fs12}to this URL popover controller,\r\nDialogue: 0,0:55:03.21,0:55:06.14,yin,,0,0,0,,离开屏幕时 它会自动被设为nil\\N{\\fs12}and it's automatically going to get set to nil as soon as it goes off screen,\r\nDialogue: 0,0:55:06.14,0:55:08.18,yin,,0,0,0,,因为指向它的是弱指针\\N{\\fs12}because it's weak. It's a weak pointer to it.\r\nDialogue: 0,0:55:08.18,0:55:10.36,yin,,0,0,0,,我们还有一件事需要做\\N{\\fs12}There's only one other thing we need to do,\r\nDialogue: 0,0:55:10.36,0:55:15.32,yin,,0,0,0,,也就是如果那个在运行 就不要运行这个segue\\N{\\fs12}which is not do this segue if that thing is up.\r\nDialogue: 0,0:55:15.32,0:55:17.68,yin,,0,0,0,,我在课上讲过这个\\N{\\fs12}And I actually talked about this in the lecture, how we do this,\r\nDialogue: 0,0:55:17.68,0:55:20.32,yin,,0,0,0,,UIViewController中有一个方法叫\\N{\\fs12}there's a method in UI view controller called\r\nDialogue: 0,0:55:20.32,0:55:24.17,yin,,0,0,0,,shouldPerformSegueWithIdentifier\\N{\\fs12}should perform segue with identifier.\r\nDialogue: 0,0:55:24.17,0:55:26.80,yin,,0,0,0,,这是系统在问\\N{\\fs12}And this is the system asking,\r\nDialogue: 0,0:55:26.80,0:55:29.43,yin,,0,0,0,,用户点击了导致segue的东西\\N{\\fs12}someone clicked on something that's supposed to cause a segue.\r\nDialogue: 0,0:55:29.43,0:55:30.88,yin,,0,0,0,,我是否应该照做\\N{\\fs12}Should I do it?\r\nDialogue: 0,0:55:30.88,0:55:32.60,yin,,0,0,0,,这里我们打算这样\\N{\\fs12}And right here we're going to say\r\nDialogue: 0,0:55:32.60,0:55:38.03,yin,,0,0,0,,如果讨论中的segue的标识符\\N{\\fs12}if the segue in question here, its identifier,\r\nDialogue: 0,0:55:38.03,0:55:42.93,yin,,0,0,0,,等于字符串Show URL\\N{\\fs12}is equal to string show URL,\r\nDialogue: 0,0:55:42.93,0:55:47.83,yin,,0,0,0,,在故事板中它就叫这个\\N{\\fs12}which is what it is in our storyboard,\r\nDialogue: 0,0:55:47.83,0:55:51.76,yin,,0,0,0,,这或许就是我们这里还要检查的原因\\N{\\fs12}and this is the reason why maybe we want to check it here as well.\r\nDialogue: 0,0:55:51.76,0:55:54.26,yin,,0,0,0,,在demo模式中 我跳过那个\\N{\\fs12}I skipped over that demo mode, but you know,\r\nDialogue: 0,0:55:54.26,0:55:57.27,yin,,0,0,0,,如果这里要检查 这里我们也应该检查\\N{\\fs12}if we're going to check it here, we might want to check it up here as well.\r\nDialogue: 0,0:55:57.27,0:56:00.40,yin,,0,0,0,,无论如何 我们有了这个 这里我将要这样返回\\N{\\fs12}But anyway, we've got this, I'm going to return, in this case,\r\nDialogue: 0,0:56:00.40,0:56:05.30,yin,,0,0,0,,如果这是URL 那么如果我有URL弹窗控制器 那么NO\\N{\\fs12}so if it's a URL, then if I have URL popover controller, then no,\r\nDialogue: 0,0:56:05.30,0:56:08.83,yin,,0,0,0,,不要执行这个segue 因为已经有了一个弹窗\\N{\\fs12}do not perform this segue, because there's already a popover up.\r\nDialogue: 0,0:56:08.83,0:56:10.96,yin,,0,0,0,,否则 我可以说YES 但我打算\\N{\\fs12}Otherwise, I could just say yes, but actually I'm going\r\nDialogue: 0,0:56:10.96,0:56:13.21,yin,,0,0,0,,做点更巧妙的事 我要说\\N{\\fs12}to do something a little trickier, I'm going to say\r\nDialogue: 0,0:56:13.21,0:56:19.05,yin,,0,0,0,,如果我有一个imageURL 那么YES 否则还是NO\\N{\\fs12}if I have a image URL, then put it up, otherwise, also don't put it up.\r\nDialogue: 0,0:56:20.66,0:56:22.34,yin,,0,0,0,,看懂了吗\\N{\\fs12}See what I did there?\r\nDialogue: 0,0:56:22.34,0:56:25.81,yin,,0,0,0,,有两个理由不直接进行URL segue\\N{\\fs12}Two reasons not to put, do that URL segue.\r\nDialogue: 0,0:56:25.81,0:56:29.69,yin,,0,0,0,,一个原因是可能没有任何照片显示出来\\N{\\fs12}If I don't have any photo showing, then that's one reason.\r\nDialogue: 0,0:56:29.69,0:56:32.35,yin,,0,0,0,,另一个原因是弹窗已经在那\\N{\\fs12}Or if I have a popup already up.\r\nDialogue: 0,0:56:32.35,0:56:35.67,yin,,0,0,0,,否则 这很有趣 我有一个否则的情况\\N{\\fs12}Else, now this is interesting, I have an else case here, which is\r\nDialogue: 0,0:56:35.67,0:56:38.90,yin,,0,0,0,,也就是super shouldPerform…\\N{\\fs12}super should performs.\r\nDialogue: 0,0:56:38.90,0:56:41.85,yin,,0,0,0,,如果我没有阻止它 那么我就要\\N{\\fs12}So if I am not preventing it, then I'm going\r\nDialogue: 0,0:56:41.85,0:56:45.92,yin,,0,0,0,,让超类UIViewController来决定是否进行这个segue\\N{\\fs12}to let my super class UI view controller decide whether it should do this segue.\r\nDialogue: 0,0:56:45.94,0:56:49.33,yin,,0,0,0,,这几乎总会说YES 不过…\\N{\\fs12}Which it's always going to say yes, pretty much, but...okay?\r\nDialogue: 0,0:56:49.33,0:56:51.93,yin,,0,0,0,,这里应该是返回\\N{\\fs12}This should be return.\r\nDialogue: 0,0:56:51.93,0:56:54.82,yin,,0,0,0,,看看这能否修正所有问题\\N{\\fs12}So let's see if that fixes all our problems\r\nDialogue: 0,0:57:05.08,0:57:07.84,yin,,0,0,0,,好 回到里约\\N{\\fs12}Alright, so let's go back to Rio.\r\nDialogue: 0,0:57:07.84,0:57:12.55,yin,,0,0,0,,这是里约 点URL 很好 再点URL\\N{\\fs12}Here we are, in Rio, let's click URL, excellent, URL again,\r\nDialogue: 0,0:57:12.55,0:57:14.98,yin,,0,0,0,,不断再点 它什么都没做\\N{\\fs12}again, again, again, it's not doing it,\r\nDialogue: 0,0:57:14.98,0:57:18.24,yin,,0,0,0,,点其它地方 所有问题都修正了\\N{\\fs12}click away, going to fix all our problems.\r\nDialogue: 0,0:57:18.24,0:57:21.46,yin,,0,0,0,,不过这里还有一个很琐细的问题 出于时间考虑\\N{\\fs12}There is a subtle problem still here, which I'm not going\r\nDialogue: 0,0:57:21.46,0:57:23.61,yin,,0,0,0,,我不打算修正 毕竟我还要讲地图\\N{\\fs12}to fix because of time, I need to get to the maps here,\r\nDialogue: 0,0:57:23.61,0:57:27.53,yin,,0,0,0,,来到竖屏模式 显示URL 看看如果\\N{\\fs12}but if I go to portrait mode and show the URL, watch what happens\r\nDialogue: 0,0:57:27.53,0:57:31.22,yin,,0,0,0,,我点这里的拍照者来显示拍照者会怎样\\N{\\fs12}if I click photographer over here to show those photographers.\r\nDialogue: 0,0:57:31.22,0:57:33.73,yin,,0,0,0,,哦 URL还在那里\\N{\\fs12}Oh! The URL thing didn't go away.\r\nDialogue: 0,0:57:33.73,0:57:36.49,yin,,0,0,0,,我点其它地方 它本应该消失的\\N{\\fs12}I thought if I clicked away from it, it's supposed to go away.\r\nDialogue: 0,0:57:36.51,0:57:41.47,yin,,0,0,0,,实际上 只要你在URL所在的栏上点击\\N{\\fs12}And the answer is, if you click in the same bar that the URL thing is,\r\nDialogue: 0,0:57:41.47,0:57:43.77,yin,,0,0,0,,这个都不会消失\\N{\\fs12}then it does allow you to click.\r\nDialogue: 0,0:57:43.77,0:57:47.43,yin,,0,0,0,,我在幻灯片中讲过 这叫passthroughViews\\N{\\fs12}That's the thing in the slides that I talked about, called pass through views.\r\nDialogue: 0,0:57:47.43,0:57:50.30,yin,,0,0,0,,这整个栏都是passthroughViews的一部分\\N{\\fs12}So this whole bar is part of the pass through views,\r\nDialogue: 0,0:57:50.30,0:57:53.67,yin,,0,0,0,,最糟糕的是 就算我点别的照片\\N{\\fs12}and the real bad thing about this is, if I click on a different photo,\r\nDialogue: 0,0:57:53.67,0:57:57.39,yin,,0,0,0,,照片会变 但URL不会更新\\N{\\fs12}it's showing me a different photo, but it's not updating the URL.\r\nDialogue: 0,0:57:57.39,0:57:58.47,yin,,0,0,0,,这太糟糕了\\N{\\fs12}So this is really bad.\r\nDialogue: 0,0:57:58.47,0:58:00.15,yin,,0,0,0,,我会在后面发布的代码中修正这个\\N{\\fs12}So I'm going to fix this in the code I post,\r\nDialogue: 0,0:58:00.15,0:58:03.86,yin,,0,0,0,,算了 就现在修正吧 更容易演示\\N{\\fs12}actually let's just fix it right now, easier to show you.\r\nDialogue: 0,0:58:03.86,0:58:05.09,yin,,0,0,0,,我来做这个\\N{\\fs12}I'm going to do this.\r\nDialogue: 0,0:58:05.09,0:58:08.80,yin,,0,0,0,,当有人将图像设置为新东西时\\N{\\fs12}Whenever someone sets my image to something new.\r\nDialogue: 0,0:58:08.80,0:58:12.86,yin,,0,0,0,,在图像视图控制器中调用setImage\\N{\\fs12}Call set image, I'm going to, in my image view controller,\r\nDialogue: 0,0:58:12.86,0:58:17.86,yin,,0,0,0,,我就会解除我拥有的任何弹窗控制器\\N{\\fs12}I'm going to dismiss any popover controller that I have.\r\nDialogue: 0,0:58:18.93,0:58:22.91,yin,,0,0,0,,这样 如果有人打开右侧那个 然后点击\\N{\\fs12}So that way if someone brings up that thing on the right and they click,\r\nDialogue: 0,0:58:22.91,0:58:25.35,yin,,0,0,0,,至少我会把URL弄走\\N{\\fs12}at least I'll put away my URL.\r\nDialogue: 0,0:58:25.35,0:58:27.26,yin,,0,0,0,,我也可以用一些代码\\N{\\fs12}I could actually have some code here\r\nDialogue: 0,0:58:27.26,0:58:30.86,yin,,0,0,0,,更新URL视图控制器 让它变化\\N{\\fs12}that updated the URL view controller and made it change,\r\nDialogue: 0,0:58:30.86,0:58:33.35,yin,,0,0,0,,这不难 我只需要跟踪它\\N{\\fs12}that wouldn't be that hard, I'd just keep track of it.\r\nDialogue: 0,0:58:33.35,0:58:36.16,yin,,0,0,0,,唯一的问题是 这就会让不一致\\N{\\fs12}The only problem is then that would be inconsistent\r\nDialogue: 0,0:58:36.16,0:58:39.07,yin,,0,0,0,,出现在竖屏模式和这个模式之间\\N{\\fs12}between this portrait mode and this mode,\r\nDialogue: 0,0:58:39.07,0:58:41.55,yin,,0,0,0,,因为这里 如果上面这里有URL\\N{\\fs12}because here, when I'm clicking, if I had URL up here,\r\nDialogue: 0,0:58:41.56,0:58:44.38,yin,,0,0,0,,如果我点这里 URL会消失\\N{\\fs12}if I click over here, it makes the URL go away.\r\nDialogue: 0,0:58:44.38,0:58:49.35,yin,,0,0,0,,因为这里这个同URL不在相同的栏中\\N{\\fs12}Because over here is now no longer in the same bar as the URL.\r\nDialogue: 0,0:58:49.35,0:58:52.53,yin,,0,0,0,,我希望程序的行为相对一致\\N{\\fs12}So I want my behavior to be at least somewhat consistent.\r\nDialogue: 0,0:58:52.53,0:58:57.59,yin,,0,0,0,,因此我打算在点击新东西时 URL消失\\N{\\fs12}So I'll make it so that when I click on something new, it makes the URL go away.\r\nDialogue: 0,0:58:58.92,0:58:59.57,yin,,0,0,0,,好\\N{\\fs12}Okay!\r\nDialogue: 0,0:58:59.57,0:59:02.60,yin,,0,0,0,,一个很好很大的demo 所有这些我都会发布\\N{\\fs12}Nice big long demo, I will, of course, post all of this.\r\nDialogue: 0,0:59:02.60,0:59:05.49,yin,,0,0,0,,现在你就知道如何用弹窗控制器了 现在你们需要\\N{\\fs12}Now you know how to do popover controllers, you should really have a good handle\r\nDialogue: 0,0:59:05.49,0:59:08.36,yin,,0,0,0,,很好地掌握Core Data表格视图控制器的使用\\N{\\fs12}on using those core data table view controllers by now, I hope.\r\nDialogue: 0,0:59:08.36,0:59:13.50,yin,,0,0,0,,我还说过 我要做的是通用app 看这有多简单\\N{\\fs12}Oh! I promised I would do universal app, look how easy this is.\r\nDialogue: 0,0:59:13.50,0:59:17.76,yin,,0,0,0,,我要这样转到iPhone 这是我的iPad\\N{\\fs12}I'm going to do my iPhone, here's my iPad,\r\nDialogue: 0,0:59:17.78,0:59:22.46,yin,,0,0,0,,我复制这个 到iPhone里面\\N{\\fs12}I'm going to take this, copy it, go over here to my iPhone,\r\nDialogue: 0,0:59:22.46,0:59:25.44,yin,,0,0,0,,删除这个 粘贴\\N{\\fs12}get rid of this thing, paste.\r\nDialogue: 0,0:59:25.44,0:59:26.94,yin,,0,0,0,,回到iPad\\N{\\fs12}Go back to iPad,\r\nDialogue: 0,0:59:26.94,0:59:33.13,yin,,0,0,0,,将我要的这个图像视图控制器复制粘贴过来\\N{\\fs12}get this image view controller, which I need, go over here, paste it.\r\nDialogue: 0,0:59:33.13,0:59:36.61,yin,,0,0,0,,给它找个空间 粘贴\\N{\\fs12}If I can find space for it. Paste.\r\nDialogue: 0,0:59:37.92,0:59:41.08,yin,,0,0,0,,好了 放到上面这里\\N{\\fs12}Alright there it is, put it up here.\r\nDialogue: 0,0:59:41.08,0:59:44.46,yin,,0,0,0,,segue到它\\N{\\fs12}Just need to make the segue to it.\r\nDialogue: 0,0:59:45.12,0:59:47.17,yin,,0,0,0,,control 拖动\\N{\\fs12}Control, drag.\r\nDialogue: 0,0:59:47.17,0:59:48.54,yin,,0,0,0,,这是一个push segue\\N{\\fs12}It's a push segue.\r\nDialogue: 0,0:59:48.54,0:59:49.42,yin,,0,0,0,,搞定\\N{\\fs12}Boom. We're done.\r\nDialogue: 0,0:59:49.42,0:59:51.43,yin,,0,0,0,,现在iPhone就能工作了\\N{\\fs12}Now iPhone will work.\r\nDialogue: 0,0:59:51.43,0:59:54.22,yin,,0,0,0,,想看它工作的可以下课来\\N{\\fs12}You can come up after class if you want\r\nDialogue: 0,0:59:54.22,0:59:55.78,yin,,0,0,0,,就是这么简单\\N{\\fs12}to see it working, but that's all there is.\r\nDialogue: 0,0:59:55.78,0:59:59.16,yin,,0,0,0,,很多时候 要同时在iPhone和iPad的UI上运行\\N{\\fs12}So a lot of times when you're working on iPhone and iPad UIs\r\nDialogue: 0,0:59:59.16,1:00:02.27,yin,,0,0,0,,你只需要弄好一个 然后复制粘贴到另一个\\N{\\fs12}you'll get one working and then you'll just copy and paste back to the other one.\r\nDialogue: 0,1:00:02.27,1:00:04.34,yin,,0,0,0,,或许有一些新特性\\N{\\fs12}Get that one maybe working with some new feature,\r\nDialogue: 0,1:00:04.35,1:00:06.70,yin,,0,0,0,,复制粘贴合适的东西回来\\N{\\fs12}copy and paste it in the appropriate things back to the other one.\r\nDialogue: 0,1:00:06.70,1:00:11.85,yin,,0,0,0,,明白吗 你可以在两者之间往复 很简单\\N{\\fs12}See what I mean, you can kind of go back and forth between, pretty straightforward.\r\nDialogue: 0,1:00:11.85,1:00:13.61,yin,,0,0,0,,好 回到幻灯片\\N{\\fs12}Okay! Back to the slides.\r\nDialogue: 0,1:00:13.61,1:00:14.76,yin,,0,0,0,,好了\\N{\\fs12}Here we go.\r\nDialogue: 0,1:00:14.76,1:00:19.49,yin,,0,0,0,,第14讲 这里\\N{\\fs12}Lecture 14, there it is.\r\nDialogue: 0,1:00:19.49,1:00:22.63,yin,,0,0,0,,好 今天地图肯定是讲不完了\\N{\\fs12}Okay. So we're not going to get all the way through the maps stuff today,\r\nDialogue: 0,1:00:22.63,1:00:25.49,yin,,0,0,0,,这没关系 因为下堂课开始还有时间\\N{\\fs12}which is fine, because I have a little bit of time at the beginning of the next lecture,\r\nDialogue: 0,1:00:25.49,1:00:29.17,yin,,0,0,0,,然后我还将在下一讲做一个map的演示demo\\N{\\fs12}and then I'm going to be doing the map demo in the next lecture anyway,\r\nDialogue: 0,1:00:29.17,1:00:30.78,yin,,0,0,0,,这样大家记忆就会很鲜活\\N{\\fs12}so it will be kind of fresh in your mind.\r\nDialogue: 0,1:00:30.78,1:00:34.23,yin,,0,0,0,,关于刚才的那个大demo 大家有问题吗\\N{\\fs12}So any questions about all that big demo I just did?\r\nDialogue: 0,1:00:34.23,1:00:35.84,yin,,0,0,0,,听起来不错吗\\N{\\fs12}All sounds good?\r\nDialogue: 0,1:00:35.84,1:00:37.46,yin,,0,0,0,,理解了吗\\N{\\fs12}Understandable?\r\nDialogue: 0,1:00:37.46,1:00:39.41,yin,,0,0,0,,好\\N{\\fs12}Okay. Alright.\r\nDialogue: 0,1:00:39.41,1:00:41.62,yin,,0,0,0,,MapKit 这里我要讲MapKit\\N{\\fs12}Map kit. Basically I'm going to be talking about map kit here,\r\nDialogue: 0,1:00:41.62,1:00:44.76,yin,,0,0,0,,不过这之前 我要讲到另一个框架\\N{\\fs12}but before I talk about map kit, I have to talk about another framework,\r\nDialogue: 0,1:00:44.77,1:00:46.74,yin,,0,0,0,,这是一个非UI框架\\N{\\fs12}which is a non-UI framework,\r\nDialogue: 0,1:00:46.74,1:00:50.14,yin,,0,0,0,,这是MapKit框架的基础 叫作Core Location\\N{\\fs12}which kind of underlies the map kit framework, called core location.\r\nDialogue: 0,1:00:50.14,1:00:53.86,yin,,0,0,0,,Core Location是一个框架 有一些对象在里面\\N{\\fs12}So core location is a framework, has a bunch of objects in it,\r\nDialogue: 0,1:00:53.86,1:00:57.99,yin,,0,0,0,,关于当前设备处在于什么位置\\N{\\fs12}that have to do with where is this device in the universe?\r\nDialogue: 0,1:00:57.99,1:01:03.41,yin,,0,0,0,,就GPS而言 也就是在地球上什么地方\\N{\\fs12}Where on the planet, you know, where, in terms of GPS\r\nDialogue: 0,1:01:03.41,1:01:06.87,yin,,0,0,0,,或是根据其它因素决定 设备在哪\\N{\\fs12}or other factors determining where it is, where is it?\r\nDialogue: 0,1:01:06.87,1:01:08.23,yin,,0,0,0,,在地球的什么地方\\N{\\fs12}Where on earth.\r\nDialogue: 0,1:01:08.23,1:01:13.15,yin,,0,0,0,,它的基本对象是CLLocation\\N{\\fs12}So, its basic object is a CL location\r\nDialogue: 0,1:01:13.15,1:01:18.45,yin,,0,0,0,,其属性包括坐标 包括纬度和经度 然后还有高度\\N{\\fs12}that it concludes a coordinate which is, you know, latitude and longitude, altitude.\r\nDialogue: 0,1:01:18.45,1:01:20.01,yin,,0,0,0,,水平/竖直精度\\N{\\fs12}Horizontal and vertical accuracy,\r\nDialogue: 0,1:01:20.01,1:01:22.35,yin,,0,0,0,,我们会谈到这个的重要性 时间戳 速度\\N{\\fs12}we'll talk about why that's important, time stamps, speed,\r\nDialogue: 0,1:01:22.35,1:01:23.53,yin,,0,0,0,,路线等等这些\\N{\\fs12}course, things like that.\r\nDialogue: 0,1:01:23.53,1:01:26.63,yin,,0,0,0,,这就是CLLocation对象\\N{\\fs12}That's the CL location object.\r\nDialogue: 0,1:01:26.63,1:01:31.34,yin,,0,0,0,,这个对象有一个很重要的属性 叫坐标(coordinate)\\N{\\fs12}This object has this very important property called coordinate,\r\nDialogue: 0,1:01:31.34,1:01:34.01,yin,,0,0,0,,这是一个C struct\\N{\\fs12}and that is a C-struct,\r\nDialogue: 0,1:01:34.01,1:01:36.32,yin,,0,0,0,,CLLocationCoordinate2D\\N{\\fs12}CL location coordinate 2D,\r\nDialogue: 0,1:01:36.32,1:01:38.89,yin,,0,0,0,,其中是CLLocationDegrees\\N{\\fs12}and inside is just CL location degrees,\r\nDialogue: 0,1:01:38.89,1:01:43.10,yin,,0,0,0,,这是一个双精度纬度值 另外一个是经度值\\N{\\fs12}which is essentially a double, which is latitude, and another one which is longitude.\r\nDialogue: 0,1:01:43.10,1:01:46.65,yin,,0,0,0,,然后高度是以米计的\\N{\\fs12}And then the altitude is in meters.\r\nDialogue: 0,1:01:46.65,1:01:50.09,yin,,0,0,0,,这就是Core Location中的基本对象\\N{\\fs12}Okay, so this is the basic object in core location.\r\nDialogue: 0,1:01:50.09,1:01:52.92,yin,,0,0,0,,问题是 如何…\\N{\\fs12}So the question is how do...oh!\r\nDialogue: 0,1:01:52.92,1:01:55.47,yin,,0,0,0,,抱歉 让我讲讲精度 它很重要\\N{\\fs12}sorry, let me talk about accuracy, very important.\r\nDialogue: 0,1:01:55.47,1:01:58.29,yin,,0,0,0,,当你获得一个位置时\\N{\\fs12}So when you get a location,\r\nDialogue: 0,1:01:58.29,1:02:02.51,yin,,0,0,0,,这个位置可能会具有变化精度\\N{\\fs12}you got it in a certain way that might have varying accuracy.\r\nDialogue: 0,1:02:02.51,1:02:06.73,yin,,0,0,0,,如果位置是从GPS获得的 那就会非常准确\\N{\\fs12}If you got that location from GPS, it could be very accurate.\r\nDialogue: 0,1:02:06.73,1:02:12.29,yin,,0,0,0,,如果是通过当地电话塔得到 那就可能非常不准\\N{\\fs12}If you got it by looking at local cell towers, it might be pretty inaccurate.\r\nDialogue: 0,1:02:12.29,1:02:15.09,yin,,0,0,0,,可能会差一英里远\\N{\\fs12}Right? It could be a mile off, actually.\r\nDialogue: 0,1:02:15.09,1:02:17.92,yin,,0,0,0,,两者之间还有一些方式\\N{\\fs12}If you got it that way. And there's ways in between.\r\nDialogue: 0,1:02:17.92,1:02:22.06,yin,,0,0,0,,在斯坦福校园 你可以通过使用wifi得到\\N{\\fs12}On Stanford campus, you can actually get it by using wi-fi.\r\nDialogue: 0,1:02:22.06,1:02:27.45,yin,,0,0,0,,它会寻找周围的wifi 以此告诉你你在哪里\\N{\\fs12}It can look around, see what wi-fi things are near you and tell by that where you are.\r\nDialogue: 0,1:02:27.45,1:02:29.71,yin,,0,0,0,,听起来有些恐怖吧 它知道你在哪\\N{\\fs12}Kind of scary, huh? So it knows where you are.\r\nDialogue: 0,1:02:29.71,1:02:32.73,yin,,0,0,0,,哪怕是在室内 这个也能奏效\\N{\\fs12}And that works even if you're indoors or whatever, so.\r\nDialogue: 0,1:02:32.73,1:02:36.68,yin,,0,0,0,,现在 这只适用于公共wifi节点这些\\N{\\fs12}Now, it only works for public wi-fi nodes, et cetera,\r\nDialogue: 0,1:02:36.68,1:02:39.02,yin,,0,0,0,,不过在斯坦福 这些wifi节点都众所周知\\N{\\fs12}but at Stanford, these wi-fi nodes are all well-known,\r\nDialogue: 0,1:02:39.02,1:02:41.35,yin,,0,0,0,,因此 它知道你在哪\\N{\\fs12}so it knows where you are.\r\nDialogue: 0,1:02:41.35,1:02:43.94,yin,,0,0,0,,指定这个精度可以使用\\N{\\fs12}And you specify this accuracy using one\r\nDialogue: 0,1:02:43.94,1:02:47.23,yin,,0,0,0,,这些kCLLocationAccuracy常数\\N{\\fs12}of this KCL location accuracy constants,\r\nDialogue: 0,1:02:47.23,1:02:49.19,yin,,0,0,0,,有一个叫BestForNavigation\\N{\\fs12}and so there's best for navigation,\r\nDialogue: 0,1:02:49.20,1:02:51.19,yin,,0,0,0,,如果你想要这个精度\\N{\\fs12}if you want that kind of accuracy, that's going\r\nDialogue: 0,1:02:51.19,1:02:54.24,yin,,0,0,0,,它会消耗电量 因为它会持续通信GPS\\N{\\fs12}to use your battery because it's going to be constantly doing GPS.\r\nDialogue: 0,1:02:54.24,1:02:56.38,yin,,0,0,0,,这只在电话插入到电源时适用\\N{\\fs12}So that would be only if your phone was plugged in,\r\nDialogue: 0,1:02:56.38,1:03:00.05,yin,,0,0,0,,例如在车上 插入到点烟器或是别的什么里\\N{\\fs12}like you're in your car, and it's plugged into the cigarette lighter or whatever,\r\nDialogue: 0,1:03:00.05,1:03:03.62,yin,,0,0,0,,现在车上应该还有USB端口 无论如何\\N{\\fs12}or I guess they have USB ports nowadays in cars, but anyway,\r\nDialogue: 0,1:03:03.62,1:03:04.97,yin,,0,0,0,,你需要有电源\\N{\\fs12}you would want power there.\r\nDialogue: 0,1:03:04.97,1:03:08.56,yin,,0,0,0,,然后是Best 这也是GPS 不过不那么耗电\\N{\\fs12}Then there's best, which is also GPS, but not quite as power hungry,\r\nDialogue: 0,1:03:08.56,1:03:10.72,yin,,0,0,0,,然后一直往下 使用wifi\\N{\\fs12}and then all the way down using wi-fi\r\nDialogue: 0,1:03:10.72,1:03:13.21,yin,,0,0,0,,这些东西的精度越来越弱\\N{\\fs12}and these other things to less and less accuracy,\r\nDialogue: 0,1:03:13.21,1:03:18.49,yin,,0,0,0,,无论位置如何获得 它都会汇报使用的精度是多少\\N{\\fs12}but how ever the location was found, it will also report to you what accuracy it used.\r\nDialogue: 0,1:03:18.49,1:03:23.09,yin,,0,0,0,,无论是水平方向 还是竖直方向的高度\\N{\\fs12}Both in terms of horizontally and then altitude wise, vertically.\r\nDialogue: 0,1:03:23.09,1:03:27.30,yin,,0,0,0,,理解精度关系到电量\\N{\\fs12}Understand that accuracy means power.\r\nDialogue: 0,1:03:27.30,1:03:30.63,yin,,0,0,0,,要求越精准 所耗电量也会越大\\N{\\fs12}The more accuracy you ask for, the more power you're going to use.\r\nDialogue: 0,1:03:30.63,1:03:34.36,yin,,0,0,0,,请选择程序能工作的最小精度\\N{\\fs12}So ask for the least accuracy your application can deal\r\nDialogue: 0,1:03:34.36,1:03:37.08,yin,,0,0,0,,这样就能避免用电过度\\N{\\fs12}with so that you use as little power as possible.\r\nDialogue: 0,1:03:37.08,1:03:39.26,yin,,0,0,0,,这一点很重要\\N{\\fs12}Very important point.\r\nDialogue: 0,1:03:39.26,1:03:41.66,yin,,0,0,0,,这里还有一些属性 我不打算讲\\N{\\fs12}Okay, some other properties there, I'm not really going\r\nDialogue: 0,1:03:41.66,1:03:43.03,yin,,0,0,0,,这里我只提供幻灯片\\N{\\fs12}to talk about them, you have the slides for them.\r\nDialogue: 0,1:03:43.03,1:03:44.47,yin,,0,0,0,,很明显的东西 速度\\N{\\fs12}Obvious things, speed\r\nDialogue: 0,1:03:44.47,1:03:48.08,yin,,0,0,0,,通过看所有点如何随时间运动来计算\\N{\\fs12}is calculated by seeing all the points that you're moving through time,\r\nDialogue: 0,1:03:48.08,1:03:51.15,yin,,0,0,0,,速度可以计算 诸如此类\\N{\\fs12}and it can calculate your speed, things like that.\r\nDialogue: 0,1:03:51.15,1:03:54.19,yin,,0,0,0,,那如何获得这些Core Location对象呢\\N{\\fs12}So how do you get one of these core location guys?\r\nDialogue: 0,1:03:54.19,1:03:58.10,yin,,0,0,0,,我要获得一个Core Location对象 它会告诉我我在哪\\N{\\fs12}I want to get a core location object, it says where I am right now.\r\nDialogue: 0,1:03:58.10,1:04:01.85,yin,,0,0,0,,答案是 使用这个类 名为CLLocationManager\\N{\\fs12}And the answer is, you use this class called CL location manager.\r\nDialogue: 0,1:04:01.85,1:04:05.72,yin,,0,0,0,,你实例化一个CLLocationManager\\N{\\fs12}So you instantiate a core location manager, CLLocationManager\r\nDialogue: 0,1:04:05.74,1:04:08.00,yin,,0,0,0,,然后你进行一些设置\\N{\\fs12}and you're going to set some things up about it,\r\nDialogue: 0,1:04:08.00,1:04:11.41,yin,,0,0,0,,然后你要它开始告诉你 你在哪里\\N{\\fs12}and then you're going to tell it to start telling you where you are,\r\nDialogue: 0,1:04:11.41,1:04:12.83,yin,,0,0,0,,它有一个委托\\N{\\fs12}and it's got a delegate,\r\nDialogue: 0,1:04:12.83,1:04:14.48,yin,,0,0,0,,它会告诉委托 你在哪里\\N{\\fs12}and it's going to start telling that delegate where you are.\r\nDialogue: 0,1:04:14.48,1:04:15.63,yin,,0,0,0,,这就是它的工作方式\\N{\\fs12}So that's basically how it works.\r\nDialogue: 0,1:04:15.63,1:04:19.21,yin,,0,0,0,,在调试器中 你可以模拟你的位置\\N{\\fs12}Now, you can simulate where you are, by the way, in the debugger.\r\nDialogue: 0,1:04:19.21,1:04:23.23,yin,,0,0,0,,使用调试栏的这个下拉菜单\\N{\\fs12}With this little thing down by the debug bar,\r\nDialogue: 0,1:04:23.23,1:04:26.52,yin,,0,0,0,,这里有一些位置 你可以模拟\\N{\\fs12}place where the pause and all that, you can just simulate where you are,\r\nDialogue: 0,1:04:26.52,1:04:28.36,yin,,0,0,0,,你还可以往其中添加地点\\N{\\fs12}you can even add places that you are,\r\nDialogue: 0,1:04:28.36,1:04:31.13,yin,,0,0,0,,你可以在这里有很多位置\\N{\\fs12}if you want to like have a whole series of locations\r\nDialogue: 0,1:04:31.13,1:04:34.43,yin,,0,0,0,,用于检查你的应用程序是否能够正常工作\\N{\\fs12}that you want to check running through to see if your application is working.\r\nDialogue: 0,1:04:34.43,1:04:38.99,yin,,0,0,0,,这是一个模拟位置的很酷的方式\\N{\\fs12}So this is a really cool way to simulate being somewhere.\r\nDialogue: 0,1:04:38.99,1:04:40.75,yin,,0,0,0,,好 CLLocationManager\\N{\\fs12}Alright, so CL location manager,\r\nDialogue: 0,1:04:40.75,1:04:43.46,yin,,0,0,0,,如何使用这个来得到我们的位置呢\\N{\\fs12}how do we use this thing to get our location?\r\nDialogue: 0,1:04:43.46,1:04:46.53,yin,,0,0,0,,你创建它 然后检查你的硬件\\N{\\fs12}You create it, you check to see what hardware you have,\r\nDialogue: 0,1:04:46.53,1:04:52.09,yin,,0,0,0,,因为不同的设备iPhone4 iPhone5 iPad\\N{\\fs12}because every different device, iPhone 4, iPhone 5, iPads,\r\nDialogue: 0,1:04:52.09,1:04:55.82,yin,,0,0,0,,都有不同的硬件 用于确定位置\\N{\\fs12}have different hardware in them for figuring out where they are,\r\nDialogue: 0,1:04:55.82,1:04:58.81,yin,,0,0,0,,因此 你要检查硬件\\N{\\fs12}and so you're going to check to see what's available.\r\nDialogue: 0,1:04:58.81,1:05:02.28,yin,,0,0,0,,然后 你要设定这个委托\\N{\\fs12}Then you're going to add, set this delegate\r\nDialogue: 0,1:05:02.28,1:05:04.40,yin,,0,0,0,,为你想要的任意对象\\N{\\fs12}to be any object you want, and then you're going\r\nDialogue: 0,1:05:04.40,1:05:08.33,yin,,0,0,0,,然后你要配置 你要怎样的更新 精度这些\\N{\\fs12}to configure it for what kind of location updates you want, accuracy, things like that,\r\nDialogue: 0,1:05:08.33,1:05:09.78,yin,,0,0,0,,然后让它运行\\N{\\fs12}and then you're going to start it running.\r\nDialogue: 0,1:05:09.78,1:05:13.66,yin,,0,0,0,,它这就会向你汇报 你在哪里\\N{\\fs12}And it's going to start reporting to you where you are.\r\nDialogue: 0,1:05:13.66,1:05:16.77,yin,,0,0,0,,那么 有哪些位置监控可用呢\\N{\\fs12}So what kinds of location monitoring are available?\r\nDialogue: 0,1:05:16.77,1:05:20.27,yin,,0,0,0,,有基于精度的汇报\\N{\\fs12}There is accuracy based reporting.\r\nDialogue: 0,1:05:20.29,1:05:25.29,yin,,0,0,0,,你指定一个精度 它在精度范围内告诉你你在哪\\N{\\fs12}So you specify an accuracy and it will tell you to that accuracy where you are.\r\nDialogue: 0,1:05:25.29,1:05:28.25,yin,,0,0,0,,你还可以得到更新\\N{\\fs12}There's updates that you can get\r\nDialogue: 0,1:05:28.25,1:05:32.91,yin,,0,0,0,,它只在重大位置变化时才会发消息给你\\N{\\fs12}where it will send you a message only when a significant change in position has happened.\r\nDialogue: 0,1:05:32.91,1:05:36.89,yin,,0,0,0,,假想这里使用的是电话塔这之类\\N{\\fs12}Imagine maybe it's using cell towers or something there,\r\nDialogue: 0,1:05:36.89,1:05:40.63,yin,,0,0,0,,也有可能使用的是wifi\\N{\\fs12}or if wi-fi is fired up for other reasons, it might be able to be using wi-fi, right?\r\nDialogue: 0,1:05:40.63,1:05:42.99,yin,,0,0,0,,估计不会是GPS\\N{\\fs12}But it's probably not going to use GPS.\r\nDialogue: 0,1:05:42.99,1:05:45.42,yin,,0,0,0,,只在重大变化发生时告诉你\\N{\\fs12}Only when significant changes occur.\r\nDialogue: 0,1:05:45.42,1:05:47.25,yin,,0,0,0,,然后还有基于区域的更新\\N{\\fs12}You also have region based updates.\r\nDialogue: 0,1:05:47.25,1:05:49.75,yin,,0,0,0,,在干洗店周围设一个圈\\N{\\fs12}Put a little circle around the dry cleaners,\r\nDialogue: 0,1:05:49.75,1:05:54.58,yin,,0,0,0,,你经过时 它会告诉你 你正在干洗店附近\\N{\\fs12}when you walk by or drive by, it will tell you, \"Oh, you're by the dry cleaner.\"\r\nDialogue: 0,1:05:54.58,1:05:55.40,yin,,0,0,0,,这是区域\\N{\\fs12}So that's region.\r\nDialogue: 0,1:05:55.40,1:05:58.95,yin,,0,0,0,,你可以设定一个小的圆形或信标区域 我会谈到这些\\N{\\fs12}So you can set up a little region, circular regions, beacons, we'll talk about those.\r\nDialogue: 0,1:05:58.95,1:06:01.59,yin,,0,0,0,,然后你还可以监控你的前进方向\\N{\\fs12}And then you can also monitor your heading.\r\nDialogue: 0,1:06:01.59,1:06:03.77,yin,,0,0,0,,我正朝哪个方向走\\N{\\fs12}So which way am I walking?\r\nDialogue: 0,1:06:03.77,1:06:07.10,yin,,0,0,0,,这可能会用到罗盘 可能会用到GPS\\N{\\fs12}Okay, so that might be using a compass, might be using GPS,\r\nDialogue: 0,1:06:07.10,1:06:08.94,yin,,0,0,0,,取决于设备有什么\\N{\\fs12}just depends on what the device has.\r\nDialogue: 0,1:06:08.94,1:06:12.24,yin,,0,0,0,,我说了 你首先应该检查能力\\N{\\fs12}So the first thing I said was, you've got to check the capabilities.\r\nDialogue: 0,1:06:12.24,1:06:15.25,yin,,0,0,0,,这里有一些方法 出于时间考虑 我不会都讲\\N{\\fs12}So here's a whole bunch of methods, I'm not going to go through them for time reasons,\r\nDialogue: 0,1:06:15.25,1:06:17.28,yin,,0,0,0,,不过你需要检查这些\\N{\\fs12}but you need to check these.\r\nDialogue: 0,1:06:17.28,1:06:22.03,yin,,0,0,0,,例如 用户可能会对你关闭定位服务\\N{\\fs12}Because, for example, the user might have turned off location services for you.\r\nDialogue: 0,1:06:22.03,1:06:24.14,yin,,0,0,0,,你需要知道 你需要作出应对\\N{\\fs12}So you've got to know, you've got to deal with that,\r\nDialogue: 0,1:06:24.14,1:06:25.83,yin,,0,0,0,,你可以要他们重新打开\\N{\\fs12}either ask them to turn it back on, okay,\r\nDialogue: 0,1:06:25.83,1:06:29.32,yin,,0,0,0,,这里也可能有受限的情况\\N{\\fs12}there's this restricted thing for this too.\r\nDialogue: 0,1:06:29.32,1:06:32.19,yin,,0,0,0,,你也可能在app中做些别的什么\\N{\\fs12}Or whatever you want to do, or do some different thing in your app,\r\nDialogue: 0,1:06:32.19,1:06:34.90,yin,,0,0,0,,你可能处在没有这些位置更新的设备\\N{\\fs12}if you work with all those location updates or whatever,\r\nDialogue: 0,1:06:34.90,1:06:38.00,yin,,0,0,0,,程序所在的设备甚至有可能没有你想要的硬件\\N{\\fs12}you might be on a device that doesn't have the hardware you need to do what you want,\r\nDialogue: 0,1:06:38.00,1:06:42.88,yin,,0,0,0,,最开始创建LocationManager时 你需要检查所有这些\\N{\\fs12}so you need to all check all this when you first create your location manager.\r\nDialogue: 0,1:06:42.88,1:06:47.39,yin,,0,0,0,,获得信息后 你可以问LocationManager\\N{\\fs12}So then getting it, you can ask a location manager,\r\nDialogue: 0,1:06:47.39,1:06:52.28,yin,,0,0,0,,我现在在哪 但我们从不这样做 我们会用委托\\N{\\fs12}\"where am I right now?\" Kind of poll it? We never do that. We use this delegate thing.\r\nDialogue: 0,1:06:52.28,1:06:53.74,yin,,0,0,0,,下面我来讲讲委托这些\\N{\\fs12}So let's talk about how the delegate thing works.\r\nDialogue: 0,1:06:53.74,1:06:56.03,yin,,0,0,0,,首先 你要指定想要的精度\\N{\\fs12}First, you specify the accuracy.\r\nDialogue: 0,1:06:56.03,1:07:00.32,yin,,0,0,0,,这是一个LocationManager属性 desiredAccuracy\\N{\\fs12}This is location manager property, desired accuracy,\r\nDialogue: 0,1:07:00.32,1:07:01.80,yin,,0,0,0,,之前我讲了精度\\N{\\fs12}I showed you the accuracies before.\r\nDialogue: 0,1:07:01.80,1:07:02.96,yin,,0,0,0,,指定这个\\N{\\fs12}Specify that.\r\nDialogue: 0,1:07:02.96,1:07:05.42,yin,,0,0,0,,你还要指定一个距离过滤器(distanceFilter)\\N{\\fs12}And also you can specify a distance filter, in other words,\r\nDialogue: 0,1:07:05.42,1:07:09.61,yin,,0,0,0,,在用户移动这么远之前 不要告诉我\\N{\\fs12}until the user moves at least this far, don't even tell me.\r\nDialogue: 0,1:07:09.61,1:07:15.01,yin,,0,0,0,,如果用户没移动一百米或是一千米 不要跟我讲\\N{\\fs12}So if they don't go at least 100 meters, or a kilometer, don't tell me about it,\r\nDialogue: 0,1:07:15.01,1:07:16.58,yin,,0,0,0,,这也能省电\\N{\\fs12}so that saves battery too.\r\nDialogue: 0,1:07:16.58,1:07:21.02,yin,,0,0,0,,这些设备中的GPS芯片 特别是最新的那些 都非常棒\\N{\\fs12}The chip, the GPS chip in these devices, especially newer ones, really awesome.\r\nDialogue: 0,1:07:21.02,1:07:24.55,yin,,0,0,0,,这里指定的很多东西可以被加载到芯片中\\N{\\fs12}A lot of this stuff that you specify here gets loaded into the chip,\r\nDialogue: 0,1:07:24.55,1:07:27.25,yin,,0,0,0,,然后芯片会亲自计算你在哪\\N{\\fs12}and the chip by itself is calculating where you are\r\nDialogue: 0,1:07:27.25,1:07:29.04,yin,,0,0,0,,你是否移动了足够远 等等\\N{\\fs12}and whether you went far enough and all that stuff,\r\nDialogue: 0,1:07:29.04,1:07:30.27,yin,,0,0,0,,然后重新唤醒手机\\N{\\fs12}and then waking the phone back up.\r\nDialogue: 0,1:07:30.27,1:07:33.68,yin,,0,0,0,,整个手机在睡眠 但GPS却在监视\\N{\\fs12}The whole phone can sleep and the GPS is still watching,\r\nDialogue: 0,1:07:33.68,1:07:36.69,yin,,0,0,0,,如果你能让这些最好地协作\\N{\\fs12}and so if you can tune these to be as minimal as possible,\r\nDialogue: 0,1:07:36.69,1:07:39.67,yin,,0,0,0,,设备的电量会节省很多\\N{\\fs12}you will save a ton of battery in the device, because only\r\nDialogue: 0,1:07:39.67,1:07:43.48,yin,,0,0,0,,因为只有GPS芯片在监控\\N{\\fs12}that GPS chip will be watching, you know, what's going on.\r\nDialogue: 0,1:07:43.48,1:07:46.96,yin,,0,0,0,,然后更新的获取需要调用方法\\N{\\fs12}Okay so then you start getting the updates\r\nDialogue: 0,1:07:46.96,1:07:48.98,yin,,0,0,0,,startUpdatingLocation\\N{\\fs12}by just calling start updating location,\r\nDialogue: 0,1:07:48.98,1:07:53.90,yin,,0,0,0,,你的委托会基于你指定的精度和距离过滤器\\N{\\fs12}and your delegate will start getting sent messages based on the accuracy and the filter\r\nDialogue: 0,1:07:53.90,1:07:56.35,yin,,0,0,0,,开始得到消息\\N{\\fs12}that you specify for distance.\r\nDialogue: 0,1:07:56.35,1:07:58.66,yin,,0,0,0,,这个委托方法是怎样的呢\\N{\\fs12}What does that delegate method look like?\r\nDialogue: 0,1:07:58.66,1:08:02.45,yin,,0,0,0,,locationManager didUpdateLocation是其中之一\\N{\\fs12}Location manager did update to location from location, is one of the ones.\r\nDialogue: 0,1:08:02.45,1:08:04.37,yin,,0,0,0,,其实还有其它一些\\N{\\fs12}There's actually some other ones that you could get sent,\r\nDialogue: 0,1:08:04.37,1:08:06.78,yin,,0,0,0,,你可以检查一下这个的说明文档\\N{\\fs12}so you want to check the documentation on this one,\r\nDialogue: 0,1:08:06.78,1:08:09.44,yin,,0,0,0,,不过这个最基本 它说 好\\N{\\fs12}but this is the basic one, where it's saying \"Okay,\r\nDialogue: 0,1:08:09.44,1:08:12.70,yin,,0,0,0,,我得到了一个新位置 在这里\\N{\\fs12}I got a new location, here it is,\" that location\r\nDialogue: 0,1:08:12.70,1:08:16.59,yin,,0,0,0,,这个位置显然有精度 时间戳等所有这些\\N{\\fs12}of course will have accuracy and time stamp, all these other things in there,\r\nDialogue: 0,1:08:16.59,1:08:20.66,yin,,0,0,0,,它会给你一个位置 便于你来使用\\N{\\fs12}and it just gives you the fun location just for your own convenience,\r\nDialogue: 0,1:08:20.66,1:08:24.88,yin,,0,0,0,,如果你只想看差异 你就不需要跟踪\\N{\\fs12}so you don't have to keep it if you just want to see the difference.\r\nDialogue: 0,1:08:24.88,1:08:27.97,yin,,0,0,0,,这是这个 LocationManager在我看来非常简单\\N{\\fs12}So that's it. It's quite simple, actually to use this location manager.\r\nDialogue: 0,1:08:27.97,1:08:31.60,yin,,0,0,0,,不过要在一小时内耗完用户的电量也很容易\\N{\\fs12}It's also quite simple to drain the user's battery in about an hour,\r\nDialogue: 0,1:08:31.60,1:08:34.26,yin,,0,0,0,,务必小心 务必知道自己在做什么\\N{\\fs12}okay, so be careful and know what you're doing here.\r\nDialogue: 0,1:08:34.26,1:08:38.70,yin,,0,0,0,,跟踪前进方向也有一个类似的API\\N{\\fs12}There's a similar API for heading, for tracking the heading.\r\nDialogue: 0,1:08:38.70,1:08:41.17,yin,,0,0,0,,委托可以汇报错误\\N{\\fs12}The delegate can report errors, and this is one case.\r\nDialogue: 0,1:08:41.17,1:08:44.76,yin,,0,0,0,,很多时候 我在demo中都对NSError说nil\\N{\\fs12}A lot of times you see me in my demos, I just say nil for the NS error,\r\nDialogue: 0,1:08:44.76,1:08:46.21,yin,,0,0,0,,我忽略了错误\\N{\\fs12}and I ignore errors,\r\nDialogue: 0,1:08:46.21,1:08:48.66,yin,,0,0,0,,有时 这样做没问题 例如Flickr取回时\\N{\\fs12}and sometimes that's okay, like if I'm doing a Flickr fetch\r\nDialogue: 0,1:08:48.66,1:08:50.62,yin,,0,0,0,,失败了也没关系 因为我知道\\N{\\fs12}and if it fails, I just don't care because I know I'm going\r\nDialogue: 0,1:08:50.62,1:08:52.72,yin,,0,0,0,,二十分钟内我还会再次取回\\N{\\fs12}to be doing another fetch in 20 minutes,\r\nDialogue: 0,1:08:52.72,1:08:55.18,yin,,0,0,0,,于是我就让它失败 其实哪怕那里\\N{\\fs12}so I'll just let it fail, although even there,\r\nDialogue: 0,1:08:55.18,1:08:57.61,yin,,0,0,0,,我也应该检查 如果它持续失败\\N{\\fs12}I probably want to check it, and if it keeps failing over and over,\r\nDialogue: 0,1:08:57.61,1:09:00.43,yin,,0,0,0,,或许我就应该让用户参与进来\\N{\\fs12}then I need to maybe get the user involved.\r\nDialogue: 0,1:09:00.43,1:09:02.25,yin,,0,0,0,,不过这里 你需要检查错误\\N{\\fs12}But here, you really want to check the errors.\r\nDialogue: 0,1:09:02.25,1:09:04.85,yin,,0,0,0,,还是出于时间考虑 我只能\\N{\\fs12}Okay, and again for time reasons, I don't have time to go\r\nDialogue: 0,1:09:04.85,1:09:07.52,yin,,0,0,0,,细到说这些错误有可能出现\\N{\\fs12}through the details more than just that these errors can occur,\r\nDialogue: 0,1:09:07.52,1:09:10.03,yin,,0,0,0,,不过面对特定错误 你需要做特定的事情\\N{\\fs12}but there are certain things you need to do in certain errors\r\nDialogue: 0,1:09:10.03,1:09:16.04,yin,,0,0,0,,这样才能写出优秀的Core Location获取app\\N{\\fs12}if you really want to be a good core location getting app.\r\nDialogue: 0,1:09:16.04,1:09:19.30,yin,,0,0,0,,后台 这些位置更新能否在后台获得\\N{\\fs12}Um, background, can you get these location updates in the background?\r\nDialogue: 0,1:09:19.30,1:09:22.25,yin,,0,0,0,,我保证我会讲这个 而且还有一张幻灯片\\N{\\fs12}Okay, I promised I was going to talk about this, and I even have a slide about it.\r\nDialogue: 0,1:09:22.25,1:09:24.41,yin,,0,0,0,,答案是 能\\N{\\fs12}And the answer is, you can.\r\nDialogue: 0,1:09:24.41,1:09:27.66,yin,,0,0,0,,你甚至可以让app\\N{\\fs12}You can even sign up to be the kind of app\r\nDialogue: 0,1:09:27.66,1:09:33.97,yin,,0,0,0,,一般只在后台运行位置管理器\\N{\\fs12}that gets the location manager will just run in the background normally.\r\nDialogue: 0,1:09:33.97,1:09:35.38,yin,,0,0,0,,这是相同位置 记得吗\\N{\\fs12}It's the same place, remember when we went\r\nDialogue: 0,1:09:35.38,1:09:37.25,yin,,0,0,0,,我在讲后台取回时讲过\\N{\\fs12}and did the background fetches, we had to go\r\nDialogue: 0,1:09:37.25,1:09:39.59,yin,,0,0,0,,有项目设定可以选\\N{\\fs12}to our project settings, and we clicked that switch?\r\nDialogue: 0,1:09:39.59,1:09:41.91,yin,,0,0,0,,位置也有一个开关\\N{\\fs12}There's another switch there that's just location,\r\nDialogue: 0,1:09:41.91,1:09:44.48,yin,,0,0,0,,开启后 你就会得到这个\\N{\\fs12}and when you do that, you'll start getting this.\r\nDialogue: 0,1:09:44.48,1:09:48.66,yin,,0,0,0,,不过这只适用于健身app\\N{\\fs12}But that's really for apps like, you know, a fitness app\r\nDialogue: 0,1:09:48.66,1:09:51.32,yin,,0,0,0,,你把手机放口袋里跑步\\N{\\fs12}where you're going off to do a mile run and your phone is\r\nDialogue: 0,1:09:51.32,1:09:53.94,yin,,0,0,0,,手机在后台记录你的进度\\N{\\fs12}in the pocket and it's tracking your progress,\r\nDialogue: 0,1:09:53.94,1:09:56.59,yin,,0,0,0,,你把手机调好\\N{\\fs12}and you've tuned it to, you know,\r\nDialogue: 0,1:09:56.59,1:10:00.30,yin,,0,0,0,,让它进行联合 记录轨迹 并向你汇报\\N{\\fs12}coalesce things and to keep track of it and report it to you.\r\nDialogue: 0,1:10:00.30,1:10:03.31,yin,,0,0,0,,如果你做健身app 你可能会很快耗光电量\\N{\\fs12}You know, when you do a fitness app, you can really drain the battery fast.\r\nDialogue: 0,1:10:03.31,1:10:06.11,yin,,0,0,0,,顺便说下 期末项目不要做健身app\\N{\\fs12}So if you're doing a fitness app, by the way, which don't do\r\nDialogue: 0,1:10:06.11,1:10:07.82,yin,,0,0,0,,顺便说下 期末项目不要做健身app\\N{\\fs12}that for your final project, but,\r\nDialogue: 0,1:10:07.82,1:10:11.76,yin,,0,0,0,,不过如果你以后真的要做健身app\\N{\\fs12}if you're doing a fitness app, for the real, for real,\r\nDialogue: 0,1:10:11.76,1:10:14.65,yin,,0,0,0,,那么你就需要很清楚自己在做什么\\N{\\fs12}then you really got to know what you're doing. So really investigate that\r\nDialogue: 0,1:10:14.66,1:10:17.91,yin,,0,0,0,,否则电量会受不了 不过你还是可以做很多很酷的事\\N{\\fs12}because you really want to be low power, but you can still do lots of cool things\r\nDialogue: 0,1:10:17.91,1:10:20.94,yin,,0,0,0,,这在跟踪用户跑步时是可以做到的\\N{\\fs12}when it comes to tracking where the user's running.\r\nDialogue: 0,1:10:20.94,1:10:24.04,yin,,0,0,0,,无论如何 像这样在后台运行\\N{\\fs12}However, running in the background like that,\r\nDialogue: 0,1:10:24.04,1:10:26.85,yin,,0,0,0,,由于会用掉很多电量\\N{\\fs12}since it uses a lot of battery, is generally only for very,\r\nDialogue: 0,1:10:26.85,1:10:29.28,yin,,0,0,0,,只用于极少量的app\\N{\\fs12}very, very, very small number of apps.\r\nDialogue: 0,1:10:29.28,1:10:33.68,yin,,0,0,0,,不过有两种方式可以获得关于你在哪的后台通知\\N{\\fs12}But there are two ways to get background notifications about where you are, okay,\r\nDialogue: 0,1:10:33.68,1:10:35.70,yin,,0,0,0,,且只消耗很少电量\\N{\\fs12}that are very low power,\r\nDialogue: 0,1:10:35.70,1:10:38.04,yin,,0,0,0,,但它们都非常粗略\\N{\\fs12}and they're a little coarser granularity, they're not going\r\nDialogue: 0,1:10:38.04,1:10:41.35,yin,,0,0,0,,它们不能准确知道你在什么地方\\N{\\fs12}to be running down the trail telling me exactly where I went on the trail,\r\nDialogue: 0,1:10:41.35,1:10:44.35,yin,,0,0,0,,不过它们能大致告诉你 你在哪\\N{\\fs12}but they are telling you kind of where you are\r\nDialogue: 0,1:10:44.35,1:10:46.12,yin,,0,0,0,,这对很多app都很有用\\N{\\fs12}and are really useful for a lot of apps.\r\nDialogue: 0,1:10:46.12,1:10:48.28,yin,,0,0,0,,我来讲讲这两种方式 你可以得到通知\\N{\\fs12}So let's talk about the two ways that you can get notified\r\nDialogue: 0,1:10:48.28,1:10:50.62,yin,,0,0,0,,后台和前台都行\\N{\\fs12}in the background and in the foreground.\r\nDialogue: 0,1:10:50.62,1:10:53.15,yin,,0,0,0,,只要能在后台得到通知\\N{\\fs12}If you can get notified in the background, then you're going\r\nDialogue: 0,1:10:53.15,1:10:55.59,yin,,0,0,0,,你当然也会自动在前台得到通知\\N{\\fs12}to get notified in the foreground automatically.\r\nDialogue: 0,1:10:55.59,1:10:58.33,yin,,0,0,0,,这就是一种后台和前台都得到通知的方式\\N{\\fs12}Here's a way that background and foreground, you can get notified.\r\nDialogue: 0,1:10:58.33,1:11:02.92,yin,,0,0,0,,第一种方法是显著位置变化监控\\N{\\fs12}The first one is called significant location change monitoring,\r\nDialogue: 0,1:11:02.92,1:11:05.12,yin,,0,0,0,,你只是获得一个CLLocationManager\\N{\\fs12}and you just get a CL location manager\r\nDialogue: 0,1:11:05.12,1:11:08.48,yin,,0,0,0,,然后你说startMonitoringSignificantLocationChanges\\N{\\fs12}and you can say start monitoring significant location changes,\r\nDialogue: 0,1:11:08.48,1:11:12.00,yin,,0,0,0,,然后 当用户移动了显著距离时\\N{\\fs12}and then when the user moves a significant amount of distance,\r\nDialogue: 0,1:11:12.00,1:11:14.94,yin,,0,0,0,,你就能通过委托得到通知\\N{\\fs12}you will get notified via your delegate.\r\nDialogue: 0,1:11:14.94,1:11:16.72,yin,,0,0,0,,就这么简单\\N{\\fs12}It's as simple as that.\r\nDialogue: 0,1:11:16.72,1:11:19.15,yin,,0,0,0,,哪怕是在后台 这也能工作\\N{\\fs12}And this works even if you're in the background.\r\nDialogue: 0,1:11:19.15,1:11:22.28,yin,,0,0,0,,哪怕在应用没有运行的时候\\N{\\fs12}Even if your application is not running.\r\nDialogue: 0,1:11:22.28,1:11:27.47,yin,,0,0,0,,应用也会得到启动 告诉用户移动到了新地方\\N{\\fs12}You will get launched to be told that the person moved to a new space.\r\nDialogue: 0,1:11:27.47,1:11:31.24,yin,,0,0,0,,这是一个很妙的API 非常节能高效\\N{\\fs12}This is an awesome API, okay, very power efficient\r\nDialogue: 0,1:11:31.24,1:11:33.98,yin,,0,0,0,,因为它知道如何管理跟踪位置\\N{\\fs12}because it knows how to manage tracking where you are\r\nDialogue: 0,1:11:33.98,1:11:37.14,yin,,0,0,0,,以一种高效的方式 同时超级有用\\N{\\fs12}in an efficient way and still super useful for you.\r\nDialogue: 0,1:11:37.14,1:11:41.70,yin,,0,0,0,,它唯一的缺点就是要求显著距离变化\\N{\\fs12}The only downside of it is significant distance. You have to be going significant distance.\r\nDialogue: 0,1:11:41.70,1:11:42.27,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,1:11:44.80,1:11:47.39,yin,,0,0,0,,问题是 我们对显著的定义有没有控制\\N{\\fs12}The question is do we have any control of the definition of significant,\r\nDialogue: 0,1:11:47.39,1:11:48.88,yin,,0,0,0,,答案是没有\\N{\\fs12}the answer is no.\r\nDialogue: 0,1:11:50.24,1:11:52.35,yin,,0,0,0,,当你的程序没有运行\\N{\\fs12}So yeah, so when you get launched in the background,\r\nDialogue: 0,1:11:52.35,1:11:54.13,yin,,0,0,0,,然后在后台被启动时\\N{\\fs12}if you get launched, like you're not running,\r\nDialogue: 0,1:11:54.13,1:11:58.26,yin,,0,0,0,,application didFinishLaunchingWithOptions会被发送\\N{\\fs12}you'll get your application did finish launching with options thing will be sent,\r\nDialogue: 0,1:11:58.26,1:12:00.36,yin,,0,0,0,,不过这里会有一个字典\\N{\\fs12}but there will be a dictionary there, and one of the things\r\nDialogue: 0,1:12:00.36,1:12:03.87,yin,,0,0,0,,字典中会有UIApplicationLaunchOptionsLocationKey\\N{\\fs12}in the dictionary will be UI application launch options location key,\r\nDialogue: 0,1:12:03.87,1:12:06.63,yin,,0,0,0,,如果里面有这个键 这意味着你被启动了\\N{\\fs12}and if that key is in there, that means you got launched\r\nDialogue: 0,1:12:06.63,1:12:10.59,yin,,0,0,0,,因为有显著变化发生 你就是这样知道 哦\\N{\\fs12}because a significant change happened, so that's how you know, \"Oh,\r\nDialogue: 0,1:12:10.59,1:12:12.01,yin,,0,0,0,,因此我被启动了\\N{\\fs12}that's why I got launched,\" okay?\r\nDialogue: 0,1:12:12.01,1:12:13.51,yin,,0,0,0,,因为这个键\\N{\\fs12}Because of that key.\r\nDialogue: 0,1:12:13.51,1:12:22.39,yin,,0,0,0,,另外一种在后台定位的方式是基于区域的监控 非常类似\\N{\\fs12}Another way to find out in the background is region based monitoring, very similar,\r\nDialogue: 0,1:12:22.39,1:12:26.07,yin,,0,0,0,,只是这里 你指定的是一个圆形区域\\N{\\fs12}except for here you actually specify either a circular region\r\nDialogue: 0,1:12:26.07,1:12:28.81,yin,,0,0,0,,或是一个信标区域\\N{\\fs12}or you can also specify a beacon.\r\nDialogue: 0,1:12:28.81,1:12:30.35,yin,,0,0,0,,等下我会讲到这个\\N{\\fs12}And I'll talk about that in a second.\r\nDialogue: 0,1:12:30.35,1:12:33.12,yin,,0,0,0,,你可以指定地球上的一个圆形区域\\N{\\fs12}So you specify circular region on the planet, you know,\r\nDialogue: 0,1:12:33.12,1:12:35.13,yin,,0,0,0,,一个坐标 以及周围的半径\\N{\\fs12}coordinate, and then a radius around it,\r\nDialogue: 0,1:12:35.13,1:12:38.88,yin,,0,0,0,,只要用户进入这个区域 你就会得到通知\\N{\\fs12}and if the user goes into that region, you'll get notified,\r\nDialogue: 0,1:12:38.88,1:12:42.68,yin,,0,0,0,,你的委托会发送消息 有必要时你还会被启动\\N{\\fs12}your delegate will send a message, or you'll get launched if necessary,\r\nDialogue: 0,1:12:42.70,1:12:44.02,yin,,0,0,0,,这样你就能知道\\N{\\fs12}and you'll find out.\r\nDialogue: 0,1:12:44.02,1:12:46.01,yin,,0,0,0,,没错 这个能有多少是受限制的\\N{\\fs12}Now, yes, there's a limit to how many of these you can have,\r\nDialogue: 0,1:12:46.01,1:12:49.96,yin,,0,0,0,,具体多少我不知道 可能是40个左右吧 你的app\\N{\\fs12}I don't know what it is, 40 or something like that, your app,\r\nDialogue: 0,1:12:49.96,1:12:52.64,yin,,0,0,0,,不过 这个也非常高效\\N{\\fs12}and but this is also incredibly efficient.\r\nDialogue: 0,1:12:52.64,1:12:56.59,yin,,0,0,0,,这个也作用于低能耗高效率的基础上\\N{\\fs12}So this is happening at a very lower, power-efficient level as well.\r\nDialogue: 0,1:12:56.59,1:13:03.35,yin,,0,0,0,,圆形区域很明显 你创建一个CLCircularRegion\\N{\\fs12}The circular region is obvious to create, you just create a CL circular region.\r\nDialogue: 0,1:13:03.35,1:13:05.40,yin,,0,0,0,,信标更有趣一些\\N{\\fs12}The beacon is a little more interesting,\r\nDialogue: 0,1:13:05.40,1:13:07.85,yin,,0,0,0,,我没有太多时间讲信标\\N{\\fs12}and I don't really have time to talk about the beacon,\r\nDialogue: 0,1:13:07.85,1:13:13.45,yin,,0,0,0,,信标针对的不是地球上的位置 而是另一个设备\\N{\\fs12}but a beacon is basically not a place on earth, but it's another device.\r\nDialogue: 0,1:13:13.45,1:13:17.52,yin,,0,0,0,,你可以写个程序 让设备成为信标\\N{\\fs12}It's possible to write an application that essentially is a beacon,\r\nDialogue: 0,1:13:17.52,1:13:19.43,yin,,0,0,0,,它会一直广播出去\\N{\\fs12}and it's broadcasting all the time,\r\nDialogue: 0,1:13:19.43,1:13:23.52,yin,,0,0,0,,如果你的app离它很近 你会被唤醒 设备会告诉你\\N{\\fs12}and if your app comes close to it, you'll get woken up and told\r\nDialogue: 0,1:13:23.52,1:13:26.41,yin,,0,0,0,,你进入到了广播设备附近的区域内\\N{\\fs12}that you went into the region of that broadcasting device.\r\nDialogue: 0,1:13:26.41,1:13:28.47,yin,,0,0,0,,这是iOS7的新特性 棒极了\\N{\\fs12}This is new for iOS 7, incredible.\r\nDialogue: 0,1:13:28.47,1:13:31.87,yin,,0,0,0,,我很想看看 人们会用这个特性做些什么\\N{\\fs12}Okay, I'm really interested to see what people come up with this technology.\r\nDialogue: 0,1:13:31.87,1:13:35.80,yin,,0,0,0,,成为一个信标… 这里 顺便说下\\N{\\fs12}Becoming a beacon is, here, by the way,\r\nDialogue: 0,1:13:35.80,1:13:39.46,yin,,0,0,0,,是一个委托方法 didEnterRegion\\N{\\fs12}is the delegate method you get, did enter region\r\nDialogue: 0,1:13:39.46,1:13:43.14,yin,,0,0,0,,还有didExitRegion 你会被启动\\N{\\fs12}and did exit region, and you'll get launched.\r\nDialogue: 0,1:13:43.14,1:13:50.17,yin,,0,0,0,,信标 成为一个… 抱歉 这里我有点快进了…\\N{\\fs12}The beacon is becoming a-- sorry, I'm fast forwarding here--\r\nDialogue: 0,1:13:50.17,1:13:52.88,yin,,0,0,0,,区域是按名称跟踪的 这是因为\\N{\\fs12}uh, yeah, regions are tracked by name, that's because they have\r\nDialogue: 0,1:13:52.88,1:13:55.36,yin,,0,0,0,,它们在你没有启动时需要退出\\N{\\fs12}to exist when you're not launching,\r\nDialogue: 0,1:13:55.36,1:13:58.38,yin,,0,0,0,,还有最大监控距离\\N{\\fs12}there are maximum monitoring distances.\r\nDialogue: 0,1:13:58.38,1:13:59.69,yin,,0,0,0,,好 信标\\N{\\fs12}Uh, okay so beacons.\r\nDialogue: 0,1:13:59.69,1:14:04.61,yin,,0,0,0,,要成为一个信标 你需要使用Core Bluetooth库\\N{\\fs12}To become a beacon, you need to use the core bluetooth library,\r\nDialogue: 0,1:14:04.61,1:14:08.42,yin,,0,0,0,,这不属于Core Location\\N{\\fs12}it's not part of CL core location library.\r\nDialogue: 0,1:14:08.42,1:14:12.81,yin,,0,0,0,,你可以查阅CBPeripheralManager\\N{\\fs12}So you want to look up CB, core bluetooth, peripheral manager,\r\nDialogue: 0,1:14:12.81,1:14:15.11,yin,,0,0,0,,看看如何成为一个信标\\N{\\fs12}and find out if you want to become a beacon.\r\nDialogue: 0,1:14:15.11,1:14:17.37,yin,,0,0,0,,你想成为信标 而不是探测信标\\N{\\fs12}Like you want to be the beacon, not detect a beacon,\r\nDialogue: 0,1:14:17.37,1:14:19.20,yin,,0,0,0,,探测信标用这个\\N{\\fs12}but if you want to detect a beacon, you use this.\r\nDialogue: 0,1:14:19.20,1:14:23.47,yin,,0,0,0,,你创建一个信标区域 CLBeaconRegion\\N{\\fs12}You create a region, which is a beacon region, CL beacon region,\r\nDialogue: 0,1:14:23.47,1:14:27.58,yin,,0,0,0,,你指定信标的特殊标识符\\N{\\fs12}and you specify its special identifier that identifies\r\nDialogue: 0,1:14:27.58,1:14:29.77,yin,,0,0,0,,靠近时它就会告诉你\\N{\\fs12}that beacon, and it just tells you when you get close,\r\nDialogue: 0,1:14:29.77,1:14:32.49,yin,,0,0,0,,它甚至可以告诉你 你离信标有多近\\N{\\fs12}it will even tell you how close you are to the beacon.\r\nDialogue: 0,1:14:32.49,1:14:36.80,yin,,0,0,0,,你离它是远是近 还是正在它上面\\N{\\fs12}Are you near it, or far, or right on top of it.\r\nDialogue: 0,1:14:36.80,1:14:38.09,yin,,0,0,0,,这非常酷\\N{\\fs12}So it's pretty darn cool.\r\nDialogue: 0,1:14:38.09,1:14:39.90,yin,,0,0,0,,这就是区域 区域监控\\N{\\fs12}So that's regions. Region monitoring.\r\nDialogue: 0,1:14:39.90,1:14:44.13,yin,,0,0,0,,区域和显著变化都能在后台通知你\\N{\\fs12}So both region and significant changes will notify you in the background.\r\nDialogue: 0,1:14:44.13,1:14:46.61,yin,,0,0,0,,MapKit留给下一讲吧\\N{\\fs12}So map kit, I'm going to talk about next time.\r\nDialogue: 0,1:14:46.61,1:14:49.16,yin,,0,0,0,,它是一个用户界面\\N{\\fs12}And it is basically a user interface\r\nDialogue: 0,1:14:49.16,1:14:51.54,yin,,0,0,0,,显示这些美丽的地图\\N{\\fs12}for putting these beautiful maps,\r\nDialogue: 0,1:14:51.54,1:14:54.46,yin,,0,0,0,,不过显然 我们需要这些Core Location的东西\\N{\\fs12}but obviously we needed that core location stuff to know\r\nDialogue: 0,1:14:54.46,1:14:58.23,yin,,0,0,0,,来知道我们在哪 东西在哪 这之类\\N{\\fs12}about how to find out about where we are, and where things are, and stuff like that.\r\nDialogue: 0,1:14:58.23,1:15:03.06,yin,,0,0,0,,周三再接着讲 到时见\\N{\\fs12}So we'll pick that up on Wednesday, and I will see you then.\r\nDialogue: 0,1:15:05.35,1:15:08.93,yin,,0,0,0,,更多内容 请访问我校官网stanford.edu\\N{\\fs12}> For more, please visit us at Stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/15. MapKit and Embed Segue.ass",
    "content": "﻿[Script Info] \r\n; Script generated by Aegisub 3.2.0 \r\n; http://www.aegisub.org/ \r\nTitle: Default Aegisub file \r\nScriptType: v4.00+ \r\nWrapStyle: 0 \r\nScaledBorderAndShadow: yes \r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage] \r\nLast Style Storage: Default \r\nActive Line: 6\r\n\r\n[V4+ Styles] \r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding \r\nStyle: yin, 冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events] \r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text \r\nDialogue: 0,0:00:05.32,0:00:09.06,yin,,0,0,0,, 斯坦福大学 \\N{\\fs12}> Stanford University. \r\nDialogue: 0,0:00:09.06,0:00:15.05,yin,,0,0,0,, 欢迎来到 CS193P 课程 2013-14 秋季第 15 讲 \\N{\\fs12}> Okay. Well, welcome to lecture 15 of CS193p for fall of 2013/14. \r\nDialogue: 0,0:00:15.05,0:00:18.31,yin,,0,0,0,, 今天的主要内容将是 MapKit\\N{\\fs12}And our primary topic today is going to be the map kit, \r\nDialogue: 0,0:00:18.31,0:00:22.01,yin,,0,0,0,, 也就是我们周一讨论的那种 UI\\N{\\fs12}which is kind of the UI on what we talked about on Monday. \r\nDialogue: 0,0:00:22.01,0:00:24.79,yin,,0,0,0,, 作为这个的一部分 特别是在演示中 \\N{\\fs12}As part of that, though, especially in the demonstration \r\nDialogue: 0,0:00:24.79,0:00:27.75,yin,,0,0,0,, 我会展示关于 segue 的两点重要内容 \\N{\\fs12}that I do, I'm going to show you two things about segue's that are pretty important. \r\nDialogue: 0,0:00:27.75,0:00:30.86,yin,,0,0,0,, 一是如何从代码中发起 segue\\N{\\fs12}One is how to fire off a segue from code. \r\nDialogue: 0,0:00:30.86,0:00:32.89,yin,,0,0,0,, 之前 我们一直都是通过 \\N{\\fs12}So far all the time that we've made a segue go, \r\nDialogue: 0,0:00:32.89,0:00:35.59,yin,,0,0,0,, 从故事板的一处 control 拖动到 \\N{\\fs12}we just control, dragged from something in a storyboard \r\nDialogue: 0,0:00:35.59,0:00:38.10,yin,,0,0,0,, 另一个故事板 然后我们再点击它 \\N{\\fs12}to another storyboard, and then we clicked on that something. \r\nDialogue: 0,0:00:38.10,0:00:42.20,yin,,0,0,0,, 得到 segue 下面我们将考虑从代码中发起 segue\\N{\\fs12}It would segue, so now we're going to able to fire off a segue from in code. \r\nDialogue: 0,0:00:42.20,0:00:44.82,yin,,0,0,0,, 然后我今天还会讲到一种新的 segue\\N{\\fs12}And then I'm also going to teach you a new kind of segue today, \r\nDialogue: 0,0:00:44.82,0:00:48.47,yin,,0,0,0,, 也就是 embed segue 这个我也会演示 \\N{\\fs12}which is the embed segue, and I'm going to demo that, as well, \r\nDialogue: 0,0:00:48.47,0:00:50.67,yin,,0,0,0,, 我有一个大的 demo 演示各种地图方面的内容 \\N{\\fs12}in a big demo that shows you all the map stuff \r\nDialogue: 0,0:00:50.67,0:00:53.49,yin,,0,0,0,, 还有手动 segue 和 embed segue\\N{\\fs12}and manual segue and the embed segue. \r\nDialogue: 0,0:00:53.49,0:00:58.61,yin,,0,0,0,, 以上就是今天的内容 \\N{\\fs12}So that's what's on tap for today. \r\nDialogue: 0,0:00:58.61,0:00:59.93,yin,,0,0,0,, 来看 MapKit\\N{\\fs12}And, so, map kit. \r\nDialogue: 0,0:00:59.93,0:01:01.08,yin,,0,0,0,,MapKit 是什么 \\N{\\fs12}So what is map kit? \r\nDialogue: 0,0:01:01.08,0:01:05.90,yin,,0,0,0,,MapKit 也就是位置的用户界面 \\N{\\fs12}Map kit is basically user interface for locations \r\nDialogue: 0,0:01:05.90,0:01:11.42,yin,,0,0,0,, 它主要的类是这个 UIView 叫作 MKMapView\\N{\\fs12}and its primary class is this UI view, called an MK map view. \r\nDialogue: 0,0:01:11.42,0:01:15.43,yin,,0,0,0,,MapView 这整个属于一个不同的框架 叫 MapKit 框架 \\N{\\fs12}The whole map view stuff is in a different framework, called a map kit framework. \r\nDialogue: 0,0:01:15.43,0:01:17.58,yin,,0,0,0,, 想使用 MapKit 框架时 \\N{\\fs12}When you want to use the map kit framework you have \r\nDialogue: 0,0:01:17.58,0:01:22.08,yin,,0,0,0,, 你需要明确到项目设置中进行关联 \\N{\\fs12}to actually explicitly go into your project settings and set it to be linked. \r\nDialogue: 0,0:01:22.08,0:01:25.64,yin,,0,0,0,, 否则 MKMapView 这些类都不会有 \\N{\\fs12}Otherwise, all these classes like MK map view won't be there, \r\nDialogue: 0,0:01:25.64,0:01:28.94,yin,,0,0,0,, 我会在 demo 中演示如何做到这个 \\N{\\fs12}and I'm going to show that in the demo, how you do that. \r\nDialogue: 0,0:01:28.94,0:01:33.45,yin,,0,0,0,, 在 MapView 之内 有这些大头针 \\N{\\fs12}So, inside of the map view, you have these little pins. \r\nDialogue: 0,0:01:33.45,0:01:35.93,yin,,0,0,0,, 这些大头针可以有不同颜色 \\N{\\fs12}They look a little red pin there, they can be different colors. \r\nDialogue: 0,0:01:35.93,0:01:40.97,yin,,0,0,0,, 这些被叫作 AnnotationView\\N{\\fs12}These are called annotation views. \r\nDialogue: 0,0:01:40.97,0:01:43.06,yin,,0,0,0,, 你可以自定义 可以创建 AnnotationView 的子类 \\N{\\fs12}So every annotation view in there, and you, \r\nDialogue: 0,0:01:43.06,0:01:45.46,yin,,0,0,0,, 你可以自定义 可以创建 AnnotationView 的子类 \\N{\\fs12}you can customize this, you can subclass annotation view \r\nDialogue: 0,0:01:45.46,0:01:47.80,yin,,0,0,0,, 你也可以让它不是一个大头针 \\N{\\fs12}to make it not look like a pin if you want. \r\nDialogue: 0,0:01:47.80,0:01:51.21,yin,,0,0,0,, 反正 这些 AnnotationView 负责 \\N{\\fs12}But these annotation views are responsible \r\nDialogue: 0,0:01:51.21,0:01:54.47,yin,,0,0,0,, 显示世界中的某个地点 \\N{\\fs12}for showing some place in the world, \r\nDialogue: 0,0:01:54.47,0:01:56.19,yin,,0,0,0,, 除了大头针以外 \\N{\\fs12}and they have a pin, \r\nDialogue: 0,0:01:56.19,0:01:58.14,yin,,0,0,0,, 这里还有一个对话框 \\N{\\fs12}but then they also have this little call out, if you click \r\nDialogue: 0,0:01:58.14,0:02:00.81,yin,,0,0,0,, 点击时 这里会有一个白条 \\N{\\fs12}on them, you see that little white bar right there? \r\nDialogue: 0,0:02:00.81,0:02:04.66,yin,,0,0,0,, 这个对话框也可以自定义 \\N{\\fs12}And that call out can be customized, a little bit. \r\nDialogue: 0,0:02:04.66,0:02:07.66,yin,,0,0,0,, 可以设置标题和副标题 \\N{\\fs12}The title that's in it and it can have a little subtitle \r\nDialogue: 0,0:02:07.66,0:02:10.48,yin,,0,0,0,, 它还可以有左侧和右侧的附属视图 \\N{\\fs12}and also it can have left and right accessory views, \r\nDialogue: 0,0:02:10.48,0:02:13.40,yin,,0,0,0,, 这里有一个左附属视图 这是一个图像视图 \\N{\\fs12}so this one has a left accessory view, which is an image view, \r\nDialogue: 0,0:02:13.40,0:02:17.13,yin,,0,0,0,, 还有一个右附属视图 这是一个按钮 你可以点它 \\N{\\fs12}and there's a right accessory view which is a little button that you can click on. \r\nDialogue: 0,0:02:17.13,0:02:19.00,yin,,0,0,0,,demo 中 所有这些部分我们都会演示 \\N{\\fs12}So in our demo we're going to do all of this. \r\nDialogue: 0,0:02:19.00,0:02:24.14,yin,,0,0,0,,demo 中 所有这些部分我们都会演示 \\N{\\fs12}And we're going to cover all of these various parts, what's going on. \r\nDialogue: 0,0:02:24.14,0:02:26.66,yin,,0,0,0,, 主要需要理解的是 如何创建 MapView\\N{\\fs12}But the main thing to understand is how you create a map view \r\nDialogue: 0,0:02:26.66,0:02:28.89,yin,,0,0,0,, 以及如何将这些东西放到地图上 \\N{\\fs12}and how you put these things on the map, so map view, \r\nDialogue: 0,0:02:28.89,0:02:30.72,yin,,0,0,0,,MapView 可以 alloc init\\N{\\fs12}just alloc init, or more often \r\nDialogue: 0,0:02:30.72,0:02:35.85,yin,,0,0,0,, 不过更常用的方法是从 Xcode 的面板中拖出 \\N{\\fs12}we drag it out, from the palette, in Xcode, \r\nDialogue: 0,0:02:35.85,0:02:42.51,yin,,0,0,0,, 要想使用大头针 我们需要加上这些 Annotation\\N{\\fs12}and the way we put the pins on there is we add these things called annotations. \r\nDialogue: 0,0:02:42.51,0:02:47.89,yin,,0,0,0,,Annotation 其实就是一个 id 响应这个协议 \\N{\\fs12}So an annotation is really just an ID, the response to this protocol. \r\nDialogue: 0,0:02:47.89,0:02:50.07,yin,,0,0,0,, 这个 MKAnnotation 协议 \\N{\\fs12}See this MK annotation protocol up here. \r\nDialogue: 0,0:02:50.07,0:02:55.86,yin,,0,0,0,, 应用程序中任何响应这个协议的对象 \\N{\\fs12}So any object in your entire application that responds to this protocol \r\nDialogue: 0,0:02:55.86,0:02:58.35,yin,,0,0,0,, 都可以被放到 MapView 上 \\N{\\fs12}can just be dropped onto the map view. \r\nDialogue: 0,0:02:58.35,0:03:00.07,yin,,0,0,0,, 这个协议中有什么呢 \\N{\\fs12}So what's in this protocol? \r\nDialogue: 0,0:03:00.07,0:03:03.35,yin,,0,0,0,, 很简单 它有一些可选方法 标题和副标题 \\N{\\fs12}Very simple, it's got a couple optional methods, the title and subtitle, \r\nDialogue: 0,0:03:03.35,0:03:05.19,yin,,0,0,0,, 我们看到的那个白色对话框 \\N{\\fs12}so in that little white call out that we saw, \r\nDialogue: 0,0:03:05.19,0:03:06.76,yin,,0,0,0,, 那里有标题和副标题 \\N{\\fs12}that's going to be the title and subtitle there. \r\nDialogue: 0,0:03:06.76,0:03:12.16,yin,,0,0,0,, 然后它有一个很重要的必须属性 也就是坐标 \\N{\\fs12}And then it's got a very important required property, which is the coordinate.\r\nDialogue: 0,0:03:12.16,0:03:14.58,yin,,0,0,0,, 坐标也就是经纬度 \\N{\\fs12}So the coordinate is just the latitude and longitude, \r\nDialogue: 0,0:03:14.58,0:03:18.48,yin,,0,0,0,, 由 CLLocation 坐标指定 这是 C struct\\N{\\fs12}as specified by this CL location coordinate, C struct. \r\nDialogue: 0,0:03:18.48,0:03:21.76,yin,,0,0,0,, 任何能够回答这些的对象 \\N{\\fs12}And so any object that can answer these, \r\nDialogue: 0,0:03:21.76,0:03:23.99,yin,,0,0,0,, 其实主要也就是坐标这个问题 \\N{\\fs12}really just this one question of the coordinate, \r\nDialogue: 0,0:03:23.99,0:03:27.98,yin,,0,0,0,, 不过通常 我们也需要标题和副标题 \\N{\\fs12}but usually we want title and subtitle too, \r\nDialogue: 0,0:03:27.98,0:03:29.68,yin,,0,0,0,, 都能被放到地图上 \\N{\\fs12}can be thrown on a map, \r\nDialogue: 0,0:03:29.68,0:03:31.75,yin,,0,0,0,, 例如 在我们的 demo 中 \\N{\\fs12}and, for example, in the demo that we're going to do, \r\nDialogue: 0,0:03:31.75,0:03:33.46,yin,,0,0,0,, 我们会扩展 Photomania\\N{\\fs12}we're going to extend photo mania. \r\nDialogue: 0,0:03:33.46,0:03:35.51,yin,,0,0,0,, 我会被照片对象放到那里 \\N{\\fs12}I'm just going to throw photo objects in there. \r\nDialogue: 0,0:03:35.51,0:03:38.46,yin,,0,0,0,, 实际上 照片对象已经实现了标题和副标题 \\N{\\fs12}In fact, photo objects already implement title and subtitle, \r\nDialogue: 0,0:03:38.46,0:03:41.82,yin,,0,0,0,, 我们只需要让照片对象成为 MKAnnotation\\N{\\fs12}so all we really need to do is make a photo object be an MK annotation \r\nDialogue: 0,0:03:41.83,0:03:43.37,yin,,0,0,0,, 并响应那个协议 \\N{\\fs12}and respond to that protocol, \r\nDialogue: 0,0:03:43.37,0:03:45.90,yin,,0,0,0,, 只需要实现坐标方法 \\N{\\fs12}is to implement the required coordinate method and that's what we're going to do \r\nDialogue: 0,0:03:45.90,0:03:47.66,yin,,0,0,0,, 照片就能放到地图上了 \\N{\\fs12}and then we can just throw photos on the map. \r\nDialogue: 0,0:03:47.66,0:03:50.84,yin,,0,0,0,, 这里不需要任何特殊的类 \\N{\\fs12}We don't have to make any other special classes or anything, \r\nDialogue: 0,0:03:50.84,0:03:54.62,yin,,0,0,0,, 只需要把照片丢到地图上 \\N{\\fs12}just throw the photos themselves up there. \r\nDialogue: 0,0:03:54.62,0:03:56.93,yin,,0,0,0,, 设定 Annotation 时 这个属性…\\N{\\fs12}When you're setting the annotations, this property, \r\nDialogue: 0,0:03:56.93,0:04:00.77,yin,,0,0,0,,MKMapView 上有一个属性是 Annotation 的 NSArray\\N{\\fs12}there's a property on MK map view which is an NS array \r\nDialogue: 0,0:04:00.77,0:04:03.66,yin,,0,0,0,, 数组中是所有 MapView 所显示的 Annotation\\N{\\fs12}of annotations, that's all the annotations that the map view is showing, \r\nDialogue: 0,0:04:03.66,0:04:05.54,yin,,0,0,0,, 不过这是一个只读属性 \\N{\\fs12}but that's read only properties, \r\nDialogue: 0,0:04:05.54,0:04:06.86,yin,,0,0,0,, 你不能那样设置数组 \\N{\\fs12}so you can't set the array that way, \r\nDialogue: 0,0:04:06.86,0:04:09.40,yin,,0,0,0,, 你需要使用 addAnnotation 方法 \\N{\\fs12}you have to use these add annotation methods \r\nDialogue: 0,0:04:09.40,0:04:11.64,yin,,0,0,0,, 或是 addAnnotations 删除也是一样 \\N{\\fs12}or add annotations, and same thing removing them. \r\nDialogue: 0,0:04:11.64,0:04:13.93,yin,,0,0,0,, 添加和删除需要用到这些方法 \\N{\\fs12}So you add and remove them with these methods, \r\nDialogue: 0,0:04:13.93,0:04:17.16,yin,,0,0,0,, 你不能直接对数组进行操作 \\N{\\fs12}you don't manipulate that array directly. \r\nDialogue: 0,0:04:17.16,0:04:20.05,yin,,0,0,0,, 这其实是一个很好的主意 \\N{\\fs12}It's a pretty good idea, if you can, \r\nDialogue: 0,0:04:20.05,0:04:21.60,yin,,0,0,0,, 如果你有信息 \\N{\\fs12}if you have the information, \r\nDialogue: 0,0:04:21.60,0:04:24.95,yin,,0,0,0,, 你可以预先把所有 Annotation 加到 MapView\\N{\\fs12}to add all of your annotations up front to the map view. \r\nDialogue: 0,0:04:24.95,0:04:27.96,yin,,0,0,0,, 实际上 添加 Annotation 开销很小 \\N{\\fs12}Adding an annotation is actually pretty low overhead, \r\nDialogue: 0,0:04:27.96,0:04:30.96,yin,,0,0,0,, 特别是 Annotation 目前不在屏幕上的情况下 \\N{\\fs12}especially if that annotation is not on screen currently. \r\nDialogue: 0,0:04:30.96,0:04:32.98,yin,,0,0,0,, 这是因为这些 MKAnnotationView\\N{\\fs12}And that's because those MK annotation views, \r\nDialogue: 0,0:04:32.98,0:04:34.92,yin,,0,0,0,, 这些带有对话框的大头针 \\N{\\fs12}the little pin that does the call out, \r\nDialogue: 0,0:04:34.92,0:04:38.44,yin,,0,0,0,, 这些东西会像表格视图的行一样被再利用 \\N{\\fs12}those things are reused like a table views rows. \r\nDialogue: 0,0:04:38.44,0:04:42.94,yin,,0,0,0,, 如果你有数百个 Annotation 但屏幕上只显示五个 \\N{\\fs12}So if you have hundreds of annotations, but only five of them are on the screen, \r\nDialogue: 0,0:04:42.94,0:04:46.04,yin,,0,0,0,, 这时你就只需要创建五个 MKAnnotationView\\N{\\fs12}you're only going to create 5 of those MK annotation views, \r\nDialogue: 0,0:04:46.05,0:04:49.42,yin,,0,0,0,, 程序使用过程中 有些会从屏幕上消失 \\N{\\fs12}and as you kind of move around in the world and they go off-screen, \r\nDialogue: 0,0:04:49.42,0:04:51.32,yin,,0,0,0,, 新的就可以再利用它们 \\N{\\fs12}they'll get reused for new ones. \r\nDialogue: 0,0:04:51.32,0:04:55.66,yin,,0,0,0,, 预先把所有 Annotation 加到 MapView\\N{\\fs12}So letting the map view all the annotations up front, \r\nDialogue: 0,0:04:55.66,0:04:59.83,yin,,0,0,0,, 对于管理内部性能非常有帮助 \\N{\\fs12}it's nice to help it manage its internal performance, or whatever. \r\nDialogue: 0,0:04:59.83,0:05:02.20,yin,,0,0,0,, 一般这是推荐的 不过你并不总知道 \\N{\\fs12}So it's generally recommended, but you don't always know, \r\nDialogue: 0,0:05:02.20,0:05:04.27,yin,,0,0,0,, 有时 你并不能预先知道所有 Annotation\\N{\\fs12}sometimes you don't know all the annotations up front, \r\nDialogue: 0,0:05:04.27,0:05:07.87,yin,,0,0,0,, 它可能是实时发生的 \\N{\\fs12}it's happening in real time or something. \r\nDialogue: 0,0:05:07.87,0:05:11.15,yin,,0,0,0,,Annotation 是怎么样的呢 \\N{\\fs12}So, what do annotations look like? \r\nDialogue: 0,0:05:11.15,0:05:12.74,yin,,0,0,0,, 一般是一个大头针 \\N{\\fs12}They generally look like a pin, \r\nDialogue: 0,0:05:12.74,0:05:16.21,yin,,0,0,0,, 不过在 MKAnnotationView 中有很多方法可以调用 \\N{\\fs12}but there's a lot of methods that you can call in MK annotation view \r\nDialogue: 0,0:05:16.21,0:05:18.20,yin,,0,0,0,, 你还可以创建 MKAnnotationView 的子类 \\N{\\fs12}and you can also subclass MK annotation view \r\nDialogue: 0,0:05:18.20,0:05:21.20,yin,,0,0,0,, 画一个不同于大头针的东西 \\N{\\fs12}to draw something different in a pin, and this call \r\nDialogue: 0,0:05:21.20,0:05:24.76,yin,,0,0,0,, 而这个对话框则较难创建子类让其变得不同 \\N{\\fs12}out is a little more difficult to subclass and make different. \r\nDialogue: 0,0:05:24.76,0:05:29.62,yin,,0,0,0,, 如果只用这种有左右视图的对话框就够了 \\N{\\fs12}So if you can get by with just doing this left and right call out business, \r\nDialogue: 0,0:05:29.63,0:05:32.26,yin,,0,0,0,, 那将很好 毕竟这会很简单 \\N{\\fs12}then that's good because that's easy. \r\nDialogue: 0,0:05:32.26,0:05:35.64,yin,,0,0,0,, 如果你还想做更多 那将不属于这门课的范畴 \\N{\\fs12}If you want to do more, then it's kind of beyond the scope of this class \r\nDialogue: 0,0:05:35.65,0:05:37.38,yin,,0,0,0,, 你需要自己去查怎么做 \\N{\\fs12}and you're going to have to do some searching around. \r\nDialogue: 0,0:05:37.38,0:05:42.05,yin,,0,0,0,, 可以是可以 不过要在基本对话框的标题 副标题 \\N{\\fs12}It's doable, but doing something different than that basic call out with title, subtitle, \r\nDialogue: 0,0:05:42.05,0:05:45.29,yin,,0,0,0,, 左右附属视图之外做别的 会比较困难 \\N{\\fs12}left and right accessory view is a little more difficult. \r\nDialogue: 0,0:05:45.29,0:05:50.12,yin,,0,0,0,, 对话框的内容很有趣 什么时候设置这些呢 \\N{\\fs12}What, the contents of that call out are kind of interesting, when do you set those up? \r\nDialogue: 0,0:05:50.12,0:05:54.16,yin,,0,0,0,,MapView 有一个委托 我们会谈到 \\N{\\fs12}Well, there is a map, okay, the map view has a delegate we're going to talk about, \r\nDialogue: 0,0:05:54.16,0:05:58.38,yin,,0,0,0,,MapView 委托的一个方法就是 \\N{\\fs12}and one of the map view delegate methods is essentially \r\nDialogue: 0,0:05:58.38,0:06:01.38,yin,,0,0,0,, 为我创建这个 MKAnnotationView\\N{\\fs12}build this MK annotation view for me, \r\nDialogue: 0,0:06:01.38,0:06:05.43,yin,,0,0,0,, 包括左右附属视图 把这些也 alloc init 了 \\N{\\fs12}including the left and right accessory views, you know, alloc init those, as well, \r\nDialogue: 0,0:06:05.43,0:06:08.40,yin,,0,0,0,, 你可以在创建时加载这些 \\N{\\fs12}and you can load those up at the time you build it, \r\nDialogue: 0,0:06:08.40,0:06:11.75,yin,,0,0,0,, 你也可以等到大头针被点时再加载这些 \\N{\\fs12}or you can wait until the pin is pressed to load those up. \r\nDialogue: 0,0:06:11.75,0:06:16.38,yin,,0,0,0,, 为什么要等大头针被点时再加载 AnnotationView 呢 \\N{\\fs12}Now why would you want to wait till the pin is pressed to load up those annotation views? \r\nDialogue: 0,0:06:16.38,0:06:17.83,yin,,0,0,0,, 看看这个例子 \\N{\\fs12}Well, let's look at this example right here. \r\nDialogue: 0,0:06:17.83,0:06:19.16,yin,,0,0,0,, 你有一个缩略图 \\N{\\fs12}You've got that thumb nail. \r\nDialogue: 0,0:06:19.16,0:06:23.01,yin,,0,0,0,, 如果缩略图需要 Flickr 取回 \\N{\\fs12}What if that thumb nail is, requires a Flickr fetch? \r\nDialogue: 0,0:06:23.01,0:06:27.49,yin,,0,0,0,, 我们肯定不想对整个世界的所有大头针取回照片 \\N{\\fs12}Okay, well you don't want to fetch that photo for all the pins in the entire world, \r\nDialogue: 0,0:06:27.49,0:06:30.45,yin,,0,0,0,, 仅仅对屏幕上可见的取回照片就够让人吃不消了 \\N{\\fs12}or even all of the pins that are visible on screen. \r\nDialogue: 0,0:06:30.45,0:06:35.04,yin,,0,0,0,, 这时 你就只希望在大头针被点时再取回 Flickr 信息 \\N{\\fs12}You only want to load that Flickr, do that Flickr fetch, when a pin is clicked on. \r\nDialogue: 0,0:06:35.04,0:06:36.87,yin,,0,0,0,,MapView 中有一个委托方法 \\N{\\fs12}So there's this delegate method in the map view \r\nDialogue: 0,0:06:36.87,0:06:39.06,yin,,0,0,0,, 叫 mapView didSelectAnnotationView\\N{\\fs12}called map view did select annotation view, \r\nDialogue: 0,0:06:39.06,0:06:41.06,yin,,0,0,0,, 点大头针时它会被调用 \\N{\\fs12}it'll get called when you click on a pin, that's a good place \r\nDialogue: 0,0:06:41.06,0:06:42.83,yin,,0,0,0,, 这时再 Flickr 取回会更好 \\N{\\fs12}to like do that Flickr fetch. \r\nDialogue: 0,0:06:42.83,0:06:44.56,yin,,0,0,0,, 加载对话框中的信息 \\N{\\fs12}Load up the callout. \r\nDialogue: 0,0:06:44.56,0:06:48.00,yin,,0,0,0,, 我们会在 demo 中演示这是怎么做的 \\N{\\fs12}And we're going to do that in the demo and see how that works too. \r\nDialogue: 0,0:06:48.00,0:06:50.88,yin,,0,0,0,, 我们有这些 MKAnnotationView\\N{\\fs12}So, we have these MK annotation views \r\nDialogue: 0,0:06:50.88,0:06:53.69,yin,,0,0,0,, 来显示这些 id \\N{\\fs12}that are going to show these ID MK annotations, \r\nDialogue: 0,0:06:53.69,0:06:56.65,yin,,0,0,0,, 两者如何关联起来呢 \\N{\\fs12}how do those two get connected up, and they get connected \r\nDialogue: 0,0:06:56.65,0:07:00.48,yin,,0,0,0,, 这需要通过这个 MapView 委托方法 \\N{\\fs12}up by this map view delegate method \r\nDialogue: 0,0:07:00.49,0:07:02.47,yin,,0,0,0,,mapView viewForAnnotation\\N{\\fs12}called map view, view for annotation, \r\nDialogue: 0,0:07:02.47,0:07:03.95,yin,,0,0,0,, 它会返回一个 MKAnnotationView\\N{\\fs12}and it returns a view for annotation. \r\nDialogue: 0,0:07:03.95,0:07:08.34,yin,,0,0,0,, 这同表格视图中的 cellForRowAtIndexPath 几乎一样 \\N{\\fs12}This is almost exactly the same as cellForRowAtIndexPath in table view. \r\nDialogue: 0,0:07:08.34,0:07:10.99,yin,,0,0,0,,cellForRowAtIndexPath 你给它一个 section 和一个行 \\N{\\fs12}cellForRowAtIndexPath, you give it a section and a row, \r\nDialogue: 0,0:07:10.99,0:07:12.58,yin,,0,0,0,, 它会返回一个 UITableViewCell\\N{\\fs12}it gives you back a UI table view cell, \r\nDialogue: 0,0:07:12.58,0:07:14.67,yin,,0,0,0,, 一个视图 来显示那个行 \\N{\\fs12}which is a view to display that row. \r\nDialogue: 0,0:07:14.67,0:07:15.54,yin,,0,0,0,, 这里也一样 \\N{\\fs12}Same thing here. \r\nDialogue: 0,0:07:15.54,0:07:17.41,yin,,0,0,0,, 它会给你一个 Annotation\\N{\\fs12}It's going to give you an annotation, \r\nDialogue: 0,0:07:17.41,0:07:20.00,yin,,0,0,0,, 你给它返回一个 MKAnnotationView\\N{\\fs12}and you're going to give it back an MK annotation view \r\nDialogue: 0,0:07:20.00,0:07:21.84,yin,,0,0,0,, 来绘制那个 Annotation\\N{\\fs12}to draw that annotation. \r\nDialogue: 0,0:07:21.84,0:07:25.17,yin,,0,0,0,,MapView 还有这个机制 \\N{\\fs12}Now, map view even has this mechanism. \r\nDialogue: 0,0:07:25.17,0:07:28.28,yin,,0,0,0,,dequeueReusable…这个 同表格视图一样 \\N{\\fs12}The dequeue reusable thing, like table view has. \r\nDialogue: 0,0:07:28.28,0:07:31.33,yin,,0,0,0,, 你可以说 sender 这里也就是 MapView\\N{\\fs12}Right? So you can say sender, which is the map view there, \r\nDialogue: 0,0:07:31.33,0:07:33.38,yin,,0,0,0,,dequeueReusableAnnotationViewWithIdentifier\\N{\\fs12}dequeue reusable annotation view with identifier, \r\nDialogue: 0,0:07:33.38,0:07:34.62,yin,,0,0,0,, 给一个标识符 \\N{\\fs12}you give an identifier, \r\nDialogue: 0,0:07:34.62,0:07:38.28,yin,,0,0,0,, 如果它在 MKAnnotationView 上有一个大头针视图 \\N{\\fs12}and if it's got a pin view on MK annotation view that it \r\nDialogue: 0,0:07:38.29,0:07:40.19,yin,,0,0,0,, 被丢到屏幕上 \\N{\\fs12}got thrown off the screen \r\nDialogue: 0,0:07:40.19,0:07:43.99,yin,,0,0,0,, 而且它能再利用它 它就会把它引入 并在这里给你 \\N{\\fs12}and it can reuse it, it'll bring it in, and give it to you here. \r\nDialogue: 0,0:07:43.99,0:07:46.05,yin,,0,0,0,, 但是如果没有 \\N{\\fs12}But if it doesn't have any, \r\nDialogue: 0,0:07:46.05,0:07:48.00,yin,,0,0,0,, 想想在表格视图下 会发生什么 \\N{\\fs12}then in the table view case, what happens? \r\nDialogue: 0,0:07:48.00,0:07:51.25,yin,,0,0,0,, 系统会自动复制原型 对吧 \\N{\\fs12}We, the system will automatically duplicate that prototype, right? \r\nDialogue: 0,0:07:51.25,0:07:54.10,yin,,0,0,0,, 故事板中我们设置有原型单元格 \\N{\\fs12}You got the prototype cell that we set up in the storyboard, \r\nDialogue: 0,0:07:54.10,0:07:56.02,yin,,0,0,0,, 复制它 但这里不会这样 \\N{\\fs12}and you'll duplicate it, but that doesn't happen here, \r\nDialogue: 0,0:07:56.02,0:07:57.98,yin,,0,0,0,, 因为地图视图中没有这个 \\N{\\fs12}because we don't get to do that in the map view, \r\nDialogue: 0,0:07:57.98,0:08:00.79,yin,,0,0,0,, 地图视图没有原型单元格这些 \\N{\\fs12}the map view doesn't have all this mechanism for prototype cells and everything. \r\nDialogue: 0,0:08:00.79,0:08:04.66,yin,,0,0,0,, 如果这个返回 nil dequeueReusable…这个 \\N{\\fs12}So, if that comes back as nil, the dequeueReusable thing, \r\nDialogue: 0,0:08:04.66,0:08:07.92,yin,,0,0,0,, 我们就需要自己来 alloc init MKAnnotationView\\N{\\fs12}then we have to alloc init the MK annotation view ourselves. \r\nDialogue: 0,0:08:07.92,0:08:11.02,yin,,0,0,0,, 例如这里 我创建的是 MKPinAnnotationView\\N{\\fs12}So here, for example, I'm making an MK pin annotation view, \r\nDialogue: 0,0:08:11.02,0:08:13.72,yin,,0,0,0,, 在 iOS 中 这能绘制一个红色大头针 \\N{\\fs12}which comes in iOS, it's the thing that can draw a red pin, \r\nDialogue: 0,0:08:13.72,0:08:17.98,yin,,0,0,0,, 应该也可以是紫色或是别的颜色 我可以 alloc init\\N{\\fs12}I think you can do purple and one other color, and I just alloc init \r\nDialogue: 0,0:08:17.98,0:08:21.49,yin,,0,0,0,, 使用 initWithAnnotation reuseIdentifier\\N{\\fs12}with init with annotation, reuse identifier. \r\nDialogue: 0,0:08:21.49,0:08:25.04,yin,,0,0,0,, 这里在 alloc init 时传入 reuseIdentifier\\N{\\fs12}Now the fact that I passed that reuse identifier there when I alloc init, \r\nDialogue: 0,0:08:25.05,0:08:27.84,yin,,0,0,0,, 意思是 如果它被丢出 \\N{\\fs12}it means that if it ever gets thrown out, \r\nDialogue: 0,0:08:27.84,0:08:29.82,yin,,0,0,0,, 它就会回到再利用队列 \\N{\\fs12}it will come back in the reuse queue. \r\nDialogue: 0,0:08:29.82,0:08:31.91,yin,,0,0,0,, 这就是将它同再利用队列关联起来的东西 \\N{\\fs12}So that's the thing that ties it to the reuse queue, \r\nDialogue: 0,0:08:31.91,0:08:33.66,yin,,0,0,0,, 这些东西就是这样来回折腾的 \\N{\\fs12}so that's how things go back and forth. \r\nDialogue: 0,0:08:33.66,0:08:36.96,yin,,0,0,0,, 然后这里面 我还要设置我的左右附属视图 \\N{\\fs12}And then, inside there, I might also set up my left and right accessory views, \r\nDialogue: 0,0:08:36.96,0:08:38.64,yin,,0,0,0,, 或许不放内容 \\N{\\fs12}maybe not put the content in there, \r\nDialogue: 0,0:08:38.64,0:08:41.63,yin,,0,0,0,, 例如图像 不过我要创建 UIImageView\\N{\\fs12}like the image, but I might create the UI image view, right, \r\nDialogue: 0,0:08:41.63,0:08:43.61,yin,,0,0,0,, 将这设为左侧的 \\N{\\fs12}and set that to be the left one \r\nDialogue: 0,0:08:43.61,0:08:45.97,yin,,0,0,0,, 然后将按钮设为右侧的 \\N{\\fs12}and then set the button to be the right one. \r\nDialogue: 0,0:08:45.97,0:08:48.94,yin,,0,0,0,, 在这之外 如果不是视图 \\N{\\fs12}Outside of that, if not a view, okay, \r\nDialogue: 0,0:08:48.94,0:08:51.29,yin,,0,0,0,, 现在我有了一个视图 要么出列 \\N{\\fs12}so now I have a view either that I DQ'd \r\nDialogue: 0,0:08:51.29,0:08:52.51,yin,,0,0,0,, 要么我自己创建 \\N{\\fs12}or that I made myself, \r\nDialogue: 0,0:08:52.52,0:08:56.70,yin,,0,0,0,, 这里我加载了加载代价小的东西 \\N{\\fs12}here's where I load up whatever is cheap to load up. \r\nDialogue: 0,0:08:56.70,0:08:58.85,yin,,0,0,0,, 到 MKAnnotationView 中 \\N{\\fs12}Into that MK annotation view. \r\nDialogue: 0,0:08:58.85,0:09:01.20,yin,,0,0,0,, 这里不要做代价大的事 \\N{\\fs12}You wouldn't want to do expensive things here, \r\nDialogue: 0,0:09:01.20,0:09:03.12,yin,,0,0,0,, 代价大的要等被点时再加载 \\N{\\fs12}we're going to wait till it's clicked. \r\nDialogue: 0,0:09:03.12,0:09:06.85,yin,,0,0,0,, 如果这里是马上要显示的关于大头针的信息 \\N{\\fs12}If this, if it's something that's going to be displayed immediately about the pin, \r\nDialogue: 0,0:09:06.85,0:09:08.55,yin,,0,0,0,, 例如你要用大头针以外的别的图像 \\N{\\fs12}like you're using a different image than the pin, \r\nDialogue: 0,0:09:08.55,0:09:09.98,yin,,0,0,0,, 那这里显然就需要设置 \\N{\\fs12}then obviously you would need to set that here, \r\nDialogue: 0,0:09:09.98,0:09:13.47,yin,,0,0,0,, 你不能等到点击时再加载这个 \\N{\\fs12}you can't wait till it's clicked on to load that up. \r\nDialogue: 0,0:09:13.47,0:09:18.09,yin,,0,0,0,,MKAnnotationView 有些什么属性 \\N{\\fs12}So what kind of properties are there on this MK annotation view, \r\nDialogue: 0,0:09:18.09,0:09:20.24,yin,,0,0,0,, 从那个方法中返回的东西 \\N{\\fs12}the thing you're returning from that method? \r\nDialogue: 0,0:09:20.24,0:09:23.20,yin,,0,0,0,, 显然有 annotation 有左右附属视图 \\N{\\fs12}There's obviously the annotation, there's the left and right call out accessory view, \r\nDialogue: 0,0:09:23.20,0:09:26.03,yin,,0,0,0,, 这些都是你可以设置的 UIView\\N{\\fs12}you see those are just UI views that you can set. \r\nDialogue: 0,0:09:26.03,0:09:27.70,yin,,0,0,0,, 还有是否启用 \\N{\\fs12}There's whether it's enabled, there's even, \r\nDialogue: 0,0:09:27.70,0:09:29.48,yin,,0,0,0,, 甚至还有是否可拖动 \\N{\\fs12}there's even whether it's dragable. \r\nDialogue: 0,0:09:29.48,0:09:33.16,yin,,0,0,0,, 如果 MKPin 是可拖动的 那么 annotation\\N{\\fs12}If the MK pin is dragable, then the annotation \r\nDialogue: 0,0:09:33.16,0:09:35.56,yin,,0,0,0,, 就不仅需要实现坐标方法 \\N{\\fs12}has to not only implement that coordinate method, \r\nDialogue: 0,0:09:35.56,0:09:38.08,yin,,0,0,0,, 它还需要实现设置坐标方法 \\N{\\fs12}it has to implement the set coordinate method. \r\nDialogue: 0,0:09:38.08,0:09:39.76,yin,,0,0,0,, 因为你要把那个大头针拖着 \\N{\\fs12}Because you're going to pick that view up, pin up, \r\nDialogue: 0,0:09:39.76,0:09:42.58,yin,,0,0,0,, 移动到别的地方 annotation 需要移动 \\N{\\fs12}and move it when it drops, the annotation has to be moved, \r\nDialogue: 0,0:09:42.58,0:09:44.60,yin,,0,0,0,, 因此 这里需要有一个设置坐标的方法 \\N{\\fs12}so it has to have a set coordinate method. \r\nDialogue: 0,0:09:44.60,0:09:48.69,yin,,0,0,0,, 否则可拖动属性就无法正常工作 \\N{\\fs12}Otherwise setting dragable here is not going to, to work. \r\nDialogue: 0,0:09:48.69,0:09:51.35,yin,,0,0,0,, 然后这里还有一个 image 属性 \\N{\\fs12}And then the image that you see here, this property, \r\nDialogue: 0,0:09:51.35,0:09:53.97,yin,,0,0,0,, 这是替代大头针的图像 \\N{\\fs12}that's the image that replaces the pin. \r\nDialogue: 0,0:09:53.97,0:09:55.31,yin,,0,0,0,, 你不用大头针 \\N{\\fs12}That's instead of the pin. \r\nDialogue: 0,0:09:55.31,0:09:57.47,yin,,0,0,0,, 这并不是对话框中的图像 \\N{\\fs12}That's not the image that's in the call out, that's, \r\nDialogue: 0,0:09:57.47,0:10:03.17,yin,,0,0,0,, 并不是左附属对话框视图中的那个图像 \\N{\\fs12}we're going to put in the left accessory call out view, call out accessory view. \r\nDialogue: 0,0:10:03.17,0:10:05.44,yin,,0,0,0,, 有一点很酷 如果你将 \\N{\\fs12}One thing that's kind of cool, if you set one \r\nDialogue: 0,0:10:05.44,0:10:08.65,yin,,0,0,0,, 一个附属视图设置为 UIControl\\N{\\fs12}of the accessory views to be a UI control, \r\nDialogue: 0,0:10:08.65,0:10:12.35,yin,,0,0,0,, 最好的例子是 UIButton 继承自 UIControl\\N{\\fs12}most notably a UI button, inherit from UI control, then, \r\nDialogue: 0,0:10:12.35,0:10:15.74,yin,,0,0,0,, 那么你就可以将按钮放到对话框的附属视图中 \\N{\\fs12}yeah, you can put that button in the call out accessory view \r\nDialogue: 0,0:10:15.74,0:10:17.43,yin,,0,0,0,, 你可以设置目标动作 \\N{\\fs12}and you can set up target action to it \r\nDialogue: 0,0:10:17.43,0:10:20.27,yin,,0,0,0,, 这些都没问题 或许能够工作 \\N{\\fs12}and that would all be fine, that would probably work, \r\nDialogue: 0,0:10:20.27,0:10:23.74,yin,,0,0,0,, 不过由于这在 MKAnnotationView 中非常常用 \\N{\\fs12}but since that's so common to do in a MK annotation view, \r\nDialogue: 0,0:10:23.74,0:10:26.37,yin,,0,0,0,, 这里有一个很棒的地图视图委托方法叫 mapView\\N{\\fs12}there's a nice map view delegate method here called map view \r\nDialogue: 0,0:10:26.37,0:10:29.31,yin,,0,0,0,,annotationView calloutAccessoryControlTapped\\N{\\fs12}annotation view call out accessory control tapped \r\nDialogue: 0,0:10:29.31,0:10:31.96,yin,,0,0,0,, 在用户轻击时 它会被调用 \\N{\\fs12}that will get called if the person taps on it. \r\nDialogue: 0,0:10:31.96,0:10:33.87,yin,,0,0,0,, 如果你将按钮放到对话框中 \\N{\\fs12}So if you put a button in that little call out, \r\nDialogue: 0,0:10:33.87,0:10:35.93,yin,,0,0,0,, 用户轻击它 这个就会被调用 \\N{\\fs12}and someone taps on it, this will get called, \r\nDialogue: 0,0:10:35.93,0:10:38.95,yin,,0,0,0,, 你会知道哪个 AnnotationView 被点击了 \\N{\\fs12}and you will know which annotation view was tapped on, \r\nDialogue: 0,0:10:38.95,0:10:41.56,yin,,0,0,0,, 你不需要对按钮进行目标动作操作 \\N{\\fs12}right, and you won't have to do target action in that button. \r\nDialogue: 0,0:10:41.56,0:10:43.84,yin,,0,0,0,, 我在 demo 中也会演示这个 \\N{\\fs12}So we'll do that in the demo, as well. \r\nDialogue: 0,0:10:43.84,0:10:46.36,yin,,0,0,0,, 再看 didSelectAnnotationView\\N{\\fs12}So, did select annotation view. \r\nDialogue: 0,0:10:46.36,0:10:48.66,yin,,0,0,0,, 这在地图视图委托中被调用 \\N{\\fs12}So this is the thing that gets called in the map view, \r\nDialogue: 0,0:10:48.66,0:10:50.42,yin,,0,0,0,, 它叫 mapView\\N{\\fs12}delegate map view, its called map view, colon, \r\nDialogue: 0,0:10:50.42,0:10:53.10,yin,,0,0,0,,didSelectAnnotationView 当大头针被点击时 \\N{\\fs12}deselect annotation view, when a pin is clicked on, okay, \r\nDialogue: 0,0:10:53.10,0:10:55.09,yin,,0,0,0,, 当有人点击了红色大头针 \\N{\\fs12}when someone actually clicks on that red pin. \r\nDialogue: 0,0:10:55.09,0:10:58.13,yin,,0,0,0,, 它会自动弹出对话框 \\N{\\fs12}Now, it's going to automatically put the call out up as long as \r\nDialogue: 0,0:10:58.15,0:11:03.53,yin,,0,0,0,, 只要 MKAnnotationView 中设置了属性 canShowCallout\\N{\\fs12}you set the property can show call out in the MK annotation view, \r\nDialogue: 0,0:11:03.53,0:11:06.64,yin,,0,0,0,, 顺便说下 如果你在创建视图时 \\N{\\fs12}by the way, if you don't implement that annotation view, \r\nDialogue: 0,0:11:06.64,0:11:09.62,yin,,0,0,0,, 不实现 mapView viewForAnnotation 委托方法 \\N{\\fs12}view for annotation delegate method where you build the view, \r\nDialogue: 0,0:11:09.62,0:11:11.36,yin,,0,0,0,, 它会自动给你创建一个 \\N{\\fs12}it'll automatically create one for you, \r\nDialogue: 0,0:11:11.36,0:11:14.48,yin,,0,0,0,, 就只有一个大头针 没有左右对话框附属视图 \\N{\\fs12}it's just going to be a pin, it's going to have no left and right call out accessory, \r\nDialogue: 0,0:11:14.50,0:11:17.09,yin,,0,0,0,, 不过对话框中有标题和副标题 \\N{\\fs12}but it will show the call out with the title and subtitle. \r\nDialogue: 0,0:11:17.09,0:11:18.71,yin,,0,0,0,, 这就是不设置时的情况 \\N{\\fs12}That's what you get if you don't do anything. \r\nDialogue: 0,0:11:18.71,0:11:20.29,yin,,0,0,0,,demo 中我也会演示这个 \\N{\\fs12}We'll do that in the demo too. \r\nDialogue: 0,0:11:20.31,0:11:22.54,yin,,0,0,0,, 这里 在 didSelectAnnotationView 中 \\N{\\fs12}So, here in did select annotation view, \r\nDialogue: 0,0:11:22.54,0:11:26.55,yin,,0,0,0,, 我点大头针 这里我可能就需要 Flickr 取回了 \\N{\\fs12}I clicked on the pin, here's where I might say oh, let's do that Flickr fetch. \r\nDialogue: 0,0:11:26.55,0:11:29.13,yin,,0,0,0,, 至少在另一个线程中发起取回 \\N{\\fs12}You know, at least let's fire it off in another thread here. \r\nDialogue: 0,0:11:29.13,0:11:31.71,yin,,0,0,0,, 我们甚至都不需要浪费时间去发起 \\N{\\fs12}We don't even want to waste our time firing it off, \r\nDialogue: 0,0:11:31.71,0:11:33.80,yin,,0,0,0,, 但愿你们在作业中也学到了这个 \\N{\\fs12}and hopefully you're learning this in your homework too, \r\nDialogue: 0,0:11:33.80,0:11:38.14,yin,,0,0,0,, 你不希望为不在屏幕上的行取回缩略图 \\N{\\fs12}you don't want to really fetch that thumb nail for a row that's not on screen, \r\nDialogue: 0,0:11:38.14,0:11:39.53,yin,,0,0,0,, 这样做是浪费时间 \\N{\\fs12}it's kind of a waste of time to do that. \r\nDialogue: 0,0:11:39.53,0:11:40.17,yin,,0,0,0,, 这里也一样 \\N{\\fs12}Same thing here. \r\nDialogue: 0,0:11:40.17,0:11:41.76,yin,,0,0,0,, 在有人点大头针之前 \\N{\\fs12}Until someone clicks on that pin, \r\nDialogue: 0,0:11:41.76,0:11:43.87,yin,,0,0,0,, 我们不希望发起 Flickr 取回 \\N{\\fs12}we probably don't want to fire this Flickr fetch off. \r\nDialogue: 0,0:11:43.87,0:11:46.56,yin,,0,0,0,,Flickr 取回以后 就像表格视图一样 \\N{\\fs12}When the Flickr fetch comes back, just like the table view, \r\nDialogue: 0,0:11:46.56,0:11:48.55,yin,,0,0,0,, 我们需要小心地确保 \\N{\\fs12}we're going to have to be careful to make sure \r\nDialogue: 0,0:11:48.55,0:11:52.47,yin,,0,0,0,, 这个对话框还同这个 annotation 保持着关联 \\N{\\fs12}that this call out is still associated with this annotation \r\nDialogue: 0,0:11:52.47,0:11:54.31,yin,,0,0,0,, 因为这些东西会被再利用 \\N{\\fs12}and all that because these things get reused, \r\nDialogue: 0,0:11:54.31,0:11:57.38,yin,,0,0,0,, 同表格视图中行会被再利用一样 \\N{\\fs12}just like the table view rows get reused. \r\nDialogue: 0,0:11:57.38,0:12:00.54,yin,,0,0,0,, 无论如何 这里你可以加载对话框附属视图 \\N{\\fs12}But anyway, so this is where you could load up your call out accessory views. \r\nDialogue: 0,0:12:00.54,0:12:04.13,yin,,0,0,0,, 这里你或许还可以 segue\\N{\\fs12}You could also maybe segue here. This might be a place to segue, \r\nDialogue: 0,0:12:04.13,0:12:08.67,yin,,0,0,0,, 不过 segue 需要在代码中进行 因为你没办法 \\N{\\fs12}but you would have to segue in code here, and, because there's no way \r\nDialogue: 0,0:12:08.67,0:12:11.66,yin,,0,0,0,, 在故事板中从大头针进行 control 拖动 \\N{\\fs12}in storyboard to like control drag from the pins, \r\nDialogue: 0,0:12:11.66,0:12:14.58,yin,,0,0,0,, 它们不在屏幕上 直到你开始添加 annotation\\N{\\fs12}they're not on screen, until you start adding annotations, \r\nDialogue: 0,0:12:14.58,0:12:19.51,yin,,0,0,0,, 因此这里我们需要手动 segue 我会在 demo 中演示 \\N{\\fs12}so here we could manual segue and we'll do that in the demo. \r\nDialogue: 0,0:12:19.52,0:12:21.65,yin,,0,0,0,, 你可以配置地图显示的方式 \\N{\\fs12}You could configure the way the map displays. \r\nDialogue: 0,0:12:21.65,0:12:25.13,yin,,0,0,0,, 首先 地图的显示就像是地图 app\\N{\\fs12}Okay, first of all, the map's display is just like the maps app. \r\nDialogue: 0,0:12:25.13,0:12:28.67,yin,,0,0,0,, 我不打算细讲所有地图配置方面的细节 \\N{\\fs12}So I'm not really going to go into all the things you can configure about the map, \r\nDialogue: 0,0:12:28.67,0:12:30.78,yin,,0,0,0,, 不过任何你能在地图 app 中做的事 \\N{\\fs12}but pretty much anything you can do in the maps app, \r\nDialogue: 0,0:12:30.78,0:12:34.57,yin,,0,0,0,, 包括 3D 旋转 缩放 \\N{\\fs12}including the 3D and rotating around, and zooming in and out, \r\nDialogue: 0,0:12:34.57,0:12:37.42,yin,,0,0,0,, 都能在地图视图中做到 \\N{\\fs12}all of that you can do with the map view. \r\nDialogue: 0,0:12:37.42,0:12:39.27,yin,,0,0,0,, 还包括混合模式 \\N{\\fs12}Also including hybrid mode, \r\nDialogue: 0,0:12:39.27,0:12:43.00,yin,,0,0,0,, 卫星图和道路图覆盖在一起 这些都可以做到 \\N{\\fs12}where it's a satellite image overlaid with roads and all that, that's all doable. \r\nDialogue: 0,0:12:43.00,0:12:45.44,yin,,0,0,0,, 你显然需要查阅 MKMapView API\\N{\\fs12}So you want to definitely check out the MK map view API \r\nDialogue: 0,0:12:45.44,0:12:49.14,yin,,0,0,0,, 看你能做多少了不起的事情 \\N{\\fs12}to see all the incredible amount of things you can do. \r\nDialogue: 0,0:12:49.15,0:12:51.64,yin,,0,0,0,, 你可以显示用户当前的位置 \\N{\\fs12}You can show the user's current location. \r\nDialogue: 0,0:12:51.64,0:12:54.83,yin,,0,0,0,, 这会用到上次课我讲到的 Core Location 内容 \\N{\\fs12}So it'll go use that core location stuff we talked about in the last lecture, \r\nDialogue: 0,0:12:54.83,0:12:57.48,yin,,0,0,0,, 使用 GPS 来知道用户当前在哪 \\N{\\fs12}find out where the user currently is using GPS, \r\nDialogue: 0,0:12:57.48,0:13:00.05,yin,,0,0,0,, 它会在地图上显示这个 \\N{\\fs12}it'll show that on your map. \r\nDialogue: 0,0:13:00.05,0:13:02.10,yin,,0,0,0,, 你还可以进行一些限制 \\N{\\fs12}You can also restrict things about it, \r\nDialogue: 0,0:13:02.10,0:13:04.26,yin,,0,0,0,, 或许你不希望用户使用 3D 模式 \\N{\\fs12}maybe you don't want the user to go into 3D mode, \r\nDialogue: 0,0:13:04.26,0:13:06.20,yin,,0,0,0,, 这时你可以关闭 pitchEnabled 属性 \\N{\\fs12}then you can turn the pitch-enabled off \r\nDialogue: 0,0:13:06.20,0:13:07.42,yin,,0,0,0,, 这样它就会无法倾斜 \\N{\\fs12}and it won't be able to pitch. \r\nDialogue: 0,0:13:07.42,0:13:11.44,yin,,0,0,0,, 倾斜可以通过两根手指的手势来做到 \\N{\\fs12}They pitch by doing kind of a little two-finger gesture there, \r\nDialogue: 0,0:13:11.44,0:13:14.10,yin,,0,0,0,, 关闭后你就不能这样做了 旋转也是 \\N{\\fs12}they won't be able to do that if you turn this off, same thing with rotate, \r\nDialogue: 0,0:13:14.10,0:13:17.55,yin,,0,0,0,, 也许你希望北一直往上 不希望用户旋转 \\N{\\fs12}maybe you'll always north up and you don't want them to be able to rotate around \r\nDialogue: 0,0:13:17.56,0:13:19.99,yin,,0,0,0,, 你也可以这样做 \\N{\\fs12}to a different, then you can do that. \r\nDialogue: 0,0:13:19.99,0:13:23.94,yin,,0,0,0,, 我简要讲讲地图的 3D\\N{\\fs12}So let's talk briefly about the 3D of the maps, \r\nDialogue: 0,0:13:23.94,0:13:27.62,yin,,0,0,0,, 这个 3D 有一个很大的问题 它并不是真正的 3D\\N{\\fs12}and a big issue with this 3D, it's not really 3D, \r\nDialogue: 0,0:13:27.62,0:13:29.19,yin,,0,0,0,, 而是一种 2.5D\\N{\\fs12}it's kind of 2 and a half D, right? \r\nDialogue: 0,0:13:29.19,0:13:32.07,yin,,0,0,0,, 这是一个 2D 地图 不过它有一些信息 \\N{\\fs12}This is a 2D map, but, you know, it has some information \r\nDialogue: 0,0:13:32.07,0:13:34.53,yin,,0,0,0,, 关于建筑及其 3D 表示 \\N{\\fs12}about buildings and their 3D representations, \r\nDialogue: 0,0:13:34.53,0:13:38.58,yin,,0,0,0,, 因此在倾斜时 你就可以看到一种 3D 表示 \\N{\\fs12}so kind of when you pitch up, it can show you a bit of a 3D representation. \r\nDialogue: 0,0:13:38.58,0:13:41.17,yin,,0,0,0,, 代码中同这交互的主要方式是 \\N{\\fs12}The main way you're going to interact with that in code is you're going to want to \r\nDialogue: 0,0:13:41.17,0:13:43.55,yin,,0,0,0,, 指定摄像头在哪 \\N{\\fs12}specify where the camera is. \r\nDialogue: 0,0:13:43.55,0:13:47.25,yin,,0,0,0,, 摄像头从哪里看街道 \\N{\\fs12}Where is the camera that's looking at the streets, \r\nDialogue: 0,0:13:47.25,0:13:49.65,yin,,0,0,0,, 或是地图上别的什么 \\N{\\fs12}or whatever, that the person looking at the map, \r\nDialogue: 0,0:13:49.65,0:13:54.30,yin,,0,0,0,, 你可以指定摄像头 通过设定摄像头在哪 \\N{\\fs12}and you can specify the camera via it, where a coordinate or where the camera is, \r\nDialogue: 0,0:13:54.30,0:13:55.50,yin,,0,0,0,, 它指向哪里 \\N{\\fs12}and which way it's pointing, \r\nDialogue: 0,0:13:55.50,0:13:57.79,yin,,0,0,0,, 倾斜了多少 处于什么高度 \\N{\\fs12}and how much is pitch, and what altitude it's at, \r\nDialogue: 0,0:13:57.79,0:14:02.03,yin,,0,0,0,, 不过最简单的做法是使用这个类方法 \\N{\\fs12}but one of the easiest ways to do it is using this class method here, \r\nDialogue: 0,0:14:02.03,0:14:03.92,yin,,0,0,0,,cameraLookingAtCenterCoordinate\\N{\\fs12}camera looking at center coordinate \r\nDialogue: 0,0:14:03.92,0:14:06.54,yin,,0,0,0,,fromEyeCoordinate eyeAltitude\\N{\\fs12}from eye coordinate, eye altitude. \r\nDialogue: 0,0:14:06.54,0:14:10.35,yin,,0,0,0,, 眼睛坐标和眼睛高度 这是摄像头的位置 \\N{\\fs12}So, the eye coordinate and the eye altitude, that's where your camera is. \r\nDialogue: 0,0:14:10.35,0:14:14.51,yin,,0,0,0,, 使用经纬度 确定摄像头在世界上的坐标 \\N{\\fs12}Where in the world, okay, using the coordinates, latitude and longitude, \r\nDialogue: 0,0:14:14.53,0:14:18.58,yin,,0,0,0,, 还有就是摄像头在多少米的高度上 \\N{\\fs12}your camera is how, what is the altitude of your camera, in meters, \r\nDialogue: 0,0:14:18.58,0:14:20.94,yin,,0,0,0,, 然后是你在看哪个点 \\N{\\fs12}and then what point are you looking at? \r\nDialogue: 0,0:14:20.94,0:14:24.83,yin,,0,0,0,, 明白了吗 这样就能设置摄像头了 \\N{\\fs12}You see how that's a way to set your camera? So you can do that to set your camera, \r\nDialogue: 0,0:14:24.83,0:14:26.93,yin,,0,0,0,, 设置摄像头有一点很酷 \\N{\\fs12}one thing that's really cool about setting your camera, \r\nDialogue: 0,0:14:26.93,0:14:28.97,yin,,0,0,0,, 当你从一个地方移到另一个地方 \\N{\\fs12}when you move from one place to another, you can kind \r\nDialogue: 0,0:14:28.97,0:14:32.21,yin,,0,0,0,, 你可以将摄像头往上移到空中 这个会动画显示 \\N{\\fs12}of move your camera up into space and it'll animate that, \r\nDialogue: 0,0:14:32.21,0:14:34.08,yin,,0,0,0,, 然后往下到新地方 \\N{\\fs12}and then come back down in the new place \r\nDialogue: 0,0:14:34.08,0:14:37.49,yin,,0,0,0,, 这就对用户进行了定位定向 \\N{\\fs12}and it really orients your user where they are on the planet \r\nDialogue: 0,0:14:37.49,0:14:41.38,yin,,0,0,0,, 随着他们从一个位置到另一个位置 \\N{\\fs12}as they go from thing, from location to location. \r\nDialogue: 0,0:14:41.38,0:14:42.85,yin,,0,0,0,, 有问题吗 没有 \\N{\\fs12}Question? No. \r\nDialogue: 0,0:14:42.85,0:14:46.61,yin,,0,0,0,, 好 再看区域 \\N{\\fs12}Okay. What about the region, \r\nDialogue: 0,0:14:46.61,0:14:49.23,yin,,0,0,0,, 考虑我们正在看地图的哪里 \\N{\\fs12}what about where on the map we're, we're seeing? \r\nDialogue: 0,0:14:49.23,0:14:53.54,yin,,0,0,0,, 区域的设置要使用这个 MKMapView 属性 region\\N{\\fs12}So the region is set with this property in MK map view called region. \r\nDialogue: 0,0:14:53.54,0:14:55.20,yin,,0,0,0,, 这是一个 MKCoordinateRegion\\N{\\fs12}It's an MK coordinate region, \r\nDialogue: 0,0:14:55.20,0:14:58.64,yin,,0,0,0,,MKCoordinateRegion 是中心坐标经纬度 \\N{\\fs12}an MK coordinate region is center-coordinate latitude and longitude, \r\nDialogue: 0,0:14:58.64,0:15:00.26,yin,,0,0,0,, 和一个跨度 \\N{\\fs12}and then a span. \r\nDialogue: 0,0:15:00.26,0:15:03.37,yin,,0,0,0,, 经纬度Δ 经度多少度 \\N{\\fs12}Latitude and longitude delta, how many degrees of longitude, \r\nDialogue: 0,0:15:03.37,0:15:04.94,yin,,0,0,0,, 纬度多少度 \\N{\\fs12}how many degrees of latitude \r\nDialogue: 0,0:15:04.94,0:15:10.21,yin,,0,0,0,, 这告诉了你 任何时刻地图上显示的是什么 \\N{\\fs12}that tells you what's showing in the map at any given time. \r\nDialogue: 0,0:15:10.21,0:15:13.14,yin,,0,0,0,, 这是可写可读的 你可以设置地图给它 \\N{\\fs12}And this is writable and readable, so you can set the map \r\nDialogue: 0,0:15:13.14,0:15:15.52,yin,,0,0,0,, 你也可以找到它现在在哪 \\N{\\fs12}to it and you can also find out where it is now \r\nDialogue: 0,0:15:15.52,0:15:17.15,yin,,0,0,0,, 在用户采用捏拉或别的什么手势时 \\N{\\fs12}after the user is done pinching or whatever. \r\nDialogue: 0,0:15:17.15,0:15:21.79,yin,,0,0,0,, 你还可以让地图维持它当前的缩放尺寸 \\N{\\fs12}You can also just have the map keep its current zoom \r\nDialogue: 0,0:15:21.79,0:15:24.38,yin,,0,0,0,, 只通过设定中心坐标来移动 \\N{\\fs12}and just move around by setting the center coordinate. \r\nDialogue: 0,0:15:24.38,0:15:28.92,yin,,0,0,0,, 这些你们应该都能预料到 这个地图类非常强大 \\N{\\fs12}This is all exactly what you would expect, is this map class is super powerful. \r\nDialogue: 0,0:15:28.92,0:15:35.13,yin,,0,0,0,, 这是 iOS 中内容非常丰富的类之一 \\N{\\fs12}I mean, one of the more action-packed classes in all of iOS, which is what it can do. \r\nDialogue: 0,0:15:35.13,0:15:38.09,yin,,0,0,0,, 还有很多 C 函数能够换算…\\N{\\fs12}And there's a ton of C functions to convert between. \r\nDialogue: 0,0:15:38.09,0:15:41.56,yin,,0,0,0,, 这只是一个视图 地图视图是一个 UIView\\N{\\fs12}Okay, this is just a view, map view is a UI view, \r\nDialogue: 0,0:15:41.56,0:15:44.23,yin,,0,0,0,, 显然你有经纬度计的地图坐标 \\N{\\fs12}and of course you've got map coordinates in latitude and longitude, \r\nDialogue: 0,0:15:44.24,0:15:46.63,yin,,0,0,0,, 你还有 x 和 y 计的视图坐标 \\N{\\fs12}and then you've got view coordinates in X and Y. \r\nDialogue: 0,0:15:46.63,0:15:48.50,yin,,0,0,0,, 有时 你希望在两者之间进行换算 \\N{\\fs12}So sometimes you want to convert between those two, \r\nDialogue: 0,0:15:48.50,0:15:50.87,yin,,0,0,0,, 因此 它有很多 C 函数来做这个 \\N{\\fs12}so it's got a bunch of C functions for doing that \r\nDialogue: 0,0:15:50.87,0:15:53.39,yin,,0,0,0,, 还有很多方法 这样你就能弄清 \\N{\\fs12}and a bunch of methods, as well, so that you can kind of find \r\nDialogue: 0,0:15:53.39,0:15:55.23,yin,,0,0,0,, 发生了什么 他们在触碰哪里 \\N{\\fs12}out what's going on, where they're touching, \r\nDialogue: 0,0:15:55.23,0:15:57.27,yin,,0,0,0,, 什么导致了事情的发生 等等 \\N{\\fs12}what's causing things, etc. \r\nDialogue: 0,0:15:57.27,0:15:59.87,yin,,0,0,0,, 这在地图视图中有很多 \\N{\\fs12}So there's a lot, a lot in the map view there. \r\nDialogue: 0,0:15:59.87,0:16:02.48,yin,,0,0,0,, 这个地图视图委托方法…\\N{\\fs12}This map view delegate method, \r\nDialogue: 0,0:16:02.48,0:16:05.01,yin,,0,0,0,, 地图视图委托方法有大约 20 个 \\N{\\fs12}there's about 20 map view delegate methods, \r\nDialogue: 0,0:16:05.01,0:16:07.11,yin,,0,0,0,, 我只能讲到其中很少几个 \\N{\\fs12}I can only cover a tiny few here, \r\nDialogue: 0,0:16:07.11,0:16:11.63,yin,,0,0,0,, 像 viewForAnnotation 和 didSelectAnnotationView\\N{\\fs12}like view for annotation and did select annotation view, \r\nDialogue: 0,0:16:11.63,0:16:13.91,yin,,0,0,0,, 不过还有一个很有趣 也就是 didChangeRegion\\N{\\fs12}but another interesting one is did change region. \r\nDialogue: 0,0:16:13.91,0:16:16.27,yin,,0,0,0,, 说它有趣是因为 它会在 \\N{\\fs12}And the reason this is interesting, this gets called, \r\nDialogue: 0,0:16:16.27,0:16:21.02,yin,,0,0,0,, 地图发生动画 四处移动 变换摄像头时被调用 \\N{\\fs12}if the map is animating, moving around, changing the camera or something, \r\nDialogue: 0,0:16:21.04,0:16:24.21,yin,,0,0,0,, 完成后 它会显示一个新区域 \\N{\\fs12}when it's done, it'll be showing a new region, \r\nDialogue: 0,0:16:24.21,0:16:25.86,yin,,0,0,0,, 它会发送这个消息给你 \\N{\\fs12}it'll send this message to you. \r\nDialogue: 0,0:16:25.86,0:16:26.86,yin,,0,0,0,, 这有什么重要的呢 \\N{\\fs12}Why is that important? \r\nDialogue: 0,0:16:26.86,0:16:27.87,yin,,0,0,0,, 为什么你要这样 \\N{\\fs12}Why would you want that? \r\nDialogue: 0,0:16:27.87,0:16:29.54,yin,,0,0,0,, 因为如果你想有动画 \\N{\\fs12}Well, because if you're going to do animation, \r\nDialogue: 0,0:16:29.54,0:16:33.22,yin,,0,0,0,, 例如现在显示的是旧金山 而用户想要看到纽约 \\N{\\fs12}like I'm showing San Francisco and the user now wants to see New York, \r\nDialogue: 0,0:16:33.22,0:16:35.57,yin,,0,0,0,, 如果你只是设定纽约的坐标 \\N{\\fs12}if you just say set the coordinate New York, \r\nDialogue: 0,0:16:35.57,0:16:37.69,yin,,0,0,0,, 它会呼地一下跳到纽约 \\N{\\fs12}it's going to go whoosh, over to New York, \r\nDialogue: 0,0:16:37.69,0:16:40.53,yin,,0,0,0,, 整个国家会在半秒之内瞬间被掠过 \\N{\\fs12}and the whole country is going to rip by in about half a second. \r\nDialogue: 0,0:16:40.53,0:16:43.41,yin,,0,0,0,, 这就没有任何动画 但是如果你想 \\N{\\fs12}So it's not going to be much of an animation, but if you want \r\nDialogue: 0,0:16:43.41,0:16:47.36,yin,,0,0,0,, 将摄像头往上移到美国上方几千米的高空 \\N{\\fs12}to move your camera up over the United States a few thousand meters, \r\nDialogue: 0,0:16:47.36,0:16:49.68,yin,,0,0,0,, 然后再回到下面 \\N{\\fs12}and then go back down. \r\nDialogue: 0,0:16:49.68,0:16:52.44,yin,,0,0,0,, 你就需要知道你到上面以后 \\N{\\fs12}You'll need to know when you get up to the top \r\nDialogue: 0,0:16:52.44,0:16:54.66,yin,,0,0,0,, 动画又会开始往下 \\N{\\fs12}so that you can start the animation going down, and so, \r\nDialogue: 0,0:16:54.66,0:16:57.04,yin,,0,0,0,, 到上面时 区域动画会被调用 \\N{\\fs12}region to animated will get called when you get to the top, \r\nDialogue: 0,0:16:57.04,0:16:59.79,yin,,0,0,0,, 动画会将摄像头移到上面去 \\N{\\fs12}you start the animation to move the camera to the top, \r\nDialogue: 0,0:16:59.79,0:17:01.70,yin,,0,0,0,, 到上面 区域被设置 \\N{\\fs12}when it gets to the top and the region is set, \r\nDialogue: 0,0:17:01.70,0:17:04.27,yin,,0,0,0,, 它会调用这个 区域将是整个美国 \\N{\\fs12}it'll call you this, and the region will be the whole United States, \r\nDialogue: 0,0:17:04.29,0:17:06.69,yin,,0,0,0,, 然后动画就可以开始回到下面 \\N{\\fs12}and then you can start your animation and go back down. \r\nDialogue: 0,0:17:06.69,0:17:10.03,yin,,0,0,0,, 优秀的 app 应该首先上升 \\N{\\fs12}And really, for nice apps, you might go up, \r\nDialogue: 0,0:17:10.03,0:17:13.12,yin,,0,0,0,, 下降到纽约 然后沿街道移动 \\N{\\fs12}down to New York, and then drive down the street. \r\nDialogue: 0,0:17:13.12,0:17:14.44,yin,,0,0,0,, 这是一个很酷的动画 \\N{\\fs12}It's kind of really cool animation, \r\nDialogue: 0,0:17:14.44,0:17:17.79,yin,,0,0,0,, 每一步 你都希望使用这个转到下一步 \\N{\\fs12}that each of those steps, you want to use this to go to the next step, \r\nDialogue: 0,0:17:17.79,0:17:20.81,yin,,0,0,0,, 而不是用动画的完成处理器 \\N{\\fs12}not the completion handlers of the animation things, \r\nDialogue: 0,0:17:20.81,0:17:23.50,yin,,0,0,0,, 这个更好 因为这里会有各种东西 \\N{\\fs12}this is much better, because this is going to have all, \r\nDialogue: 0,0:17:23.50,0:17:25.55,yin,,0,0,0,, 它会进行旋转等等 \\N{\\fs12}it's going to do all the rotation, when everything settled down, \r\nDialogue: 0,0:17:25.55,0:17:26.98,yin,,0,0,0,, 将一切安排妥帖 \\N{\\fs12}it's almost like the settle down, \r\nDialogue: 0,0:17:26.99,0:17:30.31,yin,,0,0,0,, 几乎就像是动态动画器中的 didPause\\N{\\fs12}the did pause we had in the dynamic animator. \r\nDialogue: 0,0:17:30.31,0:17:34.48,yin,,0,0,0,, 这对于好的地图动画是非常重要的方法 \\N{\\fs12}So that's an important method to know if you're going to do good map animation. \r\nDialogue: 0,0:17:34.48,0:17:38.27,yin,,0,0,0,, 除了地图视图之外 我们还有搜索 \\N{\\fs12}Alright, so in addition to the map view, we also have searching. \r\nDialogue: 0,0:17:38.27,0:17:43.76,yin,,0,0,0,, 局部搜索同 GeoCoder 很像 但强大很多 \\N{\\fs12}So local search, kind of like a geo coder, but lots more powerful. \r\nDialogue: 0,0:17:43.76,0:17:46.19,yin,,0,0,0,, 这能让你的用户指定 \\N{\\fs12}This basically lets you have, specify, \r\nDialogue: 0,0:17:46.19,0:17:48.46,yin,,0,0,0,, 一个自然语言查询 \\N{\\fs12}let's your user specify a natural language query, \r\nDialogue: 0,0:17:48.46,0:17:51.78,yin,,0,0,0,, 例如这里我可以创建一个搜索 Ike's 的请求 \\N{\\fs12}like here I might create a search request for'Ikes'. \r\nDialogue: 0,0:17:51.78,0:17:55.13,yin,,0,0,0,, 我可以在斯坦福校园的区域内进行搜索 \\N{\\fs12}And I might search in a region which is Stanford Campus, \r\nDialogue: 0,0:17:55.13,0:17:58.73,yin,,0,0,0,, 然后我发送这个 当然 这个会经过网络 \\N{\\fs12}and then I fire this off, of course, this is going to go over the network, \r\nDialogue: 0,0:17:58.73,0:18:00.69,yin,,0,0,0,, 并非所有信息都在设备上 \\N{\\fs12}not all this information is on your device. \r\nDialogue: 0,0:18:00.69,0:18:01.94,yin,,0,0,0,, 它会经过网络 \\N{\\fs12}It's going to go over the network, \r\nDialogue: 0,0:18:01.94,0:18:03.89,yin,,0,0,0,, 它会取回 会找到结果 \\N{\\fs12}it's going to do a fetch, going to figure this out, \r\nDialogue: 0,0:18:03.89,0:18:05.33,yin,,0,0,0,, 它会返回给你 \\N{\\fs12}and it's going to return to you \r\nDialogue: 0,0:18:05.33,0:18:06.87,yin,,0,0,0,, 并调用这个完成处理器 \\N{\\fs12}and call you to this completion handler \r\nDialogue: 0,0:18:06.87,0:18:09.41,yin,,0,0,0,, 你说 startWithCompletionHandler\\N{\\fs12}so you do it with start, with completion, \r\nDialogue: 0,0:18:09.41,0:18:11.30,yin,,0,0,0,, 它之后就会调用完成处理器 \\N{\\fs12}it'll call the completion handler later, \r\nDialogue: 0,0:18:11.30,0:18:14.18,yin,,0,0,0,, 你会得到一个由 MKMapItem 组成的数组 \\N{\\fs12}and you're going to get an array of MK map items. \r\nDialogue: 0,0:18:14.18,0:18:18.79,yin,,0,0,0,,MKMapItem 也就是描述地图上位置的项目 \\N{\\fs12}MK map items are basically things that describe a place on the map. \r\nDialogue: 0,0:18:18.79,0:18:21.35,yin,,0,0,0,, 其中包含有 MKPlacemark\\N{\\fs12}And they have inside of them an MK place mark, \r\nDialogue: 0,0:18:21.36,0:18:23.61,yin,,0,0,0,, 这是关于地图上位置的细节信息 \\N{\\fs12}which is detail about a place on the map, \r\nDialogue: 0,0:18:23.61,0:18:27.13,yin,,0,0,0,, 例如邮编 或是所处区域 诸如此类 \\N{\\fs12}like the postal code or region it's in, things like that. \r\nDialogue: 0,0:18:27.13,0:18:30.91,yin,,0,0,0,,MKMapItem 很酷 因为这里有一个方法 \\N{\\fs12}MK map item is kind of cool because it, there's a method \r\nDialogue: 0,0:18:30.91,0:18:33.53,yin,,0,0,0,, 叫作 openInMapsWithLaunchOptions\\N{\\fs12}in there called open in map with launch options, \r\nDialogue: 0,0:18:33.53,0:18:35.53,yin,,0,0,0,, 把这发送给一个 MKMapItem\\N{\\fs12}and if you send that to an MK map item, it will \r\nDialogue: 0,0:18:35.53,0:18:38.39,yin,,0,0,0,, 它会离开你的 app 启动地图 app 并在那里显示 \\N{\\fs12}leave your app, launch the maps app and show it there. \r\nDialogue: 0,0:18:38.39,0:18:40.53,yin,,0,0,0,, 就算你不想有一个地图视图以及所有这些 \\N{\\fs12}So if you don't want to have a map view and all that stuff, \r\nDialogue: 0,0:18:40.53,0:18:43.08,yin,,0,0,0,, 你还是可以使用这个局部搜索 \\N{\\fs12}you can still use this local search and then switch \r\nDialogue: 0,0:18:43.08,0:18:46.82,yin,,0,0,0,, 然后切换到地图 app 来显示特定位置 \\N{\\fs12}over to the maps app if you want to show them that particular location. \r\nDialogue: 0,0:18:46.82,0:18:47.76,yin,,0,0,0,, 请讲 \\N{\\fs12}Yeah? \r\nDialogue: 0,0:18:53.12,0:18:56.07,yin,,0,0,0,, 问题是 地图图块本身是怎样的 \\N{\\fs12}Yeah, so the question is what about the tiles of the map itself? \r\nDialogue: 0,0:18:56.07,0:18:57.05,yin,,0,0,0,, 所有地图数据 \\N{\\fs12}All that map data? \r\nDialogue: 0,0:18:57.05,0:19:00.62,yin,,0,0,0,, 这些显然也不在你的手机上 也需要下载 \\N{\\fs12}Yeah, that's clearly not on your phone as well, that's downloaded too. \r\nDialogue: 0,0:19:00.62,0:19:03.29,yin,,0,0,0,, 最开始看地图上的位置时 它将是一个网格 \\N{\\fs12}So when you first look at a place on the map, it's just going to be like a grid, \r\nDialogue: 0,0:19:03.29,0:19:05.82,yin,,0,0,0,, 就像是星际迷航中的空甲板 \\N{\\fs12}kind of like the hollow deck in Star Trek or whatever, \r\nDialogue: 0,0:19:05.82,0:19:09.16,yin,,0,0,0,, 只是一个网格 然后再填入图块 \\N{\\fs12}like just a grid, and then it's going to fill in with the tiles. \r\nDialogue: 0,0:19:09.16,0:19:12.68,yin,,0,0,0,, 下载有多快取决于你的网络有多快 \\N{\\fs12}And depending how fast your network is, that's how fast it's going to download it. \r\nDialogue: 0,0:19:12.68,0:19:15.74,yin,,0,0,0,, 这些都会发生在后台 你甚至不知道 \\N{\\fs12}So yeah, that's all happening, though, in the background, you don't even know. \r\nDialogue: 0,0:19:15.74,0:19:16.72,yin,,0,0,0,, 这些都会发生在后台 你甚至不知道 \\N{\\fs12}You have no idea what's going on. \r\nDialogue: 0,0:19:16.72,0:19:18.64,yin,,0,0,0,, 你可以找到委托方法 \\N{\\fs12}You can find out there are delegate methods \r\nDialogue: 0,0:19:18.64,0:19:21.90,yin,,0,0,0,, 说获取这个图块 如果你想知道 它会告诉你 \\N{\\fs12}that said got this tile, you know, it'll tell you if you want \r\nDialogue: 0,0:19:21.90,0:19:23.94,yin,,0,0,0,, 但一般情况下你并不关心 \\N{\\fs12}to know, but generally you don't care. \r\nDialogue: 0,0:19:23.94,0:19:28.61,yin,,0,0,0,, 还有办法能够获取从一个地方到另一个的方向 \\N{\\fs12}There's also a way to get directions from one place to another. \r\nDialogue: 0,0:19:28.61,0:19:32.18,yin,,0,0,0,, 你只需要创建这个 MKDirection\\N{\\fs12}So, you just create this MK directions thing, \r\nDialogue: 0,0:19:32.19,0:19:35.49,yin,,0,0,0,, 你一开始要指定一个 MKMapItem 到最后 \\N{\\fs12}you're going to specify an MK map item at the beginning, at the end, \r\nDialogue: 0,0:19:35.49,0:19:38.33,yin,,0,0,0,, 它会异步地经过网络 \\N{\\fs12}and it's going to, again, go asynchronously over the network \r\nDialogue: 0,0:19:38.33,0:19:41.31,yin,,0,0,0,, 给你返回一个可选路径的列表 \\N{\\fs12}and give you back a list of possible routes that you can take, \r\nDialogue: 0,0:19:41.31,0:19:44.69,yin,,0,0,0,, 这些返回的路径将有文字描述 \\N{\\fs12}and these routes are going to come back with text descriptions, you know, \r\nDialogue: 0,0:19:44.69,0:19:47.95,yin,,0,0,0,, 例如高速公路 101 走这么多 等等 \\N{\\fs12}take highway 101 for this much, or whatever, \r\nDialogue: 0,0:19:47.95,0:19:52.20,yin,,0,0,0,, 此外 它们还会返回 MKPolyline\\N{\\fs12}and also they're going to come back with the MK polylines. \r\nDialogue: 0,0:19:52.20,0:19:56.05,yin,,0,0,0,,MKPolyline 顾名思义 也就是一些直线 \\N{\\fs12}An MK polyline, exactly what you would think, it's a bunch of lines, \r\nDialogue: 0,0:19:56.05,0:19:59.77,yin,,0,0,0,, 一条多段线 例如图中的蓝线 \\N{\\fs12}and this polyline, you can see the blue line here, \r\nDialogue: 0,0:19:59.77,0:20:00.99,yin,,0,0,0,, 或是紫线 \\N{\\fs12}or the purple lines, \r\nDialogue: 0,0:20:01.00,0:20:06.15,yin,,0,0,0,, 也就是如何对从地图上一处到另一处的描述 \\N{\\fs12}is basically a description of how to draw and go from place to place in the map, \r\nDialogue: 0,0:20:06.15,0:20:07.43,yin,,0,0,0,, 这非常酷 \\N{\\fs12}which is really, really cool. \r\nDialogue: 0,0:20:07.43,0:20:10.79,yin,,0,0,0,, 这绕过了一个问题 也就是 如果我有一条多段线 \\N{\\fs12}But it does beg the question if I got a polyline, in hand, how do I \r\nDialogue: 0,0:20:10.79,0:20:13.33,yin,,0,0,0,, 那该如何画到地图上呢 \\N{\\fs12}put it on the map? How do I draw it on the map? \r\nDialogue: 0,0:20:13.33,0:20:17.38,yin,,0,0,0,, 答案是 我们使用 overlay(覆盖图) 来画在地图上 \\N{\\fs12}And the answer is we draw on the map using overlays. \r\nDialogue: 0,0:20:17.38,0:20:19.65,yin,,0,0,0,,overlay 也就是 \\N{\\fs12}So overlays are \r\nDialogue: 0,0:20:19.65,0:20:24.05,yin,,0,0,0,, 一些你想画在地图上的形状 \\N{\\fs12}essentially descriptions of some shape that you want to draw on the map. \r\nDialogue: 0,0:20:24.05,0:20:27.74,yin,,0,0,0,, 多段线是一种 不过这里也可以是圆形 \\N{\\fs12}So a polyline would be one, but you could also do circles, \r\nDialogue: 0,0:20:27.74,0:20:30.62,yin,,0,0,0,, 任意多边形 等等 \\N{\\fs12}you know, arbitrary polygons, things like that, \r\nDialogue: 0,0:20:30.62,0:20:34.79,yin,,0,0,0,, 做法是 你创建这个形状 \\N{\\fs12}and the way this mechanism works is you create this shape, \r\nDialogue: 0,0:20:34.79,0:20:37.29,yin,,0,0,0,, 例如一条 MKPolyline 你添加一个 overlay\\N{\\fs12}like an MK polyline, you add an overlay, \r\nDialogue: 0,0:20:37.29,0:20:39.80,yin,,0,0,0,, 使用 addOverlay 这里的 level 是说 \\N{\\fs12}you see that add overlay, the level there is whether it's \r\nDialogue: 0,0:20:39.80,0:20:43.53,yin,,0,0,0,, 是高于道路 还是高于标签 \\N{\\fs12}above the roads or just above the, or above the labels, \r\nDialogue: 0,0:20:43.53,0:20:45.10,yin,,0,0,0,, 在地图上的一切之上 \\N{\\fs12}which is kind of on top of everything in the map, \r\nDialogue: 0,0:20:45.10,0:20:47.65,yin,,0,0,0,, 你可以让多段线高于道路 \\N{\\fs12}so you could have the polyline be on the roads \r\nDialogue: 0,0:20:47.65,0:20:51.84,yin,,0,0,0,, 让 280 这些符号都在它之上 这会看起来很棒 \\N{\\fs12}and have things like 280 symbol be above it, which looks really cool. \r\nDialogue: 0,0:20:51.84,0:20:56.92,yin,,0,0,0,, 之后 MKMapView 还会问你 \\N{\\fs12}But then, the MK map view is going to ask you later, okay, \r\nDialogue: 0,0:20:56.92,0:21:01.53,yin,,0,0,0,, 要一个渲染器 来把这个画在地图上 \\N{\\fs12}now I need a renderer to draw this thing on the map. \r\nDialogue: 0,0:21:01.53,0:21:03.00,yin,,0,0,0,,MKOverlayRenderer\\N{\\fs12}An MK overlay renderer, \r\nDialogue: 0,0:21:03.00,0:21:05.32,yin,,0,0,0,, 有点像 MKAnnotationView\\N{\\fs12}which is a little bit like that MK annotation view, \r\nDialogue: 0,0:21:05.32,0:21:08.11,yin,,0,0,0,, 只是 MKOverlayRenderer 并非视图 \\N{\\fs12}except for an MK overlay renderer is not a view, \r\nDialogue: 0,0:21:08.11,0:21:11.11,yin,,0,0,0,, 它是一个在地图上绘制的机制 \\N{\\fs12}it's more of a mechanism for drawing on the map, \r\nDialogue: 0,0:21:11.11,0:21:14.28,yin,,0,0,0,, 然后这个渲染器就会被用于渲染地图 \\N{\\fs12}and then that renderer will be used to render on the map. \r\nDialogue: 0,0:21:14.28,0:21:17.54,yin,,0,0,0,, 这些渲染器来自于 iOS 种类有很多 \\N{\\fs12}Now, these renderers come with iOS, there's a whole bunch of them, \r\nDialogue: 0,0:21:17.54,0:21:23.14,yin,,0,0,0,, 圆形渲染器 多段线渲染器 多边形 还有图块渲染器 \\N{\\fs12}circle renderer, polyline renderer, polygon, there's a tile renderer. \r\nDialogue: 0,0:21:23.14,0:21:27.38,yin,,0,0,0,, 图块渲染器很酷 因为它只渲染位图 \\N{\\fs12}The tile renderer is cool because it just renders bit maps, okay, \r\nDialogue: 0,0:21:27.38,0:21:29.92,yin,,0,0,0,, 你还可以用它来替换来自苹果的数据 \\N{\\fs12}and you can actually use it to replace the data, \r\nDialogue: 0,0:21:29.92,0:21:32.14,yin,,0,0,0,, 你还可以用它来替换来自苹果的数据 \\N{\\fs12}instead of the data, that comes from Apple. \r\nDialogue: 0,0:21:32.14,0:21:35.76,yin,,0,0,0,, 如果你有自定义的地图 你可以有这个图块 \\N{\\fs12}So if you had your own custom map, you could have this tile \r\nDialogue: 0,0:21:35.76,0:21:38.16,yin,,0,0,0,, 这有些复杂 因为你需要 \\N{\\fs12}and it's a little bit involved, because you're talking \r\nDialogue: 0,0:21:38.16,0:21:41.69,yin,,0,0,0,, 能够放大缩小 它需要这个的 API\\N{\\fs12}about being able to zoom in and out and it has an API for that, \r\nDialogue: 0,0:21:41.69,0:21:43.74,yin,,0,0,0,, 不过你确实可以替换 \\N{\\fs12}but you could possibly replace, or you might just want \r\nDialogue: 0,0:21:43.74,0:21:46.36,yin,,0,0,0,, 或许你想要世界上特定地方的图块 \\N{\\fs12}to tile some image over a certain place in the world. \r\nDialogue: 0,0:21:46.36,0:21:48.02,yin,,0,0,0,, 所有这些都是内建的 \\N{\\fs12}And so all that stuff is built \r\nDialogue: 0,0:21:48.02,0:21:52.57,yin,,0,0,0,, 都在 MKShape 和 MKOverlay 中 \\N{\\fs12}in with this MK shape stuff in, in MK overlay. \r\nDialogue: 0,0:21:52.57,0:21:55.57,yin,,0,0,0,,overlay 非常酷 你可以用它们做很多事 \\N{\\fs12}So, overlays are really pretty cool and you can do a lot \r\nDialogue: 0,0:21:55.57,0:21:58.52,yin,,0,0,0,, 因此 我建议你们去看看它们 \\N{\\fs12}of stuff with them, so I encourage you to kind of look at that. \r\nDialogue: 0,0:21:59.75,0:22:01.37,yin,,0,0,0,, 好 以上是关于地图 \\N{\\fs12}Okay. So that's it for maps. \r\nDialogue: 0,0:22:01.37,0:22:02.85,yin,,0,0,0,, 这方面我会有一个大 demo\\N{\\fs12}And I'm going to do a big demo of all this stuff \r\nDialogue: 0,0:22:02.85,0:22:05.32,yin,,0,0,0,, 你可以看到这些的实际操作 不过演示前 \\N{\\fs12}so you can see all this stuff in action, but before I do that, \r\nDialogue: 0,0:22:05.32,0:22:08.10,yin,,0,0,0,, 我还要讲另外一点会出现在 demo 中的内容 \\N{\\fs12}there's another thing I'm going to do in the demo that I want to talk about briefly, \r\nDialogue: 0,0:22:08.10,0:22:09.65,yin,,0,0,0,, 也就是 embed segue\\N{\\fs12}which is embed segues. \r\nDialogue: 0,0:22:09.65,0:22:13.00,yin,,0,0,0,,segue 方面 现在你们知道如何使用 push segue\\N{\\fs12}So, so far about segues, you know how to do push segues, \r\nDialogue: 0,0:22:13.00,0:22:14.90,yin,,0,0,0,, 这是在导航控制器中 \\N{\\fs12}when you're in navigation controller, you know how \r\nDialogue: 0,0:22:14.90,0:22:18.20,yin,,0,0,0,, 拆分视图中你们知道如何使用 replace segue\\N{\\fs12}to do replace segues in a split view, although \r\nDialogue: 0,0:22:18.20,0:22:19.97,yin,,0,0,0,, 只是我没有演示 \\N{\\fs12}we didn't demo that and it's pretty rare \r\nDialogue: 0,0:22:19.97,0:22:23.22,yin,,0,0,0,, 实际替换 detail 或 master 也很罕见 \\N{\\fs12}to actually replace the detail or the master. \r\nDialogue: 0,0:22:23.22,0:22:25.70,yin,,0,0,0,,segue 中 我们通常会把 detail 留在那里 \\N{\\fs12}In a segue, we usually just leave the detail there \r\nDialogue: 0,0:22:25.70,0:22:28.69,yin,,0,0,0,, 然后一直去找它 Photomania 中就是这样做的 \\N{\\fs12}and go look for it all the time, like we did in photo mania. \r\nDialogue: 0,0:22:28.69,0:22:31.34,yin,,0,0,0,,popover segue 这是上次我们看到的 \\N{\\fs12}Pop over segues, we saw that last time, okay, \r\nDialogue: 0,0:22:31.34,0:22:33.08,yin,,0,0,0,, 那里我们使用了弹窗 \\N{\\fs12}where we said we'll do a pop over. \r\nDialogue: 0,0:22:33.08,0:22:35.03,yin,,0,0,0,, 这次我要讲的是 embed segue\\N{\\fs12}And here's another one called embed segues. \r\nDialogue: 0,0:22:35.03,0:22:37.56,yin,,0,0,0,,embed segue 很酷 \\N{\\fs12}And an embed segue is really cool, \r\nDialogue: 0,0:22:37.56,0:22:39.24,yin,,0,0,0,, 你创建一个 UIView\\N{\\fs12}you create a UI view \r\nDialogue: 0,0:22:39.24,0:22:42.24,yin,,0,0,0,, 在某个视图控制器的视图层级内 \\N{\\fs12}inside the view hierarchy of some view controller, \r\nDialogue: 0,0:22:42.24,0:22:44.57,yin,,0,0,0,, 在这个 UIView 之内 \\N{\\fs12}and inside that UI view, \r\nDialogue: 0,0:22:44.57,0:22:48.56,yin,,0,0,0,, 是另一个视图控制器的 self.view\\N{\\fs12}is the self dot view of another view controller. \r\nDialogue: 0,0:22:48.56,0:22:51.28,yin,,0,0,0,, 你将另一个视图控制器的 self.view\\N{\\fs12}So you basically take another view controller's self \r\nDialogue: 0,0:22:51.28,0:22:55.17,yin,,0,0,0,, 作为 UIView 嵌入到了另一个里面 \\N{\\fs12}dot view and embed it as a UI view inside another one. \r\nDialogue: 0,0:22:55.17,0:23:01.12,yin,,0,0,0,, 这让你能够创建非常复杂的视图 \\N{\\fs12}So, that allows you to build pretty complex views \r\nDialogue: 0,0:23:01.12,0:23:07.94,yin,,0,0,0,, 同时仍能将矩形区域的职责划分到 MVC 中 \\N{\\fs12}and still divide up the responsibility for a rectangular area into MVCs. \r\nDialogue: 0,0:23:07.96,0:23:09.91,yin,,0,0,0,, 我会在 demo 演示 \\N{\\fs12}And I'm going to do this in the demo \r\nDialogue: 0,0:23:09.91,0:23:12.29,yin,,0,0,0,, 到时你们会明白我这里讲的是什么 \\N{\\fs12}so you get a little better idea of what I'm talking about here. \r\nDialogue: 0,0:23:12.29,0:23:15.87,yin,,0,0,0,,Xcode 让这个非常非常容易做到 \\N{\\fs12}Xcode makes is really, really easy to do this. \r\nDialogue: 0,0:23:15.87,0:23:17.75,yin,,0,0,0,, 你只需要到对象面板 \\N{\\fs12}You just go to the object palette and you're going \r\nDialogue: 0,0:23:17.75,0:23:20.43,yin,,0,0,0,, 在下面找到所谓的 Container View(容器视图)\\N{\\fs12}to find something down there called container view, \r\nDialogue: 0,0:23:20.43,0:23:23.76,yin,,0,0,0,, 你将 Container View 拖到你想要的视图中 \\N{\\fs12}you drag that container view into the view you want \r\nDialogue: 0,0:23:23.76,0:23:26.87,yin,,0,0,0,, 然后就会自动创建一个视图控制器 \\N{\\fs12}and then it's going to actually automatically create a little \r\nDialogue: 0,0:23:26.87,0:23:29.08,yin,,0,0,0,, 带有一个到它的 segue\\N{\\fs12}view controller with a segue to it, \r\nDialogue: 0,0:23:29.08,0:23:31.89,yin,,0,0,0,, 不过你可以 control 拖动 从这个容器 \\N{\\fs12}but you can control, drag from this container \r\nDialogue: 0,0:23:31.89,0:23:34.97,yin,,0,0,0,, 到任何你想嵌入的 VC\\N{\\fs12}to any VC you want to be embedded there. \r\nDialogue: 0,0:23:34.97,0:23:38.85,yin,,0,0,0,,control 拖动后 它和其它 segue 没是区别 \\N{\\fs12}And then once you add control, drag, it's just like any other segue. \r\nDialogue: 0,0:23:38.85,0:23:41.00,yin,,0,0,0,, 它是一个 segue 需要准备 \\N{\\fs12}It's just a segue. It has to be prepared, right? \r\nDialogue: 0,0:23:41.00,0:23:43.51,yin,,0,0,0,, 因为它在这里需要显示一些东西 \\N{\\fs12}Because it's going to be displaying something in there, presumably. \r\nDialogue: 0,0:23:43.51,0:23:45.21,yin,,0,0,0,, 其它方面 它完全一样 \\N{\\fs12}But otherwise, it's exactly the same. \r\nDialogue: 0,0:23:45.21,0:23:48.25,yin,,0,0,0,, 不仅这个 segue 同其它 segue 很相似 \\N{\\fs12}And not only is that segue exactly like any other segue, \r\nDialogue: 0,0:23:48.25,0:23:52.85,yin,,0,0,0,, 那个容器视图也和其它 UIView 很相似 \\N{\\fs12}the view, that container you see right there, that's just like any other UI view. \r\nDialogue: 0,0:23:52.85,0:23:55.42,yin,,0,0,0,, 在主视图控制器中 \\N{\\fs12}So, in the host view controller, \r\nDialogue: 0,0:23:55.42,0:23:58.48,yin,,0,0,0,, 如果你想隐藏 你可以设置它的.hidden\\N{\\fs12}you can set its dot hidden if you want to hide it. \r\nDialogue: 0,0:23:58.48,0:24:00.49,yin,,0,0,0,, 你可以改变它的 frame\\N{\\fs12}You can change its frame, okay, \r\nDialogue: 0,0:24:00.49,0:24:03.42,yin,,0,0,0,, 你可以动画展示它的 frame 变化和移动 \\N{\\fs12}you can animate its frame changing, moving around. \r\nDialogue: 0,0:24:03.42,0:24:04.92,yin,,0,0,0,, 你可以做任何你想做的事 \\N{\\fs12}You can do anything you want, \r\nDialogue: 0,0:24:04.92,0:24:07.20,yin,,0,0,0,, 这对你只是一个不透明的 UIView\\N{\\fs12}it's just kind of an opaque UI view to you, \r\nDialogue: 0,0:24:07.20,0:24:08.54,yin,,0,0,0,, 它是视图层级的一部分 \\N{\\fs12}it's part of your view hierarchy, you can take it \r\nDialogue: 0,0:24:08.54,0:24:11.00,yin,,0,0,0,, 你将它从中抽出 放回里面 \\N{\\fs12}out of the view hierarchy, put it back in, okay, \r\nDialogue: 0,0:24:11.00,0:24:14.00,yin,,0,0,0,, 只是它的内容会被绘制为 \\N{\\fs12}it's just that its contents are going to be drawn \r\nDialogue: 0,0:24:14.00,0:24:17.07,yin,,0,0,0,, 其它某个视图控制器的 self.view\\N{\\fs12}as the self dot view of some other view controller. \r\nDialogue: 0,0:24:20.98,0:24:23.74,yin,,0,0,0,, 时机 这个需要小心 \\N{\\fs12}The timing this is little bit thing to be careful \r\nDialogue: 0,0:24:23.74,0:24:25.84,yin,,0,0,0,, 这是进行设置的时机 \\N{\\fs12}of is the timing of setting things, \r\nDialogue: 0,0:24:25.84,0:24:29.49,yin,,0,0,0,, 想想 这个嵌入发生在什么时候 \\N{\\fs12}because when does this embed happen. \r\nDialogue: 0,0:24:29.49,0:24:32.15,yin,,0,0,0,, 它的 prepareForSegue 发生在什么时候 \\N{\\fs12}When does it's prepare for segue happen, basically? \r\nDialogue: 0,0:24:32.15,0:24:35.64,yin,,0,0,0,, 相对于它嵌入到的视图控制器中发生的其它事情 \\N{\\fs12}Relative to other things happening in that view controller that it's embedded in, \r\nDialogue: 0,0:24:35.64,0:24:38.16,yin,,0,0,0,, 例如 其 outlet 被设置等等 \\N{\\fs12}like that things outlets being set, etc. \r\nDialogue: 0,0:24:38.18,0:24:40.80,yin,,0,0,0,, 答案是 这发生得很早 \\N{\\fs12}And the answer is it happens pretty early. \r\nDialogue: 0,0:24:40.80,0:24:44.34,yin,,0,0,0,, 在 outlet 设置之前 就像其它 prepareForSegue 一样 \\N{\\fs12}Before outlet setting, just like all prepare for segues do. \r\nDialogue: 0,0:24:44.34,0:24:45.73,yin,,0,0,0,, 很多时候 \\N{\\fs12}So a lot of times you're going to have \r\nDialogue: 0,0:24:45.73,0:24:49.46,yin,,0,0,0,, 你需要在准备和 outlet 设置中写相同的代码 \\N{\\fs12}to do whatever code you do in the prepare also in your outlet setting, \r\nDialogue: 0,0:24:49.46,0:24:51.27,yin,,0,0,0,, 如果它们相互依赖的话 \\N{\\fs12}if they depend on each other. \r\nDialogue: 0,0:24:51.27,0:24:53.38,yin,,0,0,0,, 之前在 Photomania 中我们见过这个 \\N{\\fs12}And we've already seen this in photo mania before, \r\nDialogue: 0,0:24:53.38,0:24:56.21,yin,,0,0,0,, 如果 prepareForSegue 依赖于一个 outlet\\N{\\fs12}anything you do in your prepare for segue that depends on an outlet, \r\nDialogue: 0,0:24:56.21,0:24:57.88,yin,,0,0,0,, 你就需要在 prepareForSegue 中这样写 \\N{\\fs12}you're going to do it in prepare segue, \r\nDialogue: 0,0:24:57.88,0:24:59.97,yin,,0,0,0,, 同时在 outlet 设置器中也这样写 \\N{\\fs12}you might also do it in the outlet setter. \r\nDialogue: 0,0:24:59.97,0:25:03.94,yin,,0,0,0,, 这样一个发生时 另一个就会实际工作 \\N{\\fs12}So whichever one happens second will do the actual work. \r\nDialogue: 0,0:25:03.94,0:25:06.85,yin,,0,0,0,, 大家都理解了我说的吗 \\N{\\fs12}Does everyone understand what I mean by that? \r\nDialogue: 0,0:25:06.85,0:25:08.76,yin,,0,0,0,, 没有 还是理解了 \\N{\\fs12}No? Yes? \r\nDialogue: 0,0:25:08.76,0:25:11.87,yin,,0,0,0,, 谁理解了我说的是什么意思 \\N{\\fs12}Who does understand what I mean by that? \r\nDialogue: 0,0:25:11.87,0:25:13.42,yin,,0,0,0,, 没有人 好 \\N{\\fs12}Nobody. Okay, well. \r\nDialogue: 0,0:25:13.42,0:25:16.72,yin,,0,0,0,, 不看演示可能有点难于理解 \\N{\\fs12}Okay, it's maybe a little hard to conceptualize without seeing it, \r\nDialogue: 0,0:25:16.72,0:25:20.29,yin,,0,0,0,,demo 中我会讲到这个 但愿到时大家就懂了 \\N{\\fs12}so in the demo I'll talk about it again and hopefully it'll make sense. \r\nDialogue: 0,0:25:20.29,0:25:22.12,yin,,0,0,0,, 好 让我们来做这个 demo\\N{\\fs12}Alright, so let's do this demo. \r\nDialogue: 0,0:25:22.12,0:25:24.55,yin,,0,0,0,, 这个 demo 很大 \\N{\\fs12}This is a very big demo. \r\nDialogue: 0,0:25:24.75,0:25:27.64,yin,,0,0,0,, 我应该有时间把它做完 \\N{\\fs12}I think I have enough time to do it all. \r\nDialogue: 0,0:25:27.64,0:25:32.73,yin,,0,0,0,, 讲稿在这里 确保我没忘记什么 \\N{\\fs12}Notes here, make sure, in case I forget something. \r\nDialogue: 0,0:25:32.73,0:25:34.87,yin,,0,0,0,, 我们打算做什么呢 \\N{\\fs12}Okay. So what are we going to do? \r\nDialogue: 0,0:25:34.87,0:25:38.15,yin,,0,0,0,, 我们将从之前做到的地方开始考虑 Photomania\\N{\\fs12}We are going to start with photo mania where we left off, \r\nDialogue: 0,0:25:38.15,0:25:43.10,yin,,0,0,0,, 这是之前我们已有的 Photomania\\N{\\fs12}so here's the exact photo mania we had before. \r\nDialogue: 0,0:25:43.10,0:25:47.10,yin,,0,0,0,, 这次 我们打算在 iPhone 故事板中工作 \\N{\\fs12}Where we left off. This time we're going to work in this iPhone, \r\nDialogue: 0,0:25:47.10,0:25:50.52,yin,,0,0,0,, 然后复制到 iPad 故事板 \\N{\\fs12}in the iPhone storyboard and then we'll copy it over to the iPad storyboard, \r\nDialogue: 0,0:25:50.52,0:25:52.86,yin,,0,0,0,, 我们可以说是在两者之间来回切换 \\N{\\fs12}so we're kind of going back and forth working on each one. \r\nDialogue: 0,0:25:52.86,0:25:55.42,yin,,0,0,0,, 今天我们打算考虑 iPhone 版 \\N{\\fs12}Today we're going to go work on the iPhone one. \r\nDialogue: 0,0:25:55.42,0:25:56.64,yin,,0,0,0,, 怎么做呢 \\N{\\fs12}So, what are we going to do here? \r\nDialogue: 0,0:25:56.64,0:25:58.54,yin,,0,0,0,, 但愿你们认识这个 \\N{\\fs12}So this, hopefully you recognize this. \r\nDialogue: 0,0:25:58.54,0:26:02.07,yin,,0,0,0,, 这是我们的故事板 这里有一系列拍照者 \\N{\\fs12}Right? This is our storyboard, this is a bunch of photographers. \r\nDialogue: 0,0:26:02.07,0:26:04.16,yin,,0,0,0,, 点击一个拍照者 我们得到该拍照者 \\N{\\fs12}We click on a photographer, we get all the photos \r\nDialogue: 0,0:26:04.16,0:26:06.68,yin,,0,0,0,, 拍的所有照片 现在是在一个表格中 \\N{\\fs12}by that photographer currently in a table. \r\nDialogue: 0,0:26:06.68,0:26:11.03,yin,,0,0,0,, 这里我要创建的 UI 几乎完全相同 \\N{\\fs12}So what I'm going to build is same UI here, almost exactly, \r\nDialogue: 0,0:26:11.03,0:26:13.23,yin,,0,0,0,, 只是这里不再是照片的表格 \\N{\\fs12}except for that instead of a table of the photos, \r\nDialogue: 0,0:26:13.23,0:26:15.87,yin,,0,0,0,, 而是照片的地图 \\N{\\fs12}I'm going to put a map of the photos up. \r\nDialogue: 0,0:26:15.87,0:26:18.74,yin,,0,0,0,, 对于拍照者的每张照片将有一个大头针 \\N{\\fs12}With a pin for every photo by that photographer. \r\nDialogue: 0,0:26:18.74,0:26:22.23,yin,,0,0,0,, 我需要一个 PhotosByPhotographer 地图视图控制器 \\N{\\fs12}So I'm going to need a photos by photographer map view controller,\r\nDialogue: 0,0:26:22.24,0:26:24.04,yin,,0,0,0,, 而不是一个 PhotosByPhotographer\\N{\\fs12}instead of a photos by photographer \r\nDialogue: 0,0:26:24.04,0:26:25.59,yin,,0,0,0,,Core Data 表格视图控制器 \\N{\\fs12}core data table view controller. \r\nDialogue: 0,0:26:25.59,0:26:28.30,yin,,0,0,0,, 这些还是需要从 Core Data 中取出 \\N{\\fs12}Okay, I'm still going to pull all of this out of core data and everything, \r\nDialogue: 0,0:26:28.30,0:26:30.11,yin,,0,0,0,, 不过我们将不使用表格视图 \\N{\\fs12}but we're not going to be doing a table view. \r\nDialogue: 0,0:26:30.11,0:26:32.94,yin,,0,0,0,, 我要做什么能理解吗 \\N{\\fs12}Does that make sense? What I'm going to do? \r\nDialogue: 0,0:26:32.94,0:26:37.44,yin,,0,0,0,, 好 我们下面来拖动创建那个视图控制器 \\N{\\fs12}Alright, so let's go ahead and drag, create that view controller. \r\nDialogue: 0,0:26:37.44,0:26:40.13,yin,,0,0,0,, 地图视图控制器也是视图控制器 \\N{\\fs12}So a map view controller is just a view controller, \r\nDialogue: 0,0:26:40.13,0:26:41.68,yin,,0,0,0,, 我将拖出一个视图控制器 \\N{\\fs12}so I'm drag out a view controller here. \r\nDialogue: 0,0:26:41.68,0:26:45.40,yin,,0,0,0,, 放在这下面 因为它将替换上面这个 \\N{\\fs12}We'll put it under here because it's going to be replacing this guy right here, \r\nDialogue: 0,0:26:45.40,0:26:48.02,yin,,0,0,0,, 也就是表格视图控制器 \\N{\\fs12}which is the table view controller of it. \r\nDialogue: 0,0:26:48.02,0:26:50.97,yin,,0,0,0,, 同任何视图控制器一样 这需要一个类 \\N{\\fs12}Now, as with any view controller, I need a class \r\nDialogue: 0,0:26:50.97,0:26:54.25,yin,,0,0,0,, 现在这是 UIViewController\\N{\\fs12}for this, right now it's, you know, UI view controller, \r\nDialogue: 0,0:26:54.25,0:26:57.16,yin,,0,0,0,, 我需要一个自定义子类 让我来创建一个 \\N{\\fs12}so I need a custom subclass, let's go create that. \r\nDialogue: 0,0:26:57.16,0:27:02.41,yin,,0,0,0,, 这个自定义子类将是一个常规的 UIViewController\\N{\\fs12}And that custom subclass is going to be a regular, old UI view controller. \r\nDialogue: 0,0:27:03.05,0:27:05.97,yin,,0,0,0,,UIViewController\\N{\\fs12}UI view, view controller, \r\nDialogue: 0,0:27:05.97,0:27:08.90,yin,,0,0,0,, 和前面一致 我打算称其为 \\N{\\fs12}and I'm going to call it, to be consistent, \r\nDialogue: 0,0:27:08.90,0:27:14.22,yin,,0,0,0,,PhotosByPhotographerMapViewController\\N{\\fs12}photos by photographer map view controller. \r\nDialogue: 0,0:27:14.22,0:27:16.72,yin,,0,0,0,, 名字显得有点长 \\N{\\fs12}They're getting to be pretty long names here, but, \r\nDialogue: 0,0:27:16.72,0:27:20.71,yin,,0,0,0,, 我也可以称它为 MapMVC 不过这会有些奇怪 \\N{\\fs12}I could call it map MVC, but that's kind of weird. \r\nDialogue: 0,0:27:20.71,0:27:22.07,yin,,0,0,0,, 这里就写 MapViewController 吧 \\N{\\fs12}So we'll call it map view controller, alright? \r\nDialogue: 0,0:27:22.07,0:27:25.22,yin,,0,0,0,,PhotosByPhotographerMapViewController\\N{\\fs12}So photos by photographer map view controller, we'll put it \r\nDialogue: 0,0:27:25.22,0:27:29.57,yin,,0,0,0,, 和其它控制器放到一起 这里 \\N{\\fs12}where we put everything, we'll put it in with our controllers, right there. \r\nDialogue: 0,0:27:29.57,0:27:31.00,yin,,0,0,0,, 我们得到这个 \\N{\\fs12}We got that. \r\nDialogue: 0,0:27:31.00,0:27:36.34,yin,,0,0,0,, 在故事板中 让我们把这个设为地图视图控制器 \\N{\\fs12}In our storyboard, let's go ahead and set this thing to be a map view controller. \r\nDialogue: 0,0:27:36.34,0:27:39.22,yin,,0,0,0,, 这里 PhotosByPhotographerMapViewController\\N{\\fs12}Here it is, photos by photographer map view controller. \r\nDialogue: 0,0:27:39.22,0:27:42.31,yin,,0,0,0,, 让我们为这个创建 UI\\N{\\fs12}Let's build a UI for this thing. \r\nDialogue: 0,0:27:42.31,0:27:43.79,yin,,0,0,0,, 在这之前 \\N{\\fs12}Actually, before we do that,\r\nDialogue: 0,0:27:43.79,0:27:47.65,yin,,0,0,0,, 我总喜欢为新类写公共 API\\N{\\fs12}I always like to do my public API for any new class. \r\nDialogue: 0,0:27:47.65,0:27:51.17,yin,,0,0,0,, 这个类的公共 API 同 PhotosByPhotographer\\N{\\fs12}The public API for this class is exactly the same as the public API \r\nDialogue: 0,0:27:51.17,0:27:54.48,yin,,0,0,0,,Core Data 表格视图控制器的公共 API 相同 \\N{\\fs12}for the photos by photographer core data table view controller. \r\nDialogue: 0,0:27:54.48,0:27:59.16,yin,,0,0,0,, 这里我们其实只是复制粘贴 \\N{\\fs12}In fact, we just copy and paste it here to this thing. \r\nDialogue: 0,0:28:01.49,0:28:03.95,yin,,0,0,0,, 当然 这里我们需要导入 \\N{\\fs12}And of course we need to be import here. \r\nDialogue: 0,0:28:05.64,0:28:07.33,yin,,0,0,0,, 和原来一样 \\N{\\fs12}So it's the same thing. \r\nDialogue: 0,0:28:07.33,0:28:10.10,yin,,0,0,0,, 你在地图视图控制器中设置这个拍照者 \\N{\\fs12}You set this photographer in our map view controller, \r\nDialogue: 0,0:28:10.10,0:28:13.13,yin,,0,0,0,, 这里拍照者的照片不再显示在表格中 \\N{\\fs12}and instead of showing the photos by that photographer \r\nDialogue: 0,0:28:13.13,0:28:15.20,yin,,0,0,0,, 而会显示在地图视图中 \\N{\\fs12}in a table, it's going to put them in a map view. \r\nDialogue: 0,0:28:15.20,0:28:19.49,yin,,0,0,0,, 回到我们的故事板 创建这个的 UI\\N{\\fs12}So let's go back to our storyboard and build the UI for this thing. \r\nDialogue: 0,0:28:19.49,0:28:22.56,yin,,0,0,0,, 这里腾出更多空间 \\N{\\fs12}And so, let's make a lot more space here. \r\nDialogue: 0,0:28:22.56,0:28:24.63,yin,,0,0,0,, 像这样 \\N{\\fs12}And go like this. \r\nDialogue: 0,0:28:24.63,0:28:27.32,yin,,0,0,0,, 把辅助编辑器弄出来 \\N{\\fs12}Get our assistant editor up here. \r\nDialogue: 0,0:28:27.34,0:28:29.62,yin,,0,0,0,, 进入自动模式 \\N{\\fs12}Let's go to automatic mode. \r\nDialogue: 0,0:28:29.62,0:28:30.59,yin,,0,0,0,, 到这里 \\N{\\fs12}Go here. \r\nDialogue: 0,0:28:30.59,0:28:35.83,yin,,0,0,0,, 这是 PhotosByPhotographerMapViewController 的代码 \\N{\\fs12}So, here is the code for our map photos by photographer map view controller, \r\nDialogue: 0,0:28:35.83,0:28:38.38,yin,,0,0,0,, 这些都不需要 \\N{\\fs12}we don't need any of this business. \r\nDialogue: 0,0:28:38.38,0:28:40.10,yin,,0,0,0,, 删除掉 \\N{\\fs12}Clear that out. \r\nDialogue: 0,0:28:40.10,0:28:42.13,yin,,0,0,0,, 我们需要一个地图视图 \\N{\\fs12}We're going to need a map view, so let's go ahead \r\nDialogue: 0,0:28:42.13,0:28:45.68,yin,,0,0,0,, 下面抓取地图视图 它和文本视图这些很像 \\N{\\fs12}and grab a map view, that is just a view like text view \r\nDialogue: 0,0:28:45.68,0:28:47.81,yin,,0,0,0,, 这里 这是地图视图 \\N{\\fs12}or any other view, here it is right here, map view. \r\nDialogue: 0,0:28:47.81,0:28:51.27,yin,,0,0,0,, 拖出来放到这里 \\N{\\fs12}So I'm going to drag that out, put this in here. \r\nDialogue: 0,0:28:51.27,0:28:56.72,yin,,0,0,0,, 这里我要考虑约束 点重置到建议约束 \\N{\\fs12}Maybe I want to do its constraints, so reset to suggested constraints. \r\nDialogue: 0,0:28:56.72,0:28:58.06,yin,,0,0,0,, 看看这些 \\N{\\fs12}Let's go take a look at those \r\nDialogue: 0,0:28:58.06,0:28:59.45,yin,,0,0,0,, 确保这里都很合理 \\N{\\fs12}and make sure it did something sensible. \r\nDialogue: 0,0:28:59.45,0:29:02.33,yin,,0,0,0,, 看起来很合理 它会匹配大小 \\N{\\fs12}Oh. Yep, looks very sensible, so it's going to stick to the size, \r\nDialogue: 0,0:29:02.33,0:29:05.78,yin,,0,0,0,, 无论 self.view 的大小是多少 它都会紧随它 \\N{\\fs12}so whatever size our self dot view is it's going to stick to it. \r\nDialogue: 0,0:29:05.78,0:29:08.22,yin,,0,0,0,, 我们再为这个地图视图创建一个 outlet\\N{\\fs12}Let's create an outlet for this map view. \r\nDialogue: 0,0:29:08.22,0:29:11.54,yin,,0,0,0,,control 拖动 起名为 mapView\\N{\\fs12}So I'm just control, dragging, I'll call it map view. \r\nDialogue: 0,0:29:11.54,0:29:14.42,yin,,0,0,0,, 这里于是得到了一个 outlet\\N{\\fs12}Alright? So we got an outlet there. \r\nDialogue: 0,0:29:14.42,0:29:19.78,yin,,0,0,0,, 注意到这里有错误和警告 \\N{\\fs12}Notice that we have this error and warning here. \r\nDialogue: 0,0:29:19.78,0:29:20.98,yin,,0,0,0,, 问题在哪 \\N{\\fs12}What's the problem? \r\nDialogue: 0,0:29:20.98,0:29:24.03,yin,,0,0,0,, 问题在于 我们需要导入 MKMapView\\N{\\fs12}The problem is we have to import MK map view. \r\nDialogue: 0,0:29:24.03,0:29:25.30,yin,,0,0,0,, 让我们这样做 \\N{\\fs12}So let's do that. \r\nDialogue: 0,0:29:25.30,0:29:28.78,yin,,0,0,0,,import \\N{\\fs12}Import map kit slash map kit. \r\nDialogue: 0,0:29:28.78,0:29:32.44,yin,,0,0,0,, 我说过 MapKit 的导入和之前我们做的不一样 \\N{\\fs12}Now, I told you that map kit, it's not enough just to import map kit like you did \r\nDialogue: 0,0:29:32.44,0:29:34.17,yin,,0,0,0,, 不能只是导入 MapKit\\N{\\fs12}for everything else we've done so far. \r\nDialogue: 0,0:29:34.17,0:29:38.38,yin,,0,0,0,, 我们需要到上面这里进行项目设置 \\N{\\fs12}We have to go to our project settings, over here, at the top, \r\nDialogue: 0,0:29:38.38,0:29:40.81,yin,,0,0,0,, 在上面的项目设置中 \\N{\\fs12}and in our project settings, along the top, you're going \r\nDialogue: 0,0:29:40.81,0:29:43.33,yin,,0,0,0,, 你会看到这里的创建阶段 \\N{\\fs12}to see this thing here called build phases. \r\nDialogue: 0,0:29:43.33,0:29:46.90,yin,,0,0,0,, 创建阶段指定了我们要关联的框架 \\N{\\fs12}And the build phases specifies what frameworks we link with. \r\nDialogue: 0,0:29:46.90,0:29:48.95,yin,,0,0,0,, 关联二进制文件和库 \\N{\\fs12}Link binary with libraries. \r\nDialogue: 0,0:29:48.95,0:29:51.09,yin,,0,0,0,, 不要忘记这一部分 否则在运行 app 时 \\N{\\fs12}So don't forget this part or when you run your app it's going \r\nDialogue: 0,0:29:51.09,0:29:53.97,yin,,0,0,0,, 它会说 没有这个类 MKMapView\\N{\\fs12}to say oh, no such class, MK map view. \r\nDialogue: 0,0:29:53.97,0:29:55.53,yin,,0,0,0,, 我们点加号 \\N{\\fs12}Alright? So we're just going to hit plus. \r\nDialogue: 0,0:29:55.53,0:29:56.58,yin,,0,0,0,, 你会看到 \\N{\\fs12}Now when you do that you're going to see \r\nDialogue: 0,0:29:56.58,0:30:02.16,yin,,0,0,0,,iOS7 有很多库和框架可供选择 \\N{\\fs12}that iOS 7 has a lot of libraries and frameworks that you can pick from here. \r\nDialogue: 0,0:30:02.16,0:30:03.98,yin,,0,0,0,, 幸运的是 它支持搜索 \\N{\\fs12}And luckily it lets you search them, \r\nDialogue: 0,0:30:03.98,0:30:06.26,yin,,0,0,0,, 我键入 map 这就得到了 MapKit\\N{\\fs12}so I'm just going to type map, and here I get map kit. \r\nDialogue: 0,0:30:06.26,0:30:10.30,yin,,0,0,0,, 这就包含了 MapKit 将它关联到我的应用 \\N{\\fs12}So now I've included map kit, I'm linking it in with my application so \r\nDialogue: 0,0:30:10.31,0:30:11.92,yin,,0,0,0,, 这就行了 \\N{\\fs12}it'll work. \r\nDialogue: 0,0:30:13.08,0:30:15.82,yin,,0,0,0,, 我们有了这个地图视图 \\N{\\fs12}Alright, so we've got this map view. \r\nDialogue: 0,0:30:15.82,0:30:19.70,yin,,0,0,0,, 这之后我就立刻需要将我自己设置为 \\N{\\fs12}One thing I want to do right off the bat is set myself \r\nDialogue: 0,0:30:19.70,0:30:21.81,yin,,0,0,0,, 这个地图视图的委托 \\N{\\fs12}to be this map view's delegate. \r\nDialogue: 0,0:30:21.81,0:30:24.35,yin,,0,0,0,, 因为我要使用所有这些地图视图委托方法 \\N{\\fs12}Because I'm going to use all those map view delegate methods \r\nDialogue: 0,0:30:24.35,0:30:26.42,yin,,0,0,0,, 我在幻灯片中讲过 \\N{\\fs12}we talked about in the slides. \r\nDialogue: 0,0:30:26.42,0:30:27.71,yin,,0,0,0,, 这里我有这个 \\N{\\fs12}So, I have this here. \r\nDialogue: 0,0:30:27.71,0:30:29.73,yin,,0,0,0,, 这是地图视图的 setter\\N{\\fs12}So this is the setter for map view \r\nDialogue: 0,0:30:29.73,0:30:31.85,yin,,0,0,0,, 我这里键入 _mapView = mapView\\N{\\fs12}and I'm just hitting underbar map view is map view, \r\nDialogue: 0,0:30:31.85,0:30:34.38,yin,,0,0,0,, 然后这里将地图视图委托设为 self\\N{\\fs12}and here I'm setting the map views delegate to be myself, \r\nDialogue: 0,0:30:34.38,0:30:36.21,yin,,0,0,0,, 这里它在警告我 \\N{\\fs12}of course it's warning me, because I have \r\nDialogue: 0,0:30:36.21,0:30:39.44,yin,,0,0,0,, 因为我需要实现 MKMapViewDelegate 下面就来做这个 \\N{\\fs12}to implement MK map view delegate, so I will do that. \r\nDialogue: 0,0:30:39.44,0:30:41.81,yin,,0,0,0,,MKMapViewDelegate\\N{\\fs12}MK map view delegate, \r\nDialogue: 0,0:30:41.81,0:30:43.73,yin,,0,0,0,, 现在 警告没有了 \\N{\\fs12}and now the warning goes away \r\nDialogue: 0,0:30:43.73,0:30:48.13,yin,,0,0,0,, 因为 MKMapViewDelegate 协议中没有必需方法 \\N{\\fs12}because there are no required methods in the MK map view delegate protocol. \r\nDialogue: 0,0:30:48.13,0:30:49.85,yin,,0,0,0,, 所有方法都是可选的 \\N{\\fs12}All of them are optional. \r\nDialogue: 0,0:30:51.10,0:30:54.14,yin,,0,0,0,, 这里我可能还要做一件事 \\N{\\fs12}Now, one other thing that I probably want \r\nDialogue: 0,0:30:54.14,0:30:58.02,yin,,0,0,0,, 在我有一个设置模型的公共 API 时 \\N{\\fs12}to do here is what I always want to do when I have a \r\nDialogue: 0,0:30:58.02,0:31:00.74,yin,,0,0,0,, 我总会做这件事 \\N{\\fs12}public API that kind of sets my model, \r\nDialogue: 0,0:31:00.74,0:31:03.02,yin,,0,0,0,, 也就是键入如下这样的代码 \\N{\\fs12}which is to do things \r\nDialogue: 0,0:31:03.02,0:31:07.87,yin,,0,0,0,,self.title = 拍照者的名字 这会很好 \\N{\\fs12}like self dot title equals the photographer's name, okay, that's a nice thing. \r\nDialogue: 0,0:31:07.87,0:31:13.36,yin,,0,0,0,, 而且这里 每次我设置拍照者时 \\N{\\fs12}And I also, here, every time I set that photographer, \r\nDialogue: 0,0:31:13.36,0:31:16.87,yin,,0,0,0,, 我都需要重置 PhotosByPhotographer\\N{\\fs12}I kind of need to reset the photos by photographer, right? \r\nDialogue: 0,0:31:16.87,0:31:19.39,yin,,0,0,0,, 因为这里要做的就是显示拍照者的照片 \\N{\\fs12}Because the whole point here is that I show the photos \r\nDialogue: 0,0:31:19.39,0:31:20.92,yin,,0,0,0,, 如果拍照者发生变化 \\N{\\fs12}by photographer, if you change the photographer, \r\nDialogue: 0,0:31:20.92,0:31:22.48,yin,,0,0,0,, 照片也需要发生变化 \\N{\\fs12}I need to change those photos. \r\nDialogue: 0,0:31:22.48,0:31:25.00,yin,,0,0,0,, 要做 PhotosByPhotographer 这些 \\N{\\fs12}So, to do the photos by photographer thing, \r\nDialogue: 0,0:31:25.00,0:31:31.17,yin,,0,0,0,, 我需要创建一个新属性 \\N{\\fs12}I am going to create a new property. \r\nDialogue: 0,0:31:31.17,0:31:34.23,yin,,0,0,0,, 名为 photosByPhotographer 加入这个 \\N{\\fs12}Called photos by photographer, so let's add that, \r\nDialogue: 0,0:31:34.23,0:31:39.20,yin,,0,0,0,, 属性 非原子 强 这就是一个 NSArray\\N{\\fs12}property, nonatomic strong, it's just going to be an NS array, \r\nDialogue: 0,0:31:39.20,0:31:45.74,yin,,0,0,0,,NSArray *photosByPhotographer\\N{\\fs12}NS array, start photos by photographer. \r\nDialogue: 0,0:31:48.19,0:31:52.01,yin,,0,0,0,, 这将是照片对象的 \\N{\\fs12}Okay, and this is going to be of photo objects. \r\nDialogue: 0,0:31:52.01,0:31:54.75,yin,,0,0,0,, 这里再导入 Photo\\N{\\fs12}So let's go ahead and import photo here too. \r\nDialogue: 0,0:31:54.75,0:31:56.29,yin,,0,0,0,, 我们需要这个 \\N{\\fs12}We're going to need that. \r\nDialogue: 0,0:31:56.29,0:31:59.58,yin,,0,0,0,, 这里是 photosByPhotographer 的 getter\\N{\\fs12}Okay, and, here's the getter for photos by photographer. \r\nDialogue: 0,0:31:59.58,0:32:00.97,yin,,0,0,0,, 很简单 \\N{\\fs12}Very, very simple, alright? \r\nDialogue: 0,0:32:00.97,0:32:03.33,yin,,0,0,0,, 这是 getter 因此我只需要说 \\N{\\fs12}It's the getter, so I'm just saying if the photographer, \r\nDialogue: 0,0:32:03.33,0:32:05.25,yin,,0,0,0,, 如果 photosByPhotographer 还没设置 \\N{\\fs12}photos by photographer is not set yet, \r\nDialogue: 0,0:32:05.25,0:32:07.61,yin,,0,0,0,, 那我就将从数据库中取回它们 \\N{\\fs12}then I'm going to go fetch them from the database. \r\nDialogue: 0,0:32:07.61,0:32:10.67,yin,,0,0,0,, 我于是创建一个取回请求 用于照片 \\N{\\fs12}So I create a fetch request, it's for photos. \r\nDialogue: 0,0:32:10.67,0:32:14.78,yin,,0,0,0,, 我创建了一个谓词 whoTook = self.photographer\\N{\\fs12}I create a predicate, who took equals self dot photographer, \r\nDialogue: 0,0:32:14.78,0:32:16.75,yin,,0,0,0,, 而这里 在表格视图中 \\N{\\fs12}and here, we're in the table view, \r\nDialogue: 0,0:32:16.75,0:32:18.44,yin,,0,0,0,, 我设置了取回结果控制器 \\N{\\fs12}I set the fetch results controller, \r\nDialogue: 0,0:32:18.44,0:32:22.13,yin,,0,0,0,, 这里我打算在 context 中执行取回请求 \\N{\\fs12}here I'm actually going to execute the fetch request in the context. \r\nDialogue: 0,0:32:22.13,0:32:26.30,yin,,0,0,0,, 这会返回一个数组 也就是这里我要存储的数组 \\N{\\fs12}And that returns an array, which is this array that I'm going to store right here, \r\nDialogue: 0,0:32:26.31,0:32:28.50,yin,,0,0,0,, 然后我们返回它 \\N{\\fs12}and then we'll return it. \r\nDialogue: 0,0:32:28.50,0:32:30.41,yin,,0,0,0,, 每次设置拍照者时 \\N{\\fs12}Now every time we set the photographer, \r\nDialogue: 0,0:32:30.41,0:32:34.85,yin,,0,0,0,, 我都要将这个重置为 nil\\N{\\fs12}I better reset this thing to nil. \r\nDialogue: 0,0:32:34.85,0:32:38.50,yin,,0,0,0,, 当有人想要时 它会惰性地进行这个取回 \\N{\\fs12}It's going to lazily do this fetch whenever someone actually wants it, \r\nDialogue: 0,0:32:38.50,0:32:40.88,yin,,0,0,0,, 但每次拍照者变化时 我需要将其设为 nil\\N{\\fs12}but I better set it to nil every time the photographer changes, \r\nDialogue: 0,0:32:40.88,0:32:44.61,yin,,0,0,0,, 否则它就不会进行这个惰性实例化 \\N{\\fs12}otherwise it's not going to do this lazy instantiation. \r\nDialogue: 0,0:32:44.61,0:32:47.61,yin,,0,0,0,, 这个惰性实例化很棒 因为这是 Core Data 取回 \\N{\\fs12}This lazy instantiation is nice because this is core data fetch, \r\nDialogue: 0,0:32:47.61,0:32:48.71,yin,,0,0,0,, 但它还在工作 \\N{\\fs12}but it's still work, \r\nDialogue: 0,0:32:48.72,0:32:51.92,yin,,0,0,0,, 在有人想要这些 photosByPhotographer 机制之前 \\N{\\fs12}and I don't want to do this work until someone actually wants those photos by \r\nDialogue: 0,0:32:51.92,0:32:54.90,yin,,0,0,0,, 我并不想要它在那工作 \\N{\\fs12}the photographer mechanism. \r\nDialogue: 0,0:32:54.90,0:32:56.91,yin,,0,0,0,, 好 我们还需要做一件事 \\N{\\fs12}Alright. So the other thing we need to do is, \r\nDialogue: 0,0:32:56.91,0:32:59.51,yin,,0,0,0,, 当地图视图被设置 或当模型被设置时 \\N{\\fs12}when our map view is set or when our model is set, \r\nDialogue: 0,0:32:59.51,0:33:01.93,yin,,0,0,0,, 我们需要更新 annotation\\N{\\fs12}we need to update the annotations. \r\nDialogue: 0,0:33:01.93,0:33:03.61,yin,,0,0,0,, 地图上有很多 annotation\\N{\\fs12}We've got all those annotations on the map \r\nDialogue: 0,0:33:03.61,0:33:05.52,yin,,0,0,0,, 这将是 PhotosByPhotographer\\N{\\fs12}that are going to be the photos by photographer, \r\nDialogue: 0,0:33:05.52,0:33:06.70,yin,,0,0,0,, 我们需要更新这些 \\N{\\fs12}so we got to update those. \r\nDialogue: 0,0:33:06.70,0:33:08.89,yin,,0,0,0,, 我们这里将有一个方法叫 \\N{\\fs12}So we're going to have a method here called update \r\nDialogue: 0,0:33:08.90,0:33:14.13,yin,,0,0,0,,updateMapViewAnnotations\\N{\\fs12}map view annotations. \r\nDialogue: 0,0:33:14.13,0:33:21.06,yin,,0,0,0,, 这里设置地图视图时需要调用它 \\N{\\fs12}And we're going to have call this both from here, when we set the map view, \r\nDialogue: 0,0:33:21.06,0:33:26.20,yin,,0,0,0,, 这里设置模型时也需要调用它 \\N{\\fs12}and also from here, when we \r\nDialogue: 0,0:33:26.20,0:33:28.58,yin,,0,0,0,, 因为我们不知道发生顺序是怎样的 \\N{\\fs12}set our model. Because we don't know what order this is going to happen. \r\nDialogue: 0,0:33:28.58,0:33:31.59,yin,,0,0,0,, 我们不知道是模型在地图视图之前设置 \\N{\\fs12}We don't know if our model is set before our map view \r\nDialogue: 0,0:33:31.59,0:33:34.15,yin,,0,0,0,, 还是地图视图在模型之前设置 \\N{\\fs12}or if our map view is set before our model. \r\nDialogue: 0,0:33:34.15,0:33:35.29,yin,,0,0,0,, 无论哪种顺序 \\N{\\fs12}Either way, this \r\nDialogue: 0,0:33:35.29,0:33:38.11,yin,,0,0,0,,updateMapViewAnnotations 都需要做正确的事 \\N{\\fs12}update map view annotations better do the right thing. \r\nDialogue: 0,0:33:39.07,0:33:41.45,yin,,0,0,0,, 这就是两处都要调用的原因 \\N{\\fs12}So that's why we're calling from both. \r\nDialogue: 0,0:33:41.45,0:33:44.50,yin,,0,0,0,, 如何实现这个 updateMapViewAnnotations 呢 \\N{\\fs12}So, how are we going to implement this update map view annotations? \r\nDialogue: 0,0:33:44.50,0:33:45.91,yin,,0,0,0,, 我其实讲过怎么做 \\N{\\fs12}Well, I told you what we're going to do, \r\nDialogue: 0,0:33:45.91,0:33:49.44,yin,,0,0,0,, 我们要将照片对象设为 MKAnnotation\\N{\\fs12}we're going to make a photo object be an MK annotation \r\nDialogue: 0,0:33:49.44,0:33:52.79,yin,,0,0,0,, 因此我们在更新地图视图 annotation 时 \\N{\\fs12}so that all we need to do to update that map view annotations \r\nDialogue: 0,0:33:52.79,0:33:56.01,yin,,0,0,0,, 只需要将照片加到地图 \\N{\\fs12}is add the photos to the map. \r\nDialogue: 0,0:33:56.01,0:34:01.34,yin,,0,0,0,, 如何将照片转化为 id MKAnnotation 呢 \\N{\\fs12}So how are we going to turn photo into an id MK annotation? \r\nDialogue: 0,0:34:01.34,0:34:04.47,yin,,0,0,0,, 答案是 我们需要做两件事 \\N{\\fs12}And the answer is two-fold. There's two things we need to do. \r\nDialogue: 0,0:34:04.47,0:34:08.65,yin,,0,0,0,, 一是 我们需要修正我们的 Core Data 数据库 \\N{\\fs12}One thing, we need to fix our model, or our, you know, core data database, \r\nDialogue: 0,0:34:08.65,0:34:10.69,yin,,0,0,0,, 来得到经纬度 \\N{\\fs12}to have the latitude and longitude, \r\nDialogue: 0,0:34:10.69,0:34:14.48,yin,,0,0,0,, 显然 不知道照片在哪就无法显示在某个地方 \\N{\\fs12}otherwise, if we don't where the photo is, we obviously can't show it on there. \r\nDialogue: 0,0:34:14.48,0:34:17.27,yin,,0,0,0,, 因此 我要添加纬度 \\N{\\fs12}Right? So, I'm going to add latitude, \r\nDialogue: 0,0:34:17.27,0:34:20.79,yin,,0,0,0,, 很幸运 Flickr 会提供这个信息 经度 \\N{\\fs12}luckily Flickr provides this information, longitude, \r\nDialogue: 0,0:34:20.79,0:34:23.80,yin,,0,0,0,, 在这里 我还可以添加缩略图 URL\\N{\\fs12}and while I'm here I'm also going to add thumb nail URL, \r\nDialogue: 0,0:34:23.82,0:34:26.11,yin,,0,0,0,, 等下我会讲 我们能用它做什么 \\N{\\fs12}and I'll show you what we can do with that in a moment too. \r\nDialogue: 0,0:34:26.11,0:34:28.92,yin,,0,0,0,, 缩略图 URL 是一个字符串 本来应该是 URL\\N{\\fs12}So a thumb nail URL is a string, it's actually a URL, \r\nDialogue: 0,0:34:28.92,0:34:30.45,yin,,0,0,0,, 不过我们只能存储字符串 \\N{\\fs12}but strings the best we can do. \r\nDialogue: 0,0:34:30.45,0:34:36.03,yin,,0,0,0,, 而经纬度都是双精度浮点数 \\N{\\fs12}Whereas the latitude and longitude are doubles. Double precision float point numbers. \r\nDialogue: 0,0:34:36.03,0:34:38.63,yin,,0,0,0,, 我把这个加到我的数据库 \\N{\\fs12}So I'm just adding this to my database. \r\nDialogue: 0,0:34:38.64,0:34:39.76,yin,,0,0,0,, 到上面这里 \\N{\\fs12}I'm going to go up here \r\nDialogue: 0,0:34:39.76,0:34:42.88,yin,,0,0,0,, 为 Photomania 创建 ManagedObject 子类 \\N{\\fs12}and create my managed object subclasses for photo mania, \r\nDialogue: 0,0:34:42.88,0:34:46.78,yin,,0,0,0,, 我只改变了照片 那么这里就只重新生成照片 \\N{\\fs12}I only change photo, so let's just only regenerate photo. \r\nDialogue: 0,0:34:46.78,0:34:49.64,yin,,0,0,0,, 这个还是放到老地方 \\N{\\fs12}We'll put this, same place, as we usually do, \r\nDialogue: 0,0:34:49.64,0:34:52.50,yin,,0,0,0,, 它问我想不想替换 我当然想 \\N{\\fs12}it's asking if I want to replace the other ones, of course I do, \r\nDialogue: 0,0:34:52.50,0:34:56.63,yin,,0,0,0,, 现在 我的照片就有了经纬度 \\N{\\fs12}and now our photo has a latitude and longitude. \r\nDialogue: 0,0:34:56.63,0:34:59.03,yin,,0,0,0,, 注意 这里是 NSNumber\\N{\\fs12}Notice these are NS numbers here, \r\nDialogue: 0,0:34:59.03,0:35:01.70,yin,,0,0,0,, 因为数据库中的一切都是对象 \\N{\\fs12}because everything in the database is an object. \r\nDialogue: 0,0:35:01.70,0:35:04.34,yin,,0,0,0,, 当然 我们需要更新 Flickr 加载器 \\N{\\fs12}Of course we need to update Flickr's loader, \r\nDialogue: 0,0:35:04.34,0:35:06.48,yin,,0,0,0,, 我们的 Photo+Flickr category\\N{\\fs12}our photo plus Flickr category, \r\nDialogue: 0,0:35:06.48,0:35:09.12,yin,,0,0,0,, 这是加载所有这些东西用的 \\N{\\fs12}right, which does the loading of all this stuff, \r\nDialogue: 0,0:35:09.12,0:35:13.12,yin,,0,0,0,, 加载纬度 这里有个东西用于这个 \\N{\\fs12}to load up the latitude, here I have a thing for that, \r\nDialogue: 0,0:35:13.12,0:35:15.77,yin,,0,0,0,, 这是纬度被加载 这里是经度 \\N{\\fs12}so here's the latitude being loaded up, here's the longitude. \r\nDialogue: 0,0:35:15.77,0:35:19.21,yin,,0,0,0,, 它会到照片字典去找经纬度 \\N{\\fs12}It's just looking at the photo dictionary for the latitude and longitude. \r\nDialogue: 0,0:35:19.21,0:35:22.39,yin,,0,0,0,, 我这里将双精度值转换为 NSNumber\\N{\\fs12}I actually take the double value and then turn it into an NS number \r\nDialogue: 0,0:35:22.39,0:35:25.46,yin,,0,0,0,, 以防这是一个字符串 \\N{\\fs12}just in case this is a string. \r\nDialogue: 0,0:35:25.46,0:35:28.14,yin,,0,0,0,, 因为字符串也实现 doubleValue\\N{\\fs12}Cause strings implement double value too, \r\nDialogue: 0,0:35:28.14,0:35:31.54,yin,,0,0,0,, 或是将自身解释为双精度值 这里我要双保险 \\N{\\fs12}or that'll interpret themselves as a double value, so I'm just going to be double safe. \r\nDialogue: 0,0:35:31.54,0:35:33.43,yin,,0,0,0,, 我不确定我能从 Flickr 得回什么 \\N{\\fs12}I'm not quite sure what I'm going to get back from Flickr, \r\nDialogue: 0,0:35:33.43,0:35:38.03,yin,,0,0,0,, 不知道 JSON 中是字符串还是数字 这里是为了保险 \\N{\\fs12}whether it's a string or a number in the JSON, so I'm just being safe there. \r\nDialogue: 0,0:35:38.03,0:35:39.70,yin,,0,0,0,, 然后这里的缩略图 URL\\N{\\fs12}And then here at the thumb nail URL, \r\nDialogue: 0,0:35:39.70,0:35:42.55,yin,,0,0,0,, 我抓取的是 FlickrPhotoFormatSquare\\N{\\fs12}I'm just grabbing the Flickr photo format square, \r\nDialogue: 0,0:35:42.55,0:35:46.09,yin,,0,0,0,, 你们在作业中处理缩略图时也是用的这个 \\N{\\fs12}which is what you're using for your thumb nail also in your homework. \r\nDialogue: 0,0:35:46.09,0:35:49.24,yin,,0,0,0,, 现在 我们的数据模型已经加载 \\N{\\fs12}So now we've got our data model being loaded \r\nDialogue: 0,0:35:49.24,0:35:53.35,yin,,0,0,0,, 这是来自 Flickr 的照片 信息已经够了 \\N{\\fs12}up with photos from Flickr that have enough information. \r\nDialogue: 0,0:35:53.35,0:35:57.38,yin,,0,0,0,, 然后我们要将照片设为 MKAnnotation 要做这个 \\N{\\fs12}Now we need to make photo be an MK annotation, and to do that, \r\nDialogue: 0,0:35:57.38,0:36:00.04,yin,,0,0,0,, 我需要加另外一个 category\\N{\\fs12}I'm going to add another category. \r\nDialogue: 0,0:36:00.04,0:36:02.55,yin,,0,0,0,, 我可以加入那个 Flickr category\\N{\\fs12}I could put in that Flickr category, \r\nDialogue: 0,0:36:02.55,0:36:05.92,yin,,0,0,0,, 但实现 MKAnnotation 的并不是一个 Flickr 的东西 \\N{\\fs12}but it's not really a Flickr thing that it implements MK annotation. \r\nDialogue: 0,0:36:05.92,0:36:10.08,yin,,0,0,0,, 因此 我要创建一个新的 category 叫 Annotation\\N{\\fs12}So I'm going to create a new category called the annotation category, \r\nDialogue: 0,0:36:10.08,0:36:11.93,yin,,0,0,0,, 在照片上 \\N{\\fs12}on photo. \r\nDialogue: 0,0:36:11.93,0:36:16.64,yin,,0,0,0,, 放到… 这仍然是模型的一部分 \\N{\\fs12}We'll put that, it's still part of our model. \r\nDialogue: 0,0:36:16.64,0:36:20.00,yin,,0,0,0,, 这是 Annotation 的接口 \\N{\\fs12}Here's the annotation interface. \r\nDialogue: 0,0:36:20.00,0:36:21.76,yin,,0,0,0,, 这个是空的 \\N{\\fs12}And, and this is, is empty.\r\nDialogue: 0,0:36:21.77,0:36:23.49,yin,,0,0,0,, 这里我要做什么呢 \\N{\\fs12}So, what am I going to do here? \r\nDialogue: 0,0:36:23.49,0:36:28.83,yin,,0,0,0,, 这里我要说 Photo 是一个 MKAnnotation\\N{\\fs12}Actually, all I'm going to do is say photo is an MK annotation. \r\nDialogue: 0,0:36:28.83,0:36:33.88,yin,,0,0,0,, 这里需要导入 MapKit\\N{\\fs12}And I'll have to import MapKit here. \r\nDialogue: 0,0:36:33.88,0:36:36.85,yin,,0,0,0,, 我说了 Photo 是一个 MKAnnotation\\N{\\fs12}So I've said that photo is an annotation. \r\nDialogue: 0,0:36:36.85,0:36:40.54,yin,,0,0,0,, 现在 我就能将照片放到照片视图中 \\N{\\fs12}Now I can put photos in that map view. \r\nDialogue: 0,0:36:40.54,0:36:43.89,yin,,0,0,0,, 不过看这里的实现 \\N{\\fs12}But if I look at the implementation over here, \r\nDialogue: 0,0:36:43.89,0:36:46.82,yin,,0,0,0,, 这里有一个警告 \\N{\\fs12}you're going to see that there's a warning. \r\nDialogue: 0,0:36:46.82,0:36:49.78,yin,,0,0,0,, 这个警告是什么 \\N{\\fs12}What do you think this warning is? \r\nDialogue: 0,0:36:49.78,0:36:50.74,yin,,0,0,0,, 没人知道吗 \\N{\\fs12}Nobody? \r\nDialogue: 0,0:36:52.63,0:36:53.89,yin,,0,0,0,, 当然 请讲 \\N{\\fs12}Surely, yes? \r\nDialogue: 0,0:36:55.03,0:36:56.49,yin,,0,0,0,, 对 缺少方法 \\N{\\fs12}Yes, missing methods. \r\nDialogue: 0,0:36:56.49,0:36:58.24,yin,,0,0,0,, 因为我说了 这里 \\N{\\fs12}Because I said, here, \r\nDialogue: 0,0:36:58.24,0:37:00.71,yin,,0,0,0,, 我实现了 MKAnnotation 协议 \\N{\\fs12}that I implement the MK annotation protocol, \r\nDialogue: 0,0:37:00.71,0:37:03.01,yin,,0,0,0,, 但我没有实现坐标这些东西 \\N{\\fs12}but I don't implement that coordinate thing, so if I click \r\nDialogue: 0,0:37:03.01,0:37:06.48,yin,,0,0,0,, 点这里 它告诉我 坐标属性需要定义 \\N{\\fs12}on this it says property coordinate has to be defined. \r\nDialogue: 0,0:37:06.48,0:37:10.15,yin,,0,0,0,, 下面我们就来实现坐标 \\N{\\fs12}So let's implement coordinate here. \r\nDialogue: 0,0:37:10.15,0:37:11.58,yin,,0,0,0,, 这很简单 \\N{\\fs12}It's really easy to do. \r\nDialogue: 0,0:37:11.58,0:37:13.98,yin,,0,0,0,, 我们只需要返回一个 CLLocation 坐标 \\N{\\fs12}We just have to return a CL location coordinate. \r\nDialogue: 0,0:37:13.98,0:37:18.40,yin,,0,0,0,, 我只需要获得经纬度双精度值就行了 \\N{\\fs12}I'm going to get it by just getting my latitude and longitude as double values. \r\nDialogue: 0,0:37:18.40,0:37:22.29,yin,,0,0,0,, 这些是 NSNumber 这些是双精度 \\N{\\fs12}Remember, these are NS numbers, these are doubles. \r\nDialogue: 0,0:37:22.29,0:37:24.34,yin,,0,0,0,, 这样警告就没了 \\N{\\fs12}So now I don't have that warning. \r\nDialogue: 0,0:37:24.34,0:37:28.07,yin,,0,0,0,, 现在照片就是 id 了 \\N{\\fs12}Now a photo is an ID angle bracket MK annotation, \r\nDialogue: 0,0:37:28.07,0:37:32.57,yin,,0,0,0,, 我于是可以把照片作为 MKAnnotation 放到地图视图中 \\N{\\fs12}and now I can just put a photo into a map view as an MK annotation. \r\nDialogue: 0,0:37:32.57,0:37:34.24,yin,,0,0,0,, 下面我们来做这个 \\N{\\fs12}So let's go back and do that. \r\nDialogue: 0,0:37:34.24,0:37:35.31,yin,,0,0,0,, 这是我的地图视图 \\N{\\fs12}There's my map view. \r\nDialogue: 0,0:37:35.31,0:37:37.62,yin,,0,0,0,, 这是 updateMapViewAnnotations 方法 \\N{\\fs12}Here's the update map view annotations. \r\nDialogue: 0,0:37:37.62,0:37:42.51,yin,,0,0,0,, 首先 我要删除所有已经存在的 annotation\\N{\\fs12}First, I'm going to remove all of our existing annotations. \r\nDialogue: 0,0:37:44.52,0:37:48.52,yin,,0,0,0,, 我要删除地图视图中已有的所有 annotation\\N{\\fs12}Okay, so I'm just removing all the annotations that are currently in the map view, \r\nDialogue: 0,0:37:48.52,0:37:52.85,yin,,0,0,0,, 然后 我要 addAnnotations\\N{\\fs12}and then I'm going to add annotations \r\nDialogue: 0,0:37:52.85,0:37:55.64,yin,,0,0,0,,self.photosByPhotographer\\N{\\fs12}self dot photos by photographer. \r\nDialogue: 0,0:37:55.64,0:37:57.75,yin,,0,0,0,, 这些都是 Photo *\\N{\\fs12}And I can, these are photo stars, \r\nDialogue: 0,0:37:57.75,0:38:00.62,yin,,0,0,0,, 不过也是 id \\N{\\fs12}but they're also ID angle bracket MK annotations. \r\nDialogue: 0,0:38:00.62,0:38:02.27,yin,,0,0,0,, 因此这里我可以调用它们 \\N{\\fs12}So I can call them here. \r\nDialogue: 0,0:38:02.27,0:38:06.54,yin,,0,0,0,, 查阅说明文档看 addAnnotations 你会看到 \\N{\\fs12}If we look at the documentation for add annotations, you'll see \r\nDialogue: 0,0:38:06.54,0:38:10.86,yin,,0,0,0,, 它取的是一个 MKAnnotation 的数组 照片就是这个 \\N{\\fs12}it takes an array of MK annotations, and a photo is that. \r\nDialogue: 0,0:38:10.86,0:38:15.57,yin,,0,0,0,, 我还要做一个很酷的事 我要放大地图 \\N{\\fs12}I'm going to do another cool thing, which is I'm going to zoom the map in \r\nDialogue: 0,0:38:15.58,0:38:19.23,yin,,0,0,0,, 显示这个拍照者的所有照片 \\N{\\fs12}to show all the photos by this photographer. \r\nDialogue: 0,0:38:19.23,0:38:22.27,yin,,0,0,0,, 我将以一种动画的方式来做这个 \\N{\\fs12}Now I'm doing this in an animated way, but that just, \r\nDialogue: 0,0:38:22.27,0:38:24.73,yin,,0,0,0,, 不过这并不是缩小然后放大回去 \\N{\\fs12}that's not really going to like zoom out and then zoom back \r\nDialogue: 0,0:38:24.73,0:38:28.40,yin,,0,0,0,, 像我之前所说的 而是咻地转到要去的位置 \\N{\\fs12}in like I was talking about, it's not going to zoom on over to where it is, \r\nDialogue: 0,0:38:28.40,0:38:29.58,yin,,0,0,0,, 这并不是很好的动画 \\N{\\fs12}so it's not great animation, \r\nDialogue: 0,0:38:29.58,0:38:33.57,yin,,0,0,0,, 你们要做的东西应该比这更好 \\N{\\fs12}you're probably going to want to do something much better than this. \r\nDialogue: 0,0:38:33.57,0:38:37.42,yin,,0,0,0,, 这就是我们需要做的 \\N{\\fs12}So that's really all we need to make this work. \r\nDialogue: 0,0:38:37.42,0:38:40.51,yin,,0,0,0,, 有一点 我确定你们学过 \\N{\\fs12}One thing, which you've I'm sure learned, \r\nDialogue: 0,0:38:40.51,0:38:44.30,yin,,0,0,0,, 也就是 我们改变了 Core Data 数据库模型 \\N{\\fs12}is that we've changed our core data base model, \r\nDialogue: 0,0:38:44.30,0:38:48.10,yin,,0,0,0,, 这样一来 已经在设备或是模拟器上运行的 Photomania\\N{\\fs12}so the photo mania that's already on my device or my simulator, \r\nDialogue: 0,0:38:48.10,0:38:49.58,yin,,0,0,0,, 就需要被删除 \\N{\\fs12}I'm going to want to delete that. \r\nDialogue: 0,0:38:49.58,0:38:52.63,yin,,0,0,0,, 因为现在它的数据库是不兼容的 \\N{\\fs12}Because its database is now incompatible. \r\nDialogue: 0,0:38:52.63,0:38:55.84,yin,,0,0,0,, 没有经纬度和缩略图 URL 在其中 \\N{\\fs12}It doesn't have latitude and longitude and thumb nail URL in there. \r\nDialogue: 0,0:38:55.84,0:38:59.11,yin,,0,0,0,, 我们运行一下这个 \\N{\\fs12}So let's go ahead and run this. \r\nDialogue: 0,0:38:59.11,0:39:05.13,yin,,0,0,0,, 但愿网络情况良好 我们能够获得 Flickr 信息 \\N{\\fs12}Hopefully our network is working and we can get stuff from Flickr. \r\nDialogue: 0,0:39:05.13,0:39:06.93,yin,,0,0,0,, 有了 我们得到了一些东西 \\N{\\fs12}There it is, we got some stuff. \r\nDialogue: 0,0:39:06.93,0:39:10.06,yin,,0,0,0,, 我们希望这里 当我们点击时 \\N{\\fs12}And now, what we'd like to have happen here is we click \r\nDialogue: 0,0:39:10.06,0:39:15.22,yin,,0,0,0,, 看到的不是表格视图 而是地图 \\N{\\fs12}and instead of a table view here, right, we'd like to see this map. \r\nDialogue: 0,0:39:15.22,0:39:17.85,yin,,0,0,0,, 如何做到这个 segue 呢 \\N{\\fs12}So how do we do that segue? \r\nDialogue: 0,0:39:17.86,0:39:20.07,yin,,0,0,0,, 这里我们有这个 iPhone 的东西 \\N{\\fs12}Alright, we have this iPhone thing here. \r\nDialogue: 0,0:39:20.07,0:39:22.50,yin,,0,0,0,, 这个地图视图的东西准备好了 \\N{\\fs12}We've got this nice map view thing ready to go, \r\nDialogue: 0,0:39:22.50,0:39:25.67,yin,,0,0,0,, 我们希望 segue 到它 这个到这里的 segue\\N{\\fs12}we want to segue to it, so this segue that goes here, \r\nDialogue: 0,0:39:25.67,0:39:28.44,yin,,0,0,0,, 我们希望它往下到这里 \\N{\\fs12}we want it to go down here. \r\nDialogue: 0,0:39:28.44,0:39:29.72,yin,,0,0,0,, 很简单 \\N{\\fs12}Really easy to do. \r\nDialogue: 0,0:39:29.72,0:39:33.99,yin,,0,0,0,, 我只需要把这些放到屏幕上 然后演示给你们 \\N{\\fs12}All we have to do is make sure it all fits on screen, so I can show it to you. \r\nDialogue: 0,0:39:33.99,0:39:34.57,yin,,0,0,0,, 好了 \\N{\\fs12}Here we go. \r\nDialogue: 0,0:39:34.57,0:39:36.84,yin,,0,0,0,, 我只需要通过 control 拖动 \\N{\\fs12}I'm just going to segue by control, dragging \r\nDialogue: 0,0:39:36.84,0:39:42.34,yin,,0,0,0,, 从拍照者表格视图中这一行 segue 到下面新的这个 \\N{\\fs12}from this row in the photographer's table view, down to our new one. \r\nDialogue: 0,0:39:42.34,0:39:44.21,yin,,0,0,0,, 这是 push 因为我们在导航控制器中 \\N{\\fs12}It's a push, because we're in the navigation controller, \r\nDialogue: 0,0:39:44.21,0:39:46.43,yin,,0,0,0,, 注意到 上面这个 segue 没了 \\N{\\fs12}and notice it took away this segue because I can only segue \r\nDialogue: 0,0:39:46.43,0:39:48.70,yin,,0,0,0,, 因为这一行只能 segue 到一个地方 \\N{\\fs12}from this row to one place, \r\nDialogue: 0,0:39:48.70,0:39:52.23,yin,,0,0,0,, 现在 我 segue 到的是下面的地图视图 \\N{\\fs12}and now I'm segueing to our map view down here. \r\nDialogue: 0,0:39:52.23,0:39:54.23,yin,,0,0,0,, 现在我们有了这个 segue\\N{\\fs12}So now we have this segue. \r\nDialogue: 0,0:39:54.23,0:39:58.26,yin,,0,0,0,, 那拍照者的 Core Data 表格视图控制器呢 \\N{\\fs12}Now what about photographers control, core data table view controller? \r\nDialogue: 0,0:39:58.26,0:40:00.91,yin,,0,0,0,, 它需要适当地为 segue 做准备 \\N{\\fs12}It has to prepare for segue properly, right? \r\nDialogue: 0,0:40:00.91,0:40:02.77,yin,,0,0,0,, 这里是 prepareForSegue\\N{\\fs12}So here's where it's prepare for segue \r\nDialogue: 0,0:40:02.78,0:40:04.30,yin,,0,0,0,, 对应 PhotosByPhotographer\\N{\\fs12}with the photos by photographer \r\nDialogue: 0,0:40:04.30,0:40:06.75,yin,,0,0,0,,Core Data 表格视图控制器 \\N{\\fs12}core data table view controller, so, \r\nDialogue: 0,0:40:06.75,0:40:13.25,yin,,0,0,0,, 这里我们要对地图视图控制做一样的事 \\N{\\fs12}we're going to do the same thing here with a map view controller. \r\nDialogue: 0,0:40:14.04,0:40:17.23,yin,,0,0,0,, 这里代码几乎完全一样 只是这里我用 \\N{\\fs12}So here, this is almost exactly the same code, it's just that I'm doing photos \r\nDialogue: 0,0:40:17.23,0:40:19.08,yin,,0,0,0,,PhotosByPhotographerMapViewController\\N{\\fs12}by photographer map view controller \r\nDialogue: 0,0:40:19.08,0:40:20.91,yin,,0,0,0,, 代替 PhotosByPhotographer\\N{\\fs12}instead of photos by photographer \r\nDialogue: 0,0:40:20.91,0:40:22.52,yin,,0,0,0,,Core Data 表格视图控制器 \\N{\\fs12}core data table view controller. \r\nDialogue: 0,0:40:22.52,0:40:25.24,yin,,0,0,0,, 我们有这些 需要导入 \\N{\\fs12}And we have these because we have to import, \r\nDialogue: 0,0:40:25.24,0:40:29.94,yin,,0,0,0,, 导入 PhotosByPhotographerMapViewController\\N{\\fs12}so let's go and import our photos by photographer map view controller. \r\nDialogue: 0,0:40:29.94,0:40:32.92,yin,,0,0,0,, 这就解决掉了所有警告 很好 \\N{\\fs12}Hopefully it gets rid of all our warnings, that's good. \r\nDialogue: 0,0:40:32.92,0:40:36.68,yin,,0,0,0,, 现在我们有了这个 segue 再试一次 \\N{\\fs12}So now we have this segue, so let's try again. \r\nDialogue: 0,0:40:36.68,0:40:38.72,yin,,0,0,0,, 但愿我们的新 segue 能够工作 \\N{\\fs12}And hopefully our new segue will work. \r\nDialogue: 0,0:40:38.72,0:40:42.85,yin,,0,0,0,, 我们有拍照者 点击 我们得到地图上的大头针 \\N{\\fs12}We got the photographers, we click, we got pins on the map. \r\nDialogue: 0,0:40:42.85,0:40:46.82,yin,,0,0,0,, 显示该拍照者的所有照片 点击一个大头针 \\N{\\fs12}Showing all those photos by that photographer, and if we click on a pin, \r\nDialogue: 0,0:40:46.82,0:40:50.67,yin,,0,0,0,, 它会显示出标题和副标题 \\N{\\fs12}it's actually going to show us the title and subtitle. \r\nDialogue: 0,0:40:50.67,0:40:51.98,yin,,0,0,0,, 这些都没有副标题 \\N{\\fs12}None of these have subtitles, \r\nDialogue: 0,0:40:51.98,0:40:54.98,yin,,0,0,0,, 看看能否找到一个有副标题的 \\N{\\fs12}let's see if we can find somebody who has subtitle. \r\nDialogue: 0,0:40:54.98,0:40:57.76,yin,,0,0,0,, 这里 这里有一个人 从苏格兰 \\N{\\fs12}There we go, there's one, this person gets around, from Scotland all the way \r\nDialogue: 0,0:40:57.76,0:41:00.87,yin,,0,0,0,, 一直跑到了非洲海岸 \\N{\\fs12}down to somewhere off the coast of Africa there. \r\nDialogue: 0,0:41:00.87,0:41:06.08,yin,,0,0,0,, 这很酷 不过我们不能做到下一步的 segue\\N{\\fs12}So this is kind of cool, but we can't do our next step of our segue, \r\nDialogue: 0,0:41:06.08,0:41:09.17,yin,,0,0,0,, 我们不能 segue 到照片显示 \\N{\\fs12}we can't segue to showing the photo, and also, \r\nDialogue: 0,0:41:09.17,0:41:14.10,yin,,0,0,0,, 而且这里要是有个小的照片缩略图就好了 \\N{\\fs12}wouldn't it be cool if we had a little thumb nail of the photo in here? \r\nDialogue: 0,0:41:14.10,0:41:15.32,yin,,0,0,0,, 让我们能够 \\N{\\fs12}So that we could kind of look \r\nDialogue: 0,0:41:15.32,0:41:17.63,yin,,0,0,0,, 在这个人拍的多张照片中查找 \\N{\\fs12}around at the various photos taken by this guy \r\nDialogue: 0,0:41:17.63,0:41:19.07,yin,,0,0,0,, 直到找到我们想要的 \\N{\\fs12}until we find the one we want, \r\nDialogue: 0,0:41:19.07,0:41:20.84,yin,,0,0,0,, 然后我们点击这里 \\N{\\fs12}and then we'll click on something over here \r\nDialogue: 0,0:41:20.84,0:41:25.36,yin,,0,0,0,,segue 到完整的照片显示 \\N{\\fs12}to segue over to our showing the photo in its grand, all its grandeur. \r\nDialogue: 0,0:41:25.36,0:41:26.54,yin,,0,0,0,, 让我们来做这个 \\N{\\fs12}So let's do that. \r\nDialogue: 0,0:41:26.54,0:41:28.80,yin,,0,0,0,, 把这些附属视图加进来 \\N{\\fs12}Let's put these accessory views in. \r\nDialogue: 0,0:41:28.80,0:41:32.84,yin,,0,0,0,, 回到我们的地图视图控制器 \\N{\\fs12}Let's go back here to our map view controller. \r\nDialogue: 0,0:41:32.84,0:41:34.51,yin,,0,0,0,, 腾出空间 \\N{\\fs12}Some space. \r\nDialogue: 0,0:41:34.51,0:41:37.30,yin,,0,0,0,, 这是我们现有的地图视图控制器 \\N{\\fs12}Alright, so there's our map view controller, what we've done so far. \r\nDialogue: 0,0:41:37.30,0:41:41.29,yin,,0,0,0,, 现在我们要用地图视图委托方法 这是我们的第一个 \\N{\\fs12}And now we're going to do that map view delegate method, this is our first one. \r\nDialogue: 0,0:41:41.29,0:41:46.16,yin,,0,0,0,, 这个会返回 MKAnnotationView\\N{\\fs12}This is the one that returns an MK annotation view \r\nDialogue: 0,0:41:46.16,0:41:49.48,yin,,0,0,0,, 给定一个特定的 annotation\\N{\\fs12}given a certain annotation. \r\nDialogue: 0,0:41:49.48,0:41:52.51,yin,,0,0,0,, 这个是 mapView viewForAnnotation\\N{\\fs12}So this is called map view, view for annotation, \r\nDialogue: 0,0:41:52.51,0:41:53.99,yin,,0,0,0,, 给定一个 annotation\\N{\\fs12}it's going to give an annotation, that's going \r\nDialogue: 0,0:41:53.99,0:41:55.40,yin,,0,0,0,, 也就是我们的一张照片 \\N{\\fs12}to be one of our photos \r\nDialogue: 0,0:41:55.40,0:41:59.98,yin,,0,0,0,, 它会要求我们返回一个视图对应那个 annotation\\N{\\fs12}and it's going to ask us to return a view for that annotation. \r\nDialogue: 0,0:41:59.98,0:42:03.50,yin,,0,0,0,, 出于时间考虑 这里就直接这样做 \\N{\\fs12}I think for speed here I have something, yeah, let's do that. \r\nDialogue: 0,0:42:03.50,0:42:06.16,yin,,0,0,0,, 这会完成幻灯片上我讲过的内容 \\N{\\fs12}Okay, so this is going to do what we saw on the slides \r\nDialogue: 0,0:42:06.16,0:42:07.93,yin,,0,0,0,, 它会有一个再利用 ID\\N{\\fs12}where it's going to have a reuse ID. \r\nDialogue: 0,0:42:07.93,0:42:10.38,yin,,0,0,0,, 顺便说下 这个代码片段非常好 \\N{\\fs12}I like, this, by the way, is a good code snippet to have. \r\nDialogue: 0,0:42:10.38,0:42:12.43,yin,,0,0,0,, 可以看到 这是完全通用的 \\N{\\fs12}You can see this is kind of completely generic \r\nDialogue: 0,0:42:12.43,0:42:14.82,yin,,0,0,0,, 用于在地图视图中做到 viewForAnnotation\\N{\\fs12}for doing a view for annotation in a map view. \r\nDialogue: 0,0:42:14.82,0:42:18.69,yin,,0,0,0,, 我有时喜欢用类名作为再利用标识符 \\N{\\fs12}I like to use the name of my class sometimes as my reuse identifier, \r\nDialogue: 0,0:42:18.69,0:42:22.76,yin,,0,0,0,, 这对于再利用有而言 具有很好的唯一性 \\N{\\fs12}that's pretty unique thing to do for reuse. \r\nDialogue: 0,0:42:22.76,0:42:23.45,yin,,0,0,0,, 这是 dequeue\\N{\\fs12}Here's the DQ. \r\nDialogue: 0,0:42:23.45,0:42:26.72,yin,,0,0,0,, 如果 dequeue 无法工作 我需要 alloc init 这个东西 \\N{\\fs12}If the DQ doesn't work, I have to alloc init this thing, \r\nDialogue: 0,0:42:26.72,0:42:29.40,yin,,0,0,0,, 我还是想显示对话框 我希望有一个大头针 \\N{\\fs12}I still wanted to show a call out, I want it to be a pin \r\nDialogue: 0,0:42:29.40,0:42:32.70,yin,,0,0,0,, 然后这里我设置好视图 带有我需要设置的那些 \\N{\\fs12}and then here I'm setting up the view with anything I need to set \r\nDialogue: 0,0:42:32.70,0:42:35.31,yin,,0,0,0,, 它会设置 annotation\\N{\\fs12}up here, it's just setting the annotation. \r\nDialogue: 0,0:42:35.31,0:42:40.93,yin,,0,0,0,, 这里面 就是我们设置左右附属视图的地方 \\N{\\fs12}So, inside here is where we want to set up the left and right accessory views. \r\nDialogue: 0,0:42:40.93,0:42:42.17,yin,,0,0,0,, 我们来做这个 \\N{\\fs12}So, let's do that. \r\nDialogue: 0,0:42:42.17,0:42:44.95,yin,,0,0,0,, 左边这个将是 UIImageView\\N{\\fs12}So the left one is going to be UI image view. \r\nDialogue: 0,0:42:44.96,0:42:48.10,yin,,0,0,0,, 这里我要创建一个图像视图 \\N{\\fs12}So I'm going to create an image view here. \r\nDialogue: 0,0:42:48.10,0:42:51.61,yin,,0,0,0,,UIImageView alloc init\\N{\\fs12}UI image view alloc init. \r\nDialogue: 0,0:42:51.61,0:42:54.53,yin,,0,0,0,, 这里 alloc init 将使用 initWithFrame\\N{\\fs12}And I'm going to actually alloc init with frame \r\nDialogue: 0,0:42:54.53,0:42:57.96,yin,,0,0,0,, 这是 iOS 中我很不喜欢的一个地方 \\N{\\fs12}and this is one of the places in iOS I really don't like. \r\nDialogue: 0,0:42:57.96,0:43:04.00,yin,,0,0,0,, 没有 API 能够知道 对话框有多大 \\N{\\fs12}There is no way, no API, to find out how big is that call out? \r\nDialogue: 0,0:43:04.00,0:43:06.20,yin,,0,0,0,, 而我需要知道对话框有多大 \\N{\\fs12}So I'd really like to know how big that call \r\nDialogue: 0,0:43:06.20,0:43:10.12,yin,,0,0,0,, 这样我才能知道图像视图要多大才合适 \\N{\\fs12}out so I can make my image view be a good size to really fit there. \r\nDialogue: 0,0:43:10.12,0:43:14.53,yin,,0,0,0,, 很不幸 这里你需要设置固定数字 \\N{\\fs12}So this is a place where you have to, unfortunately, put magic numbers. \r\nDialogue: 0,0:43:14.53,0:43:16.55,yin,,0,0,0,, 我发现的固定数字 \\N{\\fs12}And the magic numbers I found \r\nDialogue: 0,0:43:16.55,0:43:20.17,yin,,0,0,0,, 对于图像视图是 46 乘 46\\N{\\fs12}that really work is an image view that is 46 by 46, \r\nDialogue: 0,0:43:20.17,0:43:25.25,yin,,0,0,0,, 这就能很好地匹配到左侧对话框附属视图中 \\N{\\fs12}that seems to really fit nicely in that left call out accessory view, right there. \r\nDialogue: 0,0:43:25.25,0:43:28.95,yin,,0,0,0,, 这是这里很不幸的一点 \\N{\\fs12}So that's kind of an unfortunate piece of this. \r\nDialogue: 0,0:43:28.95,0:43:33.21,yin,,0,0,0,, 现在 我将把这设置为左侧对话框附属视图 \\N{\\fs12}So now I'm just going to set that as the left call out accessory view, \r\nDialogue: 0,0:43:33.21,0:43:37.39,yin,,0,0,0,, 然后右边将是一个按钮 我只想要一个按钮 \\N{\\fs12}and then the right one is going to be a button, I just want to do a button, \r\nDialogue: 0,0:43:37.39,0:43:39.33,yin,,0,0,0,, 这个的代码我也有了 \\N{\\fs12}so I think I have a code for that one, yeah, \r\nDialogue: 0,0:43:39.33,0:43:41.27,yin,,0,0,0,, 信息披露按钮 也就是这段代码 \\N{\\fs12}the disclosure button, so that's this code right here. \r\nDialogue: 0,0:43:41.27,0:43:44.02,yin,,0,0,0,, 我要创建一个 UIButton 使用 alloc init\\N{\\fs12}So I'm just going to create a UI button, alloc init. \r\nDialogue: 0,0:43:44.02,0:43:46.06,yin,,0,0,0,, 我要将它的背景图像 \\N{\\fs12}I'm going to set its background image \r\nDialogue: 0,0:43:46.06,0:43:49.04,yin,,0,0,0,, 设为这里的这个信息披露图像 \\N{\\fs12}to be this disclosure image I have right here. \r\nDialogue: 0,0:43:49.04,0:43:53.35,yin,,0,0,0,, 让我到下面这里的图像库中 \\N{\\fs12}So let me go down here to my image assets. \r\nDialogue: 0,0:43:53.35,0:43:55.66,yin,,0,0,0,, 把这个拖进来 像这样 \\N{\\fs12}And let's drag this in, like that. \r\nDialogue: 0,0:43:55.66,0:43:57.96,yin,,0,0,0,, 名为披露 我没有高清版的 不过没问题 \\N{\\fs12}Disclosure, I don't have a high-res version, but that's okay. \r\nDialogue: 0,0:43:57.96,0:44:03.08,yin,,0,0,0,, 顺便说下 这并不是很好的图像解决方案 \\N{\\fs12}This is kind of, this is not a great solution, by the way, to do an image here, \r\nDialogue: 0,0:44:03.09,0:44:07.52,yin,,0,0,0,, 因为我们需要尊重地图视图的着色风格 \\N{\\fs12}because really we want to respect the tint color of the map view \r\nDialogue: 0,0:44:07.52,0:44:09.57,yin,,0,0,0,, 而这个箭头是蓝色的 \\N{\\fs12}and that arrow is blue. \r\nDialogue: 0,0:44:09.57,0:44:10.76,yin,,0,0,0,, 这很糟糕 \\N{\\fs12}So that's bad. \r\nDialogue: 0,0:44:10.76,0:44:13.37,yin,,0,0,0,, 更好的做法是绘制一个 \\N{\\fs12}It'd be much better to either draw it \r\nDialogue: 0,0:44:13.37,0:44:16.13,yin,,0,0,0,, 就算要使用图像 你也应该来周五辅导课 \\N{\\fs12}or if we are going to use an image, you should come to Friday's section \r\nDialogue: 0,0:44:16.13,0:44:19.35,yin,,0,0,0,, 理解如何使用 Core Image 改变图像颜色 \\N{\\fs12}and understand how to change the color of an image using core image. \r\nDialogue: 0,0:44:19.35,0:44:22.24,yin,,0,0,0,, 这是本周五辅导课我们要讲的内容 \\N{\\fs12}That's what we're talking about in Friday's section this week. \r\nDialogue: 0,0:44:22.24,0:44:23.78,yin,,0,0,0,, 一则小广告 \\N{\\fs12}Little plug for that. \r\nDialogue: 0,0:44:23.78,0:44:26.22,yin,,0,0,0,, 无论如何 demo 中就用这个了 \\N{\\fs12}But anyway, for demo purposes I'll use this thing. \r\nDialogue: 0,0:44:26.22,0:44:29.86,yin,,0,0,0,, 然后使用 sizeToFit 来调整按钮图像 \\N{\\fs12}Now I'm going to size to fit this button to fit that image that I just did, \r\nDialogue: 0,0:44:29.86,0:44:34.21,yin,,0,0,0,, 然后我将它设为右对话框附属视图 \\N{\\fs12}and then I'm going to set it as the right call out accessory view right there. \r\nDialogue: 0,0:44:34.21,0:44:35.51,yin,,0,0,0,, 有问题 \\N{\\fs12}Question? \r\nDialogue: 0,0:44:39.29,0:44:43.68,yin,,0,0,0,, 你是说… 我不确定 \\N{\\fs12}You mean is the, the, you know, I'm not sure. \r\nDialogue: 0,0:44:43.68,0:44:46.44,yin,,0,0,0,, 如果视图很大的话 \\N{\\fs12}I believe it will size if you make a big view in there, \r\nDialogue: 0,0:44:46.44,0:44:49.12,yin,,0,0,0,, 它会变得更大 但看起来会很糟糕 \\N{\\fs12}it'll make it bigger, but it starts to not look very good, \r\nDialogue: 0,0:44:49.12,0:44:52.04,yin,,0,0,0,, 因此你需要选择大小 让它保持相同大小 \\N{\\fs12}so you kind of want to pick sizes that make it stay the same size \r\nDialogue: 0,0:44:52.04,0:44:53.50,yin,,0,0,0,, 由于标题和副标题 \\N{\\fs12}because of the title and subtitle. \r\nDialogue: 0,0:44:53.50,0:44:56.49,yin,,0,0,0,, 对话框这整个 \\N{\\fs12}It's a little bit, the whole thing with the call out thing is a little bit, \r\nDialogue: 0,0:44:56.49,0:45:00.92,yin,,0,0,0,, 你需要逐像素或是逐点调整 很不幸 \\N{\\fs12}kind of, you have to tweak it pixel by or point by point, unfortunately. \r\nDialogue: 0,0:45:00.92,0:45:06.47,yin,,0,0,0,, 我们来看看 到目前为止 我们都做了些什么 \\N{\\fs12}So, let's go ahead and take a look at what we got so far. \r\nDialogue: 0,0:45:06.47,0:45:09.60,yin,,0,0,0,, 现在 我们来看一张照片 点出对话框 \\N{\\fs12}Alright? So now if we look at a photo and we do the call out. \r\nDialogue: 0,0:45:09.60,0:45:11.03,yin,,0,0,0,, 这里有了图像的空间 \\N{\\fs12}We have room for the image. \r\nDialogue: 0,0:45:11.03,0:45:13.66,yin,,0,0,0,, 只是图像还没放进来 这里还有了按钮 \\N{\\fs12}We're not putting the image in there yet, and we have this little button, \r\nDialogue: 0,0:45:13.66,0:45:15.57,yin,,0,0,0,, 现在点击 它还什么都做不了 \\N{\\fs12}which when we click on does nothing. \r\nDialogue: 0,0:45:15.57,0:45:16.81,yin,,0,0,0,, 我们正在推进 \\N{\\fs12}So we're getting closer.\r\nDialogue: 0,0:45:16.81,0:45:22.01,yin,,0,0,0,, 让我们把图像放进来 同时点这个以后 segue\\N{\\fs12}So let's put this image in there, and let's make it so clicking on this segues. \r\nDialogue: 0,0:45:22.01,0:45:25.94,yin,,0,0,0,, 那如何将图像放到这个图像视图中呢 \\N{\\fs12}Alright. So, how do we put this image into the image view? \r\nDialogue: 0,0:45:25.94,0:45:30.42,yin,,0,0,0,, 这里我有一个方法 叫作… 叫什么来着 \\N{\\fs12}Well, I'm going to have a little method to do it here called, what did I call this? \r\nDialogue: 0,0:45:30.42,0:45:32.27,yin,,0,0,0,,updateLeftCalloutAccessory\\N{\\fs12}Update left call accessory, yeah, \r\nDialogue: 0,0:45:32.27,0:45:34.70,yin,,0,0,0,, 这是做这个的方法 \\N{\\fs12}so here's my method that does this. \r\nDialogue: 0,0:45:34.70,0:45:37.11,yin,,0,0,0,, 看起来有很多代码 其实不然 \\N{\\fs12}This looks like maybe a lot of code, but it's actually not that much. \r\nDialogue: 0,0:45:37.11,0:45:39.92,yin,,0,0,0,, 我做的大部分是内省 \\N{\\fs12}Mostly what I'm doing is introspection to find \r\nDialogue: 0,0:45:39.92,0:45:44.74,yin,,0,0,0,, 弄清左对话框附属视图是不是图像视图 \\N{\\fs12}out if the left call out accessory view is, in fact, an image view. \r\nDialogue: 0,0:45:44.74,0:45:48.31,yin,,0,0,0,, 因为我可能有多个大头针 使用不同的对话框 \\N{\\fs12}Because I might have multiple pins with different call outs. \r\nDialogue: 0,0:45:48.31,0:45:49.74,yin,,0,0,0,, 有些可能会显示照片 \\N{\\fs12}Some of them might be showing photos, \r\nDialogue: 0,0:45:49.74,0:45:51.61,yin,,0,0,0,, 但有些可能会显示别的 \\N{\\fs12}but some might be showing something else. \r\nDialogue: 0,0:45:51.61,0:45:52.73,yin,,0,0,0,, 也许别的这些 \\N{\\fs12}And maybe those are something else \r\nDialogue: 0,0:45:52.73,0:45:55.96,yin,,0,0,0,, 没有图像视图作为左对话框附属视图 \\N{\\fs12}they don't have an image view as a the left call out accessory view. \r\nDialogue: 0,0:45:55.96,0:46:00.78,yin,,0,0,0,, 我这里既检查确保了左对话框是图像视图 \\N{\\fs12}Alright? So I'm both checking to make sure that my left call out is an image view, \r\nDialogue: 0,0:46:00.78,0:46:03.66,yin,,0,0,0,, 我还检查确保了 annotation 是一张照片 \\N{\\fs12}I'm also checking to make sure my annotation is a photo, \r\nDialogue: 0,0:46:03.66,0:46:05.31,yin,,0,0,0,, 而不是别的什么 \\N{\\fs12}right, and not something else. \r\nDialogue: 0,0:46:05.31,0:46:07.95,yin,,0,0,0,, 毕竟地图上有别的 annotation 很正常 \\N{\\fs12}Because it's perfectly reasonable on a map to have annotations, \r\nDialogue: 0,0:46:07.95,0:46:10.21,yin,,0,0,0,, 可能有些是照片 有些是别的 \\N{\\fs12}some of which are photos, some of which are something else. \r\nDialogue: 0,0:46:10.21,0:46:12.77,yin,,0,0,0,, 例如拍照者的家乡或是别的什么 \\N{\\fs12}The hometown of the photographer or something like that. \r\nDialogue: 0,0:46:12.77,0:46:17.26,yin,,0,0,0,, 这里大部分就是这种内省 \\N{\\fs12}So that's what mostly what this is it just is introspection of those things. \r\nDialogue: 0,0:46:17.26,0:46:19.77,yin,,0,0,0,, 有了照片和图像视图之后 \\N{\\fs12}Once I have a photo and an image view, \r\nDialogue: 0,0:46:19.77,0:46:22.51,yin,,0,0,0,, 我就只需要这个骇人的图像 \\N{\\fs12}then all I'm doing is this horrendous image \r\nDialogue: 0,0:46:22.51,0:46:24.43,yin,,0,0,0,, 使用 imageWithData dataWithContentsOfURL\\N{\\fs12}with image data, data with contents URL, \r\nDialogue: 0,0:46:24.43,0:46:25.94,yin,,0,0,0,, 为什么说骇人呢 \\N{\\fs12}and why is it horrendous? \r\nDialogue: 0,0:46:25.94,0:46:27.61,yin,,0,0,0,, 显然因为我阻塞了主队列 \\N{\\fs12}Of course because I'm blocking the main queue, \r\nDialogue: 0,0:46:27.61,0:46:29.28,yin,,0,0,0,, 这是 demo 我需要做这个 \\N{\\fs12}but this is a demo so I get to do it, \r\nDialogue: 0,0:46:29.28,0:46:32.07,yin,,0,0,0,, 你们在作业中不需要 但我需要 \\N{\\fs12}you don't get to do it in your homework, but I do. \r\nDialogue: 0,0:46:32.07,0:46:33.96,yin,,0,0,0,, 这会阻塞主队列 \\N{\\fs12}So, this is going to block the main thread \r\nDialogue: 0,0:46:33.96,0:46:36.51,yin,,0,0,0,, 前往 Flickr 进行取回 \\N{\\fs12}for a short amount while it goes out to Flickr to fetch it, \r\nDialogue: 0,0:46:36.51,0:46:38.37,yin,,0,0,0,, 不过 你们懂的 \\N{\\fs12}but you get the idea. \r\nDialogue: 0,0:46:38.37,0:46:42.43,yin,,0,0,0,, 这里加个警告 我保证以后我会过来修正的 \\N{\\fs12}I put the warning in, I'm sure I'll go back and fix it some other day, yeah, sure. \r\nDialogue: 0,0:46:42.43,0:46:46.15,yin,,0,0,0,, 这是这个 我们来看看 \\N{\\fs12}Okay. So that's that. Let's go ahead and look at that. \r\nDialogue: 0,0:46:49.40,0:46:51.78,yin,,0,0,0,, 好 现在 如果我点击一个大头针 \\N{\\fs12}Alright, so now if we click on something and we click \r\nDialogue: 0,0:46:51.78,0:46:54.03,yin,,0,0,0,, 这里应该有一个图像 \\N{\\fs12}on a pin, hopefully we'll get an image, \r\nDialogue: 0,0:46:54.03,0:46:57.17,yin,,0,0,0,, 似乎无法工作 为什么呢 \\N{\\fs12}maybe that guy didn't have, oh, that's not working, why is that not working? \r\nDialogue: 0,0:46:57.17,0:47:01.10,yin,,0,0,0,, 哦 不 不是这个原因 \\N{\\fs12}Oh! I, no, that's not why. \r\nDialogue: 0,0:47:01.10,0:47:04.21,yin,,0,0,0,, 哦 我明白了 因为我们没有调用这个 \\N{\\fs12}Okay, so, oh, I see why, because we never called this. \r\nDialogue: 0,0:47:04.21,0:47:06.73,yin,,0,0,0,, 显然应当调用 这样才行 \\N{\\fs12}Okay, it'd be nice to call that. It would probably work better. \r\nDialogue: 0,0:47:06.73,0:47:08.79,yin,,0,0,0,, 在这里调用它 \\N{\\fs12}So let's call that from here. \r\nDialogue: 0,0:47:08.79,0:47:13.57,yin,,0,0,0,, 这是 viewForAnnotation\\N{\\fs12}Okay, this is the view for annotation. \r\nDialogue: 0,0:47:13.57,0:47:16.29,yin,,0,0,0,, 我从 viewForAnnotation 调用这个左对话框 \\N{\\fs12}So I'm calling this left call out here from view for annotation, right, \r\nDialogue: 0,0:47:16.29,0:47:18.08,yin,,0,0,0,, 因为我要为 annotation 返回一个小视图 \\N{\\fs12}because I'm returning the little view for annotation, \r\nDialogue: 0,0:47:18.08,0:47:20.56,yin,,0,0,0,, 这包含对话窗视图的创建 \\N{\\fs12}that includes building the call out view, \r\nDialogue: 0,0:47:20.56,0:47:24.38,yin,,0,0,0,, 这样应该就行了 我猜 \\N{\\fs12}so that'll work a lot better, I'm going to guess. \r\nDialogue: 0,0:47:24.38,0:47:26.29,yin,,0,0,0,, 到这里 \\N{\\fs12}Alright, so here we go here. \r\nDialogue: 0,0:47:26.29,0:47:28.51,yin,,0,0,0,, 点击 看起来很棒 \\N{\\fs12}Click this up, nice, that looks pretty good, right? \r\nDialogue: 0,0:47:28.51,0:47:30.83,yin,,0,0,0,, 点这每一个 都可以看到缩略图 \\N{\\fs12}So if we click on each one, we kind of get a little look at it \r\nDialogue: 0,0:47:30.83,0:47:33.25,yin,,0,0,0,, 这能帮我们决定 我们要看哪个 \\N{\\fs12}and it kind of helps us decide which one we want to step on, \r\nDialogue: 0,0:47:33.25,0:47:34.83,yin,,0,0,0,, 我们再点这个 \\N{\\fs12}press on, and we'll press on this one. \r\nDialogue: 0,0:47:34.83,0:47:36.67,yin,,0,0,0,, 不过这样做有个问题 \\N{\\fs12}Now there's a problem with the way I've done this though. \r\nDialogue: 0,0:47:36.67,0:47:38.96,yin,,0,0,0,, 找一个照片很多的人 \\N{\\fs12}Let's find somebody who has a lot of photos. \r\nDialogue: 0,0:47:38.96,0:47:40.76,yin,,0,0,0,, 但愿有人拍了很多照片 \\N{\\fs12}Hopefully somebody has a lot of photos. \r\nDialogue: 0,0:47:40.76,0:47:45.23,yin,,0,0,0,, 谁呢 看起来 15 或是 16 张已经很多了 \\N{\\fs12}Somebody, well, eh, looks like 15 photos is, or 16, alright. \r\nDialogue: 0,0:47:45.23,0:47:46.38,yin,,0,0,0,, 选这个吧 \\N{\\fs12}So let's click on this guy. \r\nDialogue: 0,0:47:46.38,0:47:48.66,yin,,0,0,0,, 点这个时 注意 耗时很长 \\N{\\fs12}When I click on this guy, look, it's taking a long time. \r\nDialogue: 0,0:47:48.68,0:47:50.42,yin,,0,0,0,, 斯坦福的网还很快 \\N{\\fs12}And this is a fast Stanford network, so, \r\nDialogue: 0,0:47:50.42,0:47:53.22,yin,,0,0,0,, 至少不慢 但它仍然阻塞了主线程 \\N{\\fs12}it's not too slow, but it still, it's blocking the main thread, \r\nDialogue: 0,0:47:53.22,0:47:55.09,yin,,0,0,0,, 而且阻塞得还很多 \\N{\\fs12}but it's blocking the main thread a lot. \r\nDialogue: 0,0:47:55.09,0:47:55.86,yin,,0,0,0,, 为什么呢 \\N{\\fs12}And why is that? \r\nDialogue: 0,0:47:55.86,0:48:01.07,yin,,0,0,0,, 因为它在为所有这 16 张照片取回缩略图 \\N{\\fs12}That's because it's fetching the thumb nail image for all 16 of those photos. \r\nDialogue: 0,0:48:01.07,0:48:02.48,yin,,0,0,0,, 预先一次性取回 \\N{\\fs12}All at once up front. \r\nDialogue: 0,0:48:02.48,0:48:07.13,yin,,0,0,0,, 我们不希望这样做 我们只希望在点大头针时取回 \\N{\\fs12}So we do not want to do that, we only want to do this fetch when you click on the pin. \r\nDialogue: 0,0:48:07.13,0:48:10.70,yin,,0,0,0,, 因此 这里我们要实现另一个地图视图委托方法 \\N{\\fs12}So we're going to implement another map view delegate \r\nDialogue: 0,0:48:10.70,0:48:13.57,yin,,0,0,0,, 可以看到这里有多少委托方法 \\N{\\fs12}method, and you can see how many methods, delegate methods, \r\nDialogue: 0,0:48:13.57,0:48:15.16,yin,,0,0,0,, 地图视图有很多 \\N{\\fs12}the map view has, quite a few. \r\nDialogue: 0,0:48:15.16,0:48:19.50,yin,,0,0,0,, 我们要的是下面这个 didSelectAnnotationView\\N{\\fs12}We want this one down here, did select annotation view. \r\nDialogue: 0,0:48:19.50,0:48:21.45,yin,,0,0,0,, 这在大头针被点时会被调用 \\N{\\fs12}That's get called when the pin gets clicked on, \r\nDialogue: 0,0:48:21.45,0:48:25.77,yin,,0,0,0,, 把 updateLeftCalloutAccessory 这个移到下面来 \\N{\\fs12}so I'm just going to move this update left call out accessory view down to here. \r\nDialogue: 0,0:48:25.77,0:48:30.12,yin,,0,0,0,, 现在运行时 哪怕有 16 张照片的人 \\N{\\fs12}So now, when we run, even the 16 guy \r\nDialogue: 0,0:48:30.12,0:48:32.86,yin,,0,0,0,, 也会立刻加载 因为这里没有取回操作 \\N{\\fs12}is going to instantly come up, because you're not doing any fetching, \r\nDialogue: 0,0:48:32.86,0:48:35.58,yin,,0,0,0,, 但点这个时 会有少许延时 \\N{\\fs12}but when we click on this, little delay. \r\nDialogue: 0,0:48:35.58,0:48:38.23,yin,,0,0,0,, 现在我不能看到全部这 16 个 它们都堆在一起 \\N{\\fs12}Now I can't see all 16 of things because they're all stacked up, \r\nDialogue: 0,0:48:38.23,0:48:39.96,yin,,0,0,0,, 这个 UI 有点小问题 \\N{\\fs12}it's a little problem with our UI, \r\nDialogue: 0,0:48:39.96,0:48:42.46,yin,,0,0,0,, 或许我们应该有办法能够点其它的 \\N{\\fs12}we probably want to have some way to click other things, \r\nDialogue: 0,0:48:42.47,0:48:46.27,yin,,0,0,0,, 这里要换照片似乎不那么容易 无论如何 \\N{\\fs12}you can kind of click other things one, but, anyway. \r\nDialogue: 0,0:48:46.27,0:48:49.58,yin,,0,0,0,, 下面 在点这里时 我希望看到这张照片 \\N{\\fs12}But now we want to, if I click here, I want to see this image \r\nDialogue: 0,0:48:49.58,0:48:51.81,yin,,0,0,0,, 在图像视图控制器中 看到完整大小的 \\N{\\fs12}in my image view controller, full-size. \r\nDialogue: 0,0:48:51.81,0:48:54.27,yin,,0,0,0,, 下面来实现这个 \\N{\\fs12}So now let's implement this little thing. \r\nDialogue: 0,0:48:54.27,0:48:58.74,yin,,0,0,0,, 这里 我们需要另外一个地图视图委托方法 \\N{\\fs12}And that it's going to do, we're going to do with another map view delegate method. \r\nDialogue: 0,0:48:58.74,0:49:00.46,yin,,0,0,0,, 这个我讲过 \\N{\\fs12}This is the one I told you about, \r\nDialogue: 0,0:49:00.46,0:49:03.86,yin,,0,0,0,,calloutAccessoryTouched 上面这个 看到了吗 \\N{\\fs12}the call out accessory touched, it's the one up here, see it? \r\nDialogue: 0,0:49:03.86,0:49:06.93,yin,,0,0,0,,calloutAccessoryControlTapped\\N{\\fs12}Call out accessory control tapped. \r\nDialogue: 0,0:49:06.93,0:49:11.62,yin,,0,0,0,, 这个在任何左 / 右附属视图中的 \\N{\\fs12}So this gets called whenever any left or right accessory view, \r\nDialogue: 0,0:49:11.62,0:49:16.45,yin,,0,0,0,,UIControl 例如 UIButton 被点时 会被调用 \\N{\\fs12}that is a UI control, like UI button is, gets tapped. This gets called. \r\nDialogue: 0,0:49:16.45,0:49:18.84,yin,,0,0,0,, 现在我只有一个 因为图像视图并不是 UIControl\\N{\\fs12}Now I only have one because the image view is not a UI control, \r\nDialogue: 0,0:49:18.84,0:49:20.48,yin,,0,0,0,, 这个我不需要担心 \\N{\\fs12}so I don't have to worry about that. \r\nDialogue: 0,0:49:20.48,0:49:23.58,yin,,0,0,0,, 这里面 我可以 segue\\N{\\fs12}So inside here, I can segue. \r\nDialogue: 0,0:49:23.58,0:49:26.51,yin,,0,0,0,, 但如何 segue 呢 \\N{\\fs12}But now, how do I segue. \r\nDialogue: 0,0:49:26.51,0:49:28.95,yin,,0,0,0,, 我从未演示过如何做这个 我在幻灯片中讲过 \\N{\\fs12}I've never shown you how to do this, we did cover it in the slides, \r\nDialogue: 0,0:49:28.95,0:49:32.07,yin,,0,0,0,, 但我从未演示过 如何从这里 segue\\N{\\fs12}but I never showed you, how do I actually segue from here? \r\nDialogue: 0,0:49:32.07,0:49:34.08,yin,,0,0,0,, 回到我的故事板 \\N{\\fs12}Because if I go back to my storyboard, \r\nDialogue: 0,0:49:34.08,0:49:37.03,yin,,0,0,0,, 没有能够 control 拖动的大头针 \\N{\\fs12}there's no pins for me to control, drag from? \r\nDialogue: 0,0:49:37.03,0:49:39.58,yin,,0,0,0,, 怎么办呢 \\N{\\fs12}How do I, what am I going to do? \r\nDialogue: 0,0:49:39.58,0:49:43.46,yin,,0,0,0,, 这里我们只需要从代码中进行 segue\\N{\\fs12}So what we're going to do here is segue from code, \r\nDialogue: 0,0:49:43.46,0:49:46.12,yin,,0,0,0,, 做法是这样的 \\N{\\fs12}and here's how you segue from code. \r\nDialogue: 0,0:49:46.12,0:49:50.90,yin,,0,0,0,,control 拖动 从这个视图控制器 \\N{\\fs12}You control, drag from the from view controller \r\nDialogue: 0,0:49:50.90,0:49:53.35,yin,,0,0,0,, 到要到的视图控制器 从整个视图控制器 \\N{\\fs12}to the to-view controller, just from the whole view controller, \r\nDialogue: 0,0:49:53.35,0:49:55.72,yin,,0,0,0,, 而不是从任何按钮或是别的什么 \\N{\\fs12}not from any button in here or anything like that, \r\nDialogue: 0,0:49:55.72,0:49:57.44,yin,,0,0,0,, 如果这里你有很多按钮 \\N{\\fs12}and if you had a lot of buttons in here, \r\nDialogue: 0,0:49:57.44,0:49:59.41,yin,,0,0,0,, 你可以从这个栏 control 拖动 \\N{\\fs12}you could control, drag from this bar \r\nDialogue: 0,0:49:59.41,0:50:01.47,yin,,0,0,0,, 这样你就不会意外地从一个按钮 control 拖动 \\N{\\fs12}so you don't accidentally control, drag from a button. \r\nDialogue: 0,0:50:01.47,0:50:04.96,yin,,0,0,0,, 我这里不是从地图视图进行 control 拖动的 \\N{\\fs12}So I'm just going, and I'm not control, dragging from the map view here. \r\nDialogue: 0,0:50:04.96,0:50:08.37,yin,,0,0,0,, 这里我将从下面这里 control 拖动 \\N{\\fs12}In fact, here I'm going to control, drag from down here. \r\nDialogue: 0,0:50:08.37,0:50:13.38,yin,,0,0,0,, 这是我的 PhotosByPhotographer\\N{\\fs12}So here's my photos by photographer, here's the, \r\nDialogue: 0,0:50:13.38,0:50:16.55,yin,,0,0,0,, 这是表示控制器本身的图标 \\N{\\fs12}the icon that represents the controller itself, so I'm going \r\nDialogue: 0,0:50:16.55,0:50:19.94,yin,,0,0,0,, 我从这里 control 拖动到这个 \\N{\\fs12}to control drag from here up to this guy. \r\nDialogue: 0,0:50:23.16,0:50:25.08,yin,,0,0,0,, 相信我 \\N{\\fs12}Oh well, trust me. \r\nDialogue: 0,0:50:25.08,0:50:27.40,yin,,0,0,0,, 从这里 control 拖动到这里 \\N{\\fs12}I'm going to control drag from here to here. \r\nDialogue: 0,0:50:27.77,0:50:28.63,yin,,0,0,0,, 好了 \\N{\\fs12}There we go. \r\nDialogue: 0,0:50:28.63,0:50:30.88,yin,,0,0,0,, 不 这个到这里 \\N{\\fs12}No. This to here. \r\nDialogue: 0,0:50:30.89,0:50:32.49,yin,,0,0,0,, 抱歉 好了 \\N{\\fs12}Sorry. There we go. \r\nDialogue: 0,0:50:32.49,0:50:35.10,yin,,0,0,0,, 我从这个视图控制器 control 拖动到这个 \\N{\\fs12}Alright. So I'm going to control, drag from this view controller to this one. \r\nDialogue: 0,0:50:35.10,0:50:38.80,yin,,0,0,0,, 我从这个视图控制器创建了一个 segue\\N{\\fs12}So, I'm creating a segue here from that view controller \r\nDialogue: 0,0:50:38.80,0:50:39.79,yin,,0,0,0,, 到另一个 \\N{\\fs12}to the other one, \r\nDialogue: 0,0:50:39.79,0:50:42.89,yin,,0,0,0,, 很通用 从一个控制器到另一个控制器 \\N{\\fs12}generically, from the controller to the other controller, \r\nDialogue: 0,0:50:42.89,0:50:45.35,yin,,0,0,0,, 很重要的是 我需要给它取个名字 \\N{\\fs12}and it's very important here I have to give it a name. \r\nDialogue: 0,0:50:45.35,0:50:47.57,yin,,0,0,0,, 我将它称作 Show Photo\\N{\\fs12}So I'm going to call it show photo, \r\nDialogue: 0,0:50:47.57,0:50:50.41,yin,,0,0,0,, 这就是它的作用 显示这张照片 \\N{\\fs12}because that's what it does, it shows this photo. \r\nDialogue: 0,0:50:50.41,0:50:52.47,yin,,0,0,0,, 为什么要取名呢 \\N{\\fs12}Why do I need to give it a name? \r\nDialogue: 0,0:50:52.47,0:50:55.58,yin,,0,0,0,, 因为在代码中 我需要引用这个 segue\\N{\\fs12}Because from code, I have to refer to this segue, \r\nDialogue: 0,0:50:55.58,0:50:57.62,yin,,0,0,0,, 引用需要用到名字 \\N{\\fs12}and I'm going to refer to it by name. \r\nDialogue: 0,0:50:57.62,0:50:58.90,yin,,0,0,0,, 叫 Show Photo\\N{\\fs12}We'll call it show photo. \r\nDialogue: 0,0:50:58.90,0:51:01.53,yin,,0,0,0,, 我们回头做这个 只需一行代码 \\N{\\fs12}So let's go back and do that. This is a one-liner. \r\nDialogue: 0,0:51:01.53,0:51:02.80,yin,,0,0,0,, 我只需要说 self…\\N{\\fs12}I just say self, \r\nDialogue: 0,0:51:02.80,0:51:05.77,yin,,0,0,0,, 我要调用 UIViewController 中的这个方法 \\N{\\fs12}and I'm going to call this method in UI view controller, \r\nDialogue: 0,0:51:05.77,0:51:09.84,yin,,0,0,0,,performSegueWithIdentifier\\N{\\fs12}called perform segue with identifier. \r\nDialogue: 0,0:51:09.84,0:51:12.28,yin,,0,0,0,, 这里 我指定 Show Photo\\N{\\fs12}And here I press, specify show photo. \r\nDialogue: 0,0:51:12.28,0:51:14.87,yin,,0,0,0,, 注意 我要指定一个 sender\\N{\\fs12}And notice I get to specify a sender. \r\nDialogue: 0,0:51:14.87,0:51:16.55,yin,,0,0,0,, 这个 sender 从哪进来 \\N{\\fs12}Okay, where does this sender come in? \r\nDialogue: 0,0:51:16.55,0:51:19.80,yin,,0,0,0,, 我要在代码中执行的这个 segue\\N{\\fs12}Well, this segue that I'm going to perform, in code here, \r\nDialogue: 0,0:51:19.80,0:51:24.20,yin,,0,0,0,, 还是需要 prepareForSegue 这是普通的 push segue\\N{\\fs12}still gets prepared for segue, it's a normal push segue \r\nDialogue: 0,0:51:24.21,0:51:25.94,yin,,0,0,0,, 它有常规的 prepareForSegue\\N{\\fs12}so it has to prepare for segue \r\nDialogue: 0,0:51:25.94,0:51:30.09,yin,,0,0,0,, 记得 prepareForSegue 吧 它需要一个 sender\\N{\\fs12}and if we remember prepare for segue, it takes a sender. \r\nDialogue: 0,0:51:30.09,0:51:31.40,yin,,0,0,0,, 这个 sender 是什么呢 \\N{\\fs12}And what is that sender? \r\nDialogue: 0,0:51:31.40,0:51:33.12,yin,,0,0,0,, 在表格视图控制器的情形中 \\N{\\fs12}Well, in the table view controller case, \r\nDialogue: 0,0:51:33.12,0:51:36.87,yin,,0,0,0,,sender 是表格视图单元格 \\N{\\fs12}remember the sender is the table view cell. \r\nDialogue: 0,0:51:36.87,0:51:39.90,yin,,0,0,0,, 这里 sender 是什么呢 \\N{\\fs12}So what would we want the, the sender to be here? \r\nDialogue: 0,0:51:39.90,0:51:43.04,yin,,0,0,0,, 或许应该是这个 annotation 视图 \\N{\\fs12}Probably this annotation view. \r\nDialogue: 0,0:51:43.04,0:51:45.92,yin,,0,0,0,, 这里的 annotation 视图 \\N{\\fs12}This annotation view, right here, \r\nDialogue: 0,0:51:45.92,0:51:50.49,yin,,0,0,0,, 也就是附属视图的对话框所在的 annotation 视图 \\N{\\fs12}is the annotation view that has the call out that we tapped that accessory view in, \r\nDialogue: 0,0:51:50.49,0:51:53.94,yin,,0,0,0,, 这就说明了 我们讨论的是哪个 annotation\\N{\\fs12}so that's going to tell us which annotation we're talking about, right?\r\nDialogue: 0,0:51:53.94,0:51:56.31,yin,,0,0,0,, 这就是我们在 prepareForSegue 时需要的 sender\\N{\\fs12}So that's the sender that we're going to see \r\nDialogue: 0,0:51:56.31,0:51:59.25,yin,,0,0,0,, 这就是我们在 prepareForSegue 时需要的 sender\\N{\\fs12}when we go do prepare for segue for this thing. \r\nDialogue: 0,0:52:00.35,0:52:03.92,yin,,0,0,0,, 好 下面来看 prepareForSegue 因为这是普通的 segue\\N{\\fs12}Alright, so let's do the prepare for segue because this is a normal segue. \r\nDialogue: 0,0:52:03.94,0:52:07.46,yin,,0,0,0,, 它需要准备 同其它 segue 一样 \\N{\\fs12}It has to be prepared, just like all the rest of the segues \r\nDialogue: 0,0:52:07.46,0:52:11.32,yin,,0,0,0,, 要做到这个 我打算做表格视图中类似的事 \\N{\\fs12}that we have, and to do that, I'm going, just like I did \r\nDialogue: 0,0:52:11.32,0:52:14.91,yin,,0,0,0,, 这里我有一小段准备代码 \\N{\\fs12}in table view, I'm, I have a little prepare here, \r\nDialogue: 0,0:52:14.91,0:52:18.86,yin,,0,0,0,, 在这里 这个准备 \\N{\\fs12}which is right here, and this prepare kind \r\nDialogue: 0,0:52:18.86,0:52:23.24,yin,,0,0,0,, 会准备这个地图视图控制器 \\N{\\fs12}of generally will prepare this map view controller \r\nDialogue: 0,0:52:23.24,0:52:27.44,yin,,0,0,0,, 让它能 segue 到一个图像视图控制器 \\N{\\fs12}to segue to an image view controller. \r\nDialogue: 0,0:52:27.44,0:52:30.01,yin,,0,0,0,, 同另外一个很类似 \\N{\\fs12}And it looks a lot like the other one, okay, here I'm going \r\nDialogue: 0,0:52:30.01,0:52:33.67,yin,,0,0,0,, 这里我要检查我们要准备的 annotation 是否…\\N{\\fs12}to find out if the annotation that we're going to prepare, \r\nDialogue: 0,0:52:33.67,0:52:35.68,yin,,0,0,0,, 我们要为视图控制器做准备 \\N{\\fs12}so we're going to prepare for view controller, this is going \r\nDialogue: 0,0:52:35.68,0:52:37.16,yin,,0,0,0,, 这是图像视图控制器 \\N{\\fs12}to be an image view controller, \r\nDialogue: 0,0:52:37.16,0:52:40.35,yin,,0,0,0,, 进行特定 segue 显示特定 annotation\\N{\\fs12}to do a certain segue to show a certain annotation. \r\nDialogue: 0,0:52:40.35,0:52:43.86,yin,,0,0,0,, 这个应该是 Photo 我只能处理 Photo\\N{\\fs12}And this had better be a photo, because that's all I know how to do. \r\nDialogue: 0,0:52:43.86,0:52:46.04,yin,,0,0,0,, 这里检查确保它是 Photo\\N{\\fs12}So I'm checking here to make sure it's a photo. \r\nDialogue: 0,0:52:46.04,0:52:49.14,yin,,0,0,0,, 如果是 然后我再检查标识符 \\N{\\fs12}And if it is a photo, then I'm going to check the identifier, \r\nDialogue: 0,0:52:49.14,0:52:51.44,yin,,0,0,0,, 同表格视图一样 如果没有标识符 \\N{\\fs12}same thing with table view, if there's no identifier, \r\nDialogue: 0,0:52:51.44,0:52:54.68,yin,,0,0,0,, 那么如果类是图像视图控制器类 \\N{\\fs12}then if the kind of class, is an image view controller class, \r\nDialogue: 0,0:52:54.68,0:52:57.05,yin,,0,0,0,, 那么我就 segue 到它 \\N{\\fs12}then I'm going to segue to it. \r\nDialogue: 0,0:52:57.05,0:53:00.65,yin,,0,0,0,, 我等下会在 prepareForSegue 中调用这个 \\N{\\fs12}So this, I'm going to call this from prepare for segue in a second. \r\nDialogue: 0,0:53:00.65,0:53:02.77,yin,,0,0,0,, 让我导入图像视图控制器 \\N{\\fs12}Let me go ahead and import image view controller. \r\nDialogue: 0,0:53:07.25,0:53:09.64,yin,,0,0,0,, 这样就不会有警告了 \\N{\\fs12}Just so you don't have the warnings there. \r\nDialogue: 0,0:53:09.64,0:53:12.13,yin,,0,0,0,, 大家都理解这段代码是做什么的了吗 \\N{\\fs12}So, everyone understand what this code does? \r\nDialogue: 0,0:53:12.13,0:53:13.82,yin,,0,0,0,, 出于时间考虑 这里我没有一行行敲 \\N{\\fs12}Well I do the code significance for speed, \r\nDialogue: 0,0:53:13.82,0:53:17.89,yin,,0,0,0,, 但我需要确保你们理解了这里的所有代码 \\N{\\fs12}but I want to make sure you understand all the code that appeared there. \r\nDialogue: 0,0:53:17.89,0:53:21.17,yin,,0,0,0,, 下面我们要做的是 prepareForSegue 这很简单 \\N{\\fs12}Alright, so now we can do the prepare for segue and it's going to be pretty easy. \r\nDialogue: 0,0:53:21.17,0:53:23.81,yin,,0,0,0,,(void) prepareForSegue\\N{\\fs12}So void, prepare for segue. \r\nDialogue: 0,0:53:23.83,0:53:29.59,yin,,0,0,0,,prepareForSegue 中 sender 是那个 MKAnnotationView\\N{\\fs12}And in prepare for segue, the sender is that MK annotation view. \r\nDialogue: 0,0:53:29.59,0:53:32.73,yin,,0,0,0,, 我们从 MKAnnotationView 知道 \\N{\\fs12}Alright? So we know from that MK annotation view \r\nDialogue: 0,0:53:32.73,0:53:33.93,yin,,0,0,0,, 它是哪个 \\N{\\fs12}which thing it is, \r\nDialogue: 0,0:53:33.93,0:53:40.86,yin,,0,0,0,, 这里我只需要说 如果 sender 是一个 MKAnnotationView\\N{\\fs12}so I'm just going to say if the sender is an MK annotation view, \r\nDialogue: 0,0:53:40.86,0:53:44.58,yin,,0,0,0,, 它显然应该是 那么我就 \\N{\\fs12}which it should be, okay, then I'm going \r\nDialogue: 0,0:53:44.58,0:53:47.28,yin,,0,0,0,, 调用上面这里我写的准备代码 \\N{\\fs12}to call this prepare thing, that I did up here, \r\nDialogue: 0,0:53:47.28,0:53:49.23,yin,,0,0,0,, 这个 prepareViewController\\N{\\fs12}this prepare view controller. \r\nDialogue: 0,0:53:49.23,0:53:50.57,yin,,0,0,0,,prepareViewController\\N{\\fs12}Prepare view controller. \r\nDialogue: 0,0:53:50.57,0:53:52.70,yin,,0,0,0,, 这里我要准备的视图控制器是 \\N{\\fs12}And the view controller I'm going to prepare is \r\nDialogue: 0,0:53:52.70,0:53:55.01,yin,,0,0,0,,segue.destinationViewController\\N{\\fs12}segue dot destination view controller. \r\nDialogue: 0,0:53:55.01,0:54:00.72,yin,,0,0,0,,forSegue 这里是 segue 的标识符 \\N{\\fs12}The segue is the segue's identifier. \r\nDialogue: 0,0:54:02.05,0:54:04.92,yin,,0,0,0,, 而我们要显示的 annotation 是什么 \\N{\\fs12}And the annotation we're going to show is what? \r\nDialogue: 0,0:54:04.92,0:54:07.22,yin,,0,0,0,,annotation 是这个 sender\\N{\\fs12}The annotation is this sender, \r\nDialogue: 0,0:54:07.22,0:54:08.72,yin,,0,0,0,, 这是一个 MKAnnotationView\\N{\\fs12}which is an MK annotation view, \r\nDialogue: 0,0:54:08.73,0:54:10.43,yin,,0,0,0,, 这是它的 annotation\\N{\\fs12}it's its annotation, \r\nDialogue: 0,0:54:10.43,0:54:13.15,yin,,0,0,0,,MKAnnotationView 有一个属性叫 annotation\\N{\\fs12}so MK annotation view has a property called annotation, \r\nDialogue: 0,0:54:13.15,0:54:16.19,yin,,0,0,0,, 返回的是 id MKAnnotation\\N{\\fs12}which returns to the ID MK annotation that, \r\nDialogue: 0,0:54:16.19,0:54:17.53,yin,,0,0,0,, 也就是这里我们要的 \\N{\\fs12}which is we want here, \r\nDialogue: 0,0:54:17.53,0:54:19.49,yin,,0,0,0,, 也就是 MKAnnotationView 所显示的 \\N{\\fs12}that that MK annotation view is showing. \r\nDialogue: 0,0:54:19.49,0:54:24.19,yin,,0,0,0,, 因此我这里说 MKAnnotationView sender annotation\\N{\\fs12}So I'm going to say MK annotation view, sender, annotation. \r\nDialogue: 0,0:54:27.77,0:54:28.74,yin,,0,0,0,, 理解吗 \\N{\\fs12}Make sense? \r\nDialogue: 0,0:54:31.55,0:54:36.41,yin,,0,0,0,, 这样我们就能在对话框附属视图被点时执行 segue 了 \\N{\\fs12}So, we make it so we perform the segue, when we call out accessory is tapped, \r\nDialogue: 0,0:54:36.41,0:54:39.32,yin,,0,0,0,, 那个发生时 prepareForSegue 会被调用 \\N{\\fs12}prepare for segue's going to get called when that happens, \r\nDialogue: 0,0:54:39.32,0:54:42.23,yin,,0,0,0,, 我们会调用这个来做实际的准备 \\N{\\fs12}and we're going to call this thing to do the actual preparation, \r\nDialogue: 0,0:54:42.23,0:54:44.32,yin,,0,0,0,, 检查确保我们考虑的是照片 \\N{\\fs12}checking to make sure we're talking about photos, \r\nDialogue: 0,0:54:44.32,0:54:47.45,yin,,0,0,0,, 确保我们 segue 到的是图像视图控制器 \\N{\\fs12}making sure we're segueing into an image view controller. \r\nDialogue: 0,0:54:48.67,0:54:50.45,yin,,0,0,0,, 大家都明白了吗 \\N{\\fs12}Everybody got that? \r\nDialogue: 0,0:54:50.45,0:54:52.54,yin,,0,0,0,, 好 看看这能否工作 \\N{\\fs12}Alright, so let's see if that works. \r\nDialogue: 0,0:54:55.45,0:54:58.35,yin,,0,0,0,, 好 点这个人 \\N{\\fs12}Okay, so let's go to this guy. \r\nDialogue: 0,0:54:58.35,0:55:00.46,yin,,0,0,0,, 在世界地图上拖动 \\N{\\fs12}This is our world traveler here. \r\nDialogue: 0,0:55:00.46,0:55:01.62,yin,,0,0,0,, 点下面这里 \\N{\\fs12}Let's go click down here. \r\nDialogue: 0,0:55:01.62,0:55:03.88,yin,,0,0,0,, 它有这个 这里有很漂亮的图像视图 \\N{\\fs12}It's got this, it's got a nice image view here. \r\nDialogue: 0,0:55:03.88,0:55:06.20,yin,,0,0,0,, 点击这个 这就 segue 了 \\N{\\fs12}Let's try and click on this, and it segues. \r\nDialogue: 0,0:55:07.51,0:55:11.07,yin,,0,0,0,, 这是同原来一样的 segue\\N{\\fs12}And we'll get the exact same kind of segue we got before. \r\nDialogue: 0,0:55:11.07,0:55:13.04,yin,,0,0,0,, 理解了吗 \\N{\\fs12}Make sense? \r\nDialogue: 0,0:55:13.04,0:55:15.09,yin,,0,0,0,, 这方面有问题吗 \\N{\\fs12}Questions about that? \r\nDialogue: 0,0:55:15.09,0:55:18.52,yin,,0,0,0,, 好 这非常棒 体现在 \\N{\\fs12}Alright. So that's really pretty awesome in, you know, \r\nDialogue: 0,0:55:18.52,0:55:21.43,yin,,0,0,0,, 只花了 20-25 分钟的时间 \\N{\\fs12}about 20 minutes, or 25 minutes we were able \r\nDialogue: 0,0:55:21.43,0:55:24.65,yin,,0,0,0,, 我们就将地图能力添加到了 iPhone 版程序 \\N{\\fs12}to add full map capability to our iPhone version. \r\nDialogue: 0,0:55:24.65,0:55:28.13,yin,,0,0,0,,iPad 版又怎么样呢 \\N{\\fs12}But what about our iPad, our iPad version? \r\nDialogue: 0,0:55:28.13,0:55:33.43,yin,,0,0,0,, 让我们把手机关闭 来做 iPad 版 \\N{\\fs12}Let's turn off my phone here, and go do the iPad version. \r\nDialogue: 0,0:55:33.43,0:55:37.91,yin,,0,0,0,,iPad 应该会和这里有所不同 \\N{\\fs12}So the iPad probably wants to be slightly different than this. \r\nDialogue: 0,0:55:37.91,0:55:40.90,yin,,0,0,0,, 不过最开始会非常类似 \\N{\\fs12}Although I'm going to start off having it be very similar. \r\nDialogue: 0,0:55:40.90,0:55:43.31,yin,,0,0,0,,iPad 中 我将删除 \\N{\\fs12}What I'm going to do in the iPad is I'm going to get rid \r\nDialogue: 0,0:55:43.31,0:55:47.11,yin,,0,0,0,, 这个拍照者表格和 PhotosByPhotographer 表格 \\N{\\fs12}of this photographer's table and photos by photographer table. \r\nDialogue: 0,0:55:47.11,0:55:48.61,yin,,0,0,0,, 删除这个后 \\N{\\fs12}So I'm just going to delete that, \r\nDialogue: 0,0:55:48.61,0:55:53.41,yin,,0,0,0,, 我将复制粘贴这里我做的这些 \\N{\\fs12}and I'm going to copy and paste what I just did, here, in this one. \r\nDialogue: 0,0:55:53.41,0:55:57.45,yin,,0,0,0,, 复制 到这里 粘贴 \\N{\\fs12}Copy, over here, paste. \r\nDialogue: 0,0:55:57.45,0:55:59.73,yin,,0,0,0,,control 拖动 \\N{\\fs12}Let's control, drag. \r\nDialogue: 0,0:55:59.73,0:56:00.82,yin,,0,0,0,,push segue\\N{\\fs12}Push segue, \r\nDialogue: 0,0:56:00.82,0:56:04.38,yin,,0,0,0,, 抱歉 这个拆分视图控制器的根视图 \\N{\\fs12}or sorry, root view of this split view controller. \r\nDialogue: 0,0:56:04.38,0:56:06.38,yin,,0,0,0,, 让我们找到所有东西 \\N{\\fs12}Let's go find everything. \r\nDialogue: 0,0:56:06.99,0:56:08.99,yin,,0,0,0,, 腾出更多空间 \\N{\\fs12}Make some more space. \r\nDialogue: 0,0:56:08.99,0:56:10.43,yin,,0,0,0,, 这里 \\N{\\fs12}There it is. \r\nDialogue: 0,0:56:10.43,0:56:12.93,yin,,0,0,0,, 下面我们要和原来做一样的事 \\N{\\fs12}So now we're going to do the exact same thing we did before. \r\nDialogue: 0,0:56:12.93,0:56:15.35,yin,,0,0,0,, 这里有拍照者 这里还会有地图 \\N{\\fs12}We got the photographers here and we're going to have the maps here. \r\nDialogue: 0,0:56:15.35,0:56:18.17,yin,,0,0,0,, 首先看看这是怎样的 \\N{\\fs12}So let's go see what that looks like, at first. \r\nDialogue: 0,0:56:21.60,0:56:23.71,yin,,0,0,0,, 这个能工作吗 \\N{\\fs12}Is this working? \r\nDialogue: 0,0:56:25.49,0:56:29.43,yin,,0,0,0,, 哦 等等 我们需要… 抱歉 \\N{\\fs12}Oh, wait, we're going to have to, sorry. \r\nDialogue: 0,0:56:29.43,0:56:31.49,yin,,0,0,0,, 这里我们需要停下来 \\N{\\fs12}We're going to have to stop here \r\nDialogue: 0,0:56:31.49,0:56:33.65,yin,,0,0,0,, 因为我们会崩溃 \\N{\\fs12}because we are going to crash \r\nDialogue: 0,0:56:33.65,0:56:38.48,yin,,0,0,0,, 因为我们改变了我们的数据库 schema\\N{\\fs12}because we changed our database schema. \r\nDialogue: 0,0:56:38.48,0:56:40.75,yin,,0,0,0,, 删掉这个 \\N{\\fs12}So let's get rid of that. \r\nDialogue: 0,0:56:40.75,0:56:42.51,yin,,0,0,0,, 再次运行 \\N{\\fs12}Run again. \r\nDialogue: 0,0:56:51.78,0:56:54.48,yin,,0,0,0,, 问题是 如果现实世界中 \\N{\\fs12}Okay, so the question is if I were in the real world \r\nDialogue: 0,0:56:54.48,0:56:57.38,yin,,0,0,0,, 我在 App 商店中的 app 改变了 schema\\N{\\fs12}and I had apps on the app store here and I changed my schema \r\nDialogue: 0,0:56:57.38,0:56:59.93,yin,,0,0,0,, 我的用户更新时如何处理这个 \\N{\\fs12}and my users upgrade, how would I handle that? \r\nDialogue: 0,0:56:59.93,0:57:03.45,yin,,0,0,0,, 答案是 我们没有教这个 \\N{\\fs12}And the answer is, and we don't teach this because, you know, \r\nDialogue: 0,0:57:03.45,0:57:05.71,yin,,0,0,0,, 因为时间有限 \\N{\\fs12}you know how it is, time constraints, \r\nDialogue: 0,0:57:05.71,0:57:08.68,yin,,0,0,0,, 实际有一个机制能对 schema 进行版本控制 \\N{\\fs12}but there's actually a mechanism for versioning your schema \r\nDialogue: 0,0:57:08.68,0:57:11.55,yin,,0,0,0,, 然后从之前版本能够自动迁徙 \\N{\\fs12}and then doing auto-migration from previous versions, \r\nDialogue: 0,0:57:11.55,0:57:14.18,yin,,0,0,0,, 从之前版本获得数据 转给新 schema\\N{\\fs12}getting the data out of a previous version to the new schema. \r\nDialogue: 0,0:57:14.18,0:57:16.22,yin,,0,0,0,,schema 需要以一种可兼容的方式进行变化 \\N{\\fs12}So you have to change your schema in a compatible way, \r\nDialogue: 0,0:57:16.22,0:57:17.88,yin,,0,0,0,, 显然 你不希望失去所有用户信息 \\N{\\fs12}obviously you want to keep all your user information, \r\nDialogue: 0,0:57:17.88,0:57:20.39,yin,,0,0,0,, 这种迁徙可以是自动的 \\N{\\fs12}but that migration can be automated. \r\nDialogue: 0,0:57:20.39,0:57:22.87,yin,,0,0,0,, 这非常酷 \\N{\\fs12}So it's pretty cool actually. \r\nDialogue: 0,0:57:22.87,0:57:26.05,yin,,0,0,0,, 具体的可以到 Core Data 说明文档中查看 \\N{\\fs12}So, check it out in the core data documentation, how to do it. \r\nDialogue: 0,0:57:26.05,0:57:29.82,yin,,0,0,0,, 这是我们的拍照者 如果点击一位拍照者 \\N{\\fs12}Alright, so here's our photographers, and if I click on a photographer, \r\nDialogue: 0,0:57:29.82,0:57:32.32,yin,,0,0,0,, 很好 我能得到地图 \\N{\\fs12}then awesome, I get the map. \r\nDialogue: 0,0:57:32.32,0:57:36.46,yin,,0,0,0,, 如果点击这些 它还是能够很好地工作 \\N{\\fs12}And if I click on these, woo, that work, this is just awesome, it works great. \r\nDialogue: 0,0:57:36.46,0:57:38.62,yin,,0,0,0,, 再来尝试展示照片 \\N{\\fs12}Let's try and show the photo. \r\nDialogue: 0,0:57:38.62,0:57:41.14,yin,,0,0,0,, 啊哦 为什么无法工作 \\N{\\fs12}Uh oh. Why doesn't that work? \r\nDialogue: 0,0:57:41.14,0:57:44.53,yin,,0,0,0,, 因为这里在它在执行 segue\\N{\\fs12}Because it's doing perform segue here. \r\nDialogue: 0,0:57:44.53,0:57:46.78,yin,,0,0,0,, 而 iPad 上我们不使用 segue\\N{\\fs12}And we don't use a segue on the iPad, \r\nDialogue: 0,0:57:46.78,0:57:51.75,yin,,0,0,0,, 我们只需要到 detail 中的图像视图控制器直接更新 \\N{\\fs12}we just go find the image view controller in our detail and update it directly, right? \r\nDialogue: 0,0:57:51.75,0:57:56.00,yin,,0,0,0,, 这里对于地图 我们需要和之前处理表格时 \\N{\\fs12}So we have to do the same fix we did when we made this work on, \r\nDialogue: 0,0:57:56.00,0:57:58.16,yin,,0,0,0,, 做相同的修正 \\N{\\fs12}with the tables, we got to do the same thing with the map. \r\nDialogue: 0,0:57:58.16,0:58:02.08,yin,,0,0,0,, 回到我的地图视图控制器 \\N{\\fs12}So, I'm going to go back, back to my map view controller. \r\nDialogue: 0,0:58:02.08,0:58:03.64,yin,,0,0,0,, 这里 \\N{\\fs12}Right here. \r\nDialogue: 0,0:58:03.64,0:58:08.28,yin,,0,0,0,, 我将放一个属性到这里 \\N{\\fs12}And I'm going to put some, I'm going to put a property in here \r\nDialogue: 0,0:58:08.28,0:58:12.94,yin,,0,0,0,, 找到我所处的拆分视图 detail 中的图像视图控制器 \\N{\\fs12}that finds an image view controller in the detail of a split view I'm in, \r\nDialogue: 0,0:58:12.94,0:58:14.44,yin,,0,0,0,, 如果有一个的话 \\N{\\fs12}if there's one there. \r\nDialogue: 0,0:58:14.44,0:58:16.83,yin,,0,0,0,, 调用这个图像视图控制器 \\N{\\fs12}Call this image view controller. \r\nDialogue: 0,0:58:16.83,0:58:19.81,yin,,0,0,0,, 这是我要添加的属性 \\N{\\fs12}And here's the property I'm going to add. \r\nDialogue: 0,0:58:19.81,0:58:22.70,yin,,0,0,0,, 这个属性将为 nil\\N{\\fs12}Right? So this property is going to be nil \r\nDialogue: 0,0:58:22.70,0:58:27.03,yin,,0,0,0,, 如果拆分视图 detail 中不存在图像视图控制器 \\N{\\fs12}if I'm not in a split view controller where my detail is in image view controller. \r\nDialogue: 0,0:58:27.03,0:58:30.32,yin,,0,0,0,, 否则 那就是那个图像视图控制器了 \\N{\\fs12}Right? Otherwise, it's going to be that image view controller. \r\nDialogue: 0,0:58:30.32,0:58:32.83,yin,,0,0,0,, 这段代码在表格视图中有过 记得吧 \\N{\\fs12}Ya'll recognize this code from our table view, right? \r\nDialogue: 0,0:58:32.83,0:58:35.55,yin,,0,0,0,, 拆分视图控制器最后一个对象 这是我们的 detail\\N{\\fs12}Split view controller last object, that's our detail. \r\nDialogue: 0,0:58:35.55,0:58:36.88,yin,,0,0,0,, 如果它处在导航控制器中 \\N{\\fs12}If it's in a navigation controller, \r\nDialogue: 0,0:58:36.88,0:58:39.45,yin,,0,0,0,, 我要看看它是不是根视图控制器 \\N{\\fs12}I'll look in to see if it's the root view controller. \r\nDialogue: 0,0:58:39.45,0:58:43.77,yin,,0,0,0,, 如果它是一个图像视图控制器 我就会返回它 \\N{\\fs12}And then if it's a view controller, an image view controller, I'll return it. \r\nDialogue: 0,0:58:43.77,0:58:45.11,yin,,0,0,0,, 否则 nil\\N{\\fs12}Otherwise nil. \r\nDialogue: 0,0:58:45.11,0:58:46.57,yin,,0,0,0,, 在 iPhone 上 这将是 nil\\N{\\fs12}So on the iPhone this is going to be nil, \r\nDialogue: 0,0:58:46.57,0:58:49.91,yin,,0,0,0,, 因为 iPhone 上不会有拆分视图 \\N{\\fs12}because it can't be a split view on the iPhone anyway, right? \r\nDialogue: 0,0:58:49.91,0:58:51.10,yin,,0,0,0,, 这很酷 \\N{\\fs12}So this is cool. \r\nDialogue: 0,0:58:51.10,0:58:53.92,yin,,0,0,0,, 现在我知道 是否有一个图像视图控制器 \\N{\\fs12}So now I know whether there is an image view controller, \r\nDialogue: 0,0:58:53.92,0:58:57.29,yin,,0,0,0,, 我可以做点什么 例如在我做那个 segue 时 \\N{\\fs12}so I could do something, for example, when I'm doing that segue, \r\nDialogue: 0,0:58:57.29,0:58:58.87,yin,,0,0,0,, 那个 segue 在哪里 \\N{\\fs12}where's that segue? \r\nDialogue: 0,0:58:58.89,0:59:01.02,yin,,0,0,0,, 这里 这个执行 segue\\N{\\fs12}Right here, this perform segue. \r\nDialogue: 0,0:59:01.04,0:59:04.70,yin,,0,0,0,, 我可以说 如果我有一个图像视图控制器 \\N{\\fs12}I could say if I have an image view controller, \r\nDialogue: 0,0:59:04.70,0:59:07.35,yin,,0,0,0,, 那么就直接更新它 \\N{\\fs12}then just update it directly, directly, \r\nDialogue: 0,0:59:07.36,0:59:09.93,yin,,0,0,0,, 否则 你可以尝试这个执行 segue\\N{\\fs12}otherwise, you can try this perform segue. \r\nDialogue: 0,0:59:09.93,0:59:11.85,yin,,0,0,0,, 顺便说下 没有办法 \\N{\\fs12}By the way, there's really no way \r\nDialogue: 0,0:59:11.85,0:59:14.36,yin,,0,0,0,, 在尝试这个执行 segue 时不崩溃 \\N{\\fs12}to try this perform segue without crashing. \r\nDialogue: 0,0:59:14.36,0:59:17.86,yin,,0,0,0,, 你需要知道 你实际在 segue\\N{\\fs12}So you really got to know whether you're actually segueing. \r\nDialogue: 0,0:59:17.86,0:59:20.41,yin,,0,0,0,, 很幸运 如果我有一个图像视图控制器 \\N{\\fs12}Luckily, here, if I have an image view controller around, \r\nDialogue: 0,0:59:20.41,0:59:21.78,yin,,0,0,0,, 我知道我不会是在 segue\\N{\\fs12}I know I'm not going to be segueing, \r\nDialogue: 0,0:59:21.78,0:59:23.87,yin,,0,0,0,, 如果我没有图像视图控制器 \\N{\\fs12}and if I don't have an image view controller around, \r\nDialogue: 0,0:59:23.87,0:59:25.82,yin,,0,0,0,, 我可能就要 segue 了 \\N{\\fs12}I probably do want to be segueing, because I got \r\nDialogue: 0,0:59:25.82,0:59:29.09,yin,,0,0,0,, 因为我需要设法展示照片 如果我要允许 \\N{\\fs12}to show the photos somehow, if I'm going to allow that, the, \r\nDialogue: 0,0:59:29.09,0:59:30.96,yin,,0,0,0,, 那个小按钮在那里 \\N{\\fs12}that little button to be there. \r\nDialogue: 0,0:59:30.96,0:59:32.84,yin,,0,0,0,, 如果我有这个 self.imageViewController\\N{\\fs12}So if I have this self-image view controller here, \r\nDialogue: 0,0:59:32.84,0:59:34.35,yin,,0,0,0,, 我可以准备它 \\N{\\fs12}I can just prepare it. \r\nDialogue: 0,0:59:34.35,0:59:36.11,yin,,0,0,0,, 我要准备控制器 \\N{\\fs12}So we've got this prepare controller, \r\nDialogue: 0,0:59:36.11,0:59:39.89,yin,,0,0,0,, 我要准备图像视图控制器 segue 是 nil\\N{\\fs12}I'm going to prepare the image view controller, segue is nil. \r\nDialogue: 0,0:59:39.89,0:59:43.08,yin,,0,0,0,,annotation 想要显示什么呢 \\N{\\fs12}The annotation, what, where does the annotation want to show, \r\nDialogue: 0,0:59:43.08,0:59:45.56,yin,,0,0,0,, 还是一样 它在这里 \\N{\\fs12}again, it's right here. \r\nDialogue: 0,0:59:45.56,0:59:47.68,yin,,0,0,0,,view.annotation\\N{\\fs12}View dot annotation. \r\nDialogue: 0,0:59:52.35,0:59:53.85,yin,,0,0,0,, 这是这个 \\N{\\fs12}So there's that. \r\nDialogue: 0,0:59:53.85,0:59:56.33,yin,,0,0,0,, 我要准备这个图像视图控制器 如果它在那里 \\N{\\fs12}Okay, so I'm just going to prepare that image view controller if it's there, \r\nDialogue: 0,0:59:56.34,0:59:57.35,yin,,0,0,0,, 否则我们就 segue\\N{\\fs12}otherwise we'll segue. \r\nDialogue: 0,0:59:57.35,0:59:58.51,yin,,0,0,0,, 都理解了吗 \\N{\\fs12}Everyone understand this? \r\nDialogue: 0,0:59:58.51,1:00:00.19,yin,,0,0,0,, 我们来看看这个 \\N{\\fs12}So let's go look at this. \r\nDialogue: 0,1:00:00.19,1:00:01.51,yin,,0,0,0,, 看这个如何工作 \\N{\\fs12}See how this works. \r\nDialogue: 0,1:00:09.64,1:00:11.66,yin,,0,0,0,, 我们还是看看某些照片 \\N{\\fs12}Alright, so let's look at some photos again. \r\nDialogue: 0,1:00:11.66,1:00:16.07,yin,,0,0,0,, 我要找一些照片 像是… 我不知道这里都有谁 \\N{\\fs12}I'll find some photos like, I don't know who we got here, \r\nDialogue: 0,1:00:16.07,1:00:18.76,yin,,0,0,0,, 这个人吧 我们得到这些 \\N{\\fs12}this guy, so we got this. \r\nDialogue: 0,1:00:18.76,1:00:19.88,yin,,0,0,0,, 点这个 \\N{\\fs12}Click this. \r\nDialogue: 0,1:00:19.88,1:00:21.28,yin,,0,0,0,, 我们得到这个 \\N{\\fs12}We got this right here. \r\nDialogue: 0,1:00:21.28,1:00:23.76,yin,,0,0,0,, 点这个小按钮 能行 \\N{\\fs12}If I click this little button, it worked. \r\nDialogue: 0,1:00:25.60,1:00:28.94,yin,,0,0,0,, 它使用了那个东西 如果我到这里别处 \\N{\\fs12}So it uses the thing, if I go over here somewhere else, \r\nDialogue: 0,1:00:28.94,1:00:31.81,yin,,0,0,0,, 我们来选这个 \\N{\\fs12}let's do this guy right here. \r\nDialogue: 0,1:00:31.81,1:00:33.62,yin,,0,0,0,, 注意到这里重叠了 \\N{\\fs12}Notice that overlaps, I don't really \r\nDialogue: 0,1:00:33.62,1:00:37.46,yin,,0,0,0,, 我不大喜欢这个 UI 不过它就是这样了 \\N{\\fs12}like that UI very much, but it is what it is. \r\nDialogue: 0,1:00:37.46,1:00:40.01,yin,,0,0,0,, 这基本上就好了 \\N{\\fs12}So that's kind of okay. \r\nDialogue: 0,1:00:40.01,1:00:44.48,yin,,0,0,0,, 这个 UI 已经不错了 只是还不那么完美 \\N{\\fs12}This is kind of okay, this UI, it's really not that great though because I'm showing \r\nDialogue: 0,1:00:44.48,1:00:47.66,yin,,0,0,0,, 这里我们有个缩略图 我点它 \\N{\\fs12}that little thumb nail there and then I'm, I click on it, \r\nDialogue: 0,1:00:47.66,1:00:49.28,yin,,0,0,0,, 再显示大图 \\N{\\fs12}I'm also showing the big one. \r\nDialogue: 0,1:00:49.28,1:00:51.85,yin,,0,0,0,, 我们干嘛不干脆不要缩略图 \\N{\\fs12}Why don't I just not have a thumb nail, \r\nDialogue: 0,1:00:51.85,1:00:56.49,yin,,0,0,0,, 不要蓝箭头 而是每次点大头针直接显示照片 \\N{\\fs12}not have the little blue arrow, and every time I click on a pin, just show the photo. \r\nDialogue: 0,1:00:56.49,1:00:58.70,yin,,0,0,0,, 没有理由不直接显示照片 \\N{\\fs12}There's no reason not to just show the photo. \r\nDialogue: 0,1:00:58.70,1:00:59.82,yin,,0,0,0,, 怎么做呢 \\N{\\fs12}So how would I do that? \r\nDialogue: 0,1:00:59.82,1:01:01.92,yin,,0,0,0,, 忘掉这个蓝色小箭头吧 \\N{\\fs12}So just forget this whole thing with that little blue arrow, \r\nDialogue: 0,1:01:01.92,1:01:03.71,yin,,0,0,0,, 我们不再需要它 \\N{\\fs12}you don't even need that blue arrow. \r\nDialogue: 0,1:01:03.71,1:01:04.77,yin,,0,0,0,, 让我们这样做 \\N{\\fs12}Let's do that. \r\nDialogue: 0,1:01:04.77,1:01:06.21,yin,,0,0,0,, 到上面这里 \\N{\\fs12}Let's go up here to, \r\nDialogue: 0,1:01:06.21,1:01:09.78,yin,,0,0,0,, 这是我们创建左右附属视图的地方 \\N{\\fs12}this is where we build the left and right accessory views, right here. \r\nDialogue: 0,1:01:09.79,1:01:14.37,yin,,0,0,0,, 这里我说 如果我没有一个图像视图控制器 \\N{\\fs12}So I'm going to say if I don't have an image view controller, \r\nDialogue: 0,1:01:14.37,1:01:17.29,yin,,0,0,0,, 那就把那些对话框放到那里 \\N{\\fs12}then go ahead and put those call outs in there. \r\nDialogue: 0,1:01:18.63,1:01:21.06,yin,,0,0,0,, 否则不要把它们放到那里 \\N{\\fs12}Otherwise don't put them there. \r\nDialogue: 0,1:01:21.06,1:01:24.86,yin,,0,0,0,, 而且 现在对话框不在那里 \\N{\\fs12}And then also, now that the call outs are there, aren't there, \r\nDialogue: 0,1:01:24.86,1:01:26.76,yin,,0,0,0,, 这个永远也不会被调用 \\N{\\fs12}this is never to get called, in here, \r\nDialogue: 0,1:01:26.76,1:01:28.22,yin,,0,0,0,, 因为不会有对话框附属视图 \\N{\\fs12}because there's no call out accessory \r\nDialogue: 0,1:01:28.22,1:01:29.77,yin,,0,0,0,, 如果我有图像视图控制器 \\N{\\fs12}if I have the image view controller. \r\nDialogue: 0,1:01:29.77,1:01:33.03,yin,,0,0,0,, 让我们把这些剪切掉 \\N{\\fs12}So let's go ahead and cut this out of here, \r\nDialogue: 0,1:01:33.03,1:01:36.38,yin,,0,0,0,, 把这些代码放到选择中 \\N{\\fs12}and let's put that code in select. \r\nDialogue: 0,1:01:36.38,1:01:38.36,yin,,0,0,0,, 这是被选择的地方 \\N{\\fs12}So here's where it's selected. \r\nDialogue: 0,1:01:38.36,1:01:42.26,yin,,0,0,0,, 被选择时 我们就要 \\N{\\fs12}So when it's selected, let's go ahead and \r\nDialogue: 0,1:01:43.15,1:01:44.75,yin,,0,0,0,, 视图控制 更高一些 \\N{\\fs12}views control higher, \r\nDialogue: 0,1:01:44.76,1:01:47.21,yin,,0,0,0,, 哦不 这个不行 \\N{\\fs12}woop, nope, that didn't work. \r\nDialogue: 0,1:01:51.17,1:01:52.92,yin,,0,0,0,,control I 好了 \\N{\\fs12}Control I, there we go. \r\nDialogue: 0,1:01:52.92,1:01:55.73,yin,,0,0,0,, 大头针被选中后 当我们点大头针时 \\N{\\fs12}Alright. So when the pin is selected, when we click on the pin, \r\nDialogue: 0,1:01:55.73,1:01:57.94,yin,,0,0,0,, 如果我有一个图像视图控制器 \\N{\\fs12}if I have an image view control around, \r\nDialogue: 0,1:01:57.94,1:01:59.21,yin,,0,0,0,, 我就会准备它 \\N{\\fs12}I'll just prepare it. \r\nDialogue: 0,1:01:59.21,1:02:03.49,yin,,0,0,0,, 否则 我会更新对话框附属视图这些 \\N{\\fs12}Otherwise, I will update the call out accessory views and all \r\nDialogue: 0,1:02:03.49,1:02:07.99,yin,,0,0,0,, 如果有图像视图控制器 这些我就都没有了 \\N{\\fs12}that stuff, which I don't have if I have an image view controller. \r\nDialogue: 0,1:02:07.99,1:02:09.51,yin,,0,0,0,, 看看这是怎样的 \\N{\\fs12}So let's see what this looks like. \r\nDialogue: 0,1:02:17.80,1:02:20.42,yin,,0,0,0,, 好 我们点击这里 \\N{\\fs12}Okay. So, no. Let's click again here. \r\nDialogue: 0,1:02:20.42,1:02:24.21,yin,,0,0,0,, 这里将有多张照片 \\N{\\fs12}And it's going to be a multiple, oops, multiple photo. \r\nDialogue: 0,1:02:24.21,1:02:27.03,yin,,0,0,0,, 我们点击一个 \\N{\\fs12}Okay, so, let's click on one here. \r\nDialogue: 0,1:02:27.03,1:02:31.72,yin,,0,0,0,, 我一点 它就会立刻自动更新图像视图 \\N{\\fs12}Alright, automatically, as soon as I click on it, it's going to update the image view. \r\nDialogue: 0,1:02:33.86,1:02:35.33,yin,,0,0,0,, 这很酷 \\N{\\fs12}So that's kind of cool. \r\nDialogue: 0,1:02:35.33,1:02:38.04,yin,,0,0,0,, 这个 UI 更好 我不再需要缩略图 \\N{\\fs12}That's a nicer UI. I don't really need that thumb nail. \r\nDialogue: 0,1:02:38.04,1:02:42.56,yin,,0,0,0,, 我也不需要其它东西 \\N{\\fs12}I don't need the, the other stuff on there. \r\nDialogue: 0,1:02:42.56,1:02:43.57,yin,,0,0,0,, 这很酷 \\N{\\fs12}So that's cool. \r\nDialogue: 0,1:02:43.57,1:02:46.17,yin,,0,0,0,, 不过这里有一点很奇怪 看这里 \\N{\\fs12}One thing though that's a little weird on it is watch this. \r\nDialogue: 0,1:02:46.17,1:02:49.13,yin,,0,0,0,, 如果我到这里 \\N{\\fs12}So now if I go here. \r\nDialogue: 0,1:02:49.13,1:02:52.49,yin,,0,0,0,, 现在我有了 deadmanjones 的照片 \\N{\\fs12}Now I've got dead man Jones, his photos, \r\nDialogue: 0,1:02:52.49,1:02:54.79,yin,,0,0,0,, 但右边还有别人的照片 \\N{\\fs12}but I've got somebody else's photo on the right. \r\nDialogue: 0,1:02:54.99,1:02:57.75,yin,,0,0,0,, 这很奇怪 这是糟糕的 UI\\N{\\fs12}That's kind of weird. Okay, that's kind of a bad UI. \r\nDialogue: 0,1:02:57.75,1:03:00.86,yin,,0,0,0,, 每次显示某拍照者的照片时 \\N{\\fs12}So let's make it so that every time we show the photos \r\nDialogue: 0,1:03:00.86,1:03:04.04,yin,,0,0,0,, 我们可以自动选一张 \\N{\\fs12}by a photographer, let's just autopick one. \r\nDialogue: 0,1:03:04.04,1:03:05.69,yin,,0,0,0,, 怎么做呢 \\N{\\fs12}How would we do that? \r\nDialogue: 0,1:03:05.69,1:03:06.91,yin,,0,0,0,, 很简单 \\N{\\fs12}Very simple. \r\nDialogue: 0,1:03:06.91,1:03:11.84,yin,,0,0,0,, 在 updateMapViewAnnotations 这里 \\N{\\fs12}When we update our view, map view annotations here, \r\nDialogue: 0,1:03:11.84,1:03:14.71,yin,,0,0,0,, 我只需要自动选择照片 \\N{\\fs12}I'm just going to autoselect a photo. \r\nDialogue: 0,1:03:14.71,1:03:18.51,yin,,0,0,0,, 不过这只在周围有图像视图控制器的前提下才行 \\N{\\fs12}But only in the case where I have an image view controller lying around. \r\nDialogue: 0,1:03:18.51,1:03:22.06,yin,,0,0,0,, 如果周围有图像视图控制器 那我就要自动选照片 \\N{\\fs12}If I have an image view controller lying around, then I'll autoselect a photo. \r\nDialogue: 0,1:03:22.06,1:03:23.51,yin,,0,0,0,, 如何自动选择呢 \\N{\\fs12}And how am I autoselecting? \r\nDialogue: 0,1:03:23.51,1:03:28.61,yin,,0,0,0,, 可以从 PhotosByPhotographer 数组中抓取第一个对象 \\N{\\fs12}Well, I'm just grabbing the first object out of our photos by photographer array. \r\nDialogue: 0,1:03:28.61,1:03:33.20,yin,,0,0,0,, 如果有的话 我将选择那个 annotation\\N{\\fs12}And if there's any in there, then I'm going to select that annotation. \r\nDialogue: 0,1:03:33.20,1:03:36.13,yin,,0,0,0,, 这会让对话框出现 \\N{\\fs12}That causes that call out to appear, but it doesn't, \r\nDialogue: 0,1:03:36.13,1:03:38.47,yin,,0,0,0,, 但选择它时 它不会调用 \\N{\\fs12}when you select it with this, it doesn't call \r\nDialogue: 0,1:03:38.47,1:03:41.65,yin,,0,0,0,, 上面这里的 didSelect 方法 \\N{\\fs12}that did select method up here to get called. \r\nDialogue: 0,1:03:41.65,1:03:46.39,yin,,0,0,0,, 上面这个方法 didSelectAnnotationView\\N{\\fs12}This method, up here, did select annotation view, \r\nDialogue: 0,1:03:46.39,1:03:49.63,yin,,0,0,0,, 这个只在用户选择时才会被调用 \\N{\\fs12}this only gets called when the user selects it. \r\nDialogue: 0,1:03:49.63,1:03:52.26,yin,,0,0,0,, 这里用户没有选择它 我们选择了它 \\N{\\fs12}So the user didn't select it here, we selected it, \r\nDialogue: 0,1:03:52.26,1:03:54.63,yin,,0,0,0,, 这样我们就仍然需要准备自身 \\N{\\fs12}so we still have to do that prepare ourself. \r\nDialogue: 0,1:03:56.55,1:03:58.51,yin,,0,0,0,, 我们来看看这个 \\N{\\fs12}Let's take a look at that. \r\nDialogue: 0,1:04:07.77,1:04:10.34,yin,,0,0,0,, 让我们选某个人 \\N{\\fs12}Alright. So let's pick somebody here. \r\nDialogue: 0,1:04:10.34,1:04:13.34,yin,,0,0,0,, 点这个 摩托车这个是自动选的 \\N{\\fs12}Click on that, and you can see it autoselected the scooter one, \r\nDialogue: 0,1:04:13.34,1:04:16.54,yin,,0,0,0,, 选择别的 到这里 还是自动选择 \\N{\\fs12}I picked something else, we'll go here, it autoselects one. \r\nDialogue: 0,1:04:16.54,1:04:17.99,yin,,0,0,0,, 到这里 还是自动选择 \\N{\\fs12}It goes here and autoselect one. \r\nDialogue: 0,1:04:17.99,1:04:22.51,yin,,0,0,0,, 这样我们就让左右两边保持同步了 \\N{\\fs12}So now we're kind of all in sync between the two, between what's \r\nDialogue: 0,1:04:22.51,1:04:24.42,yin,,0,0,0,, 这样我们就让左右两边保持同步了 \\N{\\fs12}on the right and what's on the left. \r\nDialogue: 0,1:04:24.42,1:04:27.61,yin,,0,0,0,, 点另一个 它就会变化 \\N{\\fs12}But if I click another one, it'll change it. \r\nDialogue: 0,1:04:27.61,1:04:29.22,yin,,0,0,0,, 这个 UI 很不赖 \\N{\\fs12}So that's not a bad UI.\r\nDialogue: 0,1:04:29.25,1:04:30.64,yin,,0,0,0,, 我蛮喜欢它 \\N{\\fs12}I kind of, kind of like it, it's kind of okay, \r\nDialogue: 0,1:04:30.64,1:04:33.88,yin,,0,0,0,, 不过我还打算讲另一种在 iPad 上做这个的方法 \\N{\\fs12}but I'm going to show you another way to do this on the iPad, \r\nDialogue: 0,1:04:33.88,1:04:36.00,yin,,0,0,0,, 给你们展示 embed segue\\N{\\fs12}to show you the embed segues. \r\nDialogue: 0,1:04:36.00,1:04:38.83,yin,,0,0,0,, 有人可能会争辩 是这个 UI 好 还是嵌入那个好 \\N{\\fs12}One could argue whether this is a better UI or the embedded one, \r\nDialogue: 0,1:04:38.83,1:04:40.05,yin,,0,0,0,, 你可以都看看 \\N{\\fs12}you can kind of see them both \r\nDialogue: 0,1:04:40.05,1:04:41.50,yin,,0,0,0,, 自己判断哪个更好 \\N{\\fs12}and you can tell me what you think is better. \r\nDialogue: 0,1:04:41.50,1:04:42.81,yin,,0,0,0,, 这里我打算这样 \\N{\\fs12}But what I'm going to do is, \r\nDialogue: 0,1:04:42.81,1:04:45.64,yin,,0,0,0,, 看到太阳在照片中的什么地方了吗 \\N{\\fs12}you see where the sun is right there, in that photo? \r\nDialogue: 0,1:04:45.64,1:04:48.90,yin,,0,0,0,, 我打算取左侧的地图视图 \\N{\\fs12}I'm actually going to take this map view that's on the left, \r\nDialogue: 0,1:04:48.90,1:04:51.77,yin,,0,0,0,, 把它嵌入到这个图像视图中 \\N{\\fs12}and I'm going to embed it inside this image view. \r\nDialogue: 0,1:04:51.77,1:04:54.18,yin,,0,0,0,, 地图视图会被显示到这里 \\N{\\fs12}So this map view is going to showing there, \r\nDialogue: 0,1:04:54.19,1:04:57.61,yin,,0,0,0,, 这一栏我们将只会看到拍照者 \\N{\\fs12}and so what we're going to see in this column is just the photographers, \r\nDialogue: 0,1:04:57.61,1:04:59.31,yin,,0,0,0,, 这些会是拍照者 \\N{\\fs12}these will be photographers. \r\nDialogue: 0,1:04:59.31,1:05:00.78,yin,,0,0,0,, 太阳所在的地方 \\N{\\fs12}Embedded where the sun is \r\nDialogue: 0,1:05:00.78,1:05:03.15,yin,,0,0,0,, 将嵌入我们选择的拍照者所对应的地图 \\N{\\fs12}will be the map for whatever photographer we choose \r\nDialogue: 0,1:05:03.15,1:05:04.43,yin,,0,0,0,, 然后是我们的照片 \\N{\\fs12}and then we'll have our photo, \r\nDialogue: 0,1:05:04.43,1:05:06.70,yin,,0,0,0,, 我们还是能缩放和拖动 \\N{\\fs12}and we'll still be able to zoom in our photos, zoom around, \r\nDialogue: 0,1:05:06.70,1:05:10.15,yin,,0,0,0,, 地图会在照片上 不过我们可以加一个按钮 \\N{\\fs12}it'll be occluded, right? It'll be covered up, although maybe we could add a button \r\nDialogue: 0,1:05:10.15,1:05:12.11,yin,,0,0,0,, 方便隐藏地图或是重新显示 \\N{\\fs12}somewhere that would hide that map and reshow it, \r\nDialogue: 0,1:05:12.11,1:05:14.51,yin,,0,0,0,, 放到 URL 旁边 因为那个地图 \\N{\\fs12}a little bar next to the URL, because that map, \r\nDialogue: 0,1:05:14.51,1:05:17.49,yin,,0,0,0,, 只是一个 UIView 我们可以隐藏它 \\N{\\fs12}it's just going to be a UI view, in there, we can hide, \r\nDialogue: 0,1:05:17.49,1:05:20.96,yin,,0,0,0,, 设置它为.hidden 我们可以采用动画 透明度 \\N{\\fs12}set it to dot hidden, we could animate it, transparency, \r\nDialogue: 0,1:05:20.96,1:05:24.08,yin,,0,0,0,, 淡出 怎么做都行 因为它只是 UIView\\N{\\fs12}fading away, whatever we wanted to do because it's just going to be UI view. \r\nDialogue: 0,1:05:24.08,1:05:26.47,yin,,0,0,0,, 但那个 UIView 的内容 \\N{\\fs12}But the contents of that UI view are going \r\nDialogue: 0,1:05:26.47,1:05:30.84,yin,,0,0,0,, 将同这个地图视图中的内容完全相同 \\N{\\fs12}to be the same contents that are in this map view over here, exactly the same. \r\nDialogue: 0,1:05:30.84,1:05:33.28,yin,,0,0,0,, 我将使用完全相同的视图控制器 \\N{\\fs12}I'm going to use that exact same view controller. \r\nDialogue: 0,1:05:33.28,1:05:37.67,yin,,0,0,0,, 这里我们说的还是视图控制器再利用 \\N{\\fs12}And this is, again, we're talking about view controller reuse. \r\nDialogue: 0,1:05:37.67,1:05:39.48,yin,,0,0,0,, 我们来做这个 \\N{\\fs12}So, let's go ahead and do that. \r\nDialogue: 0,1:05:39.48,1:05:42.82,yin,,0,0,0,, 顺便说下 代码中有一个警告在这里 \\N{\\fs12}By the way, we noticed we have warnings back in the code here. \r\nDialogue: 0,1:05:42.82,1:05:44.23,yin,,0,0,0,, 为什么会有警告呢 \\N{\\fs12}Why do we have this warning? \r\nDialogue: 0,1:05:44.23,1:05:47.78,yin,,0,0,0,, 因为自动选择的照片是一个 Photo *\\N{\\fs12}That's because autoselected photo is a photo star, \r\nDialogue: 0,1:05:47.78,1:05:52.16,yin,,0,0,0,, 我们没有导入任何东西来告诉这段代码 \\N{\\fs12}and we don't import anything here that tells this code \r\nDialogue: 0,1:05:52.16,1:05:55.05,yin,,0,0,0,,Photo * 是 MKAnnotation\\N{\\fs12}that a photo star is an MK annotation. \r\nDialogue: 0,1:05:55.05,1:05:58.27,yin,,0,0,0,, 因此 上面这里导入 Photo 的地方 \\N{\\fs12}So we have to go up here to where we import a photo, \r\nDialogue: 0,1:05:58.27,1:06:03.24,yin,,0,0,0,, 需要改成导入 Photo+Annotation\\N{\\fs12}and instead import photo plus MK, or sorry, plus annotation. \r\nDialogue: 0,1:06:03.24,1:06:05.52,yin,,0,0,0,, 因为这个才是 \\N{\\fs12}Because this is where, this is the file \r\nDialogue: 0,1:06:05.52,1:06:11.02,yin,,0,0,0,, 我们声明 Photo 是 MKAnnotation 的文件 \\N{\\fs12}in which we declared that photos were MK annotations. \r\nDialogue: 0,1:06:11.02,1:06:12.59,yin,,0,0,0,, 大家理解吗 \\N{\\fs12}Everyone understand that? \r\nDialogue: 0,1:06:12.59,1:06:17.98,yin,,0,0,0,, 你需要导入定义了这个的接口 \\N{\\fs12}Okay, so you got to make sure you import whichever interface defines that. \r\nDialogue: 0,1:06:18.98,1:06:21.54,yin,,0,0,0,, 好 如何做这个嵌入的东西呢 \\N{\\fs12}Okay. So how are we going to do this embed thing? \r\nDialogue: 0,1:06:21.54,1:06:25.31,yin,,0,0,0,, 来到这里的 iPad 故事板 \\N{\\fs12}Let's go over here to our iPad, storyboard, all I'm going to do \r\nDialogue: 0,1:06:25.31,1:06:30.29,yin,,0,0,0,, 我首先只需要拖动嵌入的东西到这里 \\N{\\fs12}to start is to drag an embedded thing in here, so let's do that. \r\nDialogue: 0,1:06:30.29,1:06:33.76,yin,,0,0,0,, 屏幕空间有限 这是相当大的挑战 \\N{\\fs12}This is a bit of a challenge when it comes to screen real estates. \r\nDialogue: 0,1:06:33.76,1:06:34.93,yin,,0,0,0,, 到这里 \\N{\\fs12}Let's go here. \r\nDialogue: 0,1:06:34.93,1:06:37.81,yin,,0,0,0,, 嵌入的东西在很下面这里 \\N{\\fs12}So the embedded thing, it's down towards the bottom, here it is right here. \r\nDialogue: 0,1:06:37.81,1:06:40.39,yin,,0,0,0,, 这里说是容器视图 定义了一个视图控制器区域 \\N{\\fs12}You see it says container view defines a region of view controller \r\nDialogue: 0,1:06:40.39,1:06:43.85,yin,,0,0,0,, 能够包含一个子视图控制器 \\N{\\fs12}that can include a child view controller. \r\nDialogue: 0,1:06:43.85,1:06:47.45,yin,,0,0,0,, 我要把它拖入到这里的视图控制器中 \\N{\\fs12}So I'm going to drag that into this view controller right here, \r\nDialogue: 0,1:06:47.45,1:06:49.83,yin,,0,0,0,, 这是我们的图像视图控制器 \\N{\\fs12}this is our image view controller, \r\nDialogue: 0,1:06:49.83,1:06:51.12,yin,,0,0,0,, 拖入进来 \\N{\\fs12}so let's drag that in. \r\nDialogue: 0,1:06:51.12,1:06:54.33,yin,,0,0,0,, 拖入进来后 我们不大方便 \\N{\\fs12}Now when you drag this in, it's a bit of a pain in the neck \r\nDialogue: 0,1:06:54.33,1:06:57.68,yin,,0,0,0,, 设置大小和位置这些 \\N{\\fs12}to size this to where you want and all those things, \r\nDialogue: 0,1:06:57.68,1:06:59.29,yin,,0,0,0,, 不过我会展示另一种方式 \\N{\\fs12}but I'll show you another way, \r\nDialogue: 0,1:06:59.29,1:07:02.04,yin,,0,0,0,, 当你有一个这样的大视图 你要拖入 \\N{\\fs12}when you have a big view like that, that you're dragging in \r\nDialogue: 0,1:07:02.04,1:07:04.11,yin,,0,0,0,, 你希望把它放到什么地方 \\N{\\fs12}and you want to place it somewhere to do it, \r\nDialogue: 0,1:07:04.11,1:07:06.26,yin,,0,0,0,, 你可以使用文档大纲 \\N{\\fs12}which is use the document online. \r\nDialogue: 0,1:07:06.26,1:07:08.56,yin,,0,0,0,, 这是文档大纲 这是我的容器 \\N{\\fs12}So here's the document outline, here's my container. \r\nDialogue: 0,1:07:08.56,1:07:11.21,yin,,0,0,0,, 注意到 它是作为滚动视图的子视图添加的 \\N{\\fs12}Notice it added it as a subview of my scroll view, \r\nDialogue: 0,1:07:11.21,1:07:13.70,yin,,0,0,0,, 我不希望地图到处滚动 我希望它 \\N{\\fs12}but I don't want to scroll that map around, I want it to sit \r\nDialogue: 0,1:07:13.70,1:07:15.74,yin,,0,0,0,, 定在滚动视图的顶部 \\N{\\fs12}on top of the scroll view, \r\nDialogue: 0,1:07:15.74,1:07:18.76,yin,,0,0,0,, 我希望滚动视图在后面 然后是容器视图 \\N{\\fs12}I actually want the scroll view in the back, and then the container view, \r\nDialogue: 0,1:07:18.76,1:07:20.24,yin,,0,0,0,, 然后再做活动指示器 \\N{\\fs12}and then we can do our activity indicator. \r\nDialogue: 0,1:07:20.24,1:07:25.08,yin,,0,0,0,, 这是我可以做的一件事 也就是把它移出滚动视图 \\N{\\fs12}So that's one thing I can do is move it out from being a scroll view. \r\nDialogue: 0,1:07:25.08,1:07:26.48,yin,,0,0,0,, 有没人能想到 \\N{\\fs12}And can anyone think of a way \r\nDialogue: 0,1:07:26.48,1:07:30.01,yin,,0,0,0,, 如何把这个容器放到我想要的地方 \\N{\\fs12}that I can place this container where I want? \r\nDialogue: 0,1:07:30.01,1:07:32.14,yin,,0,0,0,, 一个单词 用 A 开头 \\N{\\fs12}Magic word, begins with an A? \r\nDialogue: 0,1:07:33.88,1:07:35.70,yin,,0,0,0,, 下面这里 \\N{\\fs12}Down here? \r\nDialogue: 0,1:07:35.70,1:07:38.68,yin,,0,0,0,, 对 我们可以使用自动布局 \\N{\\fs12}Yes, we can use autolayout. \r\nDialogue: 0,1:07:38.68,1:07:40.82,yin,,0,0,0,, 指定我们要的东西 \\N{\\fs12}Right? To specify exactly what we want. \r\nDialogue: 0,1:07:40.82,1:07:42.23,yin,,0,0,0,, 修正它的宽度和高度 \\N{\\fs12}So let's fix its width and height. \r\nDialogue: 0,1:07:42.23,1:07:45.34,yin,,0,0,0,, 这里我们需要一些固定的宽度和高度数字 \\N{\\fs12}This is a case where we would want some magic numbers of width \r\nDialogue: 0,1:07:45.34,1:07:47.49,yin,,0,0,0,, 因为我们需要确定 \\N{\\fs12}and height, because we want to kind of decide how much \r\nDialogue: 0,1:07:47.49,1:07:50.34,yin,,0,0,0,, 视图遮住地图上多大的区域 \\N{\\fs12}of that view we want to occlude with the map, \r\nDialogue: 0,1:07:50.34,1:07:53.77,yin,,0,0,0,, 相对值是多少 然后我们还要把它固定在顶部 \\N{\\fs12}what the relative value is, and then let's also pin it to the top, \r\nDialogue: 0,1:07:53.77,1:07:57.91,yin,,0,0,0,, 通过标准值 然后这边再固定到右边 \\N{\\fs12}by the standard value, and then let's pin it over here to the right, \r\nDialogue: 0,1:07:57.91,1:08:00.27,yin,,0,0,0,, 这就把它放到了右上角 \\N{\\fs12}so we're going to put it in the upper right-hand corner. \r\nDialogue: 0,1:08:00.27,1:08:03.12,yin,,0,0,0,, 先看看这是怎样的 \\N{\\fs12}And let's see what that looks like, first of all, \r\nDialogue: 0,1:08:03.12,1:08:05.51,yin,,0,0,0,, 注意这里有个黄色的小东西 \\N{\\fs12}and notice we have the little yellow thing here. \r\nDialogue: 0,1:08:05.51,1:08:09.82,yin,,0,0,0,, 因为我们错放了视图 我来修正一下这个错位 \\N{\\fs12}Because we have a misplaced view, and so I'm going to go ahead and fix that misplacement. \r\nDialogue: 0,1:08:09.82,1:08:11.50,yin,,0,0,0,, 下面来看这是怎样的 \\N{\\fs12}And now let's go look and see how this looks like. \r\nDialogue: 0,1:08:11.50,1:08:15.13,yin,,0,0,0,, 这同我要的还有点差距 因为这里 \\N{\\fs12}Eh, it just doesn't quite look like I want, because it's \r\nDialogue: 0,1:08:15.13,1:08:18.57,yin,,0,0,0,, 它在这个栏下面 我不想要这样 \\N{\\fs12}under this bar, I don't really want it under this bar, \r\nDialogue: 0,1:08:18.57,1:08:21.75,yin,,0,0,0,, 离顶部是标准宽度 不过却在栏下面 \\N{\\fs12}so it's a standard width from the top, but under this bar. \r\nDialogue: 0,1:08:21.75,1:08:24.54,yin,,0,0,0,, 顺便说下 控制这些东西在不在栏下面 \\N{\\fs12}The way you can, by the way, control whether things are under the bar \r\nDialogue: 0,1:08:24.54,1:08:27.52,yin,,0,0,0,, 可以选择整个控制器 进入检查器 \\N{\\fs12}is select your whole controller and inspect it. \r\nDialogue: 0,1:08:27.52,1:08:31.02,yin,,0,0,0,, 下面这里可以看到扩展边缘 \\N{\\fs12}And you'll see down here, there's extend edges. \r\nDialogue: 0,1:08:31.02,1:08:33.43,yin,,0,0,0,, 这里我可以把在顶栏下的勾勾去掉 \\N{\\fs12}So if I say under top bars, no, \r\nDialogue: 0,1:08:33.43,1:08:35.28,yin,,0,0,0,, 这时 容器就可以移下来了 \\N{\\fs12}then it moves that container down. \r\nDialogue: 0,1:08:35.28,1:08:37.29,yin,,0,0,0,, 这里创建了一些自动布局的东西 \\N{\\fs12}Now that created some autolayout things, \r\nDialogue: 0,1:08:37.29,1:08:41.61,yin,,0,0,0,, 对这个小转轮和这个都是如此 我们修正一下 \\N{\\fs12}both for this little spinner guy and this, so let's fix those. \r\nDialogue: 0,1:08:41.61,1:08:43.23,yin,,0,0,0,, 因为一切都往下移了一些 \\N{\\fs12}Right? Because we moved everything down a little bit, \r\nDialogue: 0,1:08:43.23,1:08:47.20,yin,,0,0,0,, 这些需要被放回到应该的相对位置 \\N{\\fs12}so those need to be put back relatively to where they should be. \r\nDialogue: 0,1:08:47.20,1:08:48.60,yin,,0,0,0,, 这是这个的做法 \\N{\\fs12}So that's a way to do it. Now, of course, \r\nDialogue: 0,1:08:48.61,1:08:50.34,yin,,0,0,0,, 显然 图像视图不在这下面 \\N{\\fs12}now the image view is not under there, \r\nDialogue: 0,1:08:50.34,1:08:52.33,yin,,0,0,0,, 我可能希望一者 而非另一者 \\N{\\fs12}and I might want one and not the other, \r\nDialogue: 0,1:08:52.33,1:08:55.17,yin,,0,0,0,, 我们当然可以按自己的想法设置自动布局约束 \\N{\\fs12}and we can certainly set our autolayouts constraints to whatever we want, \r\nDialogue: 0,1:08:55.17,1:08:57.06,yin,,0,0,0,, 这里我只想演示这个扩展边缘的东西 \\N{\\fs12}but I just wanted to show you this extend edges thing. \r\nDialogue: 0,1:08:57.06,1:09:00.64,yin,,0,0,0,, 有些人之前在做作业时就发现了这个 \\N{\\fs12}Some of you discovered this when you were doing your homework before. \r\nDialogue: 0,1:09:02.05,1:09:05.30,yin,,0,0,0,, 好 通过所有这些 \\N{\\fs12}So, okay. One thing that happened through all of this, \r\nDialogue: 0,1:09:05.30,1:09:09.28,yin,,0,0,0,, 我们的得到了这个容器 我们还需要指定 \\N{\\fs12}we got this container, is we have to specify \r\nDialogue: 0,1:09:09.28,1:09:10.94,yin,,0,0,0,, 容器中有些什么 \\N{\\fs12}what's in this container, \r\nDialogue: 0,1:09:10.94,1:09:14.01,yin,,0,0,0,, 它实际会把某个东西放到这里 \\N{\\fs12}and it actually put something on here. \r\nDialogue: 0,1:09:14.01,1:09:16.56,yin,,0,0,0,, 很难看到 移下来一些 \\N{\\fs12}It's hard to see, let's move it down. \r\nDialogue: 0,1:09:16.56,1:09:19.37,yin,,0,0,0,, 这是一个通用 UIViewController\\N{\\fs12}It actually put this, this is a generic UI view controller, \r\nDialogue: 0,1:09:19.37,1:09:21.95,yin,,0,0,0,, 在检查器中 可以看到它是通用 UIViewController\\N{\\fs12}if we inspect it, you can see it's a generic UI view controller. \r\nDialogue: 0,1:09:21.95,1:09:25.46,yin,,0,0,0,, 这个视图控制器的 self.view 会出现在这里 \\N{\\fs12}So this view controller, self dot view, is going to appear in here. \r\nDialogue: 0,1:09:25.46,1:09:28.47,yin,,0,0,0,, 但我不希望这个视图控制器的 self.view 在这里 \\N{\\fs12}But I don't want this view controller, self dot view, in here. \r\nDialogue: 0,1:09:28.47,1:09:30.07,yin,,0,0,0,, 我打算删掉这个 \\N{\\fs12}So I'm going to delete that. \r\nDialogue: 0,1:09:30.07,1:09:33.51,yin,,0,0,0,, 我想要这个视图控制器的 self.view\\N{\\fs12}Instead, I want this view controller's self dot view, \r\nDialogue: 0,1:09:33.51,1:09:36.18,yin,,0,0,0,, 地图视图控制器 对吧 \\N{\\fs12}the map view controller, right? \r\nDialogue: 0,1:09:36.18,1:09:37.41,yin,,0,0,0,, 怎么做呢 \\N{\\fs12}So how do I do that? \r\nDialogue: 0,1:09:37.41,1:09:38.62,yin,,0,0,0,, 这是一个 segue\\N{\\fs12}This is a segue, \r\nDialogue: 0,1:09:38.62,1:09:40.16,yin,,0,0,0,,control 拖动 \\N{\\fs12}control, drag. \r\nDialogue: 0,1:09:40.16,1:09:43.34,yin,,0,0,0,, 从容器 control 拖动到这里 \\N{\\fs12}So I'm control, dragging from the container to here, \r\nDialogue: 0,1:09:43.34,1:09:44.92,yin,,0,0,0,, 唯一的选项是嵌入 \\N{\\fs12}only option I'm going to have is embed, \r\nDialogue: 0,1:09:44.92,1:09:47.04,yin,,0,0,0,, 因为来自这个容器 \\N{\\fs12}because the source of this is the container, \r\nDialogue: 0,1:09:47.04,1:09:49.25,yin,,0,0,0,, 这样我就把那个嵌入到了这里 \\N{\\fs12}and now I've embedded that in there. \r\nDialogue: 0,1:09:49.25,1:09:52.56,yin,,0,0,0,, 我不再需要这个 segue\\N{\\fs12}I don't want this segue anymore, \r\nDialogue: 0,1:09:52.56,1:09:54.72,yin,,0,0,0,, 因为在选择拍照者时 \\N{\\fs12}because I don't want when, I choose the photographer, \r\nDialogue: 0,1:09:54.72,1:09:57.62,yin,,0,0,0,, 我不希望加载这个表格 我们删掉它 \\N{\\fs12}I don't want to load this table up, so let's get rid of that. \r\nDialogue: 0,1:09:57.62,1:10:02.42,yin,,0,0,0,, 现在我们有了这个 让我们把它移下来 \\N{\\fs12}And so now, we have this here, let's move it down again. \r\nDialogue: 0,1:10:02.85,1:10:07.39,yin,,0,0,0,, 这个 PhotosByPhotographer 地图视图将出现在这里面 \\N{\\fs12}So this photos by photographer map view is going to appear inside here. \r\nDialogue: 0,1:10:07.39,1:10:10.06,yin,,0,0,0,, 这是一个 segue\\N{\\fs12}Now this is a segue, okay, \r\nDialogue: 0,1:10:10.06,1:10:13.43,yin,,0,0,0,, 或许我们可以称这个为 Embed Map\\N{\\fs12}maybe we would call this embed map \r\nDialogue: 0,1:10:13.43,1:10:15.91,yin,,0,0,0,, 诸如此类 因为这就是 segue 的作用 \\N{\\fs12}or something like that, because that's what this segue does. \r\nDialogue: 0,1:10:15.91,1:10:19.41,yin,,0,0,0,, 这个 segue 需要准备 同其它 segue 一样 \\N{\\fs12}This segue has to be prepared, just like any other segue, \r\nDialogue: 0,1:10:19.41,1:10:20.92,yin,,0,0,0,, 这是一个常规的 segue\\N{\\fs12}this is a normal segue. \r\nDialogue: 0,1:10:20.94,1:10:22.72,yin,,0,0,0,, 谁来做准备呢 \\N{\\fs12}Who's going to do the preparing? \r\nDialogue: 0,1:10:22.72,1:10:26.59,yin,,0,0,0,, 做准备的是这个会嵌入到的视图控制器 \\N{\\fs12}Well, it's the view controller into which this is embedded. \r\nDialogue: 0,1:10:26.59,1:10:28.98,yin,,0,0,0,, 也就是这个 \\N{\\fs12}That is this. \r\nDialogue: 0,1:10:28.98,1:10:31.77,yin,,0,0,0,, 这是一个图像视图控制器 \\N{\\fs12}Which is an image view controller. \r\nDialogue: 0,1:10:31.77,1:10:35.41,yin,,0,0,0,, 这个 PhotosByPhotographer 需要如何准备呢 \\N{\\fs12}How does this photos by photographer need to be prepared? \r\nDialogue: 0,1:10:35.41,1:10:38.45,yin,,0,0,0,, 它需要拍照者 \\N{\\fs12}It needs the photographer, right? \r\nDialogue: 0,1:10:38.45,1:10:42.39,yin,,0,0,0,, 这是它的公共 API 提醒一下你们 这里 \\N{\\fs12}That's its public API, just to remind you, over here, \r\nDialogue: 0,1:10:42.39,1:10:44.44,yin,,0,0,0,,PhotosByPhotographerMapViewController\\N{\\fs12}photos by photographer map view controller, \r\nDialogue: 0,1:10:44.44,1:10:45.75,yin,,0,0,0,, 需要一个拍照者 \\N{\\fs12}needs a photographer. \r\nDialogue: 0,1:10:45.75,1:10:48.38,yin,,0,0,0,, 准备时 我们需要传入拍照者 \\N{\\fs12}So if we're going to prepare it, we need to pass the photographer. \r\nDialogue: 0,1:10:48.38,1:10:52.73,yin,,0,0,0,, 这是一个问题 因为这个图像视图没有拍照者 \\N{\\fs12}Well, that's a problem, because this image view doesn't have the photographer. \r\nDialogue: 0,1:10:52.73,1:10:55.43,yin,,0,0,0,, 图像视图只有图像 \\N{\\fs12}All the image view has is the image. \r\nDialogue: 0,1:10:55.43,1:10:59.63,yin,,0,0,0,, 因此 我们需要创建一个图像视图控制器的子类 \\N{\\fs12}So we're going to have to create a little subclass of image view controller, \r\nDialogue: 0,1:10:59.63,1:11:02.92,yin,,0,0,0,, 命名为 PhotosByPhotographerImageViewController\\N{\\fs12}which I'm going to call photos by photographer, image view controller, \r\nDialogue: 0,1:11:02.92,1:11:05.82,yin,,0,0,0,, 它会将拍照者传过来 \\N{\\fs12}and it's going to pass the photographer on through. \r\nDialogue: 0,1:11:06.66,1:11:08.66,yin,,0,0,0,, 我们将 segue 到它 \\N{\\fs12}So we're going to segue to it, \r\nDialogue: 0,1:11:08.66,1:11:11.62,yin,,0,0,0,, 就像我们已经 segue… 这其实并不是真正的 segue\\N{\\fs12}like we are already segueing, it's not really segueing, \r\nDialogue: 0,1:11:11.62,1:11:14.17,yin,,0,0,0,, 不过我们在设置这个 detail 视图控制器 \\N{\\fs12}but we're setting this detail view controller, \r\nDialogue: 0,1:11:14.17,1:11:16.38,yin,,0,0,0,, 我们已经准备好了 \\N{\\fs12}we're preparing already, \r\nDialogue: 0,1:11:16.38,1:11:20.68,yin,,0,0,0,, 不过准备需要用到这个拍照者 \\N{\\fs12}but we're going to have to prepare it with this photographers. \r\nDialogue: 0,1:11:20.68,1:11:24.23,yin,,0,0,0,, 让我们创建这个控制器的子类 \\N{\\fs12}So let's create that subclass with this controller. \r\nDialogue: 0,1:11:25.02,1:11:29.22,yin,,0,0,0,, 它是图像视图控制器的子类 \\N{\\fs12}Okay. It's a subclass of image view controller, \r\nDialogue: 0,1:11:29.23,1:11:35.57,yin,,0,0,0,, 名为 PhotosByPhotographerImageViewController\\N{\\fs12}we're going to call it photos by photographer image view controller. \r\nDialogue: 0,1:11:35.57,1:11:39.14,yin,,0,0,0,, 同其它控制器放到一起 \\N{\\fs12}Okay. We'll put it with our controllers. \r\nDialogue: 0,1:11:39.14,1:11:43.74,yin,,0,0,0,, 现在仅在 iPad 中 我将修改这个 \\N{\\fs12}Now in the iPad only, I'm going to change this \r\nDialogue: 0,1:11:43.74,1:11:45.83,yin,,0,0,0,, 让它不再是图像视图控制器 \\N{\\fs12}to not be an image view controller anymore, \r\nDialogue: 0,1:11:45.83,1:11:50.93,yin,,0,0,0,, 而是 PhotosByPhotographerImageViewController\\N{\\fs12}I'm going to change it to be a photos by photographer image view controller. \r\nDialogue: 0,1:11:50.93,1:11:53.71,yin,,0,0,0,, 现在 它是 PhotosByPhotographerImageViewController\\N{\\fs12}So now it's a photo by photographer image view controller, \r\nDialogue: 0,1:11:53.71,1:11:54.78,yin,,0,0,0,, 也就是这个 \\N{\\fs12}which is this thing. \r\nDialogue: 0,1:11:54.78,1:11:57.72,yin,,0,0,0,, 这个的公共 API 还是和 \\N{\\fs12}The public API of this, again, it's the same \r\nDialogue: 0,1:11:57.72,1:12:00.97,yin,,0,0,0,, 所有其它 PhotosByPhotographer 一样 也就是这个 \\N{\\fs12}as all these other photos by photographer, it's this, \r\nDialogue: 0,1:12:00.97,1:12:05.53,yin,,0,0,0,, 看这个 复制这个 粘贴过来 \\N{\\fs12}actually watch this, we'll copy this, and we'll paste that, \r\nDialogue: 0,1:12:05.53,1:12:09.88,yin,,0,0,0,, 放到这里 放到这里 删掉这个 \\N{\\fs12}put that there, put that there, get rid of that, \r\nDialogue: 0,1:12:09.88,1:12:11.84,yin,,0,0,0,, 这样就可以了 \\N{\\fs12}see it going back and forth too much. \r\nDialogue: 0,1:12:11.84,1:12:14.65,yin,,0,0,0,, 它有一个拍照者 它是一个 PhotosByPhotographer\\N{\\fs12}So it has a photographer, it's a photos by photographer,\r\nDialogue: 0,1:12:14.65,1:12:17.58,yin,,0,0,0,, 不过这是一个图像视图控制器 因此它有一个拍照者 \\N{\\fs12}but this is an image view controller, so it has a photographer. \r\nDialogue: 0,1:12:17.58,1:12:19.60,yin,,0,0,0,, 它在获得拍照者时会做什么呢 \\N{\\fs12}What does it do when it gets the photographer? \r\nDialogue: 0,1:12:19.60,1:12:21.37,yin,,0,0,0,, 我们来看看 \\N{\\fs12}Well let's look at that. \r\nDialogue: 0,1:12:21.37,1:12:25.29,yin,,0,0,0,, 实际上 在看这个之前 我们先谈谈那个 embed segue\\N{\\fs12}In fact, before we even look at that, let's talk about that embed segue and, \r\nDialogue: 0,1:12:25.29,1:12:26.73,yin,,0,0,0,, 并为它做好准备 \\N{\\fs12}and having it prepare. \r\nDialogue: 0,1:12:26.73,1:12:30.28,yin,,0,0,0,, 代码在这里 我们可以看看 \\N{\\fs12}So I got that code here so we can look at it. \r\nDialogue: 0,1:12:31.86,1:12:35.38,yin,,0,0,0,, 放到这上面 马上我就会讲到 \\N{\\fs12}I'm going to put this up here, talk about all this in a second here, \r\nDialogue: 0,1:12:35.38,1:12:40.61,yin,,0,0,0,, 导入 PhotosByPhotographerMapViewController\\N{\\fs12}and I'm going to import photos by photographer map view controller. \r\nDialogue: 0,1:12:40.61,1:12:42.27,yin,,0,0,0,, 我们来看看这段代码 \\N{\\fs12}Alright, so let's look at this code that comes in. \r\nDialogue: 0,1:12:42.27,1:12:45.52,yin,,0,0,0,, 这是 PhotosByPhotographerImageViewController\\N{\\fs12}So this is photos by photographer image view controller. \r\nDialogue: 0,1:12:45.52,1:12:49.72,yin,,0,0,0,, 它现在正尝试处理那个嵌入的准备 \\N{\\fs12}It is, right now, trying to handle preparing that embed. \r\nDialogue: 0,1:12:49.72,1:12:51.96,yin,,0,0,0,, 它准备的是这个 segue\\N{\\fs12}So it's preparing this segue right here. \r\nDialogue: 0,1:12:51.96,1:12:54.36,yin,,0,0,0,, 它在对这个 segue 做准备 \\N{\\fs12}Its doing the prepare on this segue. \r\nDialogue: 0,1:12:54.36,1:12:56.15,yin,,0,0,0,, 如何做到的呢 \\N{\\fs12}How is it doing that? \r\nDialogue: 0,1:12:56.15,1:12:58.90,yin,,0,0,0,, 它会去检查 \\N{\\fs12}Well, it's looking to see \r\nDialogue: 0,1:12:58.90,1:13:00.98,yin,,0,0,0,, 目标视图控制器是不是 \\N{\\fs12}if the destination view controller \r\nDialogue: 0,1:13:00.98,1:13:03.18,yin,,0,0,0,,PhotosByPhotographerMapViewController\\N{\\fs12}is a photos by photographer map view controller, \r\nDialogue: 0,1:13:03.18,1:13:05.52,yin,,0,0,0,, 这里应该是 因为这就是我们嵌入的 \\N{\\fs12}which it should be, that's what we're embedding. \r\nDialogue: 0,1:13:05.52,1:13:07.64,yin,,0,0,0,,PhotosByPhotographerMapViewController\\N{\\fs12}Right? Photos by photographer map view controller, \r\nDialogue: 0,1:13:07.64,1:13:10.91,yin,,0,0,0,, 如果是 那它就会设置拍照者 \\N{\\fs12}and if it is, then it's going to set the photographer. \r\nDialogue: 0,1:13:10.91,1:13:12.80,yin,,0,0,0,, 很明显 \\N{\\fs12}Completely obvious, right? \r\nDialogue: 0,1:13:12.80,1:13:14.79,yin,,0,0,0,, 它会把它设为 self.photographer\\N{\\fs12}And it's setting it to self dot photographer, \r\nDialogue: 0,1:13:14.79,1:13:18.32,yin,,0,0,0,, 也就是 PhotosByPhotographerImageViewController\\N{\\fs12}that's this method right here in photos by photographer \r\nDialogue: 0,1:13:18.32,1:13:19.46,yin,,0,0,0,, 的这个方法 \\N{\\fs12}image view controller. \r\nDialogue: 0,1:13:19.46,1:13:20.32,yin,,0,0,0,, 这很好 \\N{\\fs12}That's all good. \r\nDialogue: 0,1:13:20.32,1:13:22.22,yin,,0,0,0,, 不过注意 我还抓住了 \\N{\\fs12}But notice also I'm grabbing a hold \r\nDialogue: 0,1:13:22.22,1:13:24.94,yin,,0,0,0,, 这个 PhotosByPhotographerMapViewController\\N{\\fs12}of this photos by photographer map controller. \r\nDialogue: 0,1:13:24.94,1:13:26.98,yin,,0,0,0,, 为什么我要抓住这个不放 \\N{\\fs12}Why am I grabbing a hold of this thing? \r\nDialogue: 0,1:13:26.98,1:13:29.13,yin,,0,0,0,, 抓住这个不放是因为 \\N{\\fs12}Well I'm grabbing a hold of this because \r\nDialogue: 0,1:13:29.15,1:13:33.28,yin,,0,0,0,, 这个的调用可能会发生在 \\N{\\fs12}this might get called before \r\nDialogue: 0,1:13:33.28,1:13:35.67,yin,,0,0,0,, 这个被调用之前 \\N{\\fs12}this gets called. \r\nDialogue: 0,1:13:35.67,1:13:37.45,yin,,0,0,0,, 换言之 \\N{\\fs12}In other words, \r\nDialogue: 0,1:13:37.45,1:13:41.37,yin,,0,0,0,, 在 PhotosByPhotographerMapViewController\\N{\\fs12}before my image view controllers, photos by photographer image view controller, \r\nDialogue: 0,1:13:41.37,1:13:42.91,yin,,0,0,0,, 获得其拍照者之前 \\N{\\fs12}gets it photographer, \r\nDialogue: 0,1:13:42.91,1:13:46.90,yin,,0,0,0,, 它可能被要求 segue 到嵌入的那个 \\N{\\fs12}it might be asked to segue to the embedded one, \r\nDialogue: 0,1:13:46.90,1:13:49.03,yin,,0,0,0,, 它可能还没有这个拍照者 \\N{\\fs12}and it might not have this photographer yet. \r\nDialogue: 0,1:13:49.03,1:13:53.27,yin,,0,0,0,, 因此我们需要到这里 在 setPhotographer 中 \\N{\\fs12}So we need to go here, in our set photographer, \r\nDialogue: 0,1:13:53.28,1:13:55.24,yin,,0,0,0,, 这个我们总会做 \\N{\\fs12}which we always do this anyway, \r\nDialogue: 0,1:13:55.24,1:14:02.13,yin,,0,0,0,, 写 self.title = photographer.name 这些东西 \\N{\\fs12}things like self dot title equals photographer dot name and stuff like that. \r\nDialogue: 0,1:14:02.13,1:14:04.78,yin,,0,0,0,, 这里 我们需要…\\N{\\fs12}We, here, we need to,\r\nDialogue: 0,1:14:04.78,1:14:08.14,yin,,0,0,0,, 如果我们在嵌入后到这里 那么 \\N{\\fs12}if we get here after we've embedded, then we need \r\nDialogue: 0,1:14:08.14,1:14:10.93,yin,,0,0,0,, 我们需要说 self 点地图视图控制器点拍照者 \\N{\\fs12}to say self dot map view controller photographer \r\nDialogue: 0,1:14:10.93,1:14:13.67,yin,,0,0,0,, 等于我们的拍照者 \\N{\\fs12}equals our photographer. \r\nDialogue: 0,1:14:13.67,1:14:15.40,yin,,0,0,0,, 这和之前我讲的一样 \\N{\\fs12}So this is the exact same thing we're talking \r\nDialogue: 0,1:14:15.40,1:14:18.10,yin,,0,0,0,, 之前我说 准备可以发生在设置之前 \\N{\\fs12}about for prepare can happen before the setting, \r\nDialogue: 0,1:14:18.10,1:14:20.66,yin,,0,0,0,, 设定可以发生在之后 如此往复 \\N{\\fs12}setting can happen after, you know, back and forth, so, \r\nDialogue: 0,1:14:20.66,1:14:23.52,yin,,0,0,0,, 我需要在两个地方都这样做 \\N{\\fs12}but I have to do it in both of these places. \r\nDialogue: 0,1:14:23.53,1:14:25.67,yin,,0,0,0,, 理解吗 \\N{\\fs12}Does that make sense? \r\nDialogue: 0,1:14:25.67,1:14:27.94,yin,,0,0,0,, 好 这次我看到更多人点头了 这很好 \\N{\\fs12}Good, now I'm seeing more nodding heads this time and that's good. \r\nDialogue: 0,1:14:27.94,1:14:29.75,yin,,0,0,0,, 我讲幻灯片时 很多人都一头雾水 \\N{\\fs12}Because when I talked about it in the slides you were like huh? \r\nDialogue: 0,1:14:29.75,1:14:31.12,yin,,0,0,0,, 但现在你们懂了 \\N{\\fs12}Okay, but now you understood. \r\nDialogue: 0,1:14:31.14,1:14:34.89,yin,,0,0,0,, 如果我们在被要求准备嵌入之后设置好模型 \\N{\\fs12}If we set our model after we are asked to prepare that embed, \r\nDialogue: 0,1:14:34.89,1:14:39.56,yin,,0,0,0,, 那么我们就需要回头设置拍照者 \\N{\\fs12}then we have to go back and set the photographer. \r\nDialogue: 0,1:14:39.56,1:14:46.13,yin,,0,0,0,, 最后 我们需要为这个做准备 \\N{\\fs12}Now the last thing we need to do is do the preparing of this guy now. \r\nDialogue: 0,1:14:46.13,1:14:49.83,yin,,0,0,0,, 这个需要准备 它是 detail 视图控制器 \\N{\\fs12}This guy needs to be prepared, it's the detail view controller, \r\nDialogue: 0,1:14:49.83,1:14:51.47,yin,,0,0,0,, 属于拆分视图 \\N{\\fs12}right, of this split view. \r\nDialogue: 0,1:14:51.47,1:14:53.94,yin,,0,0,0,, 这时 我们点拍照者这里时 \\N{\\fs12}And so now when we click in the photographer's thing, \r\nDialogue: 0,1:14:53.94,1:14:57.57,yin,,0,0,0,, 我们需要准备这个 通过将拍照者传递给它 \\N{\\fs12}we need to prepare this guy by passing him the photographers. \r\nDialogue: 0,1:14:57.57,1:14:59.12,yin,,0,0,0,, 这也很简单 \\N{\\fs12}So that's really easy too. \r\nDialogue: 0,1:14:59.12,1:15:00.73,yin,,0,0,0,, 这是我们准备的地方 \\N{\\fs12}Here's where we prepare, right? \r\nDialogue: 0,1:15:00.73,1:15:05.75,yin,,0,0,0,, 在拍照者表格视图 我们知道如何准备 \\N{\\fs12}So right now, in our photographers table view, we know how to prepare \r\nDialogue: 0,1:15:05.75,1:15:08.37,yin,,0,0,0,,PhotosByPhotographer Core Data 表格视图 \\N{\\fs12}the photos by photographer core data table view. \r\nDialogue: 0,1:15:08.37,1:15:10.21,yin,,0,0,0,, 我们还知道如何准备 \\N{\\fs12}We know how to prepare the photos \r\nDialogue: 0,1:15:10.21,1:15:12.34,yin,,0,0,0,,PhotosByPhotographerMapViewController\\N{\\fs12}by photographer map view controller, \r\nDialogue: 0,1:15:12.34,1:15:15.28,yin,,0,0,0,, 现在我们又知道了如何准备 \\N{\\fs12}and now we know how to prepare the photos \r\nDialogue: 0,1:15:15.28,1:15:18.07,yin,,0,0,0,,PhotosByPhotographerImageViewController\\N{\\fs12}by photographer image view controller, as well. \r\nDialogue: 0,1:15:18.07,1:15:22.41,yin,,0,0,0,, 准备方式完全相同 \\N{\\fs12}We prepare them all exactly the same way, right? \r\nDialogue: 0,1:15:22.41,1:15:25.98,yin,,0,0,0,, 不过目标视图控制器不同 \\N{\\fs12}But they're all different destination view controllers. \r\nDialogue: 0,1:15:25.98,1:15:28.42,yin,,0,0,0,, 让我们导入 除掉这个 \\N{\\fs12}So let's import, make that go away, \r\nDialogue: 0,1:15:28.42,1:15:32.90,yin,,0,0,0,,PhotosByPhotographerImageViewController\\N{\\fs12}photos by photographer image view controller, \r\nDialogue: 0,1:15:32.90,1:15:35.51,yin,,0,0,0,, 现在就可以运行了 \\N{\\fs12}and now we can run. \r\nDialogue: 0,1:15:47.25,1:15:49.93,yin,,0,0,0,, 好 可以看到美国的地图 \\N{\\fs12}Okay. So you can see our map, comes up the United States, \r\nDialogue: 0,1:15:49.93,1:15:53.15,yin,,0,0,0,, 我们还没有选拍照者 因此这里没有照片 \\N{\\fs12}we haven't chosen a photographer, so there's, there's no photos in there. \r\nDialogue: 0,1:15:53.15,1:15:54.70,yin,,0,0,0,, 让我们选一个拍照者 \\N{\\fs12}Let's pick a photographer. \r\nDialogue: 0,1:15:54.70,1:15:56.06,yin,,0,0,0,, 这个人 \\N{\\fs12}This guy. \r\nDialogue: 0,1:15:56.06,1:15:58.81,yin,,0,0,0,, 这是我们的地图 我们可以看到这在什么地方 \\N{\\fs12}Here's our map, we can kind of see where in the world we are. \r\nDialogue: 0,1:15:58.81,1:16:01.21,yin,,0,0,0,, 看起来我们是在台北 \\N{\\fs12}Looks like we are in Taipei. \r\nDialogue: 0,1:16:01.21,1:16:03.09,yin,,0,0,0,, 显示的是骑摩托车的人 \\N{\\fs12}And it's showing the scooter thing. \r\nDialogue: 0,1:16:03.09,1:16:05.75,yin,,0,0,0,, 点另一个 我们得到这个 \\N{\\fs12}If I click on the other one, we get that one. \r\nDialogue: 0,1:16:05.75,1:16:08.47,yin,,0,0,0,, 这是一个很不同的 UI\\N{\\fs12}So this is quite a different kind of UI, \r\nDialogue: 0,1:16:08.47,1:16:12.51,yin,,0,0,0,, 这里还是可以放大缩小 地图还是可以到处拖动 \\N{\\fs12}I can still zoom in and out here, I can still move this map around, \r\nDialogue: 0,1:16:12.51,1:16:16.41,yin,,0,0,0,, 我可以旋转 可以放大 \\N{\\fs12}I could rotate it around, I can zoom in. \r\nDialogue: 0,1:16:17.56,1:16:22.01,yin,,0,0,0,, 我还可以点另一个拍照者 \\N{\\fs12}I can click on another photographer here. \r\nDialogue: 0,1:16:25.32,1:16:27.76,yin,,0,0,0,, 理解这是怎么工作的吗 \\N{\\fs12}Make sense? How that's working? \r\nDialogue: 0,1:16:27.76,1:16:31.06,yin,,0,0,0,, 你可以争辩哪个 UI 更好 \\N{\\fs12}So, I mean, again, you can argue which is the better UI. \r\nDialogue: 0,1:16:31.06,1:16:31.93,yin,,0,0,0,, 这个很酷 \\N{\\fs12}This one's kind of cool. \r\nDialogue: 0,1:16:31.93,1:16:34.45,yin,,0,0,0,, 如果能在 URL 旁边有一个小按钮 \\N{\\fs12}I think if I had a little button up next to URL that said map, \r\nDialogue: 0,1:16:34.45,1:16:36.14,yin,,0,0,0,, 显示有 map 如果我点击 \\N{\\fs12}that was maybe a little map icon and I pressed it \r\nDialogue: 0,1:16:36.14,1:16:39.19,yin,,0,0,0,, 地图就消失和出现 那就更好了 \\N{\\fs12}and the map would disappear and reappear, this might be kind of cooler because \r\nDialogue: 0,1:16:39.21,1:16:41.60,yin,,0,0,0,, 看看这个 UI 拍照者 \\N{\\fs12}if you look at this UI, I have my photographers \r\nDialogue: 0,1:16:41.60,1:16:45.41,yin,,0,0,0,, 选择的照片和地图都同时显示在屏幕上 \\N{\\fs12}and my photos and the selected photo all on screen at the same time. \r\nDialogue: 0,1:16:45.41,1:16:48.18,yin,,0,0,0,, 我可以放大 看我想看的东西 \\N{\\fs12}Alright? So I can be zooming in, looking at anything I want, \r\nDialogue: 0,1:16:48.18,1:16:49.65,yin,,0,0,0,, 在这里点另一张照片 \\N{\\fs12}clicking on another photo by this guy, \r\nDialogue: 0,1:16:49.65,1:16:52.77,yin,,0,0,0,, 换到另一个拍照者 来回操作 \\N{\\fs12}switching to another photographer, back and forth, \r\nDialogue: 0,1:16:52.77,1:16:56.08,yin,,0,0,0,, 动动指尖 这些尽在掌控 \\N{\\fs12}all, right at my fingertips so that I don't have to, you know, \r\nDialogue: 0,1:16:56.08,1:17:00.59,yin,,0,0,0,, 我不需要 segue 来改变事物这些 \\N{\\fs12}be segueing and things changing and all that. \r\nDialogue: 0,1:17:02.79,1:17:06.83,yin,,0,0,0,, 好 今天就这些了 周一再会 \\N{\\fs12}Okay. That's all I have for you today, and I will see you on Monday. \r\nDialogue: 0,1:17:06.83,1:17:08.73,yin,,0,0,0,, 周五要交作业 祝大家好运 \\N{\\fs12}Good luck with your homework that's due on Friday \r\nDialogue: 0,1:17:08.73,1:17:11.76,yin,,0,0,0,, 有问题的可以来问我 \\N{\\fs12}and I'll be here for any questions you have. \r\nDialogue: 0,1:17:11.76,1:17:13.76,yin,,0,0,0,, 更多内容 请访问我校官网 stanford.edu\\N{\\fs12}> For more, please visit us at stanford.edu."
  },
  {
    "path": "Subtitles/16. Modal Segues, Text Fields, Alerts, and Action Sheets.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.2.0\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage]\r\nLast Style Storage: Default\r\nActive Line: 3\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.34,0:00:07.65,yin,,0,0,0,,斯坦福大学\\N{\\fs12}> Stanford University.\r\nDialogue: 0,0:00:07.65,0:00:15.17,yin,,0,0,0,,欢迎来到CS193P课程 2013-14秋季第16讲\\N{\\fs12}> Okay, well welcome to lecture 16 of Stanford CS193P fall of 2013-14.\r\nDialogue: 0,0:00:15.17,0:00:20.12,yin,,0,0,0,,今天 我们将谈到最后的segue\\N{\\fs12}So today we are going to talk about the last of the segues,\r\nDialogue: 0,0:00:20.14,0:00:22.51,yin,,0,0,0,,也就是modal segue(模态segue)\\N{\\fs12}which is modal segues\r\nDialogue: 0,0:00:22.51,0:00:25.94,yin,,0,0,0,,还有一种相关的segue\\N{\\fs12}and their kind of related segue\r\nDialogue: 0,0:00:25.94,0:00:28.23,yin,,0,0,0,,也就是unwind segue(解开segue)\\N{\\fs12}which is unwinding segues.\r\nDialogue: 0,0:00:28.24,0:00:31.85,yin,,0,0,0,,模态segue其实很简单\\N{\\fs12}Okay these can be a little, modal segue's really easy.\r\nDialogue: 0,0:00:31.85,0:00:35.28,yin,,0,0,0,,unwind可能有些让人困扰\\N{\\fs12}The unwinding, you know, can be a little confusing\r\nDialogue: 0,0:00:35.28,0:00:39.58,yin,,0,0,0,,但愿通过幻灯片讲解和demo演示 你们能懂\\N{\\fs12}and so hopefully both the combination of the slides and the demo will get you there.\r\nDialogue: 0,0:00:39.58,0:00:43.87,yin,,0,0,0,,不过理解这些很重要 这些unwind segue\\N{\\fs12}But it's an important one to understand, these unwinding segues.\r\nDialogue: 0,0:00:43.87,0:00:46.53,yin,,0,0,0,,我们还会简要谈到文本框\\N{\\fs12}Also, briefly we're going to talk about text fields\r\nDialogue: 0,0:00:46.53,0:00:49.47,yin,,0,0,0,,这方面我还没讲过 还有警告\\N{\\fs12}which we haven't covered yet and also alert\r\nDialogue: 0,0:00:49.47,0:00:51.81,yin,,0,0,0,,以及动作表单 然后我将进行demo\\N{\\fs12}and action sheet and then I'm going to do this demo.\r\nDialogue: 0,0:00:51.81,0:00:53.13,yin,,0,0,0,,有时间再讲摄像头\\N{\\fs12}It says camera time permitting,\r\nDialogue: 0,0:00:53.13,0:00:54.68,yin,,0,0,0,,可惜我们几乎肯定没时间\\N{\\fs12}but we will definitely not have time for that.\r\nDialogue: 0,0:00:54.68,0:00:57.41,yin,,0,0,0,,这将是我们下周三的内容\\N{\\fs12}That's what we'll start off on Wednesday with.\r\nDialogue: 0,0:00:58.97,0:01:01.17,yin,,0,0,0,,好 模态视图控制器\\N{\\fs12}All right, modal view controllers,\r\nDialogue: 0,0:01:01.17,0:01:02.83,yin,,0,0,0,,这是另一种segue的方式\\N{\\fs12}this is another way to segue,\r\nDialogue: 0,0:01:02.83,0:01:05.47,yin,,0,0,0,,将视图控制器放到屏幕上的另一种方式\\N{\\fs12}another way to put a view controller on screen.\r\nDialogue: 0,0:01:05.47,0:01:08.49,yin,,0,0,0,,在导航控制器中 你们已经知道\\N{\\fs12}You already know about popovers and you know about push segues\r\nDialogue: 0,0:01:08.49,0:01:10.04,yin,,0,0,0,,popover和push segue\\N{\\fs12}in a navigation controller.\r\nDialogue: 0,0:01:10.04,0:01:12.97,yin,,0,0,0,,这里是又一种方式 叫作模态视图控制器\\N{\\fs12}So this is another way called modal view controllers.\r\nDialogue: 0,0:01:12.97,0:01:16.27,yin,,0,0,0,,模态视图控制器是将视图控制器放到屏幕上时\\N{\\fs12}And a modal view controller is a way of putting a view controller on screen\r\nDialogue: 0,0:01:16.27,0:01:19.06,yin,,0,0,0,,它会占据整个屏幕\\N{\\fs12}where it takes over the entire screen.\r\nDialogue: 0,0:01:19.06,0:01:22.40,yin,,0,0,0,,在这个视图控制器处在屏幕上时\\N{\\fs12}For the lifetime of that view controller being on screen,\r\nDialogue: 0,0:01:22.40,0:01:25.02,yin,,0,0,0,,它会占据整个屏幕\\N{\\fs12}it's in charge of the entire screen.\r\nDialogue: 0,0:01:25.02,0:01:30.27,yin,,0,0,0,,在iPhone上 占据方式是覆盖整块屏幕\\N{\\fs12}On the iPhone it takes over the entire screen by covering the entire screen.\r\nDialogue: 0,0:01:30.27,0:01:33.13,yin,,0,0,0,,在iPad上 它通常以弹窗形式占据整块屏幕\\N{\\fs12}On the iPad it usually takes over by being in a popover.\r\nDialogue: 0,0:01:33.13,0:01:35.42,yin,,0,0,0,,我们知道 弹窗本质上是模态的\\N{\\fs12}And as we know, popovers are essentially modal.\r\nDialogue: 0,0:01:35.42,0:01:36.64,yin,,0,0,0,,它们处在一种模式中\\N{\\fs12}They're in a mode.\r\nDialogue: 0,0:01:36.64,0:01:39.69,yin,,0,0,0,,弹窗出现时 其它一切都会变得灰暗\\N{\\fs12}When your popover comes up, everything else is kind of dark gray.\r\nDialogue: 0,0:01:39.69,0:01:42.61,yin,,0,0,0,,点别的地方时 弹窗就会消失\\N{\\fs12}And if you click on anything else, the popover goes away, right?\r\nDialogue: 0,0:01:42.61,0:01:44.69,yin,,0,0,0,,它其实也是一种占据\\N{\\fs12}So it's essentially taking over as well.\r\nDialogue: 0,0:01:44.69,0:01:49.01,yin,,0,0,0,,模态视图控制器是一种将视图控制器放到屏幕上\\N{\\fs12}So modal view controllers are a way to put things up\r\nDialogue: 0,0:01:49.02,0:01:51.09,yin,,0,0,0,,并占据整个屏幕的方式\\N{\\fs12}on screen that takes over.\r\nDialogue: 0,0:01:51.09,0:01:53.64,yin,,0,0,0,,我们来看看这个的iPhone版本\\N{\\fs12}So let's look at the iPhone version of this.\r\nDialogue: 0,0:01:53.64,0:01:54.59,yin,,0,0,0,,这是一个小demo\\N{\\fs12}Here's a little demo of it.\r\nDialogue: 0,0:01:54.59,0:01:56.41,yin,,0,0,0,,这是联系人app\\N{\\fs12}So this is the contacts app\r\nDialogue: 0,0:01:56.41,0:01:58.52,yin,,0,0,0,,这里有我的联系人名录\\N{\\fs12}and you can see I've got my contacts there,\r\nDialogue: 0,0:01:58.52,0:02:04.37,yin,,0,0,0,,如果我想在这里加一个联系人 我该怎么做\\N{\\fs12}my winning contacts, and so what if I want to add another contact here?\r\nDialogue: 0,0:02:04.37,0:02:07.90,yin,,0,0,0,,假设我要添加Montay Ball或是谁\\N{\\fs12}Let's say I want to add Montay Ball [assumed spelling] or something like that.\r\nDialogue: 0,0:02:07.90,0:02:09.56,yin,,0,0,0,,如何做到呢\\N{\\fs12}How would I do that?\r\nDialogue: 0,0:02:09.56,0:02:13.24,yin,,0,0,0,,我会点右上角的那个加号\\N{\\fs12}Well I would press that little plus up there in the corner,\r\nDialogue: 0,0:02:13.24,0:02:15.33,yin,,0,0,0,,点加号后会怎样\\N{\\fs12}and what would happen when I press plus?\r\nDialogue: 0,0:02:15.33,0:02:16.05,yin,,0,0,0,,我们看看\\N{\\fs12}So let's watch.\r\nDialogue: 0,0:02:16.05,0:02:19.71,yin,,0,0,0,,点加号 一整个新的视图控制器会滑入\\N{\\fs12}So I hit plus, and a whole new view controller slides in\r\nDialogue: 0,0:02:19.71,0:02:21.39,yin,,0,0,0,,完全占据屏幕\\N{\\fs12}and completely takes over the screen.\r\nDialogue: 0,0:02:21.39,0:02:23.05,yin,,0,0,0,,这不是push\\N{\\fs12}Now this was not a push.\r\nDialogue: 0,0:02:23.05,0:02:26.16,yin,,0,0,0,,这个取消按钮并不是回退按钮\\N{\\fs12}Okay, that cancel button there, that's not a back button.\r\nDialogue: 0,0:02:26.16,0:02:28.05,yin,,0,0,0,,它实际占据了整个屏幕\\N{\\fs12}It actually took over the whole screen.\r\nDialogue: 0,0:02:28.05,0:02:31.68,yin,,0,0,0,,只是取消碰巧处在回退相同的位置\\N{\\fs12}Now cancel happens to be in the same place that back would be,\r\nDialogue: 0,0:02:31.68,0:02:35.19,yin,,0,0,0,,这是很不错的UI一致性\\N{\\fs12}which is kind of decent UI consistency there,\r\nDialogue: 0,0:02:35.19,0:02:39.47,yin,,0,0,0,,不过这里使用的是不同机制\\N{\\fs12}but it's a different, totally different modal mechanism.\r\nDialogue: 0,0:02:39.47,0:02:46.03,yin,,0,0,0,,这个模态视图控制器占据了屏幕\\N{\\fs12}So not only, so we have this modal view controller that's taking over the screen.\r\nDialogue: 0,0:02:46.03,0:02:49.77,yin,,0,0,0,,这里还有另一个按钮 说添加照片\\N{\\fs12}And for example, there's another button on this one, add photo,\r\nDialogue: 0,0:02:49.77,0:02:53.58,yin,,0,0,0,,这就会使用另一个模态视图控制器 覆盖这个屏幕\\N{\\fs12}which uses another modal view controller and covers this guy's screen.\r\nDialogue: 0,0:02:53.58,0:02:55.46,yin,,0,0,0,,再看点击添加照片时会发生什么\\N{\\fs12}So let's watch what happens when we hit add photo.\r\nDialogue: 0,0:02:55.46,0:02:57.11,yin,,0,0,0,,这又覆盖了整个屏幕\\N{\\fs12}See? That covers up the whole screen again.\r\nDialogue: 0,0:02:57.11,0:03:02.17,yin,,0,0,0,,这发生了两层模态segue\\N{\\fs12}So now we have two levels of modal segues happening here.\r\nDialogue: 0,0:03:02.17,0:03:04.21,yin,,0,0,0,,这不是push 没有回退按钮\\N{\\fs12}And again it's not a push, there's no back button.\r\nDialogue: 0,0:03:04.21,0:03:07.63,yin,,0,0,0,,这里 取消按钮处在右侧\\N{\\fs12}In this one the cancel button happens to be on the right.\r\nDialogue: 0,0:03:07.63,0:03:14.16,yin,,0,0,0,,我运行的这个设备上没有任何照片和视频可供选择\\N{\\fs12}And I don't have any photos or videos to choose here on this device that I'm running on,\r\nDialogue: 0,0:03:14.16,0:03:17.49,yin,,0,0,0,,但你可以看到 没有回退按钮\\N{\\fs12}but you can see no back button there.\r\nDialogue: 0,0:03:17.49,0:03:19.67,yin,,0,0,0,,如果我点取消\\N{\\fs12}Now, when I cancel, okay\r\nDialogue: 0,0:03:19.67,0:03:23.07,yin,,0,0,0,,这个模态视图控制器会消失 看看\\N{\\fs12}and this modal view controller goes away, watch what happens.\r\nDialogue: 0,0:03:23.07,0:03:24.01,yin,,0,0,0,,它会消失\\N{\\fs12}It disappears.\r\nDialogue: 0,0:03:24.01,0:03:26.98,yin,,0,0,0,,我回到了之前的模态视图控制器\\N{\\fs12}I go back to the previous modal obviously.\r\nDialogue: 0,0:03:26.98,0:03:29.59,yin,,0,0,0,,然后如果我取消这个\\N{\\fs12}And then if I cancel this modal,\r\nDialogue: 0,0:03:29.59,0:03:32.47,yin,,0,0,0,,那样我就又会回到再之前\\N{\\fs12}okay, then I'll go back to the previous one from that.\r\nDialogue: 0,0:03:32.47,0:03:35.69,yin,,0,0,0,,模态占据屏幕 直到你点完成\\N{\\fs12}So modal takes over the screen until it's, you hit either done\r\nDialogue: 0,0:03:35.69,0:03:38.46,yin,,0,0,0,,或是取消 这时它就会消失\\N{\\fs12}or cancel or something and then it goes away and goes back\r\nDialogue: 0,0:03:38.46,0:03:40.55,yin,,0,0,0,,并回到你原来的地方\\N{\\fs12}to where you were, exactly where you were.\r\nDialogue: 0,0:03:40.55,0:03:43.65,yin,,0,0,0,,很简单 我只是想保证你们理解了\\N{\\fs12}So, it's pretty straightforward but just want\r\nDialogue: 0,0:03:43.65,0:03:47.25,yin,,0,0,0,,我们能用模态视图控制器做些什么\\N{\\fs12}to make sure you understand what we're doing here with modal view controllers.\r\nDialogue: 0,0:03:47.25,0:03:49.88,yin,,0,0,0,,下面是需要考虑的一些东西\\N{\\fs12}Now some things to think about,\r\nDialogue: 0,0:03:49.88,0:03:52.94,yin,,0,0,0,,模态segue会让用户有些失去方向\\N{\\fs12}modal segues can be a little disorienting to the user\r\nDialogue: 0,0:03:52.94,0:03:55.56,yin,,0,0,0,,他们本来是在很好的app中 本来很舒服\\N{\\fs12}because they're in their nice app, they're really comfy,\r\nDialogue: 0,0:03:55.56,0:03:59.00,yin,,0,0,0,,之后突然间 整个屏幕都被别的东西所占据\\N{\\fs12}and then all the sudden their whole screen is completely taken over by something else.\r\nDialogue: 0,0:03:59.00,0:04:00.86,yin,,0,0,0,,他们会想 哦 这是什么\\N{\\fs12}And like whoa, what's this? Now,\r\nDialogue: 0,0:04:00.88,0:04:05.48,yin,,0,0,0,,在合适的地方使用模态视图控制器倒还没问题\\N{\\fs12}you know, if you're using modal view controllers in the proper places, it's okay.\r\nDialogue: 0,0:04:05.48,0:04:06.45,yin,,0,0,0,,用户能接受\\N{\\fs12}The user's fine with that.\r\nDialogue: 0,0:04:06.45,0:04:09.97,yin,,0,0,0,,例如联系人 添加联系人 他们能够很理解\\N{\\fs12}Like the contacts, they're adding a new contact, they understand okay well I have\r\nDialogue: 0,0:04:09.97,0:04:13.01,yin,,0,0,0,,我需要填入这个联系人的信息 然后点完成\\N{\\fs12}to completely specify this contact before I say done,\r\nDialogue: 0,0:04:13.01,0:04:16.15,yin,,0,0,0,,否则这里我什么事情都做不了\\N{\\fs12}so I kind of can't do anything else anyway until I'm done.\r\nDialogue: 0,0:04:16.15,0:04:18.68,yin,,0,0,0,,但模态视图控制器有可能会被滥用\\N{\\fs12}But modal view controllers can be overused.\r\nDialogue: 0,0:04:18.68,0:04:20.39,yin,,0,0,0,,很多学生都在过度使用它\\N{\\fs12}I see students overusing it a lot.\r\nDialogue: 0,0:04:20.39,0:04:21.32,yin,,0,0,0,,他们总是喜欢说\\N{\\fs12}They're just kind of like oh,\r\nDialogue: 0,0:04:21.32,0:04:22.84,yin,,0,0,0,,我需要把这个视图控制器放到屏幕上\\N{\\fs12}well I need to put the view controller on the screen\r\nDialogue: 0,0:04:22.84,0:04:24.61,yin,,0,0,0,,就用模态视图控制器吧\\N{\\fs12}so I'll just put it up modally.\r\nDialogue: 0,0:04:24.61,0:04:28.66,yin,,0,0,0,,其实有时 push到屏幕上会更好\\N{\\fs12}And, whereas it might be better to push it onto screen if it's,\r\nDialogue: 0,0:04:28.66,0:04:32.02,yin,,0,0,0,,例如总需要回退的时候\\N{\\fs12}if going back makes sense at all times.\r\nDialogue: 0,0:04:32.02,0:04:35.49,yin,,0,0,0,,如果push什么东西 总回退没有意义\\N{\\fs12}If you push something and it doesn't make sense to go back\r\nDialogue: 0,0:04:35.49,0:04:38.46,yin,,0,0,0,,那使用push可能就不是正确的方式了\\N{\\fs12}at all times, then push is probably not right.\r\nDialogue: 0,0:04:38.46,0:04:40.65,yin,,0,0,0,,不过有时你要问自己 我能否像这样设计UI\\N{\\fs12}But then you might ask yourself, can I design my UI\r\nDialogue: 0,0:04:40.65,0:04:44.74,yin,,0,0,0,,在导航控制器中总让它回退 而没有问题\\N{\\fs12}so it is always okay to go back, right? You know, in a navigation controller.\r\nDialogue: 0,0:04:44.74,0:04:47.38,yin,,0,0,0,,模态视图控制器很容易被滥用\\N{\\fs12}So modal view controllers tend to get overused.\r\nDialogue: 0,0:04:47.38,0:04:51.87,yin,,0,0,0,,用户有时会被它们弄得一头雾水 因此 请小心使用\\N{\\fs12}Users can sometimes by disoriented by them so use them with care.\r\nDialogue: 0,0:04:51.87,0:04:54.27,yin,,0,0,0,,如何设置一个模态segue呢\\N{\\fs12}How do we set a modal segue up?\r\nDialogue: 0,0:04:54.27,0:04:55.14,yin,,0,0,0,,很简单\\N{\\fs12}Super simple.\r\nDialogue: 0,0:04:55.14,0:04:58.53,yin,,0,0,0,,到故事板 找到你想要模态segue到的视图控制器\\N{\\fs12}Got our story board, have the view controller you want to modal segue to,\r\nDialogue: 0,0:04:58.53,0:04:59.99,yin,,0,0,0,,我们只需要control拖动\\N{\\fs12}we just control drag.\r\nDialogue: 0,0:04:59.99,0:05:03.11,yin,,0,0,0,,control拖动 问你要怎样的segue\\N{\\fs12}Control drag, and when it says what kind of segue do you want\r\nDialogue: 0,0:05:03.11,0:05:05.45,yin,,0,0,0,,你选modal 而不是原来的push\\N{\\fs12}you say modal instead of push for example.\r\nDialogue: 0,0:05:05.45,0:05:07.34,yin,,0,0,0,,这样就能设置好了\\N{\\fs12}And bam, that's all that's necessary to set it up.\r\nDialogue: 0,0:05:07.34,0:05:08.78,yin,,0,0,0,,这是一个常规的segue\\N{\\fs12}And it's a normal segue\r\nDialogue: 0,0:05:08.78,0:05:11.94,yin,,0,0,0,,和其它segue一样需要准备\\N{\\fs12}so you're going to prepare for segue just like any other segues.\r\nDialogue: 0,0:05:11.94,0:05:14.53,yin,,0,0,0,,把它放到屏幕上时 情况同push很像\\N{\\fs12}It's very, when it comes to pushing it,\r\nDialogue: 0,0:05:14.53,0:05:18.43,yin,,0,0,0,,把它放到屏幕上时 情况同push很像\\N{\\fs12}or you know not pushing it, putting it on screen, it's very much like pushing.\r\nDialogue: 0,0:05:18.43,0:05:21.61,yin,,0,0,0,,你们会对此非常习惯\\N{\\fs12}So it's very, you'll be very used to that.\r\nDialogue: 0,0:05:21.61,0:05:25.51,yin,,0,0,0,,你也可以手动进行segue 就像上周我们讲的\\N{\\fs12}It can be manually segued to just like we talked about last week.\r\nDialogue: 0,0:05:25.51,0:05:28.61,yin,,0,0,0,,你甚至可以通过创建视图控制器\\N{\\fs12}You can even put them up by creating view controllers\r\nDialogue: 0,0:05:28.61,0:05:32.23,yin,,0,0,0,,把它们放到屏幕上 不过课上我没讲这个\\N{\\fs12}and put them on screen but we don't really talk about that in this class\r\nDialogue: 0,0:05:32.23,0:05:35.24,yin,,0,0,0,,因为这是很过时的做法\\N{\\fs12}because that's really old style way of doing things.\r\nDialogue: 0,0:05:35.24,0:05:39.80,yin,,0,0,0,,我们一般是在故事板中control拖动来设置segue\\N{\\fs12}We do things in storyboard and we control drag to set up segues.\r\nDialogue: 0,0:05:39.80,0:05:43.61,yin,,0,0,0,,它也需要准备 怎样准备呢\\N{\\fs12}So it's normal to prepare. What does a prepare look like?\r\nDialogue: 0,0:05:43.61,0:05:45.97,yin,,0,0,0,,同其它prepareForSegue类似\\N{\\fs12}It looks like any other prepare for segue, right?\r\nDialogue: 0,0:05:45.97,0:05:49.84,yin,,0,0,0,,你得到目标控制器 检查标识符\\N{\\fs12}You get the destination controller, maybe check the identifier.\r\nDialogue: 0,0:05:49.84,0:05:51.36,yin,,0,0,0,,看它是什么类\\N{\\fs12}You see what class it is.\r\nDialogue: 0,0:05:51.36,0:05:54.78,yin,,0,0,0,,然后你再设置你的…\\N{\\fs12}You know you set up your des- your,\r\nDialogue: 0,0:05:54.78,0:05:59.88,yin,,0,0,0,,通过传入视图控制器想要的公共API来做准备\\N{\\fs12}you prepare by passing whatever public API that view controller wants.\r\nDialogue: 0,0:05:59.88,0:06:02.69,yin,,0,0,0,,下面这里是模态segue变得有趣的地方\\N{\\fs12}Okay now here's where modal segues get interesting though.\r\nDialogue: 0,0:06:02.69,0:06:05.68,yin,,0,0,0,,也就是接收回复\\N{\\fs12}That's hearing back okay?\r\nDialogue: 0,0:06:05.68,0:06:08.03,yin,,0,0,0,,模态segue做了什么事情以后\\N{\\fs12}So a modal segue has gone off and done something\r\nDialogue: 0,0:06:08.03,0:06:11.46,yin,,0,0,0,,例如在联系人app中创建了一个新联系人\\N{\\fs12}like created a new contact in your contact app,\r\nDialogue: 0,0:06:11.46,0:06:13.26,yin,,0,0,0,,这时 联系人app中\\N{\\fs12}and now the contacts app,\r\nDialogue: 0,0:06:13.26,0:06:16.33,yin,,0,0,0,,发起segue的视图控制器希望收到回复\\N{\\fs12}you know the view controller that put it up wants to hear back.\r\nDialogue: 0,0:06:16.33,0:06:19.09,yin,,0,0,0,,你刚创建的联系人是什么\\N{\\fs12}Okay well what was that contact you just created?\r\nDialogue: 0,0:06:19.09,0:06:25.31,yin,,0,0,0,,接收回复很有趣 这是另一种segue\\N{\\fs12}Okay so this hearing back is kind of the interesting yet another kind of segue.\r\nDialogue: 0,0:06:25.31,0:06:29.46,yin,,0,0,0,,我们将这称作unwind segue\\N{\\fs12}This hearing back we call these unwind segues.\r\nDialogue: 0,0:06:29.46,0:06:34.60,yin,,0,0,0,,unwind segue是说 你回给发起你的人\\N{\\fs12}An unwind segue means you're going back to someone who put you up.\r\nDialogue: 0,0:06:34.60,0:06:36.10,yin,,0,0,0,,有人把你放到屏幕上\\N{\\fs12}Someone who put you on screen.\r\nDialogue: 0,0:06:36.10,0:06:38.42,yin,,0,0,0,,一个视图控制器把另一个放到屏幕上\\N{\\fs12}We call a view controller that puts another view controller\r\nDialogue: 0,0:06:38.42,0:06:40.48,yin,,0,0,0,,所谓presenting view controller\\N{\\fs12}on screen, a presenting view controller\r\nDialogue: 0,0:06:40.48,0:06:42.92,yin,,0,0,0,,它呈现(present)出另一个视图控制器\\N{\\fs12}because it's presenting this other view controller.\r\nDialogue: 0,0:06:42.92,0:06:46.70,yin,,0,0,0,,unwind segue会回到这个presenting视图控制器\\N{\\fs12}So an unwind segue, you're going back to someone who presented to you.\r\nDialogue: 0,0:06:46.70,0:06:50.61,yin,,0,0,0,,unwind segue也只能回到presenting视图控制器\\N{\\fs12}Unwind segues can only go back to someone who presented you.\r\nDialogue: 0,0:06:50.61,0:06:53.72,yin,,0,0,0,,不能unwind到某个非presenting视图控制器\\N{\\fs12}You can't unwind to someone else who didn't present you.\r\nDialogue: 0,0:06:53.72,0:06:57.19,yin,,0,0,0,,不过在模态引出模态再引出模态的情况下\\N{\\fs12}But in the case where we had modal and then that modal brought up another modal,\r\nDialogue: 0,0:06:57.19,0:06:59.92,yin,,0,0,0,,你可以一次解开两层\\N{\\fs12}you can unwind two levels at once.\r\nDialogue: 0,0:06:59.92,0:07:01.64,yin,,0,0,0,,解开可以是到\\N{\\fs12}Okay so you can unwind to anybody\r\nDialogue: 0,0:07:01.64,0:07:05.22,yin,,0,0,0,,直接或间接present出你的人\\N{\\fs12}who presented you either directly or indirectly.\r\nDialogue: 0,0:07:05.22,0:07:07.84,yin,,0,0,0,,unwind segue最有趣的一点是\\N{\\fs12}Most interesting thing about unwind segues,\r\nDialogue: 0,0:07:07.84,0:07:09.92,yin,,0,0,0,,只有这一种segue\\N{\\fs12}they're the only kind of segue\r\nDialogue: 0,0:07:09.92,0:07:13.01,yin,,0,0,0,,不创建一个新的视图控制器\\N{\\fs12}that doesn't create a new view controller.\r\nDialogue: 0,0:07:13.01,0:07:16.37,yin,,0,0,0,,其它segue 无论是push 是modal 还是replace\\N{\\fs12}Every other segue-- pushing, modal, replace--\r\nDialogue: 0,0:07:16.37,0:07:19.46,yin,,0,0,0,,都总会创建另外一个视图控制器\\N{\\fs12}all these segues always create another view controller.\r\nDialogue: 0,0:07:19.46,0:07:22.20,yin,,0,0,0,,每次都会从头实例化一个\\N{\\fs12}They instantiate one from scratch, every time.\r\nDialogue: 0,0:07:22.20,0:07:24.35,yin,,0,0,0,,每次在导航控制器中push时\\N{\\fs12}Okay every time you push in a navigation controller,\r\nDialogue: 0,0:07:24.35,0:07:25.86,yin,,0,0,0,,你都会得到一个新视图控制器\\N{\\fs12}you get a new view controller.\r\nDialogue: 0,0:07:25.86,0:07:28.40,yin,,0,0,0,,每次modal segue 你也会得到新的\\N{\\fs12}Every time you modally segue, you get a new one.\r\nDialogue: 0,0:07:28.40,0:07:31.69,yin,,0,0,0,,unwind segue不会这样做 因为它会unwind回\\N{\\fs12}Unwinds obviously don't do that because they're unwinding back\r\nDialogue: 0,0:07:31.69,0:07:32.85,yin,,0,0,0,,present出你的那个\\N{\\fs12}to someone who presented you.\r\nDialogue: 0,0:07:32.85,0:07:34.90,yin,,0,0,0,,这显然存在\\N{\\fs12}They obviously already exist.\r\nDialogue: 0,0:07:34.90,0:07:36.62,yin,,0,0,0,,理解我说的吗\\N{\\fs12}Does that make sense? See what I'm saying?\r\nDialogue: 0,0:07:36.62,0:07:39.19,yin,,0,0,0,,unwind segue这样看有点古怪\\N{\\fs12}So it's kind of a-- unwind is kind of a weird segue in that way.\r\nDialogue: 0,0:07:39.19,0:07:43.34,yin,,0,0,0,,它总是会回到已经存在的视图控制器\\N{\\fs12}It always goes back to somebody who already exists.\r\nDialogue: 0,0:07:43.34,0:07:45.44,yin,,0,0,0,,通常而言 unwind会和modal一同使用\\N{\\fs12}Normally this unwinding is used with modal.\r\nDialogue: 0,0:07:45.44,0:07:48.30,yin,,0,0,0,,其实它也可以同push一起用\\N{\\fs12}It actually can be used with pushing though.\r\nDialogue: 0,0:07:48.30,0:07:49.81,yin,,0,0,0,,你可以push push push\\N{\\fs12}You could push and push and push\r\nDialogue: 0,0:07:49.81,0:07:52.30,yin,,0,0,0,,然后一直unwind回顶部\\N{\\fs12}and then unwind all the way back up to the top.\r\nDialogue: 0,0:07:52.30,0:07:55.57,yin,,0,0,0,,unwind可以被用在导航控制器中\\N{\\fs12}Okay so unwinding can be used inside navigation controller,\r\nDialogue: 0,0:07:55.57,0:07:59.22,yin,,0,0,0,,不过最常用的还是modal控制器\\N{\\fs12}but most often probably used in modal controller.\r\nDialogue: 0,0:07:59.22,0:08:01.75,yin,,0,0,0,,我们来谈谈unwind 以及如何设置\\N{\\fs12}Okay so let's talk about unwinding and how we set that up\r\nDialogue: 0,0:08:01.75,0:08:04.53,yin,,0,0,0,,如何让它工作 毕竟我说了\\N{\\fs12}and how we make it work because it's a little, again,\r\nDialogue: 0,0:08:04.53,0:08:06.46,yin,,0,0,0,,它有点让人困扰\\N{\\fs12}like I say it's a little disorienting\r\nDialogue: 0,0:08:06.46,0:08:09.72,yin,,0,0,0,,因为它没有作为图像显示在故事板中\\N{\\fs12}because it's graphically not shown in the storyboard\r\nDialogue: 0,0:08:09.72,0:08:11.33,yin,,0,0,0,,同其它segue不一样\\N{\\fs12}in the same way as other segues.\r\nDialogue: 0,0:08:11.33,0:08:13.34,yin,,0,0,0,,没有线画在那里\\N{\\fs12}There's not the line being drawn.\r\nDialogue: 0,0:08:13.34,0:08:16.29,yin,,0,0,0,,不过关于unwind segue最重要的一点\\N{\\fs12}But the way you set it up, and the most important thing about an unwind segue\r\nDialogue: 0,0:08:16.29,0:08:18.64,yin,,0,0,0,,在于指定动作方法\\N{\\fs12}is to specify the action method\r\nDialogue: 0,0:08:18.64,0:08:22.65,yin,,0,0,0,,这会在presenting视图控制器中被调用\\N{\\fs12}that's going to get called in the presenting view controller--\r\nDialogue: 0,0:08:22.65,0:08:24.72,yin,,0,0,0,,present出这些东西的那个控制器\\N{\\fs12}the one that's presenting these guys--\r\nDialogue: 0,0:08:24.72,0:08:29.50,yin,,0,0,0,,unwind时有些方法需要在这其中得到调用\\N{\\fs12}some method has to be called in them when you unwind.\r\nDialogue: 0,0:08:29.50,0:08:33.08,yin,,0,0,0,,这种方法是一种IBAction\\N{\\fs12}That kind of method, it's an IB action, right?\r\nDialogue: 0,0:08:33.10,0:08:36.65,yin,,0,0,0,,这是Xcode特别注意的一种东西\\N{\\fs12}It's the kind of thing that Xcode is, pays special attention to.\r\nDialogue: 0,0:08:36.65,0:08:38.72,yin,,0,0,0,,看起来像是一个目标动作方法\\N{\\fs12}So it looks kind of like a target action method,\r\nDialogue: 0,0:08:38.72,0:08:41.25,yin,,0,0,0,,不过弄对参数非常重要\\N{\\fs12}but the argument is very important to get right.\r\nDialogue: 0,0:08:41.25,0:08:44.54,yin,,0,0,0,,这是一个UIStoryboardSegue\\N{\\fs12}It's a UI storyboard segue.\r\nDialogue: 0,0:08:44.54,0:08:48.29,yin,,0,0,0,,这是因为 这个unwind发生时 这个方法会被调用\\N{\\fs12}That's because when this unwind happens, this method's going to get called\r\nDialogue: 0,0:08:48.30,0:08:52.98,yin,,0,0,0,,而且它会把unwind segue传给你\\N{\\fs12}and it's going to pass you the unwind segue.\r\nDialogue: 0,0:08:52.98,0:08:56.52,yin,,0,0,0,,正在发生的segue本身会被传给你\\N{\\fs12}The segue itself that is happening is going to be passed to you.\r\nDialogue: 0,0:08:56.52,0:08:59.33,yin,,0,0,0,,看这个segue 你可以弄清\\N{\\fs12}And when you look in that segue, you can for example find\r\nDialogue: 0,0:08:59.33,0:09:01.45,yin,,0,0,0,,这个unwind的来源在哪\\N{\\fs12}out who's the source of this unwind.\r\nDialogue: 0,0:09:01.45,0:09:03.81,yin,,0,0,0,,也就是你present的东西\\N{\\fs12}That's going to be the thing you presented or the thing\r\nDialogue: 0,0:09:03.81,0:09:06.41,yin,,0,0,0,,或是一直present下去的东西\\N{\\fs12}that you presented that somebody else presented or presented down the way,\r\nDialogue: 0,0:09:06.41,0:09:08.51,yin,,0,0,0,,这就是源视图控制器\\N{\\fs12}that's going to be the source view controller.\r\nDialogue: 0,0:09:08.51,0:09:11.89,yin,,0,0,0,,这是我们唯一考虑segue的源视图控制器的情况\\N{\\fs12}So this is the only case where we've looked at the segue's source view controller.\r\nDialogue: 0,0:09:11.89,0:09:14.10,yin,,0,0,0,,我们一般只看segue的目标\\N{\\fs12}Usually we're looking at the segue's destination.\r\nDialogue: 0,0:09:14.10,0:09:18.10,yin,,0,0,0,,但这里 unwind segue的目标会接收这个信息\\N{\\fs12}But in this case the unwind segue destination is receiving this message\r\nDialogue: 0,0:09:18.11,0:09:20.94,yin,,0,0,0,,我们于是就能知道来源在哪\\N{\\fs12}so it knows who it is, and so it's looking at the source.\r\nDialogue: 0,0:09:20.94,0:09:24.75,yin,,0,0,0,,显然 这个segue方法的第一行\\N{\\fs12}Okay so obviously the first line in a segue method\r\nDialogue: 0,0:09:24.75,0:09:29.74,yin,,0,0,0,,通常都是 我从哪里unwind来的\\N{\\fs12}like this is usually who's unwi- who am I unwinding from.\r\nDialogue: 0,0:09:29.74,0:09:32.11,yin,,0,0,0,,知道从哪unwind来后\\N{\\fs12}Now that you know who you're unwinding from, you could ask\r\nDialogue: 0,0:09:32.11,0:09:35.10,yin,,0,0,0,,你可以问它 例如添加联系人视图控制器\\N{\\fs12}that thing, like the contact, the add contact view controller,\r\nDialogue: 0,0:09:35.10,0:09:37.87,yin,,0,0,0,,你添加的联系人是谁\\N{\\fs12}what was the contact you added.\r\nDialogue: 0,0:09:37.87,0:09:39.52,yin,,0,0,0,,你刚unwind给我\\N{\\fs12}You just unwound to me.\r\nDialogue: 0,0:09:39.52,0:09:41.26,yin,,0,0,0,,显然你添加了联系人\\N{\\fs12}Obviously you've chose your contact.\r\nDialogue: 0,0:09:41.26,0:09:42.62,yin,,0,0,0,,你添加的联系人是谁\\N{\\fs12}What was the contact you added?\r\nDialogue: 0,0:09:42.62,0:09:44.69,yin,,0,0,0,,这样你就得到了联系人 然后添加\\N{\\fs12}And so now you've got the contact, you could add it\r\nDialogue: 0,0:09:44.69,0:09:47.33,yin,,0,0,0,,到联系人列表 或是做别的什么\\N{\\fs12}to the list of contacts or whatever you want to do.\r\nDialogue: 0,0:09:47.33,0:09:51.94,yin,,0,0,0,,创建这个方法是最重要的事\\N{\\fs12}So creating that method is the most important thing to do,\r\nDialogue: 0,0:09:51.94,0:09:54.42,yin,,0,0,0,,仅仅是这个方法的创建\\N{\\fs12}and just the very creation of that method\r\nDialogue: 0,0:09:54.42,0:09:56.43,yin,,0,0,0,,就会自动让Xcode意识到\\N{\\fs12}will automatically make Xcode realize\r\nDialogue: 0,0:09:56.43,0:09:59.19,yin,,0,0,0,,你可以unwind到那个视图控制器\\N{\\fs12}that you can unwind to that view controller.\r\nDialogue: 0,0:09:59.19,0:10:02.22,yin,,0,0,0,,如果视图控制器有这种方法 IBAction\\N{\\fs12}If a view controller has this kind of method, IB action,\r\nDialogue: 0,0:10:02.22,0:10:05.03,yin,,0,0,0,,任何名称 取一个UIStoryboardSegue\\N{\\fs12}any name takes a UI Storyboard segue,\r\nDialogue: 0,0:10:05.03,0:10:08.51,yin,,0,0,0,,那个视图控制器现在就可以被unwind到了\\N{\\fs12}that view controller can now be unwound to.\r\nDialogue: 0,0:10:08.51,0:10:11.12,yin,,0,0,0,,那个视图控制器present出的任何视图控制器\\N{\\fs12}So any view controller that that view controller presents\r\nDialogue: 0,0:10:11.12,0:10:12.57,yin,,0,0,0,,能够unwind回它\\N{\\fs12}can unwind back to it.\r\nDialogue: 0,0:10:12.57,0:10:14.86,yin,,0,0,0,,如何设置这种unwind segue呢\\N{\\fs12}Okay so how do you set up that unwind?\r\nDialogue: 0,0:10:14.86,0:10:16.79,yin,,0,0,0,,这有点奇特\\N{\\fs12}Okay this is a little odd.\r\nDialogue: 0,0:10:16.79,0:10:19.52,yin,,0,0,0,,在添加联系人的视图控制器中\\N{\\fs12}In the, let's say, add contact view controller,\r\nDialogue: 0,0:10:19.52,0:10:23.10,yin,,0,0,0,,模态方式present的那个 它会有一个按钮\\N{\\fs12}the one that's being presented modally, it might have a button\r\nDialogue: 0,0:10:23.10,0:10:28.31,yin,,0,0,0,,说完成 或是保存新联系人 或创建新联系人\\N{\\fs12}in there like done or save new contact or create new contact.\r\nDialogue: 0,0:10:28.31,0:10:32.40,yin,,0,0,0,,这个按钮 实际会开启这个unwind segue\\N{\\fs12}That button, okay, really wants to start this unwind segue.\r\nDialogue: 0,0:10:32.40,0:10:36.49,yin,,0,0,0,,但你不能从那个按钮control拖动回\\N{\\fs12}But you can't control drag from that button all the way back\r\nDialogue: 0,0:10:36.49,0:10:39.35,yin,,0,0,0,,有这个方法的原来那个视图控制器\\N{\\fs12}to the other view controller that has this method.\r\nDialogue: 0,0:10:39.35,0:10:41.30,yin,,0,0,0,,你可能认为你能 但你不能\\N{\\fs12}You'd think you could, but you can't.\r\nDialogue: 0,0:10:41.30,0:10:45.32,yin,,0,0,0,,你应从那个按钮control拖动到下面那个绿色小按钮\\N{\\fs12}Instead, you control drag from that button down to the little green button--\r\nDialogue: 0,0:10:45.32,0:10:46.57,yin,,0,0,0,,看到那张图了吗\\N{\\fs12}you see that image I have there--\r\nDialogue: 0,0:10:46.57,0:10:49.36,yin,,0,0,0,,视图控制器底部的那个绿色小按钮\\N{\\fs12}the little green button at the bottom of the view controller\r\nDialogue: 0,0:10:49.36,0:10:52.40,yin,,0,0,0,,这会开启unwind segue\\N{\\fs12}that is starting the unwind segue.\r\nDialogue: 0,0:10:52.40,0:10:53.82,yin,,0,0,0,,到模态方式present的那个\\N{\\fs12}The thing that was presented modally.\r\nDialogue: 0,0:10:53.82,0:10:54.93,yin,,0,0,0,,你到下面这个绿按钮 然后放手\\N{\\fs12}So you go down to that green thing--\r\nDialogue: 0,0:10:54.93,0:10:57.51,yin,,0,0,0,,你到下面这个绿按钮 然后放手\\N{\\fs12}and when you do to that green thing and you let go,\r\nDialogue: 0,0:10:57.51,0:11:02.61,yin,,0,0,0,,它会给你一系列方法 例如这里的完成\\N{\\fs12}it's going to give you a list of all these methods like done right there.\r\nDialogue: 0,0:11:02.61,0:11:04.79,yin,,0,0,0,,这些方法都是IBAction\\N{\\fs12}Okay all the methods that are IB actions\r\nDialogue: 0,0:11:04.79,0:11:07.24,yin,,0,0,0,,将UIStoryboardSegue作为参数\\N{\\fs12}that take UI storyboard segues as arguments.\r\nDialogue: 0,0:11:07.24,0:11:09.32,yin,,0,0,0,,其中有些方法\\N{\\fs12}Now some of those methods might be\r\nDialogue: 0,0:11:09.32,0:11:14.07,yin,,0,0,0,,可能在故事板中完全无关的视图控制器中\\N{\\fs12}in completely unrelated view controllers off somewhere else in your storyboard because it's going to show you all of them.\r\nDialogue: 0,0:11:14.07,0:11:16.30,yin,,0,0,0,,Xcode知道所有这些 把它们都显示给你\\N{\\fs12}Xcode knows about all of them. It shows you all of them.\r\nDialogue: 0,0:11:16.30,0:11:21.13,yin,,0,0,0,,如果你选择的 不在present出你的视图控制器中\\N{\\fs12}If you pick one that wasn't, is not in a view controller that presented you,\r\nDialogue: 0,0:11:21.14,0:11:23.66,yin,,0,0,0,,unwind就不会发生 就像你什么都没做\\N{\\fs12}the unwind just will not happen. It's like you did nothing.\r\nDialogue: 0,0:11:23.66,0:11:25.59,yin,,0,0,0,,它不会崩溃 但是什么都不会做\\N{\\fs12}It's not going to crash but it's just not going to do anything.\r\nDialogue: 0,0:11:25.59,0:11:28.41,yin,,0,0,0,,完成按钮什么都不会做\\N{\\fs12}So the done button would just do nothing.\r\nDialogue: 0,0:11:28.41,0:11:32.05,yin,,0,0,0,,但如果运行时 它能够找到那个方法\\N{\\fs12}But if it can find, at run time if it can find that method\r\nDialogue: 0,0:11:32.05,0:11:36.79,yin,,0,0,0,,追溯present出你的链 它会调用那个方法\\N{\\fs12}up the change of, chain of who presented you, it will call that method.\r\nDialogue: 0,0:11:36.79,0:11:39.10,yin,,0,0,0,,这只是unwind的一部分\\N{\\fs12}Now that's only part of unwinding.\r\nDialogue: 0,0:11:39.10,0:11:42.37,yin,,0,0,0,,unwind的一部分是让present出你的视图控制器\\N{\\fs12}Part of unwinding is letting the view controller who presented you\r\nDialogue: 0,0:11:42.37,0:11:44.33,yin,,0,0,0,,知道 好 我完成了\\N{\\fs12}know yeah I'm done.\r\nDialogue: 0,0:11:44.33,0:11:45.84,yin,,0,0,0,,而这里是从公共API\\N{\\fs12}And here's from public API\r\nDialogue: 0,0:11:45.84,0:11:48.35,yin,,0,0,0,,你从我这里获得信息\\N{\\fs12}and myself [inaudible] get information out of me.\r\nDialogue: 0,0:11:48.35,0:11:51.77,yin,,0,0,0,,不过unwind还有另一部分 也就是为其做准备\\N{\\fs12}But there's another part of it which is preparing that unwind segue.\r\nDialogue: 0,0:11:51.77,0:11:54.65,yin,,0,0,0,,unwind segue也需要准备\\N{\\fs12}So the unwind segue has to be prepared as well.\r\nDialogue: 0,0:11:54.65,0:11:57.99,yin,,0,0,0,,而且准备unwind segue有时甚至比\\N{\\fs12}And in fact preparing an unwind segue is even more important\r\nDialogue: 0,0:11:57.99,0:12:02.26,yin,,0,0,0,,准备其它segue更重要 因为只有这个机会下\\N{\\fs12}sometimes than preparing other segues because it's the only chance\r\nDialogue: 0,0:12:02.26,0:12:07.87,yin,,0,0,0,,被present的模态视图控制器会在消失之前做点什么\\N{\\fs12}that the presented modal view controller has to do anything before it goes away.\r\nDialogue: 0,0:12:07.87,0:12:11.38,yin,,0,0,0,,也就是准备这个unwind segue的回退\\N{\\fs12}And that's to prepare that unwind segue to go back.\r\nDialogue: 0,0:12:11.38,0:12:14.99,yin,,0,0,0,,在demo中 我们会进一步完善Photomania\\N{\\fs12}So in the demo we're going to do a photo, some more photo mania\r\nDialogue: 0,0:12:14.99,0:12:16.53,yin,,0,0,0,,我们会添加一张照片\\N{\\fs12}and we're going to add a photo.\r\nDialogue: 0,0:12:16.53,0:12:19.09,yin,,0,0,0,,我们会允许从摄像头拍照\\N{\\fs12}We're going to allow us to take a photo with the camera instead\r\nDialogue: 0,0:12:19.09,0:12:22.02,yin,,0,0,0,,而不是从Flickr取回 当这个模态视图控制器\\N{\\fs12}of getting it from Flickr, and when that modal view controller\r\nDialogue: 0,0:12:22.02,0:12:25.38,yin,,0,0,0,,让你完成添加照片时 它需要将照片\\N{\\fs12}that lets you add that photo is done, it has to put that photo\r\nDialogue: 0,0:12:25.38,0:12:27.68,yin,,0,0,0,,放入到数据库 然后才能unwind\\N{\\fs12}in the database before it unwinds.\r\nDialogue: 0,0:12:27.68,0:12:30.39,yin,,0,0,0,,准备完成时segue的回退\\N{\\fs12}So it prepares for the segue back when it's done\r\nDialogue: 0,0:12:30.39,0:12:32.38,yin,,0,0,0,,需要将照片放入数据库\\N{\\fs12}by putting that photo in the database.\r\nDialogue: 0,0:12:32.38,0:12:36.55,yin,,0,0,0,,准备unwind segue是非常重要的\\N{\\fs12}Okay so preparing for unwind segues is very important.\r\nDialogue: 0,0:12:36.55,0:12:40.98,yin,,0,0,0,,考虑prepareForSegue时\\N{\\fs12}Now, the thing about preparing for segues is you, when you do the prepare for segue,\r\nDialogue: 0,0:12:40.98,0:12:43.85,yin,,0,0,0,,你需要segue的标识符\\N{\\fs12}you need the segue's identifier, because you've got to know\r\nDialogue: 0,0:12:43.85,0:12:46.30,yin,,0,0,0,,分辨出讲的是哪个unwind segue\\N{\\fs12}which unwind segue am I talking about\r\nDialogue: 0,0:12:46.30,0:12:49.08,yin,,0,0,0,,这对于unwind segue也很困难\\N{\\fs12}and that is also difficult with unwind segues.\r\nDialogue: 0,0:12:49.08,0:12:52.21,yin,,0,0,0,,设置这个的唯一位置是文档大纲\\N{\\fs12}The only place to set that is in the document outline.\r\nDialogue: 0,0:12:52.21,0:12:55.79,yin,,0,0,0,,当你通过control拖动到绿色小按钮\\N{\\fs12}Okay so when you create an unwind segue by control dragging\r\nDialogue: 0,0:12:55.79,0:12:57.25,yin,,0,0,0,,来创建unwind segue时\\N{\\fs12}down to the little green thing,\r\nDialogue: 0,0:12:57.25,0:13:00.87,yin,,0,0,0,,在文档大纲中 会有一行写着unwind segue\\N{\\fs12}in the document outline there'll be a little line in there unwind segue,\r\nDialogue: 0,0:13:00.87,0:13:03.18,yin,,0,0,0,,从某个按钮\\N{\\fs12}you know, from a whatever button.\r\nDialogue: 0,0:13:03.18,0:13:05.65,yin,,0,0,0,,你可以点这个 然后在检查器中\\N{\\fs12}And you can click on that and then inspect it just\r\nDialogue: 0,0:13:05.65,0:13:09.00,yin,,0,0,0,,同其它segue一样 说标识符是什么\\N{\\fs12}like any other segue and say the identifier is whatever.\r\nDialogue: 0,0:13:09.00,0:13:11.44,yin,,0,0,0,,然后在prepareForSegue中 你就有了标识符\\N{\\fs12}And then in prepare for segue you'll have the identifier.\r\nDialogue: 0,0:13:11.44,0:13:13.44,yin,,0,0,0,,为什么这里有所不同 要隐藏起来呢\\N{\\fs12}Why is that different or a little hidden?\r\nDialogue: 0,0:13:13.44,0:13:16.31,yin,,0,0,0,,因为unwind segue在故事板上\\N{\\fs12}Well because unwind segues don't have a, you know,\r\nDialogue: 0,0:13:16.31,0:13:19.05,yin,,0,0,0,,没有一图 说它们要去哪\\N{\\fs12}a drawing on the storyboard that says where they go\r\nDialogue: 0,0:13:19.05,0:13:20.64,yin,,0,0,0,,因为它们不知道要去哪\\N{\\fs12}because they don't really know where they go.\r\nDialogue: 0,0:13:20.64,0:13:24.75,yin,,0,0,0,,这取决于谁present出它们 它们要unwind到哪\\N{\\fs12}It depends on who presented them as to where they unwind to.\r\nDialogue: 0,0:13:24.75,0:13:27.52,yin,,0,0,0,,没有线会显示它们回去哪里\\N{\\fs12}So there's no line showing them going back.\r\nDialogue: 0,0:13:27.52,0:13:29.82,yin,,0,0,0,,这就是需要使用文档大纲的原因\\N{\\fs12}So that's why you have to use the document outline.\r\nDialogue: 0,0:13:29.82,0:13:32.09,yin,,0,0,0,,我会演示所有这些\\N{\\fs12}So I'm going to demo all this\r\nDialogue: 0,0:13:32.09,0:13:35.77,yin,,0,0,0,,但愿到时候你们就都明白了\\N{\\fs12}so hopefully it'll all make sense once you see it.\r\nDialogue: 0,0:13:35.77,0:13:39.72,yin,,0,0,0,,如何从代码上取消模态视图控制器\\N{\\fs12}How about dismissing modal view controllers from code?\r\nDialogue: 0,0:13:39.72,0:13:41.45,yin,,0,0,0,,你想让它从屏幕上消失\\N{\\fs12}So you just want to get it off the screen.\r\nDialogue: 0,0:13:41.45,0:13:44.22,yin,,0,0,0,,你不打算unwind 只打算让它从屏幕上消失\\N{\\fs12}You're not going to unwind, you just want to get it off the screen.\r\nDialogue: 0,0:13:44.22,0:13:47.83,yin,,0,0,0,,顺便说下 unwind会自动让它从屏幕上消失\\N{\\fs12}By the way, unwinding automatically takes it off the screen.\r\nDialogue: 0,0:13:47.83,0:13:49.82,yin,,0,0,0,,如果你有一个模态视图控制器 你unwind\\N{\\fs12}If you have a modal view controller and you unwind,\r\nDialogue: 0,0:13:49.82,0:13:53.05,yin,,0,0,0,,它会自动从屏幕上消失 你不需要另外要求\\N{\\fs12}it will automatically be removed from the screen, you do not have to dismiss it.\r\nDialogue: 0,0:13:53.05,0:13:55.41,yin,,0,0,0,,不过你也可以手动让它们消失\\N{\\fs12}But you can also dismiss them manually\r\nDialogue: 0,0:13:55.41,0:13:58.68,yin,,0,0,0,,做法是发送消息dismissViewControllerAnimated\\N{\\fs12}by sending the message dismiss view controller animated.\r\nDialogue: 0,0:13:58.68,0:13:59.74,yin,,0,0,0,,这个方法\\N{\\fs12}This method is sent\r\nDialogue: 0,0:13:59.74,0:14:02.43,yin,,0,0,0,,会被发送给presenting视图控制器\\N{\\fs12}to the presenting view controller,\r\nDialogue: 0,0:14:02.43,0:14:04.36,yin,,0,0,0,,不是被present的那个\\N{\\fs12}not the presented.\r\nDialogue: 0,0:14:04.36,0:14:06.40,yin,,0,0,0,,而是present的那个\\N{\\fs12}The presenting.\r\nDialogue: 0,0:14:06.40,0:14:10.03,yin,,0,0,0,,你跟视图控制器说 dismissViewControllerAnimated\\N{\\fs12}You say to a view controller, dismiss view controller animated.\r\nDialogue: 0,0:14:10.03,0:14:15.88,yin,,0,0,0,,这意味着让任何你present的视图控制器消失\\N{\\fs12}It means dismiss any view controller that you have presented.\r\nDialogue: 0,0:14:15.88,0:14:21.22,yin,,0,0,0,,幸运的是 如果你想在实际视图控制器中说这个\\N{\\fs12}And luckily though if you want to kind of say that in the actual view controller,\r\nDialogue: 0,0:14:21.22,0:14:23.18,yin,,0,0,0,,还有一个很棒的方法在UIViewController中\\N{\\fs12}there's a nice method in UI view controller\r\nDialogue: 0,0:14:23.18,0:14:25.18,yin,,0,0,0,,叫presentingViewController\\N{\\fs12}called presenting view controller\r\nDialogue: 0,0:14:25.18,0:14:28.99,yin,,0,0,0,,这会告诉你 谁present出了你 如果有的话\\N{\\fs12}which will tell you who presented you, if anyone presented you.\r\nDialogue: 0,0:14:28.99,0:14:31.16,yin,,0,0,0,,你可以让你自己消失\\N{\\fs12}So that's a, you can dismiss yourself basically\r\nDialogue: 0,0:14:31.16,0:14:33.40,yin,,0,0,0,,做法是 self.presentingViewController\\N{\\fs12}by saying self view controller\r\nDialogue: 0,0:14:33.40,0:14:35.28,yin,,0,0,0,,dismissViewControllerAnimated\\N{\\fs12}dismiss animated.\r\nDialogue: 0,0:14:35.28,0:14:38.34,yin,,0,0,0,,根据定义 那个present出你\\N{\\fs12}And since by definition that guy presented you,\r\nDialogue: 0,0:14:38.34,0:14:42.15,yin,,0,0,0,,这就会让你消失\\N{\\fs12}when you dismiss it's going to dismiss you.\r\nDialogue: 0,0:14:42.15,0:14:47.26,yin,,0,0,0,,很多人不喜欢这样 因为他们认为\\N{\\fs12}So just a little frowned upon because some people would argue\r\nDialogue: 0,0:14:47.26,0:14:50.24,yin,,0,0,0,,当一个模态视图控制器被取消时\\N{\\fs12}that when a view controller, modal view controller gets canceled,\r\nDialogue: 0,0:14:50.24,0:14:51.40,yin,,0,0,0,,应当unwind\\N{\\fs12}you want to unwind.\r\nDialogue: 0,0:14:51.40,0:14:53.80,yin,,0,0,0,,就算什么信息都没传回来\\N{\\fs12}Even if you're not communicating anything back,\r\nDialogue: 0,0:14:53.80,0:14:57.11,yin,,0,0,0,,你至少要让它知道 对 我取消了\\N{\\fs12}just want to let the guy know, yeah I got canceled.\r\nDialogue: 0,0:14:57.11,0:14:59.68,yin,,0,0,0,,如果只是取消后让自己消失\\N{\\fs12}If you just cancel yourself by dismissing yourself,\r\nDialogue: 0,0:14:59.68,0:15:04.09,yin,,0,0,0,,那present出你的人就不能得到任何通知\\N{\\fs12}then the guy who presented you doesn't get notified that you submitted yourself.\r\nDialogue: 0,0:15:04.09,0:15:06.69,yin,,0,0,0,,也有人说 取消了的话\\N{\\fs12}But some people say yeah but if I'm cancelling I don't want\r\nDialogue: 0,0:15:06.69,0:15:09.64,yin,,0,0,0,,我就不需要让它知道 我什么都没做\\N{\\fs12}that guy to know that I'm, I didn't do anything,\r\nDialogue: 0,0:15:09.65,0:15:13.01,yin,,0,0,0,,我没有添加联系人 我干嘛要让它知道\\N{\\fs12}I didn't add the contact in the contact case, so I don't even want him to know.\r\nDialogue: 0,0:15:13.01,0:15:14.90,yin,,0,0,0,,我只需要让我自己消失即可\\N{\\fs12}So I'm just going to dismiss myself.\r\nDialogue: 0,0:15:14.90,0:15:16.76,yin,,0,0,0,,具体采取哪种想法\\N{\\fs12}So it's kind of an art of programming as to\r\nDialogue: 0,0:15:16.76,0:15:19.55,yin,,0,0,0,,取决于你认为怎样编程是正确的\\N{\\fs12}which you believe is the right thing there.\r\nDialogue: 0,0:15:19.55,0:15:20.64,yin,,0,0,0,,这通常不是问题\\N{\\fs12}It's usually not an issue\r\nDialogue: 0,0:15:20.64,0:15:23.54,yin,,0,0,0,,因为在故事板中 你都把它接了起来\\N{\\fs12}because in your storyboard you're wiring it up anyway,\r\nDialogue: 0,0:15:23.54,0:15:26.76,yin,,0,0,0,,你总可以把取消按钮作为unwind接起来\\N{\\fs12}so you could always wire it up as an unwind that cancel button instead\r\nDialogue: 0,0:15:26.76,0:15:30.41,yin,,0,0,0,,而不是让取消按钮进行目标动作 然后自己消失\\N{\\fs12}of having the cancel button do target action and dismiss itself.\r\nDialogue: 0,0:15:30.41,0:15:34.34,yin,,0,0,0,,你总是可以断开任何可能设置起的目标动作\\N{\\fs12}You can always just disconnect any target action that might be set up.\r\nDialogue: 0,0:15:36.02,0:15:40.46,yin,,0,0,0,,模态视图控制器如何出现在屏幕上呢\\N{\\fs12}Okay how does the modal view controller appear on screen?\r\nDialogue: 0,0:15:40.46,0:15:43.54,yin,,0,0,0,,这是由这个模态过渡样式属性设置的\\N{\\fs12}That's set by this modal transition style property\r\nDialogue: 0,0:15:43.54,0:15:47.34,yin,,0,0,0,,它位于被present的视图控制器中 这里有各种选项\\N{\\fs12}in the presented view controller and it has various choices here\r\nDialogue: 0,0:15:47.34,0:15:49.73,yin,,0,0,0,,例如CoverVertical是从下面滑上来\\N{\\fs12}like cover vertically is slide up from the bottom\r\nDialogue: 0,0:15:49.74,0:15:51.23,yin,,0,0,0,,demo中用的就是这个\\N{\\fs12}like I showed in the demo there.\r\nDialogue: 0,0:15:51.23,0:15:52.74,yin,,0,0,0,,还是FlipHorizontal\\N{\\fs12}There's also flip horizontal\r\nDialogue: 0,0:15:52.74,0:15:55.07,yin,,0,0,0,,也就是水平翻转\\N{\\fs12}which will flip the new one in horizontally.\r\nDialogue: 0,0:15:55.07,0:15:58.95,yin,,0,0,0,,还有CrossDissolve 也就是交叉溶解淡入\\N{\\fs12}There's also cross dissolve, right, which kind of fades the new one in.\r\nDialogue: 0,0:15:58.95,0:16:03.61,yin,,0,0,0,,PartialCurl则是卷起原来那个 展示下方的新视图\\N{\\fs12}And partial curl which will curl up the current one and show the new one underneath.\r\nDialogue: 0,0:16:03.61,0:16:05.35,yin,,0,0,0,,这个有些奇特\\N{\\fs12}That one's kind of a weird one,\r\nDialogue: 0,0:16:05.35,0:16:08.37,yin,,0,0,0,,想用这种卷起的人可以去看说明文档\\N{\\fs12}so you'll want to check the documentation if you want to use that curl.\r\nDialogue: 0,0:16:08.37,0:16:10.17,yin,,0,0,0,,这里会施加一些限制\\N{\\fs12}It puts some limitations on you.\r\nDialogue: 0,0:16:10.17,0:16:12.51,yin,,0,0,0,,卷起后 你就不能再用模态了\\N{\\fs12}Once you curl it, you can't go modal again for example.\r\nDialogue: 0,0:16:12.51,0:16:14.48,yin,,0,0,0,,你不能present出另一个\\N{\\fs12}You can't present another one.\r\nDialogue: 0,0:16:14.48,0:16:19.11,yin,,0,0,0,,而且卷起的那个 没有获得viewDidDisappear\\N{\\fs12}Also the one that curls up, doesn't get view did disappear\r\nDialogue: 0,0:16:19.11,0:16:20.14,yin,,0,0,0,,因为它没有消失\\N{\\fs12}because it doesn't disappear.\r\nDialogue: 0,0:16:20.14,0:16:21.48,yin,,0,0,0,,它只是卷起了\\N{\\fs12}It kind of just curls up.\r\nDialogue: 0,0:16:21.48,0:16:24.13,yin,,0,0,0,,卷起后 屏幕上看不到它\\N{\\fs12}You can't really see it behind the curl but it's still\r\nDialogue: 0,0:16:24.13,0:16:27.01,yin,,0,0,0,,但它还在屏幕上 这对编程而言很奇怪\\N{\\fs12}on screen so that's a little weird programming wise.\r\nDialogue: 0,0:16:27.01,0:16:28.63,yin,,0,0,0,,一般而言 模态的东西会出来\\N{\\fs12}Okay normally a modal thing comes up\r\nDialogue: 0,0:16:28.63,0:16:30.76,yin,,0,0,0,,后面那个会被完全覆盖\\N{\\fs12}and the one behind it gets completely covered\r\nDialogue: 0,0:16:30.76,0:16:33.20,yin,,0,0,0,,这就会得到viewDidDisappear 因为视图确实消失了\\N{\\fs12}so it gets view did disappear because it's view did disappear.\r\nDialogue: 0,0:16:33.20,0:16:37.24,yin,,0,0,0,,完全被模态那个所覆盖 但卷起不是这样\\N{\\fs12}It was completely obscured by the modal one, but with the curl, not so much.\r\nDialogue: 0,0:16:37.24,0:16:38.70,yin,,0,0,0,,卷起要小心使用\\N{\\fs12}So be careful with curl.\r\nDialogue: 0,0:16:38.70,0:16:41.37,yin,,0,0,0,,iPad上的所有这些呢\\N{\\fs12}Now what about all this business on the iPad?\r\nDialogue: 0,0:16:41.37,0:16:44.96,yin,,0,0,0,,iPad上 我说了 我们将主要使用弹窗\\N{\\fs12}Okay, so on iPad again mostly we're going to try and do popovers\r\nDialogue: 0,0:16:44.96,0:16:47.80,yin,,0,0,0,,用于这类东西 而不是模态视图控制器\\N{\\fs12}for this kind of stuff instead of modal view controllers.\r\nDialogue: 0,0:16:47.80,0:16:49.10,yin,,0,0,0,,不过你也可以用模态视图控制器\\N{\\fs12}But you can do modal view controllers\r\nDialogue: 0,0:16:49.10,0:16:52.74,yin,,0,0,0,,你甚至可以让模态视图控制器覆盖整个屏幕\\N{\\fs12}and you can even have a modal view controller that controls, covers the whole screen.\r\nDialogue: 0,0:16:52.74,0:16:56.50,yin,,0,0,0,,你还可以决定它如何工作 如何覆盖\\N{\\fs12}And you determine how it works, how it covers,\r\nDialogue: 0,0:16:56.50,0:16:58.50,yin,,0,0,0,,使用这个模态过渡样式属性\\N{\\fs12}using this modal presentation style property.\r\nDialogue: 0,0:16:58.50,0:17:01.78,yin,,0,0,0,,这是一个不同的属性 它有一个选项便是全屏\\N{\\fs12}It's a different property, and one of the options is full screen--\r\nDialogue: 0,0:17:01.78,0:17:04.29,yin,,0,0,0,,iPad上不推荐这样做\\N{\\fs12}not recommended on the iPad.\r\nDialogue: 0,0:17:04.29,0:17:09.19,yin,,0,0,0,,PageSheet和FormSheet只是iPad上不同的\\N{\\fs12}There's page sheet and form sheet which are just different size versions\r\nDialogue: 0,0:17:09.19,0:17:10.95,yin,,0,0,0,,大小规格\\N{\\fs12}of the thing on the iPad.\r\nDialogue: 0,0:17:10.95,0:17:13.39,yin,,0,0,0,,iPad屏幕上的其它地方会变灰暗\\N{\\fs12}The rest of the iPad screen will be dark gray, you know kind\r\nDialogue: 0,0:17:13.39,0:17:15.42,yin,,0,0,0,,就像弹窗的背景一样\\N{\\fs12}of grayed out like a popover's background is,\r\nDialogue: 0,0:17:15.42,0:17:19.59,yin,,0,0,0,,一个会显示竖屏宽度 另一个会较小\\N{\\fs12}and then it'll show up, one's portrait sized, one's a little smaller.\r\nDialogue: 0,0:17:19.59,0:17:22.05,yin,,0,0,0,,CurrentContext这个很有趣\\N{\\fs12}And then the current context is an interesting one.\r\nDialogue: 0,0:17:22.05,0:17:25.26,yin,,0,0,0,,如果你有一个视图控制器和一个弹窗\\N{\\fs12}If you have a popover, if you have a view controller and popover\r\nDialogue: 0,0:17:25.26,0:17:27.78,yin,,0,0,0,,而那个视图控制器做了模态这些\\N{\\fs12}and that view controller does a modal,\r\nDialogue: 0,0:17:27.78,0:17:30.02,yin,,0,0,0,,那么如果是CurrentContext 这是默认值\\N{\\fs12}then if its current context, which is the default,\r\nDialogue: 0,0:17:30.02,0:17:31.82,yin,,0,0,0,,它就会出现在弹窗中\\N{\\fs12}it'll appear inside the popover.\r\nDialogue: 0,0:17:31.82,0:17:34.04,yin,,0,0,0,,这将是弹窗中的模态\\N{\\fs12}So it'll be modal inside the popover.\r\nDialogue: 0,0:17:34.04,0:17:34.62,yin,,0,0,0,,懂了吗\\N{\\fs12}You see what I mean?\r\nDialogue: 0,0:17:34.62,0:17:40.07,yin,,0,0,0,,它会同present它的视图控制器保持相同的context\\N{\\fs12}So it's going to keep the same context as the view controller that presented it.\r\nDialogue: 0,0:17:40.07,0:17:42.11,yin,,0,0,0,,无论如何 这些的细节你们都可以自己去查\\N{\\fs12}So anyway you can look all this up for details.\r\nDialogue: 0,0:17:42.11,0:17:45.79,yin,,0,0,0,,这两个属性在Xcode中都可以设置\\N{\\fs12}It's all settable in Xcode as well, these two properties.\r\nDialogue: 0,0:17:45.79,0:17:47.30,yin,,0,0,0,,以上是模态视图控制器\\N{\\fs12}All right so that's it for modal view controllers.\r\nDialogue: 0,0:17:47.30,0:17:51.58,yin,,0,0,0,,我会给出demo 你们会看到现场演示\\N{\\fs12}I'm going to demo it so you'll see it all in action.\r\nDialogue: 0,0:17:51.58,0:17:53.70,yin,,0,0,0,,再看另一个主题 UITextField(文本框)\\N{\\fs12}All right, different topic, UI text field.\r\nDialogue: 0,0:17:53.70,0:17:57.66,yin,,0,0,0,,我们看到过UITextView和UILabel\\N{\\fs12}So we've seen UI text view and UI label.\r\nDialogue: 0,0:17:57.66,0:17:59.76,yin,,0,0,0,,这是文本的两极\\N{\\fs12}Okay these are kind of two ends of the spectrum of text.\r\nDialogue: 0,0:17:59.76,0:18:02.14,yin,,0,0,0,,UILabel 不可编辑\\N{\\fs12}UI label, non editable.\r\nDialogue: 0,0:18:02.14,0:18:04.65,yin,,0,0,0,,其中可以有带属性的文本\\N{\\fs12}You know you can have attributed text in there\r\nDialogue: 0,0:18:04.65,0:18:07.91,yin,,0,0,0,,不过文本是静态的 你不能选它\\N{\\fs12}but it's static text, can't select it or anything like that.\r\nDialogue: 0,0:18:07.91,0:18:09.66,yin,,0,0,0,,通常都只一行文字\\N{\\fs12}Usually one line of text.\r\nDialogue: 0,0:18:09.68,0:18:12.76,yin,,0,0,0,,然后UITextView几乎就是一个文本编辑器\\N{\\fs12}Then you've got UI text view which is almost like a text editor,\r\nDialogue: 0,0:18:12.76,0:18:16.96,yin,,0,0,0,,完全可编辑 所有字体和颜色 想要怎样都行\\N{\\fs12}okay fully editable, all fonts and colors, everything we want.\r\nDialogue: 0,0:18:16.96,0:18:20.14,yin,,0,0,0,,UITextField可以说是介于两者之间\\N{\\fs12}So UI text field is kind of in between those two.\r\nDialogue: 0,0:18:20.14,0:18:23.63,yin,,0,0,0,,它是一种UIControl 同UIButton这些一样\\N{\\fs12}It's a UI control, like a UI button or something like that\r\nDialogue: 0,0:18:23.63,0:18:26.89,yin,,0,0,0,,你可以从这里设置目标动作\\N{\\fs12}that you can set up target action from.\r\nDialogue: 0,0:18:26.89,0:18:28.43,yin,,0,0,0,,这些目标动作\\N{\\fs12}And that target action can happen\r\nDialogue: 0,0:18:28.43,0:18:31.28,yin,,0,0,0,,可以在你完成文本编辑\\N{\\fs12}when you're done editing the text or other\r\nDialogue: 0,0:18:31.28,0:18:33.36,yin,,0,0,0,,或其它文本操作后发生\\N{\\fs12}things that are happening in the text and you can just,\r\nDialogue: 0,0:18:33.36,0:18:37.36,yin,,0,0,0,,你control拖动来做这个 你会看到各种选项\\N{\\fs12}when you control drag to do it you'll see the options you have in the little\r\nDialogue: 0,0:18:37.36,0:18:40.94,yin,,0,0,0,,位于出现的目标动作窗口\\N{\\fs12}target action window that comes up.\r\nDialogue: 0,0:18:40.94,0:18:43.65,yin,,0,0,0,,不过UITextField通常也只有一行文字\\N{\\fs12}But it's also usually just one line of text.\r\nDialogue: 0,0:18:43.65,0:18:45.92,yin,,0,0,0,,不像UITextView可以有很多文本\\N{\\fs12}It's not like UI text view that has [inaudible].\r\nDialogue: 0,0:18:45.92,0:18:48.71,yin,,0,0,0,,而且 用户通常只是提供文本\\N{\\fs12}Also, the user is usually just providing the text,\r\nDialogue: 0,0:18:48.71,0:18:52.25,yin,,0,0,0,,不涉及到颜色 字体这些文本属性\\N{\\fs12}they're not doing any colors or any of that attributed text business.\r\nDialogue: 0,0:18:52.25,0:18:56.41,yin,,0,0,0,,一般而言 UITextField只是纯文本\\N{\\fs12}Generally UI text field is just the text and nothing but the text.\r\nDialogue: 0,0:18:56.41,0:18:59.03,yin,,0,0,0,,不过 它有很多特性\\N{\\fs12}Having said that, it's got a lot of features\r\nDialogue: 0,0:18:59.03,0:19:02.18,yin,,0,0,0,,这让它非常酷 可以作为密码输入\\N{\\fs12}to make it really cool for doing things like entering passwords\r\nDialogue: 0,0:19:02.18,0:19:04.93,yin,,0,0,0,,或是搜索框 等等\\N{\\fs12}or having a search field, all those kind of things.\r\nDialogue: 0,0:19:04.93,0:19:06.95,yin,,0,0,0,,这是一个很强大的类\\N{\\fs12}So it's a pretty powerful little class.\r\nDialogue: 0,0:19:06.95,0:19:11.76,yin,,0,0,0,,你可以把它看成是一个可编辑的UILabel\\N{\\fs12}But it's kind of like an editable UI label if you want to think of it that way.\r\nDialogue: 0,0:19:11.76,0:19:13.38,yin,,0,0,0,,UITextField有一点很有趣\\N{\\fs12}One thing that's interesting about a UI text field\r\nDialogue: 0,0:19:13.38,0:19:16.30,yin,,0,0,0,,也就是点它时 键盘会出现\\N{\\fs12}of course is that when you click in it, the keyboard appears.\r\nDialogue: 0,0:19:16.30,0:19:18.59,yin,,0,0,0,,讲UITextView时 我并没讲键盘如何出现\\N{\\fs12}Now we didn't really talk about how this keyboard appears\r\nDialogue: 0,0:19:18.59,0:19:20.35,yin,,0,0,0,,讲UITextView时 我并没讲键盘如何出现\\N{\\fs12}when we talked about UI text view,\r\nDialogue: 0,0:19:20.35,0:19:22.42,yin,,0,0,0,,键盘是如何出现的呢\\N{\\fs12}but how does that work that the keyboard appears?\r\nDialogue: 0,0:19:22.42,0:19:27.56,yin,,0,0,0,,答案是 有一个方法叫becomeFirstResponder\\N{\\fs12}And the answer is, there is a method called become first responder\r\nDialogue: 0,0:19:27.56,0:19:30.24,yin,,0,0,0,,如果你把它发送给一个文本框\\N{\\fs12}that is sent, that if you send it to a text field\r\nDialogue: 0,0:19:30.24,0:19:33.27,yin,,0,0,0,,或是它被发送到一个文本框 键盘就会出现\\N{\\fs12}or it gets sent to a text field, will cause the keyboard to appear.\r\nDialogue: 0,0:19:33.27,0:19:35.69,yin,,0,0,0,,你把这个方法发送给文本框\\N{\\fs12}So this is a method you send to the text field.\r\nDialogue: 0,0:19:35.69,0:19:37.41,yin,,0,0,0,,它也可以被发送给文本视图\\N{\\fs12}You can also send it to a text view.\r\nDialogue: 0,0:19:37.41,0:19:39.76,yin,,0,0,0,,这样做时 键盘就会出现\\N{\\fs12}And when you do that, the keyboard will appear.\r\nDialogue: 0,0:19:39.76,0:19:41.79,yin,,0,0,0,,类似地 如果你想让键盘消失\\N{\\fs12}And similarly, if you want the keyboard to go away,\r\nDialogue: 0,0:19:41.79,0:19:44.68,yin,,0,0,0,,你可以发送消息resignFirstResponder给文本框\\N{\\fs12}you send a message to the text field, resign first responder.\r\nDialogue: 0,0:19:44.68,0:19:46.22,yin,,0,0,0,,第一响应器FirstResponder\\N{\\fs12}But first responder means\r\nDialogue: 0,0:19:46.22,0:19:50.05,yin,,0,0,0,,说的是在键盘上按键后会显示在哪里\\N{\\fs12}where do keyboard presses on the keyboard go?\r\nDialogue: 0,0:19:50.05,0:19:52.03,yin,,0,0,0,,如果你说 成为第一响应器\\N{\\fs12}So if you say become first responder,\r\nDialogue: 0,0:19:52.03,0:19:53.58,yin,,0,0,0,,文本框会变成第一响应器\\N{\\fs12}the text field becomes the first responder\r\nDialogue: 0,0:19:53.58,0:19:56.41,yin,,0,0,0,,键盘会出现 按键会显示到那个文本框中\\N{\\fs12}and the keyboard will appear and key presses will go to that text field\r\nDialogue: 0,0:19:56.41,0:19:59.22,yin,,0,0,0,,resign也一样 键盘会消失\\N{\\fs12}and similar to resign, it'll go away.\r\nDialogue: 0,0:20:01.10,0:20:04.31,yin,,0,0,0,,UITextField有委托 不像UILabel\\N{\\fs12}There's a delegate for UI text field unlike UI label\r\nDialogue: 0,0:20:04.31,0:20:06.26,yin,,0,0,0,,这里你可以看到很多东西\\N{\\fs12}and there's a lot of stuff you can see there.\r\nDialogue: 0,0:20:06.26,0:20:08.29,yin,,0,0,0,,demo中我会演示一个简单的例子\\N{\\fs12}I'll show you a brief example in the demo.\r\nDialogue: 0,0:20:08.29,0:20:13.80,yin,,0,0,0,,例如 当键盘上点击回车键时\\N{\\fs12}For example, when the keyboard presses the return key, when the return key is pressed\r\nDialogue: 0,0:20:13.80,0:20:16.25,yin,,0,0,0,,文本框被编辑 文本框的委托\\N{\\fs12}and that text field is being edited the text field's delegate\r\nDialogue: 0,0:20:16.25,0:20:18.65,yin,,0,0,0,,会发送这条消息 textFieldShouldReturn\\N{\\fs12}will send this message, text field should return.\r\nDialogue: 0,0:20:18.65,0:20:22.64,yin,,0,0,0,,返回应不应该发送它的目标动作\\N{\\fs12}Return yes or no whether it should send its target action basically.\r\nDialogue: 0,0:20:22.64,0:20:26.64,yin,,0,0,0,,这里 你可以做resignFirstResponder这些事\\N{\\fs12}And in there you can do things like resign first responder.\r\nDialogue: 0,0:20:26.64,0:20:31.09,yin,,0,0,0,,当键盘弹出后 有人点了回车 你可以让键盘消失\\N{\\fs12}So when the keyboard comes up, someone hits return, you can make the keyboard go away\r\nDialogue: 0,0:20:31.09,0:20:32.93,yin,,0,0,0,,这通常就是用户所期望的\\N{\\fs12}which is usually what users expect.\r\nDialogue: 0,0:20:32.93,0:20:34.81,yin,,0,0,0,,demo中我也会演示这个\\N{\\fs12}So we'll see that in the demo as well.\r\nDialogue: 0,0:20:34.81,0:20:36.00,yin,,0,0,0,,还有其它委托方法\\N{\\fs12}But there are other delegate methods,\r\nDialogue: 0,0:20:36.00,0:20:37.66,yin,,0,0,0,,我只是给你们举出了一个例子\\N{\\fs12}I just want to give you an example of one of them there.\r\nDialogue: 0,0:20:37.66,0:20:39.18,yin,,0,0,0,,这些方法大概有十个\\N{\\fs12}There's probably about 10 of them.\r\nDialogue: 0,0:20:39.18,0:20:41.73,yin,,0,0,0,,你们可以自己去说明文档查查\\N{\\fs12}Check out the documentation on that.\r\nDialogue: 0,0:20:41.73,0:20:44.43,yin,,0,0,0,,这里是另一个 textFieldDidEndEditing\\N{\\fs12}Over here's another one, text field did end editing.\r\nDialogue: 0,0:20:44.43,0:20:48.89,yin,,0,0,0,,resignFirstResponder完成后 这就会被发送给委托\\N{\\fs12}That's sent to the delegate when it resigns first responder.\r\nDialogue: 0,0:20:48.89,0:20:51.86,yin,,0,0,0,,当它不再是第一响应器时 这条信息就会被发送\\N{\\fs12}So when it stops being first responder, this message gets sent.\r\nDialogue: 0,0:20:51.86,0:20:56.51,yin,,0,0,0,,它还有一个广播站 广播每一次按键\\N{\\fs12}It also has a radio station that it broadcasts on every single keystroke.\r\nDialogue: 0,0:20:56.51,0:21:00.69,yin,,0,0,0,,如果你想知道每次敲入文本框的是什么字符\\N{\\fs12}Okay so if you want to find out every single character that's typed\r\nDialogue: 0,0:21:00.69,0:21:04.07,yin,,0,0,0,,你可以注册到这个广播站\\N{\\fs12}in your text field you can sign up to listen to this radio station\r\nDialogue: 0,0:21:04.07,0:21:06.87,yin,,0,0,0,,这样你就会知道发生了什么\\N{\\fs12}and you'll find out what's going on.\r\nDialogue: 0,0:21:06.87,0:21:10.26,yin,,0,0,0,,我说了 UITextField是受控的 你也可以设置目标动作\\N{\\fs12}And like I said, UI text field is controlled so you can set up target action as well.\r\nDialogue: 0,0:21:10.26,0:21:13.01,yin,,0,0,0,,想知道文本框中发生了什么 你有很多方式\\N{\\fs12}So there's a lot of ways to find out what's going on a text field\r\nDialogue: 0,0:21:13.01,0:21:15.59,yin,,0,0,0,,取决于你想要怎样的粒度\\N{\\fs12}depending on the granularity that you want.\r\nDialogue: 0,0:21:15.59,0:21:18.44,yin,,0,0,0,,键盘 其实并没有\\N{\\fs12}The keyboard, the exper- we don't,\r\nDialogue: 0,0:21:18.44,0:21:21.64,yin,,0,0,0,,一个属性说 给我一个键盘\\N{\\fs12}there's really no property like give me the keyboard\r\nDialogue: 0,0:21:21.64,0:21:23.55,yin,,0,0,0,,然后我可以设置它的属性\\N{\\fs12}so that I can set properties on it.\r\nDialogue: 0,0:21:23.55,0:21:26.22,yin,,0,0,0,,如果你想控制键盘的样子\\N{\\fs12}Okay when you want to control the appearance of the keyboard,\r\nDialogue: 0,0:21:26.22,0:21:31.45,yin,,0,0,0,,你就需要发送消息给类 UITextField\\N{\\fs12}you have to send messages to the class, UI text field\r\nDialogue: 0,0:21:31.45,0:21:34.70,yin,,0,0,0,,或UITextView 来弹出键盘\\N{\\fs12}or UI text view that brings the keyboard up.\r\nDialogue: 0,0:21:34.70,0:21:39.74,yin,,0,0,0,,这些对象 这些类 都会实现这个协议\\N{\\fs12}And those objects, those classes will all implement this protocol\r\nDialogue: 0,0:21:39.74,0:21:42.28,yin,,0,0,0,,名为UITextInputTraits\\N{\\fs12}called UI text input traits.\r\nDialogue: 0,0:21:42.28,0:21:46.39,yin,,0,0,0,,这是一组属性 你可以在文本框或文本视图中设置\\N{\\fs12}So these are the set of properties that you can set on a text field or on a text view\r\nDialogue: 0,0:21:46.39,0:21:49.45,yin,,0,0,0,,这不会控制文本框或文本视图的任何东西\\N{\\fs12}that aren't really controlling anything about the text view or the text field,\r\nDialogue: 0,0:21:49.45,0:21:54.04,yin,,0,0,0,,它们控制的是弹出键盘的属性\\N{\\fs12}they're controlling the properties of the keyboard that they would bring up.\r\nDialogue: 0,0:21:54.04,0:21:57.33,yin,,0,0,0,,这里有些属性 例如自动大写\\N{\\fs12}So what are some of the properties you can have like auto capitalization.\r\nDialogue: 0,0:21:57.33,0:21:59.14,yin,,0,0,0,,有时在文本框中\\N{\\fs12}Sometimes it's nice you have a text field,\r\nDialogue: 0,0:21:59.14,0:22:02.27,yin,,0,0,0,,你希望第一个键入的字母是大写\\N{\\fs12}the first character you type, you want it to be capitalized.\r\nDialogue: 0,0:22:02.27,0:22:05.75,yin,,0,0,0,,或者每个单词的首字母大写\\N{\\fs12}Or every word you type, separate word you want it\r\nDialogue: 0,0:22:05.75,0:22:09.80,yin,,0,0,0,,你可以设置你想要的大写方式\\N{\\fs12}to be capitalized so you can set the kind of capitalization type that you have.\r\nDialogue: 0,0:22:09.80,0:22:12.83,yin,,0,0,0,,或许文本框中是密码\\N{\\fs12}Maybe it's a password. This text field's a password\r\nDialogue: 0,0:22:12.83,0:22:15.99,yin,,0,0,0,,你希望键入时显示点\\N{\\fs12}and so you want it to be the dots when you type them.\r\nDialogue: 0,0:22:15.99,0:22:20.27,yin,,0,0,0,,出于安全考虑 这里让输入字符都是点\\N{\\fs12}Okay so secure text entry will make [inaudible] the dots.\r\nDialogue: 0,0:22:20.27,0:22:24.76,yin,,0,0,0,,回车键 键盘弹出时 它会有一个回车\\N{\\fs12}The return key, when the keyboard comes up it has a little return, okay,\r\nDialogue: 0,0:22:24.76,0:22:26.41,yin,,0,0,0,,这个上面可以有词汇\\N{\\fs12}and that can have a word on it\r\nDialogue: 0,0:22:26.41,0:22:29.51,yin,,0,0,0,,例如搜索 前进或是返回\\N{\\fs12}like search or go, okay, or return.\r\nDialogue: 0,0:22:29.51,0:22:31.94,yin,,0,0,0,,你可以通过returnKeyType来控制\\N{\\fs12}And you can control that with a return key type.\r\nDialogue: 0,0:22:31.94,0:22:35.85,yin,,0,0,0,,所有这些都是在UITextField中设置的属性\\N{\\fs12}So these are all things that you set, properties you set in your UI text field\r\nDialogue: 0,0:22:35.85,0:22:38.63,yin,,0,0,0,,不过实际控制的是键盘\\N{\\fs12}but you're really controlling the keyboard.\r\nDialogue: 0,0:22:38.63,0:22:39.94,yin,,0,0,0,,关于键盘还有一点\\N{\\fs12}One thing about the keyboard,\r\nDialogue: 0,0:22:39.94,0:22:42.74,yin,,0,0,0,,它会出现在其它视图之上\\N{\\fs12}it comes up on top of other views.\r\nDialogue: 0,0:22:42.74,0:22:43.78,yin,,0,0,0,,并覆盖它们\\N{\\fs12}It covers them.\r\nDialogue: 0,0:22:43.78,0:22:45.96,yin,,0,0,0,,它从底部出现 覆盖它们\\N{\\fs12}It comes up from the bottom, covers them.\r\nDialogue: 0,0:22:45.96,0:22:49.15,yin,,0,0,0,,如果文本框在最下面 这就会成问题\\N{\\fs12}All right, that can be a problem if your text field's at the bottom\r\nDialogue: 0,0:22:49.15,0:22:51.99,yin,,0,0,0,,因为要输入的地方被盖住了\\N{\\fs12}because you just covered the thing you're typing in.\r\nDialogue: 0,0:22:51.99,0:22:56.29,yin,,0,0,0,,一 在设计中确保UI里这个不会发生\\N{\\fs12}So A, try to design your UIs so that doesn't happen.\r\nDialogue: 0,0:22:56.29,0:23:00.45,yin,,0,0,0,,二 如果你的视图可以滚动\\N{\\fs12}But B, you can for example, if your view is scrollable,\r\nDialogue: 0,0:23:00.45,0:23:04.18,yin,,0,0,0,,你可以将文本框或整个视图往上滚动\\N{\\fs12}maybe scroll that text field up or even just move the whole view up\r\nDialogue: 0,0:23:04.20,0:23:07.21,yin,,0,0,0,,这样在弹出键盘时 你就还是能看到你\\N{\\fs12}so that while the keyboard's up, you can still see your text field\r\nDialogue: 0,0:23:07.21,0:23:09.18,yin,,0,0,0,,要键入的文本框\\N{\\fs12}that you're typing into.\r\nDialogue: 0,0:23:09.18,0:23:12.06,yin,,0,0,0,,要知道键盘弹出\\N{\\fs12}And so the way you find out the keyboard's come up\r\nDialogue: 0,0:23:12.06,0:23:13.70,yin,,0,0,0,,并盖住了多少\\N{\\fs12}and how much it's covering\r\nDialogue: 0,0:23:13.70,0:23:15.80,yin,,0,0,0,,你可以收听这个广播站\\N{\\fs12}is by tuning into this radio station\r\nDialogue: 0,0:23:15.80,0:23:20.00,yin,,0,0,0,,UIKeyboard Will或Did Show或Hide Notifications\\N{\\fs12}UI keyboard will or did show or hide notification.\r\nDialogue: 0,0:23:20.00,0:23:23.80,yin,,0,0,0,,该通知会由你所在的窗口发送\\N{\\fs12}It's a notification sent by the window you're in.\r\nDialogue: 0,0:23:23.80,0:23:27.43,yin,,0,0,0,,视图控制器的self.view.window\\N{\\fs12}Okay, self dot view dot window for view controller.\r\nDialogue: 0,0:23:27.43,0:23:30.43,yin,,0,0,0,,由这个广播站得到的用户信息\\N{\\fs12}And the user info that you get with this radio station\r\nDialogue: 0,0:23:30.44,0:23:34.11,yin,,0,0,0,,会告诉你 键盘的矩形出现在哪\\N{\\fs12}will tell you the rectangles of where the keyboard appeared\r\nDialogue: 0,0:23:34.11,0:23:36.66,yin,,0,0,0,,你有义务将它挪开\\N{\\fs12}and it's your responsibility to move it out of the way.\r\nDialogue: 0,0:23:36.66,0:23:41.77,yin,,0,0,0,,UIKit中唯一自动进行移动的类是\\N{\\fs12}The only class in the kit, in the UI kit that will move the thing automatically\r\nDialogue: 0,0:23:41.77,0:23:44.29,yin,,0,0,0,,UITableViewController\\N{\\fs12}for you is UI table view controller.\r\nDialogue: 0,0:23:44.29,0:23:46.81,yin,,0,0,0,,如果你在表格视图中有一行\\N{\\fs12}So if you have a row in a table view that's\r\nDialogue: 0,0:23:46.81,0:23:48.63,yin,,0,0,0,,处在UITableViewController中\\N{\\fs12}in a UI table view controller\r\nDialogue: 0,0:23:48.63,0:23:51.91,yin,,0,0,0,,而且它是可编辑文本 你将键盘弹出\\N{\\fs12}and it's editable text and you bring the keyboard up,\r\nDialogue: 0,0:23:51.91,0:23:54.28,yin,,0,0,0,,它会自动滚动表格视图 来移动它\\N{\\fs12}it'll automatically scroll the table view so move it.\r\nDialogue: 0,0:23:54.28,0:23:55.86,yin,,0,0,0,,这是唯一的自动做法\\N{\\fs12}Okay so that's the only one that automatically does it.\r\nDialogue: 0,0:23:55.86,0:23:58.48,yin,,0,0,0,,其它情况下 都需要你自己来\\N{\\fs12}Otherwise it's your responsibility to make,\r\nDialogue: 0,0:23:58.48,0:24:01.63,yin,,0,0,0,,移动被键盘挡住的东西\\N{\\fs12}move anything that gets obscured by the keyboard.\r\nDialogue: 0,0:24:03.27,0:24:05.70,yin,,0,0,0,,其它文本框属性 你们可以自己去查\\N{\\fs12}Other text field properties, you can go look those up.\r\nDialogue: 0,0:24:05.70,0:24:09.73,yin,,0,0,0,,它有一个很好的左右附属视图 就像annotation对话框\\N{\\fs12}It has a nice left and right accessory view kind of like the annotation call out.\r\nDialogue: 0,0:24:09.73,0:24:12.55,yin,,0,0,0,,你甚至还可以往键盘上加一个小视图\\N{\\fs12}You can even add a little view to the keyboard\r\nDialogue: 0,0:24:12.55,0:24:14.97,yin,,0,0,0,,使用这个inputAccessoryView\\N{\\fs12}with this input accessory view.\r\nDialogue: 0,0:24:14.97,0:24:17.80,yin,,0,0,0,,文本框中有很多内容值得一看\\N{\\fs12}There's a lot of stuff to look at in text field, I can't,\r\nDialogue: 0,0:24:17.80,0:24:19.53,yin,,0,0,0,,我今天没时间一一讲到\\N{\\fs12}I don't have time to cover it all today\r\nDialogue: 0,0:24:19.53,0:24:23.36,yin,,0,0,0,,你们可以自己去看UITextField的说明文档\\N{\\fs12}but you can look it all up in UI text field's documentation.\r\nDialogue: 0,0:24:23.36,0:24:25.88,yin,,0,0,0,,今天在demo演示前我想讲的最后一点是\\N{\\fs12}All right the last thing I'm going to talk about today before the demo is\r\nDialogue: 0,0:24:25.88,0:24:27.58,yin,,0,0,0,,动作表单和警告\\N{\\fs12}action sheet and alert.\r\nDialogue: 0,0:24:27.58,0:24:30.99,yin,,0,0,0,,动作表单和警告是弹出到屏幕上的东西\\N{\\fs12}So action sheet and alert are things that pop up on the screen\r\nDialogue: 0,0:24:30.99,0:24:32.75,yin,,0,0,0,,来警告用户一些事情\\N{\\fs12}to alert the user of something obviously\r\nDialogue: 0,0:24:32.75,0:24:35.44,yin,,0,0,0,,或是让它们作出一些选择\\N{\\fs12}or to give them kind of a branching decision.\r\nDialogue: 0,0:24:35.44,0:24:39.09,yin,,0,0,0,,动作表单用于用户选择 警告用于警告用户\\N{\\fs12}Okay action sheet for branching decisions alerts to alert them of something.\r\nDialogue: 0,0:24:39.09,0:24:43.33,yin,,0,0,0,,我讲它们是因为 它们有很类似的API\\N{\\fs12}They have very, the reason I talk about them together, they have very similar APIs,\r\nDialogue: 0,0:24:43.33,0:24:45.41,yin,,0,0,0,,换言之 也就是编程接口\\N{\\fs12}in other words programming interfaces.\r\nDialogue: 0,0:24:45.41,0:24:47.19,yin,,0,0,0,,只是用于不同的环境下\\N{\\fs12}They're used in different circumstances though.\r\nDialogue: 0,0:24:47.19,0:24:50.67,yin,,0,0,0,,警告更多的是说 有什么事发生了\\N{\\fs12}An alert is more saying something happened,\r\nDialogue: 0,0:24:50.67,0:24:53.37,yin,,0,0,0,,请注意 或是 我需要一点信息\\N{\\fs12}pay attention, or I need a little piece of information,\r\nDialogue: 0,0:24:53.37,0:24:56.24,yin,,0,0,0,,请现在就给我 否则我无法继续\\N{\\fs12}please give it to me right now or I can't proceed.\r\nDialogue: 0,0:24:56.24,0:25:00.60,yin,,0,0,0,,它有点像模态视图控制器 只是它只能\\N{\\fs12}It's a little bit like a modal view controller except for that it can only,\r\nDialogue: 0,0:25:00.60,0:25:03.30,yin,,0,0,0,,问一个简单问题 得到一个简单答案\\N{\\fs12}you know, ask a simple question and get a simple answer.\r\nDialogue: 0,0:25:03.30,0:25:05.08,yin,,0,0,0,,这就是警告的作用\\N{\\fs12}So that's what an alert is for.\r\nDialogue: 0,0:25:05.08,0:25:06.68,yin,,0,0,0,,不要过度使用警告\\N{\\fs12}Don't overuse alerts either.\r\nDialogue: 0,0:25:06.68,0:25:10.17,yin,,0,0,0,,同模态视图控制器一样 警告也不要过度使用\\N{\\fs12}Just like I say don't overuse modal view controllers, don't overuse alerts.\r\nDialogue: 0,0:25:10.17,0:25:11.95,yin,,0,0,0,,不要任何需要信息的时候\\N{\\fs12}Don't every time you need a piece of information\r\nDialogue: 0,0:25:11.95,0:25:14.68,yin,,0,0,0,,都弹出警告窗口找用户要\\N{\\fs12}from the user just put up an alert and ask them for it.\r\nDialogue: 0,0:25:14.68,0:25:18.83,yin,,0,0,0,,让用户自己去点然后输入会更好\\N{\\fs12}You know it's nicer for them to be able to just click on something and start typing.\r\nDialogue: 0,0:25:18.83,0:25:21.15,yin,,0,0,0,,你们可以看看联系人app\\N{\\fs12}Take a look for example at the contacts app.\r\nDialogue: 0,0:25:21.15,0:25:25.50,yin,,0,0,0,,虽然联系人app会在模态视图控制器中弹出添加联系人\\N{\\fs12}Even that contact app where it brought up the add contact in a modal view controller,\r\nDialogue: 0,0:25:25.50,0:25:31.02,yin,,0,0,0,,但在添加文本 URL或电子邮件时\\N{\\fs12}when it comes to adding things like text or the, you know, URLs or emails,\r\nDialogue: 0,0:25:31.02,0:25:33.09,yin,,0,0,0,,都只需要点击相应位置 然后键入\\N{\\fs12}you just click right there and you just type them in.\r\nDialogue: 0,0:25:33.09,0:25:36.19,yin,,0,0,0,,并不需要再次使用模态来获得这些信息\\N{\\fs12}It doesn't go modal again on you just for that kind of information,\r\nDialogue: 0,0:25:36.19,0:25:40.55,yin,,0,0,0,,你们自己去看看 怎么使用才好\\N{\\fs12}so check that out to see how that can be nicely used.\r\nDialogue: 0,0:25:40.55,0:25:44.73,yin,,0,0,0,,动作表单 可以从iPhone底部滑上来\\N{\\fs12}Action sheets are, they slide up from the bottom on the iPhone,\r\nDialogue: 0,0:25:44.73,0:25:47.96,yin,,0,0,0,,在iPad中通常是以弹窗形式出现\\N{\\fs12}they usually appear on a popover on the iPad.\r\nDialogue: 0,0:25:47.96,0:25:50.35,yin,,0,0,0,,它们被用于用户选择\\N{\\fs12}They are for really branching decisions, so\r\nDialogue: 0,0:25:50.35,0:25:52.77,yin,,0,0,0,,下面 用户想做点什么\\N{\\fs12}the user wants to do something next\r\nDialogue: 0,0:25:52.77,0:25:55.29,yin,,0,0,0,,但之前他需要告诉你\\N{\\fs12}but you, they need to tell you something\r\nDialogue: 0,0:25:55.29,0:25:58.58,yin,,0,0,0,,让你知道下一步怎么走\\N{\\fs12}so you can decide which way to go.\r\nDialogue: 0,0:25:58.58,0:26:00.92,yin,,0,0,0,,这就是动作表单的作用\\N{\\fs12}So that's what action sheets are for.\r\nDialogue: 0,0:26:00.92,0:26:02.88,yin,,0,0,0,,重复一次 它们都是模态的\\N{\\fs12}And again they're modal.\r\nDialogue: 0,0:26:02.88,0:26:06.80,yin,,0,0,0,,动作表单会让一切停止 直到用户回答了问题\\N{\\fs12}They stop everything until the person answers the question of what's an action sheet.\r\nDialogue: 0,0:26:06.80,0:26:10.20,yin,,0,0,0,,确保这确实是你想要的UI\\N{\\fs12}So make sure that's really the UI you want as opposed\r\nDialogue: 0,0:26:10.20,0:26:14.68,yin,,0,0,0,,你要的不是UI中的按钮 push出不同视图控制器\\N{\\fs12}to just having, you know, buttons in your UI that push different view controllers.\r\nDialogue: 0,0:26:14.68,0:26:17.46,yin,,0,0,0,,那也是进行分支决定的方法\\N{\\fs12}That's another way to do branching decisions as well.\r\nDialogue: 0,0:26:17.46,0:26:22.08,yin,,0,0,0,,我们会看到动作表单 这些的demo会在周三\\N{\\fs12}And we'll see action sheets. I'll be demoing those on Wednesday.\r\nDialogue: 0,0:26:22.08,0:26:24.41,yin,,0,0,0,,这两者的API是怎样的呢\\N{\\fs12}All right, what's the API for these two things look like?\r\nDialogue: 0,0:26:24.41,0:26:25.16,yin,,0,0,0,,很类似\\N{\\fs12}Very similar.\r\nDialogue: 0,0:26:25.16,0:26:27.14,yin,,0,0,0,,我首先来讲动作表单\\N{\\fs12}I'll start with action sheets first.\r\nDialogue: 0,0:26:27.14,0:26:28.34,yin,,0,0,0,,你只需alloc init\\N{\\fs12}You just alloc init it.\r\nDialogue: 0,0:26:28.34,0:26:30.89,yin,,0,0,0,,这是动作表单的指定初始化器\\N{\\fs12}Here's the designated initializer for action sheet.\r\nDialogue: 0,0:26:30.89,0:26:32.04,yin,,0,0,0,,它需要一个标题\\N{\\fs12}You can see that it takes a title--\r\nDialogue: 0,0:26:32.04,0:26:34.29,yin,,0,0,0,,动作表单顶部有一个标题\\N{\\fs12}the action sheet has a little title at the top.\r\nDialogue: 0,0:26:34.29,0:26:35.59,yin,,0,0,0,,它还有一个委托\\N{\\fs12}It has a delegate.\r\nDialogue: 0,0:26:35.59,0:26:39.59,yin,,0,0,0,,委托会告诉你 动作表单中选的是什么\\N{\\fs12}The delegate mostly will tell you what was chosen in the action sheet.\r\nDialogue: 0,0:26:39.59,0:26:43.07,yin,,0,0,0,,如果是在警告视图中 它会告诉你按的是哪个按钮\\N{\\fs12}Or in alert view it'll tell you which button was chosen.\r\nDialogue: 0,0:26:43.09,0:26:45.75,yin,,0,0,0,,还有一些特殊按钮 一个是取消按钮\\N{\\fs12}There are some special buttons, a cancel button,\r\nDialogue: 0,0:26:45.75,0:26:49.84,yin,,0,0,0,,这会取消动作表单 不做任何决定\\N{\\fs12}okay which cancels the action sheet without making a decision.\r\nDialogue: 0,0:26:49.84,0:26:51.03,yin,,0,0,0,,毁灭性按钮\\N{\\fs12}Destructive button,\r\nDialogue: 0,0:26:51.03,0:26:53.79,yin,,0,0,0,,动作表单中可以有一个这样的按钮\\N{\\fs12}that's, you can have one button in your action sheet like that\r\nDialogue: 0,0:26:53.79,0:26:56.13,yin,,0,0,0,,它可以被标成红色\\N{\\fs12}and that will be like in red or otherwise\r\nDialogue: 0,0:26:56.13,0:26:58.21,yin,,0,0,0,,告诉用户 如果你选这个\\N{\\fs12}telling the user, if you choose this,\r\nDialogue: 0,0:26:58.21,0:26:59.65,yin,,0,0,0,,毁灭性的事情会发生\\N{\\fs12}something destructive's going to happen.\r\nDialogue: 0,0:26:59.65,0:27:02.62,yin,,0,0,0,,例如删除这样的事情\\N{\\fs12}This is like delete, or something like that.\r\nDialogue: 0,0:27:02.62,0:27:04.51,yin,,0,0,0,,这就是毁灭性按钮\\N{\\fs12}So that's what destructive button is.\r\nDialogue: 0,0:27:04.51,0:27:06.94,yin,,0,0,0,,然后你可以有任意数量的标题\\N{\\fs12}And then you can have as many other titles as you want.\r\nDialogue: 0,0:27:06.94,0:27:09.16,yin,,0,0,0,,这些是你可以选的其它分支\\N{\\fs12}Those are all the other branches you can take besides the\r\nDialogue: 0,0:27:09.16,0:27:11.86,yin,,0,0,0,,除了毁灭性按钮 或是取消 什么都不做\\N{\\fs12}destructive one or cancel, not doing anything.\r\nDialogue: 0,0:27:11.86,0:27:14.29,yin,,0,0,0,,你还可以通过程序添加按钮\\N{\\fs12}You can also add buttons programmatically.\r\nDialogue: 0,0:27:14.29,0:27:16.75,yin,,0,0,0,,如果你想在alloc init中提供它们\\N{\\fs12}If you don't want to provide them in the alloc init\r\nDialogue: 0,0:27:16.75,0:27:20.12,yin,,0,0,0,,你可以调用动作表单中的addButtonWithTitle\\N{\\fs12}you can just call add button with title to add in the action sheet.\r\nDialogue: 0,0:27:20.12,0:27:23.90,yin,,0,0,0,,然后是显示动作表单 你可以这样做\\N{\\fs12}And then it's time to display the action sheet and you'd kind\r\nDialogue: 0,0:27:23.90,0:27:26.87,yin,,0,0,0,,取决于你处在怎样的上下文中\\N{\\fs12}of do this, depends on where, what context you're in.\r\nDialogue: 0,0:27:26.87,0:27:29.86,yin,,0,0,0,,在iPhone上 几乎总是用showInView\\N{\\fs12}On the iPhone, you've almost always going to do show in view.\r\nDialogue: 0,0:27:29.86,0:27:32.32,yin,,0,0,0,,视图很多时候是self.view\\N{\\fs12}A lot of times self dot view,\r\nDialogue: 0,0:27:32.32,0:27:36.09,yin,,0,0,0,,或者是self.view中的某个视图\\N{\\fs12}or if you have a view that's inside your self dot view, you could show it from that.\r\nDialogue: 0,0:27:36.09,0:27:37.43,yin,,0,0,0,,在iPhone上这些都行\\N{\\fs12}But it doesn't really matter on the iPhone\r\nDialogue: 0,0:27:37.43,0:27:39.75,yin,,0,0,0,,因为它总会从底部滑上来\\N{\\fs12}because it's always going to slide up from the bottom.\r\nDialogue: 0,0:27:39.75,0:27:41.42,yin,,0,0,0,,无论你怎么在iPhone上呈现动作表单\\N{\\fs12}No matter how you present an action sheet on an iPhone,\r\nDialogue: 0,0:27:41.42,0:27:43.63,yin,,0,0,0,,它总会从底部滑上来\\N{\\fs12}it's always going to slide up from the bottom.\r\nDialogue: 0,0:27:43.63,0:27:47.74,yin,,0,0,0,,不过iPad上 它会以弹窗形式出现\\N{\\fs12}But on the iPad, since it's going to appear in a popover,\r\nDialogue: 0,0:27:47.74,0:27:51.49,yin,,0,0,0,,使用showFromBarButtonItem这些显然会更好\\N{\\fs12}it makes a lot of sense to, for example, use show from bar button item\r\nDialogue: 0,0:27:51.49,0:27:52.70,yin,,0,0,0,,弹窗会出现\\N{\\fs12}and it'll put the popover\r\nDialogue: 0,0:27:52.70,0:27:55.67,yin,,0,0,0,,弹窗上的小箭头会指向那个栏按钮项目\\N{\\fs12}and the little arrow on the popover will point at that bar button item.\r\nDialogue: 0,0:27:55.67,0:27:57.43,yin,,0,0,0,,你甚至可以用showFromRect\\N{\\fs12}Or even show from rect.\r\nDialogue: 0,0:27:57.43,0:27:59.95,yin,,0,0,0,,你在视图中任意指定一个矩形\\N{\\fs12}So you specify an arbitrary rectangle in your view\r\nDialogue: 0,0:27:59.95,0:28:02.48,yin,,0,0,0,,弹窗到这里 然后指向它\\N{\\fs12}and it'll bring a popover up and point to that.\r\nDialogue: 0,0:28:02.48,0:28:06.06,yin,,0,0,0,,例如 想象你有一些文本\\N{\\fs12}So for example, let's imagine you are, have some text\r\nDialogue: 0,0:28:06.06,0:28:09.08,yin,,0,0,0,,用户双击了一个词\\N{\\fs12}and someone double clicks a word and then they want\r\nDialogue: 0,0:28:09.08,0:28:14.31,yin,,0,0,0,,他想定义这个词 或是复制这个词\\N{\\fs12}to define the word or copy the word or something like that.\r\nDialogue: 0,0:28:14.31,0:28:16.26,yin,,0,0,0,,复制粘贴我可能不会用它\\N{\\fs12}I probably wouldn't use it for copy and paste but\r\nDialogue: 0,0:28:16.26,0:28:17.91,yin,,0,0,0,,反正是对这个词做点什么\\N{\\fs12}do something with that word.\r\nDialogue: 0,0:28:17.91,0:28:21.56,yin,,0,0,0,,这时你可能会说 showFromRect 并把这个词给矩形\\N{\\fs12}And then you might say, show from rect and give the rectangle of the word.\r\nDialogue: 0,0:28:21.56,0:28:22.81,yin,,0,0,0,,懂我的意思吗\\N{\\fs12}You see what I mean?\r\nDialogue: 0,0:28:22.81,0:28:25.77,yin,,0,0,0,,iBooks就是这样做的\\N{\\fs12}So this is like, this is what, you know, iBooks does.\r\nDialogue: 0,0:28:25.77,0:28:27.14,yin,,0,0,0,,你点一个词 你说定义\\N{\\fs12}You select a word and you say define,\r\nDialogue: 0,0:28:27.14,0:28:30.51,yin,,0,0,0,,它会弹窗 这不是动作表单 不过这是弹窗\\N{\\fs12}it'll make a little popover-- that's not an action sheet but it'll make a little popover.\r\nDialogue: 0,0:28:30.51,0:28:32.65,yin,,0,0,0,,你可以对动作表单做相同的事\\N{\\fs12}So you can do the same thing with action sheets.\r\nDialogue: 0,0:28:32.65,0:28:35.10,yin,,0,0,0,,在iPad上 你需要用showFromRect\\N{\\fs12}Okay so on the iPad you're going to use show from rect,\r\nDialogue: 0,0:28:35.10,0:28:36.40,yin,,0,0,0,,showFromBarButtonItem\\N{\\fs12}show from bar button item.\r\nDialogue: 0,0:28:36.40,0:28:38.46,yin,,0,0,0,,在iPhone上 选哪个都没关系\\N{\\fs12}On the iPhone it almost doesn't matter which one you use,\r\nDialogue: 0,0:28:38.46,0:28:40.82,yin,,0,0,0,,它总会从底部弹出\\N{\\fs12}it's going to come up from the bottom.\r\nDialogue: 0,0:28:42.03,0:28:45.52,yin,,0,0,0,,弄清选的是哪个按钮 这是委托方法\\N{\\fs12}Finding out which button is chosen, this is the delegate method you get,\r\nDialogue: 0,0:28:45.52,0:28:47.76,yin,,0,0,0,,didDismissWithButtonIndex\\N{\\fs12}did dismiss with button index.\r\nDialogue: 0,0:28:47.76,0:28:49.61,yin,,0,0,0,,这都是由按钮索引完成的\\N{\\fs12}It's all done by button index.\r\nDialogue: 0,0:28:49.61,0:28:52.40,yin,,0,0,0,,你可以去查哪个是取消按钮 哪个是毁灭性按钮\\N{\\fs12}You can look up which is the cancel button and which is the destructive button,\r\nDialogue: 0,0:28:52.40,0:28:53.82,yin,,0,0,0,,哪些是其它按钮\\N{\\fs12}which are the other buttons.\r\nDialogue: 0,0:28:53.82,0:28:58.06,yin,,0,0,0,,你还可以取得按钮标题和索引 并对比选择的那个\\N{\\fs12}You can also get the button title and index and compare it to the one that was chosen.\r\nDialogue: 0,0:28:58.06,0:29:00.08,yin,,0,0,0,,这里如果要本地化 你就需要小心一些\\N{\\fs12}Be a little careful there if you're doing localization\r\nDialogue: 0,0:29:00.08,0:29:03.05,yin,,0,0,0,,因为你的动作表单可能会有本地化的词\\N{\\fs12}because your action sheet might have localized words in it\r\nDialogue: 0,0:29:03.05,0:29:04.84,yin,,0,0,0,,这时你要看哪个被选了\\N{\\fs12}and then you want to see which one is chosen.\r\nDialogue: 0,0:29:04.84,0:29:08.88,yin,,0,0,0,,确保你对比了本地化的词\\N{\\fs12}Make sure you're comparing localized, the localized words, all right?\r\nDialogue: 0,0:29:08.88,0:29:13.41,yin,,0,0,0,,否则 如果你想更独立于本地化 你可以只使用索引\\N{\\fs12}Or otherwise just use indexes if you want to kind of be more localization independent.\r\nDialogue: 0,0:29:13.41,0:29:18.47,yin,,0,0,0,,你也可以在程序中 取消一个动作表单\\N{\\fs12}You can programmatically dismiss an action sheet.\r\nDialogue: 0,0:29:18.47,0:29:20.16,yin,,0,0,0,,为什么要这样做呢\\N{\\fs12}And why would you ever want to do this?\r\nDialogue: 0,0:29:20.16,0:29:22.60,yin,,0,0,0,,弹出动作表单 让用户进行选择\\N{\\fs12}Okay you put up an action sheet, a decision branch [inaudible],\r\nDialogue: 0,0:29:22.60,0:29:24.63,yin,,0,0,0,,为什么又要取消这个\\N{\\fs12}why would you ever want to dismiss it yourself?\r\nDialogue: 0,0:29:24.63,0:29:28.78,yin,,0,0,0,,主要原因在于 你有可能被放入后台\\N{\\fs12}Well, the main reason is, you get put in the background.\r\nDialogue: 0,0:29:28.78,0:29:30.52,yin,,0,0,0,,有动作表单时\\N{\\fs12}So anytime you have an action sheet up\r\nDialogue: 0,0:29:30.52,0:29:33.62,yin,,0,0,0,,用户如果点击home键进入另一个app\\N{\\fs12}and someone clicks the home button to go to another app,\r\nDialogue: 0,0:29:33.62,0:29:36.22,yin,,0,0,0,,这个动作表单就应当取消\\N{\\fs12}you should dismiss that action sheet.\r\nDialogue: 0,0:29:36.22,0:29:37.92,yin,,0,0,0,,为什么这样做呢\\N{\\fs12}Why would you do that?\r\nDialogue: 0,0:29:37.92,0:29:40.44,yin,,0,0,0,,因为当用户回到你时\\N{\\fs12}Well because when the user comes back to you,\r\nDialogue: 0,0:29:40.44,0:29:42.63,yin,,0,0,0,,这就可能是第二天了\\N{\\fs12}they'll probably be, that could be the next day.\r\nDialogue: 0,0:29:42.63,0:29:45.63,yin,,0,0,0,,用户可能根本记不得这个动作表单为什么弹出\\N{\\fs12}They might be kind of confused why this action sheet is up.\r\nDialogue: 0,0:29:45.63,0:29:48.64,yin,,0,0,0,,用户不记得为什么要进行这个选择\\N{\\fs12}They don't remember why they forced that branching decision.\r\nDialogue: 0,0:29:48.64,0:29:51.76,yin,,0,0,0,,你应当让用户回到之前那一步\\N{\\fs12}So you're better to go back to the previous step for them\r\nDialogue: 0,0:29:51.76,0:29:55.44,yin,,0,0,0,,让其再次选择做分支决策 然后再弹出动作表单\\N{\\fs12}and let them choose that branching decision again and make the action sheet come back up.\r\nDialogue: 0,0:29:55.44,0:29:57.54,yin,,0,0,0,,怎么知道你进入了后台呢\\N{\\fs12}So how do you find out you entered the background?\r\nDialogue: 0,0:29:57.54,0:29:58.88,yin,,0,0,0,,这里有个很棒的广播站\\N{\\fs12}There's this nice radio station,\r\nDialogue: 0,0:29:58.88,0:30:01.04,yin,,0,0,0,,UIApplicationDidEnterBackgroundNotification\\N{\\fs12}UI application did enter background notification.\r\nDialogue: 0,0:30:01.04,0:30:02.39,yin,,0,0,0,,你只需要收听这个\\N{\\fs12}You just listen to that, boom,\r\nDialogue: 0,0:30:02.39,0:30:04.24,yin,,0,0,0,,你就知道自己是否被丢到了后台\\N{\\fs12}you'll find out you were put in the background.\r\nDialogue: 0,0:30:04.24,0:30:07.19,yin,,0,0,0,,如果被丢到后台 取消动作表单\\N{\\fs12}Just dismiss the action sheet, and you know how to do this\r\nDialogue: 0,0:30:07.19,0:30:08.82,yin,,0,0,0,,使用block 这很简单\\N{\\fs12}with blocks so it's really really easy.\r\nDialogue: 0,0:30:08.82,0:30:11.41,yin,,0,0,0,,一行代码 弹出动作表单后\\N{\\fs12}One liner when you put up the action sheet\r\nDialogue: 0,0:30:11.41,0:30:13.98,yin,,0,0,0,,一行代码 当广播站说到了后台后\\N{\\fs12}to put a one liner in there that when it gets to this radio station,\r\nDialogue: 0,0:30:13.98,0:30:15.92,yin,,0,0,0,,动作表单就会被取消\\N{\\fs12}it just dismisses it.\r\nDialogue: 0,0:30:18.05,0:30:20.90,yin,,0,0,0,,弹窗还有一些特殊考虑\\N{\\fs12}There's special popover considerations.\r\nDialogue: 0,0:30:20.90,0:30:23.56,yin,,0,0,0,,这里弹窗动作表单也有相同的问题\\N{\\fs12}We have the same problem here with popover action sheets\r\nDialogue: 0,0:30:23.56,0:30:25.13,yin,,0,0,0,,同Photomania中一样\\N{\\fs12}that we had when we did PhotoMania\r\nDialogue: 0,0:30:25.13,0:30:28.82,yin,,0,0,0,,我们点URL时会得到越来越多的弹窗\\N{\\fs12}where we kept pressing a URL and we got more and more and more of them.\r\nDialogue: 0,0:30:28.82,0:30:30.20,yin,,0,0,0,,这里也是一样\\N{\\fs12}Okay same thing here.\r\nDialogue: 0,0:30:30.20,0:30:35.50,yin,,0,0,0,,在动作表单弹出时要小心 不要再弹出\\N{\\fs12}You have to be careful if your action sheet's already up, don't put it up again.\r\nDialogue: 0,0:30:37.00,0:30:38.98,yin,,0,0,0,,再看警告视图\\N{\\fs12}Alert view.\r\nDialogue: 0,0:30:38.98,0:30:42.04,yin,,0,0,0,,警告视图可以有多个按钮 像左边这样\\N{\\fs12}Alert view can have multiple buttons like the one on the left.\r\nDialogue: 0,0:30:42.04,0:30:44.76,yin,,0,0,0,,也可以有文本框 像右边这样\\N{\\fs12}It can also have a little text field in it like the one on the right\r\nDialogue: 0,0:30:44.76,0:30:46.08,yin,,0,0,0,,这很有趣\\N{\\fs12}which is kind of fun.\r\nDialogue: 0,0:30:46.08,0:30:48.74,yin,,0,0,0,,它的API同动作表单完全一样\\N{\\fs12}And its API looks exactly like action sheet.\r\nDialogue: 0,0:30:48.74,0:30:52.92,yin,,0,0,0,,你可以从程序添加按钮\\N{\\fs12}You can add buttons programmatically.\r\nDialogue: 0,0:30:52.92,0:30:55.77,yin,,0,0,0,,显示它只需要一个方法show\\N{\\fs12}Showing it is always just the one method show\r\nDialogue: 0,0:30:55.77,0:30:58.70,yin,,0,0,0,,因为警告总会弹出到屏幕中央\\N{\\fs12}because alerts always come up in the middle of the screen.\r\nDialogue: 0,0:30:58.70,0:31:01.85,yin,,0,0,0,,我想我说过 只有表格视图控制器可以移开\\N{\\fs12}I think I said only table view controllers will move out of the way.\r\nDialogue: 0,0:31:01.85,0:31:03.37,yin,,0,0,0,,警告也可以移开\\N{\\fs12}Alerts will also move out of the way.\r\nDialogue: 0,0:31:03.37,0:31:06.02,yin,,0,0,0,,如果由于有文本框而弹出键盘\\N{\\fs12}If you bring up a keyboard because there's a text field in your alert,\r\nDialogue: 0,0:31:06.02,0:31:08.93,yin,,0,0,0,,警告会往上移\\N{\\fs12}the alert will move up.\r\nDialogue: 0,0:31:08.93,0:31:12.83,yin,,0,0,0,,显示 在iPad和iPhone上 都只需要show\\N{\\fs12}So anyway, show. On either iPad or iPhone, you just do show.\r\nDialogue: 0,0:31:12.83,0:31:15.39,yin,,0,0,0,,这是在警告中获得文本框的方式\\N{\\fs12}Here's how you get a text field in your alert.\r\nDialogue: 0,0:31:15.39,0:31:17.80,yin,,0,0,0,,你只需要说alert.alertViewStyle =\\N{\\fs12}You just say alert dot alertviewstyle equals\r\nDialogue: 0,0:31:17.80,0:31:19.34,yin,,0,0,0,,这其中一种有文本的样式\\N{\\fs12}one of these styles that has text:\r\nDialogue: 0,0:31:19.34,0:31:22.18,yin,,0,0,0,,SecureText PlainText LoginAndPassword\\N{\\fs12}secure text, plain text, login and password.\r\nDialogue: 0,0:31:22.18,0:31:24.14,yin,,0,0,0,,然后你得到文本框\\N{\\fs12}And then you get the text field\r\nDialogue: 0,0:31:24.14,0:31:26.18,yin,,0,0,0,,你能从中获得文本\\N{\\fs12}so you can get the text out of them\r\nDialogue: 0,0:31:26.18,0:31:28.68,yin,,0,0,0,,通过alertView textFieldAtIndex\\N{\\fs12}by alert view text field add index.\r\nDialogue: 0,0:31:28.68,0:31:31.28,yin,,0,0,0,,索引0 这是只有一个文本框的情况\\N{\\fs12}Okay, index zero if there's only one text field.\r\nDialogue: 0,0:31:31.28,0:31:34.28,yin,,0,0,0,,索引0和1 例如有帐号和密码的情况\\N{\\fs12}Index zero and one if there's login and password for example.\r\nDialogue: 0,0:31:34.28,0:31:36.41,yin,,0,0,0,,这就是得到文本框的方式\\N{\\fs12}So that's how you can get text field.\r\nDialogue: 0,0:31:37.08,0:31:42.26,yin,,0,0,0,,下面是demo时间 所有这些我都会在demo中演示\\N{\\fs12}All right, time for the demo so I'm going to show all of these things in the demo.\r\nDialogue: 0,0:31:42.26,0:31:45.24,yin,,0,0,0,,我说了 我们会完善Photomania\\N{\\fs12}And like I said, what we're going to do is we're going to enhance PhotoMania\r\nDialogue: 0,0:31:45.24,0:31:49.09,yin,,0,0,0,,让用户能够通过摄像头来拍照\\N{\\fs12}so that it can, so the user can take photos with their camera.\r\nDialogue: 0,0:31:49.09,0:31:51.99,yin,,0,0,0,,今天我们不打算讲到摄像头那部分\\N{\\fs12}Now we're not actually going to get to the camera part today,\r\nDialogue: 0,0:31:51.99,0:31:53.37,yin,,0,0,0,,不过其它我们都会演示\\N{\\fs12}but we're going to do all the rest of it.\r\nDialogue: 0,0:31:53.37,0:31:56.61,yin,,0,0,0,,最重要的是 我们将用到modal segue\\N{\\fs12}Most importantly we're going to do that modal segue\r\nDialogue: 0,0:31:56.61,0:31:58.03,yin,,0,0,0,,和unwind segue\\N{\\fs12}and unwind segue\r\nDialogue: 0,0:31:58.03,0:32:01.86,yin,,0,0,0,,让这个找用户要照片的视图控制器出现\\N{\\fs12}to put this view controller up that's going to ask for the photo.\r\nDialogue: 0,0:32:01.86,0:32:03.30,yin,,0,0,0,,这将是一个视图控制器\\N{\\fs12}Okay it's going to be a view controller.\r\nDialogue: 0,0:32:03.30,0:32:06.33,yin,,0,0,0,,它的作用就是让用户使用摄像头拍照\\N{\\fs12}Its only job is to let the user take a picture with the camera,\r\nDialogue: 0,0:32:06.33,0:32:09.61,yin,,0,0,0,,给照片一个标题和一个副标题 找到其位置\\N{\\fs12}give it a title and subtitle, find out their location.\r\nDialogue: 0,0:32:09.61,0:32:12.32,yin,,0,0,0,,这里我还会回头给出Core Location的demo\\N{\\fs12}Okay I'm going to go back and show you a core location demo here\r\nDialogue: 0,0:32:12.32,0:32:14.17,yin,,0,0,0,,因为之前我没演示过\\N{\\fs12}because I never showed you that before.\r\nDialogue: 0,0:32:14.17,0:32:16.39,yin,,0,0,0,,然后 我将能创建一张照片\\N{\\fs12}And then now I can create a photo\r\nDialogue: 0,0:32:16.39,0:32:19.40,yin,,0,0,0,,因为这里我有了所有信息 标题 子标题 图像\\N{\\fs12}because I've got all the pieces-- title, subtitle, image,\r\nDialogue: 0,0:32:19.40,0:32:22.08,yin,,0,0,0,,我要设置一个缩略图 然后是位置\\N{\\fs12}I'll make a thumbnail, and then the location.\r\nDialogue: 0,0:32:22.08,0:32:24.68,yin,,0,0,0,,我可以在数据库中创建一张照片\\N{\\fs12}Now I can make a photo in the database.\r\nDialogue: 0,0:32:24.68,0:32:27.60,yin,,0,0,0,,大家都理解我们要做什么了吗\\N{\\fs12}Okay everyone understand what we're going to do?\r\nDialogue: 0,0:32:27.60,0:32:30.29,yin,,0,0,0,,好 下面来演示\\N{\\fs12}Okay, let's dive right in here.\r\nDialogue: 0,0:32:30.29,0:32:33.92,yin,,0,0,0,,先看看后面的内容 因为后面我们不会回到幻灯片了\\N{\\fs12}I'm going, let's show coming up because I'm not going to go back to the slides.\r\nDialogue: 0,0:32:33.92,0:32:36.33,yin,,0,0,0,,后面我会继续这个demo 加入摄像头部分\\N{\\fs12}I'll continue this demo by doing the actual camera part\r\nDialogue: 0,0:32:36.33,0:32:38.24,yin,,0,0,0,,然后我还会谈到Core Motion\\N{\\fs12}and then I'm also going to talk about core motion\r\nDialogue: 0,0:32:38.24,0:32:41.30,yin,,0,0,0,,也就是加速计 陀螺仪这些\\N{\\fs12}which is accelerometer, gyro, all that stuff,\r\nDialogue: 0,0:32:41.30,0:32:44.01,yin,,0,0,0,,这是周三的内容 我们有另外一个demo\\N{\\fs12}on Wednesday, okay with another demo.\r\nDialogue: 0,0:32:44.01,0:32:48.24,yin,,0,0,0,,周五的辅导课是Sprite Kit\\N{\\fs12}Friday's section is sprite kit\r\nDialogue: 0,0:32:48.24,0:32:53.28,yin,,0,0,0,,这是iOS7的新工具包 用于2.5D游戏\\N{\\fs12}which is a new iOS 7 kit for doing 2.5D games.\r\nDialogue: 0,0:32:53.28,0:32:54.76,yin,,0,0,0,,看起来是3D\\N{\\fs12}Okay games that look 3D\r\nDialogue: 0,0:32:54.76,0:32:57.21,yin,,0,0,0,,但实际上是由2D图像做成\\N{\\fs12}but they're really made out of 2D images.\r\nDialogue: 0,0:32:57.21,0:32:59.76,yin,,0,0,0,,然后下一周放假\\N{\\fs12}And then next week we have off and then\r\nDialogue: 0,0:32:59.76,0:33:04.58,yin,,0,0,0,,回来以后 我们还有各式主题\\N{\\fs12}when we come back we'll have more miscellaneous topics.\r\nDialogue: 0,0:33:04.58,0:33:08.29,yin,,0,0,0,,好 Photomania 在哪\\N{\\fs12}Okay so PhotoMania, where is it?\r\nDialogue: 0,0:33:08.29,0:33:11.93,yin,,0,0,0,,在上课之前 我给Photomania加了一个东西\\N{\\fs12}Okay so just before class I added one thing to PhotoMania\r\nDialogue: 0,0:33:11.93,0:33:14.45,yin,,0,0,0,,我打算展示我所加的代码\\N{\\fs12}and I'm going to show you the code I added.\r\nDialogue: 0,0:33:14.45,0:33:19.64,yin,,0,0,0,,我为用户加了一个拍照者到数据库\\N{\\fs12}What I did was I added a photographer to my database for the user.\r\nDialogue: 0,0:33:19.64,0:33:24.28,yin,,0,0,0,,这是一个拍照者 也就是使用我们设备的用户\\N{\\fs12}Okay this is the photographer, the user, who's using my device.\r\nDialogue: 0,0:33:24.28,0:33:27.51,yin,,0,0,0,,因为这里我将添加这位用户所拍的照片\\N{\\fs12}That's because I'm going to add photos and he's going to,\r\nDialogue: 0,0:33:27.51,0:33:29.34,yin,,0,0,0,,因为这里我将添加这位用户所拍的照片\\N{\\fs12}her or she, is going to be the photographer.\r\nDialogue: 0,0:33:29.34,0:33:31.20,yin,,0,0,0,,怎么做到呢\\N{\\fs12}So how did I do that?\r\nDialogue: 0,0:33:31.20,0:33:35.73,yin,,0,0,0,,我将两个方法加到了我的Photographer category\\N{\\fs12}I added these two methods to my photographer category here,\r\nDialogue: 0,0:33:35.73,0:33:37.81,yin,,0,0,0,,userInManagedObjectContext\\N{\\fs12}user in managed object context.\r\nDialogue: 0,0:33:37.81,0:33:41.92,yin,,0,0,0,,这给了我一个唯一的拍照者 用于用户\\N{\\fs12}That gives me a photographer for the user, unique photographer.\r\nDialogue: 0,0:33:41.92,0:33:46.85,yin,,0,0,0,,然后isUser则是检验 这个拍照者是不是用户\\N{\\fs12}And then is user which just tells me whether a particular photographer is the user.\r\nDialogue: 0,0:33:46.85,0:33:49.74,yin,,0,0,0,,这个的实现我做得很简单\\N{\\fs12}And the implementation of these, I kind of went cheapo,\r\nDialogue: 0,0:33:49.74,0:33:51.94,yin,,0,0,0,,或许还有更好的做法\\N{\\fs12}there'll probably be much better ways to do this,\r\nDialogue: 0,0:33:51.94,0:33:55.94,yin,,0,0,0,,我只是创建了一个拍照者 名为 My Photos\\N{\\fs12}but I just created a photographer with the name my photos,\r\nDialogue: 0,0:33:55.94,0:33:59.16,yin,,0,0,0,,我还在前面加了个空格 这样它就会排在前面\\N{\\fs12}and I put a spacebar at the beginning so it would sort at the beginning.\r\nDialogue: 0,0:33:59.16,0:34:00.71,yin,,0,0,0,,更好的做法\\N{\\fs12}But really the way to do this would be\r\nDialogue: 0,0:34:00.71,0:34:04.74,yin,,0,0,0,,其实是添加另一个属性到拍照者 也就是\"是用户\"\\N{\\fs12}to add another attribute to your photographer which is, is the user.\r\nDialogue: 0,0:34:04.74,0:34:09.28,yin,,0,0,0,,然后排序再把这个排到第一位 然后再按名字排\\N{\\fs12}And then when you sort, you would sort by that first, and then secondarily by the name.\r\nDialogue: 0,0:34:09.28,0:34:12.35,yin,,0,0,0,,这样这个名字就不需要这么特殊\\N{\\fs12}And that would make it so that this name wouldn't have\r\nDialogue: 0,0:34:12.35,0:34:15.70,yin,,0,0,0,,因为我们将使用属性来设置\\N{\\fs12}to be unique because it would be the, you know, that attribute set.\r\nDialogue: 0,0:34:15.70,0:34:19.44,yin,,0,0,0,,这里 我检查了用户是不是self\\N{\\fs12}And then here I'm just checking to see if the user is self.\r\nDialogue: 0,0:34:20.35,0:34:22.16,yin,,0,0,0,,我在这里只加了一行\\N{\\fs12}The only other line of code I added\r\nDialogue: 0,0:34:22.16,0:34:28.12,yin,,0,0,0,,也就是 在数据库context可用时 我总会在app委托中\\N{\\fs12}to this was I always create this magic user in app delegate\r\nDialogue: 0,0:34:28.12,0:34:31.11,yin,,0,0,0,,创建这个特殊的用户\\N{\\fs12}when the database context becomes available.\r\nDialogue: 0,0:34:31.11,0:34:32.71,yin,,0,0,0,,就是这样了\\N{\\fs12}That's it.\r\nDialogue: 0,0:34:32.71,0:34:34.86,yin,,0,0,0,,大家都明白之前我做的吗\\N{\\fs12}Everyone understand what I did so far?\r\nDialogue: 0,0:34:34.86,0:34:35.92,yin,,0,0,0,,所有我都展示过\\N{\\fs12}I've shown you everything.\r\nDialogue: 0,0:34:35.92,0:34:37.76,yin,,0,0,0,,我们看看这是怎样的\\N{\\fs12}So let's look what this looks like.\r\nDialogue: 0,0:34:37.76,0:34:39.83,yin,,0,0,0,,运行Photomania 可以看到这里\\N{\\fs12}So here I'm running PhotoMania and you can see right here\r\nDialogue: 0,0:34:39.83,0:34:43.88,yin,,0,0,0,,最开始我就有一个拍照者 My Photos 我可以点它\\N{\\fs12}at the beginning I have a photographer, my photos, and I can click on it.\r\nDialogue: 0,0:34:43.88,0:34:44.95,yin,,0,0,0,,它会显示我的所有照片\\N{\\fs12}I'll show all my photos.\r\nDialogue: 0,0:34:44.95,0:34:48.87,yin,,0,0,0,,现在一张都没有 因为摄像头这些我们还没用到\\N{\\fs12}I don't have any yet because we haven't hooked up this whole camera business.\r\nDialogue: 0,0:34:48.87,0:34:52.43,yin,,0,0,0,,不过在这个UI中 我会考虑我的照片\\N{\\fs12}But what I'm going to do in this UI is when I'm looking\r\nDialogue: 0,0:34:52.43,0:34:55.03,yin,,0,0,0,,并在这上面加一个小按钮\\N{\\fs12}at my photos, I'm going to add a little button up here,\r\nDialogue: 0,0:34:55.03,0:34:59.13,yin,,0,0,0,,形如相机 它会通过模态present出一个视图控制器\\N{\\fs12}looks like a camera, and it's going to modally present a view controller\r\nDialogue: 0,0:34:59.13,0:35:02.60,yin,,0,0,0,,这就让我能够拍照 并存入数据库中\\N{\\fs12}that lets me take a picture and put it in the database.\r\nDialogue: 0,0:35:04.33,0:35:06.56,yin,,0,0,0,,好 我们将把它加到这里\\N{\\fs12}Good. All right so that's what we're going to do, we're just going to add this here.\r\nDialogue: 0,0:35:06.56,0:35:09.17,yin,,0,0,0,,看_Night Flyer_时 我们不希望\\N{\\fs12}Now, that camera, we don't want that camera button here\r\nDialogue: 0,0:35:09.17,0:35:10.77,yin,,0,0,0,,相机按钮出现在这里\\N{\\fs12}when we're looking at night flyer.\r\nDialogue: 0,0:35:10.77,0:35:13.53,yin,,0,0,0,,我们显然不能添加_Night Flyer_的照片\\N{\\fs12}Okay we don't want that night flyer to be able to add one,\r\nDialogue: 0,0:35:13.53,0:35:17.09,yin,,0,0,0,,我们只能对My Photos做这件事\\N{\\fs12}so we're only going to do it when it's my photos.\r\nDialogue: 0,0:35:17.09,0:35:20.42,yin,,0,0,0,,这个要怎么做呢\\N{\\fs12}All right, so how are we going to do that?\r\nDialogue: 0,0:35:20.42,0:35:22.73,yin,,0,0,0,,看我们的视图\\N{\\fs12}Let's go look at our view.\r\nDialogue: 0,0:35:23.96,0:35:26.18,yin,,0,0,0,,我们打算在iPhone上来做\\N{\\fs12}We're going to do this on the iPhone.\r\nDialogue: 0,0:35:26.35,0:35:29.44,yin,,0,0,0,,周三我们可能不会再在iPad上做\\N{\\fs12}Probably not going to get around to doing it on the iPad\r\nDialogue: 0,0:35:29.44,0:35:31.41,yin,,0,0,0,,我们将只针对iPhone\\N{\\fs12}on Wednesday, we'll just do it iPhone only.\r\nDialogue: 0,0:35:31.41,0:35:33.90,yin,,0,0,0,,这是我的拍照者列表\\N{\\fs12}Here is my list of photographers.\r\nDialogue: 0,0:35:33.90,0:35:37.12,yin,,0,0,0,,这是那个地图视图 带有特定拍照者的照片\\N{\\fs12}Here is that map view with the photos by a given photographers.\r\nDialogue: 0,0:35:37.12,0:35:40.27,yin,,0,0,0,,这里是我希望有那个按钮的位置\\N{\\fs12}Here's where I want to have that little map button.\r\nDialogue: 0,0:35:40.27,0:35:48.10,yin,,0,0,0,,因此 我只需要到这下面 抓取一个栏按钮项目\\N{\\fs12}So I'm just going to go down here and grab a bar button item.\r\nDialogue: 0,0:35:48.10,0:35:49.24,yin,,0,0,0,,它在这里\\N{\\fs12}Here's one right here.\r\nDialogue: 0,0:35:49.24,0:35:50.32,yin,,0,0,0,,放到这里\\N{\\fs12}Put it here.\r\nDialogue: 0,0:35:50.32,0:35:54.51,yin,,0,0,0,,我可以在这里写相机 拍照或别的什么\\N{\\fs12}I could say the word camera or take photo or something here,\r\nDialogue: 0,0:35:54.51,0:35:59.00,yin,,0,0,0,,不过这里可以用一个内建的相机按钮\\N{\\fs12}but it actually turns out there's a nice built-in one for camera.\r\nDialogue: 0,0:35:59.00,0:36:00.83,yin,,0,0,0,,内建栏按钮项目\\N{\\fs12}Whoo, built in bar button item.\r\nDialogue: 0,0:36:00.83,0:36:02.49,yin,,0,0,0,,看起来很棒\\N{\\fs12}Looks good.\r\nDialogue: 0,0:36:02.49,0:36:08.04,yin,,0,0,0,,重复一次 我只打算在拍照者是用户本人时\\N{\\fs12}So again I only want to have this camera appear when I'm showing the photographer\r\nDialogue: 0,0:36:08.04,0:36:10.26,yin,,0,0,0,,才显示这个按钮\\N{\\fs12}who is the user.\r\nDialogue: 0,0:36:10.26,0:36:14.14,yin,,0,0,0,,我要在PhotosByPhotographerMapViewController中\\N{\\fs12}So I'm going to put a little bit of code in my photos\r\nDialogue: 0,0:36:14.14,0:36:17.44,yin,,0,0,0,,加入一段用于这个的代码\\N{\\fs12}by photographer map view controller which is the code for that thing,\r\nDialogue: 0,0:36:17.44,0:36:20.87,yin,,0,0,0,,只在那种情形下显示按钮\\N{\\fs12}to only show that button in that circumstance.\r\nDialogue: 0,0:36:20.87,0:36:31.21,yin,,0,0,0,,首先 我要创建一个outlet到它\\N{\\fs12}So first of all I'm going to create a little outlet to it.\r\nDialogue: 0,0:36:31.21,0:36:35.51,yin,,0,0,0,,这里腾出一些空间来显示这些\\N{\\fs12}Trying to make it more space here as I show these.\r\nDialogue: 0,0:36:35.51,0:36:39.66,yin,,0,0,0,,这里是这个\\N{\\fs12}Okay so here is this guy right here\r\nDialogue: 0,0:36:39.66,0:36:42.72,yin,,0,0,0,,我要到.m文件\\N{\\fs12}and I'm going to go to the dot m.\r\nDialogue: 0,0:36:42.72,0:36:45.48,yin,,0,0,0,,这是我的PhotosByPhotographerMapViewController\\N{\\fs12}So here's my photos by photographer with map view controller.\r\nDialogue: 0,0:36:45.48,0:36:46.86,yin,,0,0,0,,这个就在这里\\N{\\fs12}That's this. That's where this is.\r\nDialogue: 0,0:36:46.86,0:36:49.07,yin,,0,0,0,,我要control拖动\\N{\\fs12}So I'm going to control drag\r\nDialogue: 0,0:36:49.07,0:36:52.74,yin,,0,0,0,,从这个小按钮 为它创建一个outlet\\N{\\fs12}from this little button right here to make a outlet for it.\r\nDialogue: 0,0:36:52.74,0:36:56.68,yin,,0,0,0,,命名为addPhotoBarButtonItem\\N{\\fs12}I'm going to call it the add photo bar button item.\r\nDialogue: 0,0:36:56.68,0:36:59.13,yin,,0,0,0,,这样我就得到了addPhotoBarButtonItem\\N{\\fs12}So I've got my add photo bar button item.\r\nDialogue: 0,0:36:59.13,0:37:01.27,yin,,0,0,0,,然后我还要加一点代码\\N{\\fs12}And now I'm just going to put a little bit of code\r\nDialogue: 0,0:37:01.27,0:37:05.75,yin,,0,0,0,,只在拍照者是用户时才把按钮放到这里\\N{\\fs12}that only puts that here if my current photographer--\r\nDialogue: 0,0:37:05.75,0:37:09.56,yin,,0,0,0,,这是我为这些设定拍照者的地方\\N{\\fs12}here's where I set my photographer for this thing-- is the user.\r\nDialogue: 0,0:37:09.56,0:37:11.97,yin,,0,0,0,,这里我将有一个方法 self\\N{\\fs12}So I'm going to have a little method here. I'm going to call it self\r\nDialogue: 0,0:37:11.98,0:37:16.44,yin,,0,0,0,,updateAddPhotoBarButtonItem\\N{\\fs12}update, add photo, bar button item.\r\nDialogue: 0,0:37:16.44,0:37:23.68,yin,,0,0,0,,我需要这个更新函数\\N{\\fs12}And I'm just going to have a little-- this update this thing.\r\nDialogue: 0,0:37:23.68,0:37:26.73,yin,,0,0,0,,我们这里需要Photographer+Create\\N{\\fs12}We need photographer create for that\r\nDialogue: 0,0:37:26.73,0:37:29.13,yin,,0,0,0,,因为这就是我们要加入的地方\\N{\\fs12}because that's where that thing we just added.\r\nDialogue: 0,0:37:29.13,0:37:32.38,yin,,0,0,0,,这是我刚才快速键入的\\N{\\fs12}All right so here's what I just typed in right here really fast\r\nDialogue: 0,0:37:32.38,0:37:34.06,yin,,0,0,0,,你们可以离线去看\\N{\\fs12}and you can look at this offline.\r\nDialogue: 0,0:37:34.06,0:37:37.51,yin,,0,0,0,,这里没有什么新东西 我就不讲了\\N{\\fs12}There's nothing really new to teach you here so I'm not going to go through it.\r\nDialogue: 0,0:37:37.51,0:37:40.98,yin,,0,0,0,,只需要知道 它会更新这里这个导航项目的\\N{\\fs12}But suffice it to say it's really updating the right bar button items\r\nDialogue: 0,0:37:40.98,0:37:44.65,yin,,0,0,0,,正确的栏按钮项目 来决定有没有这个\\N{\\fs12}of this navigation item right here to have this or not.\r\nDialogue: 0,0:37:44.65,0:37:48.70,yin,,0,0,0,,我们来看看\\N{\\fs12}So let's go take a look.\r\nDialogue: 0,0:37:48.70,0:37:51.28,yin,,0,0,0,,来到这里 它有这个\\N{\\fs12}Okay so we go here, it's got this.\r\nDialogue: 0,0:37:51.28,0:37:53.75,yin,,0,0,0,,回到这里 它没有\\N{\\fs12}Go back here, doesn't have it.\r\nDialogue: 0,0:37:53.75,0:37:56.08,yin,,0,0,0,,这很好\\N{\\fs12}See? Okay so that's good.\r\nDialogue: 0,0:37:56.08,0:37:58.19,yin,,0,0,0,,下面我们需要 按这个按钮时\\N{\\fs12}So now we need to make it so when we press this\r\nDialogue: 0,0:37:58.19,0:38:00.47,yin,,0,0,0,,程序就会modal segue到新UI\\N{\\fs12}we do this modal segue to a new UI.\r\nDialogue: 0,0:38:00.47,0:38:05.10,yin,,0,0,0,,我们来做这个 回到iPhone故事板来腾空间\\N{\\fs12}So let's go do that, back to our iPhone storyboard to make space.\r\nDialogue: 0,0:38:05.10,0:38:10.34,yin,,0,0,0,,让我们把这个做成新UI来做这个\\N{\\fs12}All right so let's make this new UI that we want to do that,\r\nDialogue: 0,0:38:10.34,0:38:14.34,yin,,0,0,0,,我要创建一个新视图控制器 拖出来\\N{\\fs12}so I'm going to create a new view controller here, drag this out.\r\nDialogue: 0,0:38:14.34,0:38:16.70,yin,,0,0,0,,这是我的新视图控制器\\N{\\fs12}Here's my new view controller.\r\nDialogue: 0,0:38:16.72,0:38:19.25,yin,,0,0,0,,将它很好地对齐到这里\\N{\\fs12}Okay, and we'll line it up there nicely.\r\nDialogue: 0,0:38:19.25,0:38:21.96,yin,,0,0,0,,这个视图控制器中有些什么呢\\N{\\fs12}And what is this view controller going to have in it?\r\nDialogue: 0,0:38:21.96,0:38:25.38,yin,,0,0,0,,我们看看 我要从这里拖出很多好东西\\N{\\fs12}Well, let's see, I'm going to drag a whole bunch of nice stuff out here.\r\nDialogue: 0,0:38:25.38,0:38:29.94,yin,,0,0,0,,它需要一个取消按钮 这里我们放个取消\\N{\\fs12}It wants a cancel button, so let's do a cancel.\r\nDialogue: 0,0:38:29.94,0:38:33.32,yin,,0,0,0,,这时我会决定 我其实不想添加\\N{\\fs12}That's if I decide eh, I don't really want to add one after all.\r\nDialogue: 0,0:38:33.32,0:38:35.33,yin,,0,0,0,,它还需要一个完成按钮\\N{\\fs12}It wants a done button.\r\nDialogue: 0,0:38:35.33,0:38:36.76,yin,,0,0,0,,来执行完成操作\\N{\\fs12}So if we're going to do a done,\r\nDialogue: 0,0:38:36.76,0:38:40.22,yin,,0,0,0,,它还需要一个拍照按钮\\N{\\fs12}it probably wants a take photo button, okay,\r\nDialogue: 0,0:38:40.22,0:38:45.42,yin,,0,0,0,,点它会弹出拍照用户界面\\N{\\fs12}that we'll click that will cause us to bring up the camera taking user interface.\r\nDialogue: 0,0:38:45.42,0:38:48.44,yin,,0,0,0,,这个放到上面这里\\N{\\fs12}I will put these somewhere here, put that up there.\r\nDialogue: 0,0:38:48.44,0:38:51.12,yin,,0,0,0,,这个对齐地放到这里\\N{\\fs12}Let's put this one lined up over there.\r\nDialogue: 0,0:38:51.12,0:38:52.37,yin,,0,0,0,,这个放到别处\\N{\\fs12}Put this somewhere.\r\nDialogue: 0,0:38:52.37,0:38:55.93,yin,,0,0,0,,我需要一个图像视图 一个UIImageView\\N{\\fs12}We need a view, I want to have an image view, a UI image view\r\nDialogue: 0,0:38:55.93,0:38:58.44,yin,,0,0,0,,为我显示我刚拍的照片\\N{\\fs12}that shows me what I just took with the camera.\r\nDialogue: 0,0:38:58.44,0:39:02.84,yin,,0,0,0,,把这个拖出来 放到这里\\N{\\fs12}So let's drag that out, put that here let's say.\r\nDialogue: 0,0:39:02.84,0:39:08.31,yin,,0,0,0,,或许是这样 拉成一个正方形\\N{\\fs12}Maybe, I don't know, something like let's make it square.\r\nDialogue: 0,0:39:09.23,0:39:11.34,yin,,0,0,0,,这就是我的正方形\\N{\\fs12}There, that's my square one.\r\nDialogue: 0,0:39:11.34,0:39:13.15,yin,,0,0,0,,把拍照拉下一些\\N{\\fs12}Put take photo down here.\r\nDialogue: 0,0:39:13.15,0:39:16.57,yin,,0,0,0,,然后 对于标题和副标题再放一些文本框\\N{\\fs12}Okay, and then I'm going to have some text fields for the title and subtitle.\r\nDialogue: 0,0:39:16.57,0:39:17.83,yin,,0,0,0,,把它们拖出来\\N{\\fs12}So let's drag those out.\r\nDialogue: 0,0:39:17.83,0:39:20.43,yin,,0,0,0,,这是文本框 我们第一次用它\\N{\\fs12}So here's text field, first time we've used that.\r\nDialogue: 0,0:39:20.43,0:39:22.44,yin,,0,0,0,,像这样 这就有了一个\\N{\\fs12}But here we go. There's one there.\r\nDialogue: 0,0:39:22.44,0:39:26.10,yin,,0,0,0,,拉宽一些 像这样\\N{\\fs12}Let's make it a little wider, like that.\r\nDialogue: 0,0:39:26.10,0:39:29.44,yin,,0,0,0,,为标题和副标题粘贴复制\\N{\\fs12}Let's copy and paste for title and subtitle.\r\nDialogue: 0,0:39:29.44,0:39:32.00,yin,,0,0,0,,为这些东西加个标签\\N{\\fs12}Let's get a label for each of these things.\r\nDialogue: 0,0:39:32.00,0:39:37.90,yin,,0,0,0,,这是副标题标签 复制粘贴 这是标题标签\\N{\\fs12}There's the subtitle label and let's copy and paste the new title label.\r\nDialogue: 0,0:39:37.90,0:39:41.04,yin,,0,0,0,,然后把这些对齐\\N{\\fs12}And then let's line these things up.\r\nDialogue: 0,0:39:41.04,0:39:43.12,yin,,0,0,0,,像这样\\N{\\fs12}Something like that.\r\nDialogue: 0,0:39:43.12,0:39:46.25,yin,,0,0,0,,我们要对齐基线\\N{\\fs12}We'll line up the baselines probably of our--\r\nDialogue: 0,0:39:46.25,0:39:49.89,yin,,0,0,0,,把这个挪开 这里对齐基线\\N{\\fs12}let's get that out of the way-- line up the baselines here.\r\nDialogue: 0,0:39:49.89,0:39:52.34,yin,,0,0,0,,中间可能好了\\N{\\fs12}Center's probably just as good.\r\nDialogue: 0,0:39:52.34,0:39:55.00,yin,,0,0,0,,就这样吧 这就标题和副标题\\N{\\fs12}So anyway, so there's our title, there's our subtitle.\r\nDialogue: 0,0:39:55.00,0:39:58.83,yin,,0,0,0,,然后我们创建一个UIViewController的自定义子类\\N{\\fs12}And now let's create a custom UI view controller subclass\r\nDialogue: 0,0:39:58.83,0:40:02.09,yin,,0,0,0,,这样我们就能把所有这些东西关联起来\\N{\\fs12}so we can wire all this business up to something.\r\nDialogue: 0,0:40:02.09,0:40:05.39,yin,,0,0,0,,我们可以到这里点新文件\\N{\\fs12}So we can go here, new, file.\r\nDialogue: 0,0:40:05.39,0:40:06.92,yin,,0,0,0,,创建一个新的\\N{\\fs12}And we're creating a new one.\r\nDialogue: 0,0:40:06.92,0:40:09.19,yin,,0,0,0,,这将是一个常规的UIViewController\\N{\\fs12}This is going to be a normal UI view controller.\r\nDialogue: 0,0:40:09.19,0:40:12.77,yin,,0,0,0,,让我们把它称作AddPhotoViewController\\N{\\fs12}It's going to call, let's call it add photo view controller\r\nDialogue: 0,0:40:12.77,0:40:13.92,yin,,0,0,0,,这就是它的作用\\N{\\fs12}because that's what it does, right?\r\nDialogue: 0,0:40:13.92,0:40:17.58,yin,,0,0,0,,它会添加一张照片到数据库 这是一个很好的名字\\N{\\fs12}It adds a photo to the database so that's a good name for it.\r\nDialogue: 0,0:40:17.58,0:40:21.43,yin,,0,0,0,,把这同其它所有控制器放一起\\N{\\fs12}We'll put it where all the rest of our controllers are.\r\nDialogue: 0,0:40:21.43,0:40:22.75,yin,,0,0,0,,这里\\N{\\fs12}There it is.\r\nDialogue: 0,0:40:22.75,0:40:24.75,yin,,0,0,0,,这是我们的init\\N{\\fs12}Okay, this is our init, we don't need any\r\nDialogue: 0,0:40:24.75,0:40:27.44,yin,,0,0,0,,这一大堆样板内容都不需要\\N{\\fs12}of this boilerplate that it puts in here.\r\nDialogue: 0,0:40:27.44,0:40:29.71,yin,,0,0,0,,删掉这些\\N{\\fs12}Get rid of that.\r\nDialogue: 0,0:40:29.71,0:40:33.28,yin,,0,0,0,,让我们来设置它的ID\\N{\\fs12}Let's go ahead and set our identity of this thing\r\nDialogue: 0,0:40:33.28,0:40:36.12,yin,,0,0,0,,设为这个新的AddPhotoViewController\\N{\\fs12}to be this new add photo view controller.\r\nDialogue: 0,0:40:36.12,0:40:40.35,yin,,0,0,0,,让我们关联一些outlet 来指向这其中一些东西\\N{\\fs12}Let's wire up some outlets to point to some of these things.\r\nDialogue: 0,0:40:44.29,0:40:49.00,yin,,0,0,0,,我们需要outlet到这两个文本框 让我们来做这个\\N{\\fs12}All right so, we need an outlet to both of these text fields, so let's do that.\r\nDialogue: 0,0:40:49.00,0:40:53.75,yin,,0,0,0,,这是我们的标题文本框 和这个关联起来\\N{\\fs12}This is our title text field and we'll wire this one up.\r\nDialogue: 0,0:40:53.75,0:40:58.00,yin,,0,0,0,,这是我们的副标题文本框\\N{\\fs12}This is our subtitle text field.\r\nDialogue: 0,0:40:58.00,0:41:00.47,yin,,0,0,0,,我们再点亮取消按钮\\N{\\fs12}And let's light the cancel button.\r\nDialogue: 0,0:41:00.47,0:41:01.61,yin,,0,0,0,,关联起这个\\N{\\fs12}Let's wire that up.\r\nDialogue: 0,0:41:01.61,0:41:05.39,yin,,0,0,0,,取消 完成\\N{\\fs12}Cancel. Done.\r\nDialogue: 0,0:41:05.39,0:41:08.59,yin,,0,0,0,,我们再来关联拍照片按钮\\N{\\fs12}Let's wire up the take photo.\r\nDialogue: 0,0:41:08.59,0:41:10.52,yin,,0,0,0,,拍照片\\N{\\fs12}Take photo.\r\nDialogue: 0,0:41:11.60,0:41:13.90,yin,,0,0,0,,完成 好\\N{\\fs12}Done. Okay.\r\nDialogue: 0,0:41:13.90,0:41:18.42,yin,,0,0,0,,我不喜欢这样 我们这样\\N{\\fs12}Now you know I don't like those like that so we'll do that.\r\nDialogue: 0,0:41:18.42,0:41:23.37,yin,,0,0,0,,我们再把这个图像视图关联起来\\N{\\fs12}Let's also wire up this image view right here.\r\nDialogue: 0,0:41:23.37,0:41:26.63,yin,,0,0,0,,我还要做一件事 碰到这样的图像视图时\\N{\\fs12}Okay I'm also going to do something that I did in image view controller\r\nDialogue: 0,0:41:26.63,0:41:30.43,yin,,0,0,0,,我总喜欢在图像视图控制器中做这件事 也就是\\N{\\fs12}which I always like to do when I have an image view like that, which is I'm going\r\nDialogue: 0,0:41:30.43,0:41:34.78,yin,,0,0,0,,设置一个非原子的 强的UIImage *image属性\\N{\\fs12}to have a non atomic strong UI image star image.\r\nDialogue: 0,0:41:34.78,0:41:36.84,yin,,0,0,0,,这里有一个属性叫image\\N{\\fs12}Okay so I'm going to have a property called image\r\nDialogue: 0,0:41:36.84,0:41:39.38,yin,,0,0,0,,不过我会将它存在图像视图中\\N{\\fs12}but I'm going to store it in the image view.\r\nDialogue: 0,0:41:39.38,0:41:42.08,yin,,0,0,0,,我们对视图控制器做过相同的事\\N{\\fs12}Same exact thing we did for view controller.\r\nDialogue: 0,0:41:42.08,0:41:46.94,yin,,0,0,0,,这里我们将加入setImage\\N{\\fs12}So here I'm just going to have set image.\r\nDialogue: 0,0:41:46.94,0:41:49.85,yin,,0,0,0,,它会在图像视图控制器中进行设置\\N{\\fs12}Okay and it's just going to set in the image view controller\r\nDialogue: 0,0:41:49.85,0:41:50.95,yin,,0,0,0,,并返回图像视图控制器\\N{\\fs12}and return the image view controller.\r\nDialogue: 0,0:41:50.95,0:41:52.99,yin,,0,0,0,,这样做是因为我需要\\N{\\fs12}And the reason I'm doing this is because I'm going to need\r\nDialogue: 0,0:41:52.99,0:41:56.24,yin,,0,0,0,,在以后图像被设置时做些事情\\N{\\fs12}to do some things when the image is set in the future.\r\nDialogue: 0,0:41:56.24,0:42:00.36,yin,,0,0,0,,因此 我需要预先把这个准备好\\N{\\fs12}So I'm just kind of getting it ahead of myself and getting it ready for that.\r\nDialogue: 0,0:42:00.36,0:42:02.35,yin,,0,0,0,,大家都理解我刚做的吗\\N{\\fs12}Everyone understand what I'm doing there though?\r\nDialogue: 0,0:42:04.10,0:42:10.84,yin,,0,0,0,,好 下面把这个放到屏幕上\\N{\\fs12}Okay, so let's go ahead and put this on screen briefly\r\nDialogue: 0,0:42:10.84,0:42:14.72,yin,,0,0,0,,通过创建一个modal segue 从这里到这里\\N{\\fs12}by creating a modal segue from here to here.\r\nDialogue: 0,0:42:14.72,0:42:17.62,yin,,0,0,0,,我还想简单展示一下这些文本框\\N{\\fs12}And I just want to show you a little bit about these text fields.\r\nDialogue: 0,0:42:17.62,0:42:21.11,yin,,0,0,0,,我要让这个像这样\\N{\\fs12}So I'm just going to have this guy right here go like this,\r\nDialogue: 0,0:42:21.11,0:42:23.70,yin,,0,0,0,,这里不选push 而选modal\\N{\\fs12}and instead of push I'm going to do modal.\r\nDialogue: 0,0:42:23.70,0:42:26.62,yin,,0,0,0,,这就会让这个用modal方式显示在屏幕上\\N{\\fs12}So that's going to put this thing on screen modally.\r\nDialogue: 0,0:42:26.62,0:42:29.33,yin,,0,0,0,,这是一个modal segue\\N{\\fs12}This is a modal segue right here.\r\nDialogue: 0,0:42:29.33,0:42:34.16,yin,,0,0,0,,这里我们可以称它为Add Photo Segue\\N{\\fs12}This for example, we could call it the add photo segue.\r\nDialogue: 0,0:42:34.16,0:42:37.47,yin,,0,0,0,,检查标识符或许甚至可以掠过\\N{\\fs12}I'll probably skip even checking that identifier.\r\nDialogue: 0,0:42:37.47,0:42:39.81,yin,,0,0,0,,无论如何 我们试运行一下\\N{\\fs12}But anyway, let's go ahead and run\r\nDialogue: 0,0:42:39.81,0:42:43.07,yin,,0,0,0,,把这个放到屏幕上 展示一些文本框的内容\\N{\\fs12}so we can get this thing on screen and I can show you something about the text field.\r\nDialogue: 0,0:42:43.07,0:42:44.99,yin,,0,0,0,,这里是我们的相机\\N{\\fs12}So here we go, here's our camera.\r\nDialogue: 0,0:42:44.99,0:42:47.74,yin,,0,0,0,,点它 它会用modal方式显示在屏幕上\\N{\\fs12}And when I click this, it comes up on screen modally.\r\nDialogue: 0,0:42:47.74,0:42:50.87,yin,,0,0,0,,modal一定要有取消的办法\\N{\\fs12}Now one thing about modal, you better have a way to get rid of it.\r\nDialogue: 0,0:42:50.87,0:42:52.91,yin,,0,0,0,,这个我们还没关联\\N{\\fs12}And we haven't wired any of this up.\r\nDialogue: 0,0:42:52.91,0:42:54.99,yin,,0,0,0,,我的app这就完了\\N{\\fs12}This is, my app is done now.\r\nDialogue: 0,0:42:54.99,0:42:56.53,yin,,0,0,0,,我无法回退\\N{\\fs12}I can't get back.\r\nDialogue: 0,0:42:56.53,0:43:00.06,yin,,0,0,0,,我需要要么unwind 要么取消\\N{\\fs12}So I have to either unwind or I have to cancel myself.\r\nDialogue: 0,0:43:00.06,0:43:02.28,yin,,0,0,0,,但我现在还没做这些\\N{\\fs12}But we're not doing that right now,\r\nDialogue: 0,0:43:02.28,0:43:04.63,yin,,0,0,0,,我现在只想看看这些文本框\\N{\\fs12}what I'm doing now is I want to look at these text fields.\r\nDialogue: 0,0:43:04.63,0:43:08.45,yin,,0,0,0,,我点标题 然后就可以开始输入标题\\N{\\fs12}So if I click here title, okay, and I could type, start typing\r\nDialogue: 0,0:43:08.45,0:43:11.77,yin,,0,0,0,,好 这就是我想要的标题了\\N{\\fs12}in a title here, and I'm like okay that's where I want the title to be.\r\nDialogue: 0,0:43:11.77,0:43:14.59,yin,,0,0,0,,但点这个没反应\\N{\\fs12}Oh, I can't get, I can't get rid of this.\r\nDialogue: 0,0:43:14.59,0:43:16.81,yin,,0,0,0,,键盘无法消失\\N{\\fs12}There's no way to get rid of this keyboard.\r\nDialogue: 0,0:43:16.81,0:43:18.57,yin,,0,0,0,,点别处都没用\\N{\\fs12}Okay there's nowhere I can click,\r\nDialogue: 0,0:43:18.57,0:43:20.42,yin,,0,0,0,,我什么都做不了 这个一直都在\\N{\\fs12}there's nothing I can do, this thing is up.\r\nDialogue: 0,0:43:20.42,0:43:23.74,yin,,0,0,0,,而且我的照片在它下面 照片也看不见\\N{\\fs12}And my photo is underneath it, so I can't see my photo.\r\nDialogue: 0,0:43:23.74,0:43:25.30,yin,,0,0,0,,这太糟糕了\\N{\\fs12}Okay this is awful.\r\nDialogue: 0,0:43:25.30,0:43:31.21,yin,,0,0,0,,在点return时 我需要能够消掉这个键盘\\N{\\fs12}So I really want to be able to dismiss this keyboard when I hit return here.\r\nDialogue: 0,0:43:31.21,0:43:34.56,yin,,0,0,0,,我们可以使用UITextFieldDelegate来做这个\\N{\\fs12}So we can do that using the UI text field's delegate.\r\nDialogue: 0,0:43:34.56,0:43:36.44,yin,,0,0,0,,我们来做这个\\N{\\fs12}So let's go ahead and do that.\r\nDialogue: 0,0:43:36.44,0:43:38.28,yin,,0,0,0,,我们到这里来\\N{\\fs12}Okay we're going to go here\r\nDialogue: 0,0:43:38.28,0:43:41.41,yin,,0,0,0,,我要做点有趣的事 我从没这样做过\\N{\\fs12}and I'm going to do something a little interesting we haven't done before\r\nDialogue: 0,0:43:41.41,0:43:44.54,yin,,0,0,0,,也就是 我要在故事板中关联一个委托\\N{\\fs12}which is I'm going to wire up a delegate in the storyboard.\r\nDialogue: 0,0:43:44.54,0:43:46.21,yin,,0,0,0,,这一般是在代码中做的事\\N{\\fs12}Normally we would do this in code.\r\nDialogue: 0,0:43:46.21,0:43:49.01,yin,,0,0,0,,例如文本框的setter被调用时\\N{\\fs12}Like when the setter for that text field was called we'd say\r\nDialogue: 0,0:43:49.01,0:43:52.98,yin,,0,0,0,,我们说textField.delegate = self\\N{\\fs12}self, you know, we'd say text field dot delegate equals self.\r\nDialogue: 0,0:43:52.98,0:43:55.83,yin,,0,0,0,,但这里 我直接control拖动\\N{\\fs12}But here I'm going to do it by control dragging\r\nDialogue: 0,0:43:55.83,0:43:58.59,yin,,0,0,0,,从文本框到我的视图控制器\\N{\\fs12}from the text field down to my view controller.\r\nDialogue: 0,0:43:58.59,0:44:03.46,yin,,0,0,0,,这时 我就可以设置它的委托了 看到了吧\\N{\\fs12}And when I do you'll see that I can set its delegate.\r\nDialogue: 0,0:44:03.46,0:44:08.62,yin,,0,0,0,,我将文本框的委托设置为我的视图控制器\\N{\\fs12}So I'm setting the text field's delegate to be my view controller.\r\nDialogue: 0,0:44:08.62,0:44:10.36,yin,,0,0,0,,另一个我也来设置\\N{\\fs12}I'll set the other one too.\r\nDialogue: 0,0:44:10.36,0:44:13.76,yin,,0,0,0,,这两个 右键点击你都能看到\\N{\\fs12}So both of these guys, if you right click on them you'll see\r\nDialogue: 0,0:44:13.76,0:44:17.68,yin,,0,0,0,,它们的委托是Add Photo View Controller\\N{\\fs12}that their delegate is my add photo view controller.\r\nDialogue: 0,0:44:17.68,0:44:22.29,yin,,0,0,0,,在AddPhotoViewController中\\N{\\fs12}Now I still have to, in my add photo view controller right\r\nDialogue: 0,0:44:22.29,0:44:24.65,yin,,0,0,0,,这里 我还需要说\\N{\\fs12}here, I still have to say oh yes,\r\nDialogue: 0,0:44:24.65,0:44:28.74,yin,,0,0,0,,我是一个UITextFieldDelegate\\N{\\fs12}I'm a UI text field delegate.\r\nDialogue: 0,0:44:28.74,0:44:31.82,yin,,0,0,0,,还是那句话 所有这些方法都是可选的\\N{\\fs12}All right now again, all these methods are optional\r\nDialogue: 0,0:44:31.82,0:44:33.56,yin,,0,0,0,,没有这些关系也不大\\N{\\fs12}so it really wouldn't be that big a deal if I didn't\r\nDialogue: 0,0:44:33.56,0:44:36.48,yin,,0,0,0,,不过 为了程序的恰当 我会这样做\\N{\\fs12}but still, just to be proper, I should do that.\r\nDialogue: 0,0:44:36.48,0:44:39.52,yin,,0,0,0,,现在 我可以实现这其中一些\\N{\\fs12}And I, now I can implement some of these ones.\r\nDialogue: 0,0:44:39.52,0:44:42.39,yin,,0,0,0,,例如这里有一个叫\\N{\\fs12}Like a good one here would be shou- what's it called?\r\nDialogue: 0,0:44:42.39,0:44:43.65,yin,,0,0,0,,textFieldShouldReturn\\N{\\fs12}Text field should return.\r\nDialogue: 0,0:44:43.65,0:44:46.58,yin,,0,0,0,,textField打头的还有一些\\N{\\fs12}So here's some of the text field ones. These ones [inaudible].\r\nDialogue: 0,0:44:46.58,0:44:49.36,yin,,0,0,0,,我们要的是textFieldShouldReturn\\N{\\fs12}So let's do text field should return.\r\nDialogue: 0,0:44:49.36,0:44:52.97,yin,,0,0,0,,如果文本框问我 我是否该return\\N{\\fs12}And so if the text field asks me, should I return?\r\nDialogue: 0,0:44:52.97,0:44:55.89,yin,,0,0,0,,我会说 是 你该return\\N{\\fs12}I'm going to say yes, you should return.\r\nDialogue: 0,0:44:55.89,0:45:00.17,yin,,0,0,0,,也就是说 如果有目标动作在return时发生 做就是了\\N{\\fs12}Meaning if you have target action that fires when you return, go ahead and do it.\r\nDialogue: 0,0:45:00.17,0:45:04.58,yin,,0,0,0,,不过我还要说 文本框先生 请消掉第一响应器\\N{\\fs12}But I'm also going to say, Mr. Text Field, please resign first responder.\r\nDialogue: 0,0:45:04.58,0:45:08.24,yin,,0,0,0,,换言之 停止使用键盘\\N{\\fs12}In other words, stop using the keyboard.\r\nDialogue: 0,0:45:08.24,0:45:11.54,yin,,0,0,0,,加入这些代码 然后运行\\N{\\fs12}So just by putting this in here, now when we run\r\nDialogue: 0,0:45:11.54,0:45:15.83,yin,,0,0,0,,转到这个界面 点这里\\N{\\fs12}and bring this baby back up and we click here\r\nDialogue: 0,0:45:15.83,0:45:19.63,yin,,0,0,0,,开始输入 点return 文本被留在了这里\\N{\\fs12}and we start typing and we hit return, it leaves the text in there,\r\nDialogue: 0,0:45:19.64,0:45:24.65,yin,,0,0,0,,虽然这里有一些拼写错误校正\\N{\\fs12}even does its little fixing the misspellings.\r\nDialogue: 0,0:45:24.65,0:45:26.79,yin,,0,0,0,,键盘消失了\\N{\\fs12}And the keyboard goes away.\r\nDialogue: 0,0:45:26.79,0:45:29.12,yin,,0,0,0,,我可以让它弹出来 然后再让它消失\\N{\\fs12}And I can bring this one back and make this one go away.\r\nDialogue: 0,0:45:29.12,0:45:32.79,yin,,0,0,0,,这个UI就好很多了 特别是让键盘能够消失\\N{\\fs12}So it's a much nicer UI to be able to make that keyboard go away especially\r\nDialogue: 0,0:45:32.79,0:45:36.15,yin,,0,0,0,,键盘下如果有东西 你就不需要滚动到上面来\\N{\\fs12}if you have something underneath the keyboard and you don't scroll it up.\r\nDialogue: 0,0:45:36.15,0:45:37.95,yin,,0,0,0,,我展示这个\\N{\\fs12}So I just wanted to show you that just\r\nDialogue: 0,0:45:37.95,0:45:39.79,yin,,0,0,0,,只是想让你们知道 一\\N{\\fs12}to show you how we can A,\r\nDialogue: 0,0:45:39.79,0:45:42.32,yin,,0,0,0,,如何在故事板中设置文本框委托\\N{\\fs12}set the text delegate in the storyboard,\r\nDialogue: 0,0:45:42.32,0:45:45.27,yin,,0,0,0,,二 如何使用委托来做一些有价值的事\\N{\\fs12}and B, how we could use a delegate method to do something valuable.\r\nDialogue: 0,0:45:45.27,0:45:47.97,yin,,0,0,0,,以上就是关于文本框我要演示的东西\\N{\\fs12}So that's all I'm going to show you for text field.\r\nDialogue: 0,0:45:47.97,0:45:51.63,yin,,0,0,0,,剩下的内容你们应该可以自己去看\\N{\\fs12}I think you can figure out the rest on your own.\r\nDialogue: 0,0:45:51.63,0:45:55.07,yin,,0,0,0,,下面我们再回到segue\\N{\\fs12}All right so now let's get back to the segueing okay?\r\nDialogue: 0,0:45:55.07,0:45:58.08,yin,,0,0,0,,我们有这个 它segue到这里\\N{\\fs12}So we have this guy right here and it segues to here.\r\nDialogue: 0,0:45:58.08,0:46:00.32,yin,,0,0,0,,我们已经设置了这个modal segue\\N{\\fs12}So we already set up this modal segue,\r\nDialogue: 0,0:46:00.32,0:46:03.98,yin,,0,0,0,,我们没有准备它 也不能从它unwind\\N{\\fs12}but we don't actually prepare it nor can we unwind from it.\r\nDialogue: 0,0:46:03.98,0:46:06.85,yin,,0,0,0,,这两个视图控制器之间的整个关系还没有完成\\N{\\fs12}So we really haven't finished with the whole relationship\r\nDialogue: 0,0:46:06.85,0:46:08.14,yin,,0,0,0,,这两个视图控制器之间的整个关系还没有完成\\N{\\fs12}between these two view controllers.\r\nDialogue: 0,0:46:08.14,0:46:14.43,yin,,0,0,0,,我们首先看看这个模态视图控制器的公共API\\N{\\fs12}So let's first look at the public API of this modal view controller to kind\r\nDialogue: 0,0:46:14.43,0:46:16.59,yin,,0,0,0,,来理解它是如何通信的\\N{\\fs12}of understand how it's going to communicate.\r\nDialogue: 0,0:46:16.59,0:46:19.69,yin,,0,0,0,,我们来看看AddPhotoViewController的公共API\\N{\\fs12}So I'm going to look at the public API of add photo view controller\r\nDialogue: 0,0:46:19.69,0:46:21.15,yin,,0,0,0,,它有两个东西\\N{\\fs12}and it really has two things.\r\nDialogue: 0,0:46:21.15,0:46:22.67,yin,,0,0,0,,它有一个输入\\N{\\fs12}It has an input\r\nDialogue: 0,0:46:22.67,0:46:35.11,yin,,0,0,0,,也就是photographerTakingPhoto(拍照的拍照者)\\N{\\fs12}which is the photographer who is taking the photo.\r\nDialogue: 0,0:46:35.11,0:46:40.51,yin,,0,0,0,,这里我们或许总是会传入用户 这个特殊拍照者\\N{\\fs12}Now hopefully we always pass in the user, right, that special photographer.\r\nDialogue: 0,0:46:40.51,0:46:42.98,yin,,0,0,0,,不过这个AddPhotoViewController可以更通用一些\\N{\\fs12}But this add photo view controller can be more generic\r\nDialogue: 0,0:46:42.98,0:46:45.10,yin,,0,0,0,,它可以说 给我一个拍照者\\N{\\fs12}about it and just say, hey give me a photographer,\r\nDialogue: 0,0:46:45.10,0:46:48.11,yin,,0,0,0,,我要拍张照 然后为这个拍照者将其添加到数据库\\N{\\fs12}I'll take a photo and add it to the database for that photographer.\r\nDialogue: 0,0:46:48.11,0:46:50.38,yin,,0,0,0,,不过我们会有我们的地图\\N{\\fs12}But we're going to have our map,\r\nDialogue: 0,0:46:50.38,0:46:52.88,yin,,0,0,0,,PhotosByPhotographerMapViewController\\N{\\fs12}photos by photographer map view controller.\r\nDialogue: 0,0:46:52.88,0:46:56.09,yin,,0,0,0,,如果是用户 而且相机按钮被点\\N{\\fs12}If it's the user and that camera button gets pressed,\r\nDialogue: 0,0:46:56.09,0:46:58.09,yin,,0,0,0,,我们就会传入用户的那个\\N{\\fs12}we're going to pass in the user's one.\r\nDialogue: 0,0:46:58.09,0:46:59.45,yin,,0,0,0,,这是入\\N{\\fs12}So that's the in.\r\nDialogue: 0,0:46:59.45,0:47:05.05,yin,,0,0,0,,这里导入Photographer\\N{\\fs12}So that's import photographer.\r\nDialogue: 0,0:47:05.05,0:47:07.92,yin,,0,0,0,,我们还需要导入Photo\\N{\\fs12}And we're also going to import photo while I'm here\r\nDialogue: 0,0:47:07.92,0:47:14.27,yin,,0,0,0,,因为这个视图控制器还有一个输出 也就是\\N{\\fs12}because this thing, this view controller also has an output which is\r\nDialogue: 0,0:47:14.27,0:47:15.88,yin,,0,0,0,,非原子 强\\N{\\fs12}nonatomic strong\r\nDialogue: 0,0:47:15.88,0:47:20.38,yin,,0,0,0,,添加到数据库的照片\\N{\\fs12}the photo that was added to the database.\r\nDialogue: 0,0:47:20.38,0:47:22.19,yin,,0,0,0,,应该是Photo\\N{\\fs12}Oops, photo.\r\nDialogue: 0,0:47:22.19,0:47:25.02,yin,,0,0,0,,这是一个AddPhotoViewController\\N{\\fs12}Okay so this is an add photo view controller.\r\nDialogue: 0,0:47:25.02,0:47:27.50,yin,,0,0,0,,它为给定拍照者添加一张照片\\N{\\fs12}It adds a photo for that given photographer\r\nDialogue: 0,0:47:27.50,0:47:32.18,yin,,0,0,0,,完成这个后 这就会被设为它添加的照片\\N{\\fs12}and when it's done doing that, this will be set to the photo it added.\r\nDialogue: 0,0:47:32.18,0:47:36.76,yin,,0,0,0,,segue到它的人 unwind回来后就能看到\\N{\\fs12}So anyone who segues to it, when they unwind back, they can look\r\nDialogue: 0,0:47:36.76,0:47:38.98,yin,,0,0,0,,添加的是什么照片\\N{\\fs12}and see what was the photo that was added?\r\nDialogue: 0,0:47:38.98,0:47:41.23,yin,,0,0,0,,理解这里我们做的是什么吗\\N{\\fs12}That make sense what we're doing there?\r\nDialogue: 0,0:47:41.23,0:47:46.20,yin,,0,0,0,,我们需要从入和出两方面来实现这个API\\N{\\fs12}So we have to implement this API both on the way in and on the way out.\r\nDialogue: 0,0:47:46.20,0:47:47.93,yin,,0,0,0,,首先看入\\N{\\fs12}So let's talk about on the way in first\r\nDialogue: 0,0:47:47.93,0:47:50.26,yin,,0,0,0,,因为这是你们习惯的常规segue\\N{\\fs12}because that's normal segueing that you're used to.\r\nDialogue: 0,0:47:50.26,0:47:54.16,yin,,0,0,0,,在PhotosByPhotographerMapViewController中来做\\N{\\fs12}We're just going to do this in our photos by photographer map view controller\r\nDialogue: 0,0:47:54.16,0:47:56.75,yin,,0,0,0,,我们只需要准备这个segue\\N{\\fs12}and all we're going to do is prepare that segue.\r\nDialogue: 0,0:47:56.75,0:47:58.42,yin,,0,0,0,,这之前\\N{\\fs12}Before we do that let's go ahead\r\nDialogue: 0,0:47:58.42,0:48:03.10,yin,,0,0,0,,我们先导入AddPhotoViewController\\N{\\fs12}and import our add photo view controller\r\nDialogue: 0,0:48:03.10,0:48:05.55,yin,,0,0,0,,因为我们要用它 我们要准备它\\N{\\fs12}because we're going to use it. We're going to prepare it.\r\nDialogue: 0,0:48:05.55,0:48:07.61,yin,,0,0,0,,让我们这样做\\N{\\fs12}And so let's do that.\r\nDialogue: 0,0:48:07.61,0:48:09.21,yin,,0,0,0,,这是prepareForSegue\\N{\\fs12}And here's prepare for segue.\r\nDialogue: 0,0:48:09.21,0:48:12.19,yin,,0,0,0,,这是一个很常规的segue 和其它segue一样\\N{\\fs12}This is a normal segue just like any other segue\r\nDialogue: 0,0:48:12.19,0:48:13.69,yin,,0,0,0,,我要准备它\\N{\\fs12}and I'm just going to prepare it.\r\nDialogue: 0,0:48:13.69,0:48:16.35,yin,,0,0,0,,让我们说 如果sender…\\N{\\fs12}Let's say if the sender--\r\nDialogue: 0,0:48:16.35,0:48:21.35,yin,,0,0,0,,不对 如果segue的目标视图控制器\\N{\\fs12}no if the segue's destination view controller is kind\r\nDialogue: 0,0:48:21.35,0:48:26.37,yin,,0,0,0,,是AddPhotoViewController这一类\\N{\\fs12}of class, add photo view controller,\r\nDialogue: 0,0:48:26.37,0:48:31.46,yin,,0,0,0,,那么AddPhotoViewController *apvc\\N{\\fs12}then add photo view controller-- add photo view controller--\r\nDialogue: 0,0:48:31.46,0:48:35.64,yin,,0,0,0,,= (AddPh… 你们不要沿用我这种糟糕的风格\\N{\\fs12}equals add ph- yeah you guys should not be using my bad style\r\nDialogue: 0,0:48:35.64,0:48:39.12,yin,,0,0,0,,我这里只是出于demo方便\\N{\\fs12}here but that's demo naming right there.\r\nDialogue: 0,0:48:39.12,0:48:41.46,yin,,0,0,0,,segue.destinationViewController\\N{\\fs12}Segue dot destination view controller.\r\nDialogue: 0,0:48:41.46,0:48:45.12,yin,,0,0,0,,这里我有了要segue到的视图控制器\\N{\\fs12}Okay so now I have the view controller I'm segueing to here\r\nDialogue: 0,0:48:45.12,0:48:47.03,yin,,0,0,0,,在这个modal segue中\\N{\\fs12}in this modal segue so I'm going\r\nDialogue: 0,0:48:47.03,0:48:49.49,yin,,0,0,0,,我要设置它的photographerTakingPhoto\\N{\\fs12}to set its photographer that's taking the photo\r\nDialogue: 0,0:48:49.49,0:48:51.53,yin,,0,0,0,,= self.photographer\\N{\\fs12}equal to self dot photographer.\r\nDialogue: 0,0:48:51.53,0:48:54.94,yin,,0,0,0,,这将总是用户 因为只有是用户时\\N{\\fs12}Now this is always going to be the user because the only time\r\nDialogue: 0,0:48:54.94,0:48:58.95,yin,,0,0,0,,那个相机按钮才会出现在右上角\\N{\\fs12}that little camera button is there is when it's the user.\r\nDialogue: 0,0:48:58.95,0:49:03.00,yin,,0,0,0,,不过这里出于双保险考虑 我可以检查是不是用户\\N{\\fs12}But to be double safe here, maybe I would want to check and see is user, right,\r\nDialogue: 0,0:49:03.00,0:49:05.29,yin,,0,0,0,,不过这里出于双保险考虑 我可以检查是不是用户\\N{\\fs12}[inaudible] photographer is user.\r\nDialogue: 0,0:49:05.29,0:49:08.35,yin,,0,0,0,,这里我就不检查了 毕竟是demo\\N{\\fs12}But I'm not going to be double safe because it's demo.\r\nDialogue: 0,0:49:08.35,0:49:09.97,yin,,0,0,0,,这是这个segue\\N{\\fs12}So there, that's that segue.\r\nDialogue: 0,0:49:09.97,0:49:13.67,yin,,0,0,0,,如果sender是annotation 我还要处理这个segue\\N{\\fs12}I'm still going to do this segue if the sender is an annotation.\r\nDialogue: 0,0:49:13.67,0:49:16.24,yin,,0,0,0,,换言之 有人点了大头针\\N{\\fs12}In other words, someone clicks on the pin, [inaudible] do that one too.\r\nDialogue: 0,0:49:16.24,0:49:19.85,yin,,0,0,0,,这里或许我应该放到else里面\\N{\\fs12}I could probably put an else in here if I wanted to.\r\nDialogue: 0,0:49:19.85,0:49:21.65,yin,,0,0,0,,或者else if\\N{\\fs12}Even else if.\r\nDialogue: 0,0:49:21.65,0:49:23.39,yin,,0,0,0,,像这样\\N{\\fs12}Something like that.\r\nDialogue: 0,0:49:23.39,0:49:25.93,yin,,0,0,0,,因为这里不是一种情况 就是另一种\\N{\\fs12}Okay because obviously it's going to be one or the other.\r\nDialogue: 0,0:49:25.93,0:49:29.77,yin,,0,0,0,,或许我还应该检查segue标识符 确保是Add Photo\\N{\\fs12}I also probably could've checked my segues identifier here to make sure it's add photo.\r\nDialogue: 0,0:49:29.77,0:49:31.45,yin,,0,0,0,,想的话 我可以那样做\\N{\\fs12}I can do that if I want to.\r\nDialogue: 0,0:49:31.45,0:49:35.89,yin,,0,0,0,,无论如何 但愿这部分segue你们完全理解了\\N{\\fs12}But anyway, hopefully this side of this segue you totally understand, right?\r\nDialogue: 0,0:49:35.89,0:49:39.93,yin,,0,0,0,,常规segue 我们只是采用了modal方式\\N{\\fs12}Okay, normal segueing, we're just doing it modally rather than not.\r\nDialogue: 0,0:49:39.93,0:49:41.85,yin,,0,0,0,,现在往前解决了\\N{\\fs12}Okay, so now we've got to it.\r\nDialogue: 0,0:49:41.85,0:49:45.27,yin,,0,0,0,,下面才是麻烦的部分 即unwind\\N{\\fs12}Now the hard part, unwinding.\r\nDialogue: 0,0:49:45.27,0:49:50.38,yin,,0,0,0,,我们希望在完成工作时听到它的回复\\N{\\fs12}So now we want to hear about it when the thing is done.\r\nDialogue: 0,0:49:50.38,0:49:52.32,yin,,0,0,0,,我说过 这个完成时\\N{\\fs12}And I told you that that's done\r\nDialogue: 0,0:49:52.32,0:49:58.86,yin,,0,0,0,,通过实现一个特殊的IBAction方法\\N{\\fs12}by implementing a special IB action, okay, method,\r\nDialogue: 0,0:49:58.87,0:50:03.21,yin,,0,0,0,,叫什么都行 它unwind时会发生什么呢\\N{\\fs12}and we can call it anything we want. And what is going to happen when it's unwinding?\r\nDialogue: 0,0:50:03.21,0:50:04.98,yin,,0,0,0,,一张照片会被添加\\N{\\fs12}Well a photo's going to be added.\r\nDialogue: 0,0:50:04.98,0:50:08.76,yin,,0,0,0,,或许我应该把这个方法叫作addedPhoto\\N{\\fs12}So maybe I'll call this method added photo.\r\nDialogue: 0,0:50:08.76,0:50:10.34,yin,,0,0,0,,因为这就是它的作用\\N{\\fs12}Because that's what it does.\r\nDialogue: 0,0:50:10.34,0:50:17.28,yin,,0,0,0,,真正关键的是 参数是一个UIStoryboardSegue\\N{\\fs12}And the real key is that the argument is a UI storyboard segue.\r\nDialogue: 0,0:50:17.28,0:50:22.50,yin,,0,0,0,,这是unwind时需要调用的方法\\N{\\fs12}So this method is the method that's going to get called when we unwind, all right?\r\nDialogue: 0,0:50:22.50,0:50:26.73,yin,,0,0,0,,加入这个之后 Xcode就知道了\\N{\\fs12}Now the very adding of this has caused Xcode to know about it,\r\nDialogue: 0,0:50:26.73,0:50:30.30,yin,,0,0,0,,当我们回到故事板control拖动\\N{\\fs12}so that if we go back to our storyboard and wind u-\r\nDialogue: 0,0:50:30.30,0:50:34.58,yin,,0,0,0,,来关联 来unwind 它就会自动\\N{\\fs12}you know control drag to hook up and unwind, it's going to know about it.\r\nDialogue: 0,0:50:34.58,0:50:36.24,yin,,0,0,0,,让我们来做这个\\N{\\fs12}So let's go do that.\r\nDialogue: 0,0:50:36.24,0:50:38.59,yin,,0,0,0,,我们回到了这里\\N{\\fs12}We're back in our thing here.\r\nDialogue: 0,0:50:38.59,0:50:39.65,yin,,0,0,0,,取消\\N{\\fs12}Cancel.\r\nDialogue: 0,0:50:39.65,0:50:41.74,yin,,0,0,0,,我们简单谈下取消\\N{\\fs12}Let's talk about cancel briefly.\r\nDialogue: 0,0:50:41.76,0:50:44.18,yin,,0,0,0,,这里我打算在点取消时\\N{\\fs12}I'm going to make the executive decision that cancel,\r\nDialogue: 0,0:50:44.18,0:50:46.97,yin,,0,0,0,,仅仅消掉而不unwind\\N{\\fs12}it's just going to dismiss, it's not going to unwind.\r\nDialogue: 0,0:50:46.97,0:50:50.11,yin,,0,0,0,,我这里已经有了一个取消方法\\N{\\fs12}All right? And I already have a cancel method right here.\r\nDialogue: 0,0:50:50.11,0:50:52.05,yin,,0,0,0,,我已经将它同目标动作关联了起来\\N{\\fs12}I already wired it up for target action.\r\nDialogue: 0,0:50:52.05,0:50:53.55,yin,,0,0,0,,怎么做到呢\\N{\\fs12}So how do I do that?\r\nDialogue: 0,0:50:53.55,0:50:58.24,yin,,0,0,0,,self.presentingViewController\\N{\\fs12}Self dot presenting view controller presenting\r\nDialogue: 0,0:50:58.25,0:51:01.26,yin,,0,0,0,,dismiss… YES\\N{\\fs12}dismiss, yes.\r\nDialogue: 0,0:51:01.26,0:51:06.79,yin,,0,0,0,,该完成处理器在视图控制器完全被消掉时就会被调用\\N{\\fs12}And this completion handler is called once the view controller is fully dismissed.\r\nDialogue: 0,0:51:06.79,0:51:10.15,yin,,0,0,0,,也就是说 在其viewDidDisappear被调用之后\\N{\\fs12}In other words, after its view did disappear is called.\r\nDialogue: 0,0:51:10.15,0:51:12.59,yin,,0,0,0,,那时 我们什么都不需要做\\N{\\fs12}We don't need to do anything at that time.\r\nDialogue: 0,0:51:12.59,0:51:16.17,yin,,0,0,0,,有些人认为 这比它实际更神奇\\N{\\fs12}Some people think this, this is more magic than it is.\r\nDialogue: 0,0:51:16.17,0:51:19.32,yin,,0,0,0,,这是一个很简单的方式 在这个东西消失后\\N{\\fs12}It's really just a simple way to, after this thing is gone,\r\nDialogue: 0,0:51:19.32,0:51:21.16,yin,,0,0,0,,做点什么来收尾\\N{\\fs12}do something to clean up or something.\r\nDialogue: 0,0:51:21.16,0:51:24.64,yin,,0,0,0,,不过 我们不需要做这个\\N{\\fs12}But we're no, we don't need to do that.\r\nDialogue: 0,0:51:24.64,0:51:26.57,yin,,0,0,0,,无论如何 取消就是这样了\\N{\\fs12}So anyways, so that's it. So that cancel.\r\nDialogue: 0,0:51:26.57,0:51:28.76,yin,,0,0,0,,我们现在可以运行一下\\N{\\fs12}So in fact if we run right now\r\nDialogue: 0,0:51:30.57,0:51:33.77,yin,,0,0,0,,选My Photos再到这里 取消就能奏效了\\N{\\fs12}and we bring our photos and we go up here, cancel will work you see?\r\nDialogue: 0,0:51:33.77,0:51:35.22,yin,,0,0,0,,视图被消掉了\\N{\\fs12}It just dismisses it.\r\nDialogue: 0,0:51:35.22,0:51:38.16,yin,,0,0,0,,它没有unwind 没有调用addedPhoto\\N{\\fs12}And it doesn't unwind, it doesn't call that added photo.\r\nDialogue: 0,0:51:38.16,0:51:40.70,yin,,0,0,0,,取消只是让其消失\\N{\\fs12}It just cancels it, gone.\r\nDialogue: 0,0:51:40.70,0:51:43.90,yin,,0,0,0,,完成 这个是我们要unwind的\\N{\\fs12}Now done, this is the one we want to unwind.\r\nDialogue: 0,0:51:43.90,0:51:47.55,yin,,0,0,0,,我们希望它创建这张照片 然后unwind回来\\N{\\fs12}We want it to create this photo and then unwind back\r\nDialogue: 0,0:51:47.55,0:51:51.99,yin,,0,0,0,,到这个地图视图控制器 并调用addedPhoto\\N{\\fs12}to this map view controller right here and call added photo.\r\nDialogue: 0,0:51:51.99,0:51:54.68,yin,,0,0,0,,addedPhoto被调用时 我们要做什么\\N{\\fs12}Okay what's, what are we going to do when added photo is called?\r\nDialogue: 0,0:51:54.68,0:51:56.74,yin,,0,0,0,,我们来看看\\N{\\fs12}Well, let's see.\r\nDialogue: 0,0:51:56.74,0:51:59.23,yin,,0,0,0,,我们来做一些事情\\N{\\fs12}Let's do a couple of things.\r\nDialogue: 0,0:51:59.23,0:52:03.25,yin,,0,0,0,,一 让我们确保这个的来源\\N{\\fs12}One, let's make sure that the source\r\nDialogue: 0,0:52:03.25,0:52:07.94,yin,,0,0,0,,是一个AddPhotoViewController\\N{\\fs12}of this is an add photo view controller,\r\nDialogue: 0,0:52:07.94,0:52:09.23,yin,,0,0,0,,它显然应该是\\N{\\fs12}which it should be\r\nDialogue: 0,0:52:09.23,0:52:11.24,yin,,0,0,0,,因为我们只知道对这个进行unwind\\N{\\fs12}because it's the only thing we know how to unwind for.\r\nDialogue: 0,0:52:11.24,0:52:13.79,yin,,0,0,0,,而且 还有谁能调用addedPhoto呢\\N{\\fs12}And also because who else would call added photo?\r\nDialogue: 0,0:52:13.79,0:52:15.19,yin,,0,0,0,,无论如何 我们会检查它\\N{\\fs12}But we'll check it anyway.\r\nDialogue: 0,0:52:15.19,0:52:17.44,yin,,0,0,0,,然后 我要复制粘贴这个\\N{\\fs12}And then we're going to do, I'm going to copy and paste this\r\nDialogue: 0,0:52:17.44,0:52:19.41,yin,,0,0,0,,这就不需要重新键入了\\N{\\fs12}so I don't have to type all that again.\r\nDialogue: 0,0:52:19.41,0:52:20.85,yin,,0,0,0,,不过这里要变\\N{\\fs12}Okay now I'm just going to change,\r\nDialogue: 0,0:52:20.85,0:52:23.04,yin,,0,0,0,,这是源视图控制器\\N{\\fs12}but this is the source view controller instead\r\nDialogue: 0,0:52:23.04,0:52:25.50,yin,,0,0,0,,而不是目标视图控制器\\N{\\fs12}of the destination view controller.\r\nDialogue: 0,0:52:25.50,0:52:26.93,yin,,0,0,0,,我有了我的apvc\\N{\\fs12}So I've got my APVC.\r\nDialogue: 0,0:52:26.93,0:52:30.51,yin,,0,0,0,,然后我说 添加的照片是什么\\N{\\fs12}Now I'm going to say, okay well what was the photo that was added?\r\nDialogue: 0,0:52:30.51,0:52:33.48,yin,,0,0,0,,是apvc的addedPhoto\\N{\\fs12}Well it's the APVCs added photo.\r\nDialogue: 0,0:52:33.48,0:52:38.17,yin,,0,0,0,,这是它公共API的一部分 公共API的出那部分\\N{\\fs12}That's part of its public API, the out of its public API.\r\nDialogue: 0,0:52:38.17,0:52:40.47,yin,,0,0,0,,我把这抓出来 我打算说\\N{\\fs12}So I'm grabbing that out, and now I'm going to say\r\nDialogue: 0,0:52:40.47,0:52:43.73,yin,,0,0,0,,如果我们加了一张照片 那么我想做什么呢\\N{\\fs12}if we added a photo, then what might I want to do?\r\nDialogue: 0,0:52:43.73,0:52:47.27,yin,,0,0,0,,我在显示PhotosByPhotographer\\N{\\fs12}I'm the map view-- I'm showing photos by a photographer\r\nDialogue: 0,0:52:47.27,0:52:49.33,yin,,0,0,0,,因此我可以这样\\N{\\fs12}so I probably want to do, for example,\r\nDialogue: 0,0:52:49.33,0:52:53.02,yin,,0,0,0,,mapView addAnnotation 这张addedPhoto\\N{\\fs12}map view, add annotation this added photo.\r\nDialogue: 0,0:52:53.02,0:52:55.48,yin,,0,0,0,,换言之 将这张照片加到我的地图\\N{\\fs12}In other words, add this photo to my map.\r\nDialogue: 0,0:52:55.48,0:53:01.16,yin,,0,0,0,,我还可以说 self.mapView 显示那个annotation\\N{\\fs12}I might also want to say self dot map view show that annotation.\r\nDialogue: 0,0:53:01.16,0:53:05.48,yin,,0,0,0,,放大到那个拍照所在的位置\\N{\\fs12}Zoom in to that part of the world where the photo was taken.\r\nDialogue: 0,0:53:05.48,0:53:07.40,yin,,0,0,0,,我或许还可以说\\N{\\fs12}I might want to say, I probably want to say\r\nDialogue: 0,0:53:07.40,0:53:09.36,yin,,0,0,0,,photosByPhotographer = nil\\N{\\fs12}photos by photography equals nil\r\nDialogue: 0,0:53:09.36,0:53:10.61,yin,,0,0,0,,并重新计算这个\\N{\\fs12}and have that recalculate\r\nDialogue: 0,0:53:10.61,0:53:12.98,yin,,0,0,0,,因为我为这个拍照者添加了一张新照片\\N{\\fs12}because I've added a new photo for this photographer.\r\nDialogue: 0,0:53:12.98,0:53:15.95,yin,,0,0,0,,这样下次有人问我这个 它就能够工作\\N{\\fs12}So the next time someone asks me about that it'll work.\r\nDialogue: 0,0:53:15.95,0:53:19.46,yin,,0,0,0,,否则 出于教学目的 我可以查看日志\\N{\\fs12}Otherwise, for instructional purposes here, I'm going to log\r\nDialogue: 0,0:53:19.46,0:53:20.78,yin,,0,0,0,,这里我可以说\\N{\\fs12}and say\r\nDialogue: 0,0:53:20.78,0:53:25.39,yin,,0,0,0,,AddPhotoViewController没有…\\N{\\fs12}add photo view controller, did not--\r\nDialogue: 0,0:53:25.39,0:53:32.60,yin,,0,0,0,,我甚至可以说 出乎意料地没有添加照片\\N{\\fs12}or I'll even say-- unexpectedly did not add a photo.\r\nDialogue: 0,0:53:32.60,0:53:37.28,yin,,0,0,0,,因为unwind时 应该会添加一张照片\\N{\\fs12}Okay because if I'm getting unwound to, it should have added a photo.\r\nDialogue: 0,0:53:37.28,0:53:40.27,yin,,0,0,0,,如果这里是nil 那就肯定出错了\\N{\\fs12}Okay so if this is nil, then something's wrong.\r\nDialogue: 0,0:53:40.27,0:53:43.00,yin,,0,0,0,,我们会看到这种情况发生\\N{\\fs12}So but we're going to see that happen because we're going\r\nDialogue: 0,0:53:43.00,0:53:46.11,yin,,0,0,0,,我们会尝试没添加照片到数据库的情况\\N{\\fs12}to try this without adding the, without the photo being added\r\nDialogue: 0,0:53:46.11,0:53:48.02,yin,,0,0,0,,看看那时会发生什么\\N{\\fs12}to the database and see what happens here.\r\nDialogue: 0,0:53:48.02,0:53:50.54,yin,,0,0,0,,大家都理解这些对吧\\N{\\fs12}So everyone understands what happen- what's going on here right?\r\nDialogue: 0,0:53:50.54,0:53:52.80,yin,,0,0,0,,我们正unwind回这个\\N{\\fs12}We're unwinding back to this guy.\r\nDialogue: 0,0:53:52.80,0:53:55.95,yin,,0,0,0,,这个正在接收unwind\\N{\\fs12}This guy is receiving the unwind\r\nDialogue: 0,0:53:55.95,0:53:58.98,yin,,0,0,0,,并对添加的照片做些什么\\N{\\fs12}and doing something with the photo that was added with the add photo.\r\nDialogue: 0,0:53:58.98,0:54:03.64,yin,,0,0,0,,好 让我们把这些关联起来\\N{\\fs12}All right so now let's go ahead and wire that up.\r\nDialogue: 0,0:54:03.64,0:54:08.08,yin,,0,0,0,,我说了 我们会选择这里导致unwind的UI\\N{\\fs12}So as I said, we're going to pick whatever UI in here is going to cause the unwind,\r\nDialogue: 0,0:54:08.08,0:54:09.03,yin,,0,0,0,,也就是完成按钮\\N{\\fs12}which is the done button.\r\nDialogue: 0,0:54:09.03,0:54:11.47,yin,,0,0,0,,我要control拖动到这个绿色按钮\\N{\\fs12}I'm going to control drag to this green button.\r\nDialogue: 0,0:54:11.47,0:54:14.08,yin,,0,0,0,,释放后 看看会发生什么\\N{\\fs12}And when I let go, watch what happens.\r\nDialogue: 0,0:54:14.08,0:54:17.95,yin,,0,0,0,,看到addedPhoto出现在列表中了吗\\N{\\fs12}You see how added photo is in the list?\r\nDialogue: 0,0:54:17.95,0:54:22.53,yin,,0,0,0,,拥有UIStoryboardSegue作为参数的任何IBAction\\N{\\fs12}And every single IB action that had a UI storyboard segue as an argument\r\nDialogue: 0,0:54:22.53,0:54:24.16,yin,,0,0,0,,都会被列在这里\\N{\\fs12}would be listed here.\r\nDialogue: 0,0:54:24.16,0:54:27.65,yin,,0,0,0,,不过这里只有addedPhoto 这正是我们要的\\N{\\fs12}But added photo, obviously only one, it's the one we want,\r\nDialogue: 0,0:54:27.65,0:54:28.82,yin,,0,0,0,,我要点这个\\N{\\fs12}so I'm going to click that.\r\nDialogue: 0,0:54:28.82,0:54:34.00,yin,,0,0,0,,现在 我创建了unwind 它会unwind回这个\\N{\\fs12}So now I've created an unwind that will unwind back to this guy.\r\nDialogue: 0,0:54:34.00,0:54:38.04,yin,,0,0,0,,我说过 这只能在文档大纲中看到\\N{\\fs12}And I told you that the only place you can really see this is in the document outline.\r\nDialogue: 0,0:54:38.04,0:54:38.88,yin,,0,0,0,,这里\\N{\\fs12}You can see it right here.\r\nDialogue: 0,0:54:38.88,0:54:43.29,yin,,0,0,0,,看到了吗 unwind segue从完成到退出\\N{\\fs12}See? Unwind segue from done to exit.\r\nDialogue: 0,0:54:43.29,0:54:45.84,yin,,0,0,0,,这是一个常规的segue\\N{\\fs12}And I can, this is a normal segue\r\nDialogue: 0,0:54:45.84,0:54:48.06,yin,,0,0,0,,因此我可以设置它的标识符\\N{\\fs12}so I could set its identifier for example to something\r\nDialogue: 0,0:54:48.06,0:54:52.00,yin,,0,0,0,,例如Do Add Photo这之类\\N{\\fs12}like do add photo or something like that\r\nDialogue: 0,0:54:52.00,0:54:54.76,yin,,0,0,0,,因为该unwind segue的作用就是添加照片\\N{\\fs12}because that's what this unwind segue does. It does the add photo.\r\nDialogue: 0,0:54:54.76,0:54:56.95,yin,,0,0,0,,这就是完成的作用\\N{\\fs12}It's the done basically.\r\nDialogue: 0,0:54:56.95,0:54:58.42,yin,,0,0,0,,不过这个我甚至不需要做\\N{\\fs12}Okay but I wouldn't even need to do that.\r\nDialogue: 0,0:54:58.42,0:55:02.44,yin,,0,0,0,,最后我还是需要做这个 不过目前还不用\\N{\\fs12}So let's go-- well I will need to do it eventually-- but for this so far I didn't.\r\nDialogue: 0,0:55:02.44,0:55:06.30,yin,,0,0,0,,下面我运行一下 看会发生什么\\N{\\fs12}So let's go ahead and see what happens here when we run this.\r\nDialogue: 0,0:55:06.30,0:55:08.68,yin,,0,0,0,,我打算到这里 再到这里\\N{\\fs12}Okay so I'm going to go here, I'm going to go here,\r\nDialogue: 0,0:55:08.68,0:55:12.65,yin,,0,0,0,,这次点完成 看它unwind\\N{\\fs12}and I'm going to hit done this time and we'll watch it unwind.\r\nDialogue: 0,0:55:12.65,0:55:14.18,yin,,0,0,0,,它unwind了\\N{\\fs12}Okay it unwound, right?\r\nDialogue: 0,0:55:14.18,0:55:17.54,yin,,0,0,0,,窗口被消掉\\N{\\fs12}It dis- dismissed it.\r\nDialogue: 0,0:55:17.54,0:55:20.35,yin,,0,0,0,,看看下面这里的控制台信息\\N{\\fs12}And look down in my console down here.\r\nDialogue: 0,0:55:20.35,0:55:24.15,yin,,0,0,0,,AddPhotoViewController出乎意料地没有添加照片\\N{\\fs12}Add photo view unexpectedly did not add a photo\r\nDialogue: 0,0:55:24.15,0:55:25.97,yin,,0,0,0,,这正是我们所期望的\\N{\\fs12}which is exactly what we'd expect, right?\r\nDialogue: 0,0:55:25.97,0:55:31.40,yin,,0,0,0,,它unwind到了这里 做了这个 但没有添加照片\\N{\\fs12}It unwound over to here, did this, but it never added the photo\r\nDialogue: 0,0:55:31.40,0:55:35.60,yin,,0,0,0,,因为UI中我没有获得所有信息\\N{\\fs12}because I never take all the information here that's in my UI\r\nDialogue: 0,0:55:35.60,0:55:38.61,yin,,0,0,0,,例如标题 副标题 照片\\N{\\fs12}like the title, the subtitle, the photo--\r\nDialogue: 0,0:55:38.61,0:55:41.94,yin,,0,0,0,,我没有把这些添加到照片中 并添加到数据库\\N{\\fs12}I never put them into a photo and added it to the database.\r\nDialogue: 0,0:55:41.94,0:55:43.14,yin,,0,0,0,,它说得没错\\N{\\fs12}So it's right.\r\nDialogue: 0,0:55:43.14,0:55:47.97,yin,,0,0,0,,这里的汇报很正确 因为确实没有添加照片\\N{\\fs12}This thing is properly reporting here that it did not add a photo.\r\nDialogue: 0,0:55:47.97,0:55:50.08,yin,,0,0,0,,我们来处理这个 怎么做呢\\N{\\fs12}So let's do that. How do we do that?\r\nDialogue: 0,0:55:50.08,0:55:54.69,yin,,0,0,0,,这就是prepareForSegue对unwind非常重要的地方\\N{\\fs12}This is where prepare for segue is so important for unwinds.\r\nDialogue: 0,0:55:54.69,0:55:56.60,yin,,0,0,0,,因为prepareForSegue…\\N{\\fs12}Because prepare for segue--\r\nDialogue: 0,0:55:56.60,0:56:00.84,yin,,0,0,0,,因为这个unwind segue发生在这个视图控制器中\\N{\\fs12}since this unwind segue happens in this view controller, okay--\r\nDialogue: 0,0:56:00.84,0:56:03.88,yin,,0,0,0,,unwind到这里 所以这个需要准备\\N{\\fs12}unwinds over to there, this guy gets to prepare.\r\nDialogue: 0,0:56:03.88,0:56:09.09,yin,,0,0,0,,这个在做准备时 需要创建照片\\N{\\fs12}And what this guy wants to do when he prepares is create that photo.\r\nDialogue: 0,0:56:09.09,0:56:10.34,yin,,0,0,0,,理解吗\\N{\\fs12}Make sense?\r\nDialogue: 0,0:56:10.34,0:56:13.41,yin,,0,0,0,,这里要创建照片 我们只需要prepareForSegue\\N{\\fs12}So all we got to do to make that photo is implement prepare\r\nDialogue: 0,0:56:13.41,0:56:15.87,yin,,0,0,0,,这里 在添加视图控制器中\\N{\\fs12}for segue here in this add view controller.\r\nDialogue: 0,0:56:15.87,0:56:17.71,yin,,0,0,0,,我们来做这个\\N{\\fs12}So let's do that.\r\nDialogue: 0,0:56:17.71,0:56:20.77,yin,,0,0,0,,添加视图控制器中 放到这里\\N{\\fs12}Add view controller. Let's put this right here.\r\nDialogue: 0,0:56:20.77,0:56:23.51,yin,,0,0,0,,这是常规的prepareForSegue\\N{\\fs12}This is normal prepare for segue here.\r\nDialogue: 0,0:56:23.51,0:56:26.64,yin,,0,0,0,,我们需要明确是哪个segue\\N{\\fs12}We need to figure out which segue it is\r\nDialogue: 0,0:56:26.64,0:56:32.09,yin,,0,0,0,,我们这里不能看目标视图控制器\\N{\\fs12}and so we could-- we really can't look at the destination view controller here.\r\nDialogue: 0,0:56:32.09,0:56:34.52,yin,,0,0,0,,因为添加照片视图控制器可以说是\\N{\\fs12}Because add photo view controller is kind of like part\r\nDialogue: 0,0:56:34.52,0:56:36.99,yin,,0,0,0,,另外一个视图控制器的视图的一部分\\N{\\fs12}of the view of that other view controller.\r\nDialogue: 0,0:56:36.99,0:56:39.60,yin,,0,0,0,,关于PhotosByPhotographerMapViewController\\N{\\fs12}So it really can't be looking, it can't know anything\r\nDialogue: 0,0:56:39.60,0:56:42.00,yin,,0,0,0,,它不知道任何信息\\N{\\fs12}about the photos by photographer map view controller.\r\nDialogue: 0,0:56:42.00,0:56:46.27,yin,,0,0,0,,不过我们可以看segue的标识符\\N{\\fs12}But what we can do is look at the segue's identifier.\r\nDialogue: 0,0:56:46.27,0:56:49.49,yin,,0,0,0,,如果segue的标识符是之前我设置的\\N{\\fs12}So if the segue's identifier is what I set there\r\nDialogue: 0,0:56:49.49,0:56:51.68,yin,,0,0,0,,也就是Do Add Photo\\N{\\fs12}which was do add photo, right?\r\nDialogue: 0,0:56:51.68,0:56:53.87,yin,,0,0,0,,这是我之前在故事板中设置的\\N{\\fs12}That's what I set it to in the storyboard--\r\nDialogue: 0,0:56:53.87,0:56:57.06,yin,,0,0,0,,或许这里我们可以这样做\\N{\\fs12}and probably we want to have this be called something\r\nDialogue: 0,0:56:57.06,0:57:02.33,yin,,0,0,0,,写上UNWIND_SEGUE_IDENTIFIER 像这样\\N{\\fs12}like unwind segue identifier or something like that.\r\nDialogue: 0,0:57:02.33,0:57:07.86,yin,,0,0,0,,在上面这里定义 复制 #define\\N{\\fs12}We'll put this up here. Copy, pound sign, define.\r\nDialogue: 0,0:57:07.86,0:57:11.42,yin,,0,0,0,,像这样 这就定义了一个常数\\N{\\fs12}Like that. So I have a nice constant there.\r\nDialogue: 0,0:57:11.42,0:57:14.02,yin,,0,0,0,,马上我们就会用到这个常数\\N{\\fs12}We're going to need this constant in a second as you'll see.\r\nDialogue: 0,0:57:14.02,0:57:17.96,yin,,0,0,0,,如果这是unwind 那么我们就希望创建照片\\N{\\fs12}So if this is the unwind, then we want to create that photo.\r\nDialogue: 0,0:57:17.96,0:57:19.20,yin,,0,0,0,,创建照片需要什么呢\\N{\\fs12}So what do we need to create the photo?\r\nDialogue: 0,0:57:19.20,0:57:22.80,yin,,0,0,0,,首先 我需要一个ManagedObjectContext\\N{\\fs12}Well, first thing I need is a managed object context.\r\nDialogue: 0,0:57:22.80,0:57:26.30,yin,,0,0,0,,如果对数据库无能为力 我就创建不了照片\\N{\\fs12}Okay I can't create a photo unless I have a handle on the database.\r\nDialogue: 0,0:57:26.30,0:57:31.76,yin,,0,0,0,,不过我可以做到 因为self.photographerTakingPhoto\\N{\\fs12}But I do because self dot photographer taking the photo\r\nDialogue: 0,0:57:31.76,0:57:34.05,yin,,0,0,0,,有一个ManagedObjectContext 我要把这张照片\\N{\\fs12}has a managed object context, so I'm going to put this photo\r\nDialogue: 0,0:57:34.05,0:57:37.09,yin,,0,0,0,,放到拍照者相同的数据库中 这也正是我要的\\N{\\fs12}in the same database that the photographer's in which is exactly what I want.\r\nDialogue: 0,0:57:37.77,0:57:39.01,yin,,0,0,0,,这很好\\N{\\fs12}So that's good.\r\nDialogue: 0,0:57:39.01,0:57:43.49,yin,,0,0,0,,如果这个context不是nil 那么我们就能创建照片\\N{\\fs12}So if that context is not nil, then we can create our photo.\r\nDialogue: 0,0:57:43.49,0:57:50.99,yin,,0,0,0,,Photo *photo = … 之前还需要导入Photo\\N{\\fs12}So photo star photo equals, and let's import photo.\r\nDialogue: 0,0:57:50.99,0:57:53.36,yin,,0,0,0,,如何创建照片呢\\N{\\fs12}Okay, so how do we create a photo?\r\nDialogue: 0,0:57:53.36,0:57:58.73,yin,,0,0,0,,NSEntityDescription insertNewObjectForIdentity…\\N{\\fs12}NS entity description, insert new object for identity,\r\nDialogue: 0,0:57:58.73,0:58:00.19,yin,,0,0,0,,Photo\\N{\\fs12}photo,\r\nDialogue: 0,0:58:00.19,0:58:02.88,yin,,0,0,0,,而context是context\\N{\\fs12}and the context is that context.\r\nDialogue: 0,0:58:02.88,0:58:04.64,yin,,0,0,0,,我这就创建了一张照片\\N{\\fs12}All right I've created a photo!\r\nDialogue: 0,0:58:04.64,0:58:06.50,yin,,0,0,0,,下面 我只需要设置照片中的所有信息\\N{\\fs12}Now I just need to set everything in the photo.\r\nDialogue: 0,0:58:06.50,0:58:14.67,yin,,0,0,0,,photo.title = self.titleTextField.text\\N{\\fs12}So photo dot title equals self dot title text field dot text.\r\nDialogue: 0,0:58:14.67,0:58:18.89,yin,,0,0,0,,错了 删掉方括号\\N{\\fs12}Oops. Get rid of these square brackets.\r\nDialogue: 0,0:58:18.89,0:58:24.85,yin,,0,0,0,,然后photo.subtitle = self.subtitleTextField.text\\N{\\fs12}All right, and photo dot subtitle equals self dot subtitle title field dot text.\r\nDialogue: 0,0:58:24.85,0:58:27.90,yin,,0,0,0,,这时 我们就能从那些文本框中抓出文本了\\N{\\fs12}So here's how we are grabbing the text out of those text fields\r\nDialogue: 0,0:58:27.90,0:58:30.02,yin,,0,0,0,,就像使用标签一样\\N{\\fs12}just using, just like a label, right?\r\nDialogue: 0,0:58:30.02,0:58:33.23,yin,,0,0,0,,抓取文本属性 这是一个NSString\\N{\\fs12}Just grabbing the text property which is an NS string.\r\nDialogue: 0,0:58:33.23,0:58:36.21,yin,,0,0,0,,我们还从该照片中获得什么\\N{\\fs12}And what else do we got to get out of this photo?\r\nDialogue: 0,0:58:36.21,0:58:38.10,yin,,0,0,0,,还有不少信息\\N{\\fs12}Well quite a few other things actually.\r\nDialogue: 0,0:58:38.10,0:58:40.83,yin,,0,0,0,,我们得到photo.whoTook\\N{\\fs12}We got photo dot who took.\r\nDialogue: 0,0:58:40.83,0:58:45.14,yin,,0,0,0,,都知道这是什么吧\\N{\\fs12}Everyone know what that is?\r\nDialogue: 0,0:58:45.14,0:58:49.17,yin,,0,0,0,,photographerTakingPhoto 这就是这里的whoTook\\N{\\fs12}All right, photographer taking the photo, that's who took this thing.\r\nDialogue: 0,0:58:49.17,0:58:52.84,yin,,0,0,0,,photo.latitude呢\\N{\\fs12}How about photo dot latitude?\r\nDialogue: 0,0:58:52.84,0:58:55.22,yin,,0,0,0,,我们还没有纬度\\N{\\fs12}Okay, well we don't have the latitude.\r\nDialogue: 0,0:58:55.22,0:59:00.82,yin,,0,0,0,,我们需要获取纬度 为此 这里我需要添加一些属性\\N{\\fs12}We've got to get that latitude, so to do that I'm going to add some properties here.\r\nDialogue: 0,0:59:00.82,0:59:02.52,yin,,0,0,0,,我添加了这些属性\\N{\\fs12}Okay so I added these properties.\r\nDialogue: 0,0:59:02.52,0:59:06.61,yin,,0,0,0,,一个是跟踪位置 在CLLocation中\\N{\\fs12}One is to keep track of our location, in the CL location.\r\nDialogue: 0,0:59:06.61,0:59:08.91,yin,,0,0,0,,一个是跟踪图像的URL\\N{\\fs12}One is to keep track of the URL of our image.\r\nDialogue: 0,0:59:08.91,0:59:10.28,yin,,0,0,0,,一个是缩略图\\N{\\fs12}One is our thumbnail.\r\nDialogue: 0,0:59:10.28,0:59:14.69,yin,,0,0,0,,而且我还说 addedPhoto等于某个东西\\N{\\fs12}And also I'm going to say add photo, added photo equals something.\r\nDialogue: 0,0:59:14.69,0:59:16.62,yin,,0,0,0,,这个设置为读写\\N{\\fs12}So I'm going to make this one read write and I'm going\r\nDialogue: 0,0:59:16.62,0:59:18.99,yin,,0,0,0,,而这个设置为只读\\N{\\fs12}to make this one read only over here.\r\nDialogue: 0,0:59:18.99,0:59:22.50,yin,,0,0,0,,这样这个参数就只能往外出去\\N{\\fs12}So that this is truly an outgoing parameter.\r\nDialogue: 0,0:59:22.50,0:59:25.35,yin,,0,0,0,,这里面设置为读写\\N{\\fs12}So I'll make it read write here internally.\r\nDialogue: 0,0:59:25.35,0:59:29.80,yin,,0,0,0,,我需要导入Core Location\\N{\\fs12}So I need to import core location,\r\nDialogue: 0,0:59:29.80,0:59:33.46,yin,,0,0,0,,因为这里在用Core Location\\N{\\fs12}okay because I'm using core location right here.\r\nDialogue: 0,0:59:33.46,0:59:36.66,yin,,0,0,0,,我们还要设置这个位置 等下我们就会这样做\\N{\\fs12}Okay and we're going to have to set this location which we'll do in a moment.\r\nDialogue: 0,0:59:36.66,0:59:37.95,yin,,0,0,0,,不过现在 我们到这里\\N{\\fs12}But in the meantime, let's go here.\r\nDialogue: 0,0:59:37.95,0:59:43.38,yin,,0,0,0,,这将是self.location.coordinate.latitude\\N{\\fs12}This is going to be self dot location dot coordinate dot latitude.\r\nDialogue: 0,0:59:43.38,0:59:45.53,yin,,0,0,0,,然后photo.longitude =\\N{\\fs12}And photo out longitude equals\r\nDialogue: 0,0:59:45.53,0:59:49.47,yin,,0,0,0,,self.location.coordinate.longitude\\N{\\fs12}self dot location dot coordinate dot longitude.\r\nDialogue: 0,0:59:49.47,0:59:53.06,yin,,0,0,0,,然后我们说photo.imageURL =\\N{\\fs12}And then let's say photo dot image URL equals\r\nDialogue: 0,0:59:53.06,0:59:57.23,yin,,0,0,0,,self.imageURL absoluteString\\N{\\fs12}self dot image dot URL, absolute string\r\nDialogue: 0,0:59:57.23,0:59:59.07,yin,,0,0,0,,我们需要实现这个\\N{\\fs12}and we're going to have to implement this.\r\nDialogue: 0,0:59:59.07,1:00:02.61,yin,,0,0,0,,因为现在 我们的图像只是在那个图像视图中\\N{\\fs12}Because right now our image is just in that image view.\r\nDialogue: 0,1:00:02.61,1:00:05.92,yin,,0,0,0,,我们需要把它放到磁盘上 并得到一个URL\\N{\\fs12}We're going to have to put it on disk and get a URL to it.\r\nDialogue: 0,1:00:05.92,1:00:07.41,yin,,0,0,0,,我们需要实现这个\\N{\\fs12}So we'll have to implement that.\r\nDialogue: 0,1:00:07.43,1:00:09.72,yin,,0,0,0,,然后我们有photo.thumbnailURL =\\N{\\fs12}And then we got photo dot thumbnail URL equals\r\nDialogue: 0,1:00:09.72,1:00:13.26,yin,,0,0,0,,这里还是一样的做法 absoluteString\\N{\\fs12}or do the same thing here, absolute string.\r\nDialogue: 0,1:00:13.26,1:00:15.20,yin,,0,0,0,,最后我们要说\\N{\\fs12}Okay and then finally we're going to say\r\nDialogue: 0,1:00:15.20,1:00:18.73,yin,,0,0,0,,self.addedPhoto = photo\\N{\\fs12}self dot added photo equals the photo.\r\nDialogue: 0,1:00:22.13,1:00:25.03,yin,,0,0,0,,在unwind中 在unwind的准备中\\N{\\fs12}So in the unwind, in preparing for the unwind,\r\nDialogue: 0,1:00:25.03,1:00:26.85,yin,,0,0,0,,我们将照片放入了数据库\\N{\\fs12}we put that photo in the database.\r\nDialogue: 0,1:00:26.85,1:00:29.06,yin,,0,0,0,,不过这里可能会有问题\\N{\\fs12}Now, there could be a problem here.\r\nDialogue: 0,1:00:29.06,1:00:31.41,yin,,0,0,0,,如果用户还没有拍照呢\\N{\\fs12}What happens if the user hasn't taken a photo yet?\r\nDialogue: 0,1:00:31.41,1:00:34.40,yin,,0,0,0,,它们没有点拍照\\N{\\fs12}Okay, they haven't hit take photo.\r\nDialogue: 0,1:00:34.40,1:00:35.90,yin,,0,0,0,,我不能做这些\\N{\\fs12}Th- I can't do this.\r\nDialogue: 0,1:00:35.90,1:00:39.76,yin,,0,0,0,,空照片什么意义都没有\\N{\\fs12}Okay a photo of, blank photo makes no sense whatsoever.\r\nDialogue: 0,1:00:39.76,1:00:43.03,yin,,0,0,0,,这是一个常规的segue准备\\N{\\fs12}So this is a normal segue preparation.\r\nDialogue: 0,1:00:43.03,1:00:45.15,yin,,0,0,0,,我还可以这样做 BOOL\\N{\\fs12}So I can also do bool\r\nDialogue: 0,1:00:45.16,1:00:49.70,yin,,0,0,0,,shouldPerformSegueWithIdentifier\\N{\\fs12}should perform segue with the identifier.\r\nDialogue: 0,1:00:49.70,1:00:54.40,yin,,0,0,0,,用来检查点击时是否应该进行unwind\\N{\\fs12}So this is whether we should do the unwind at all when we click it.\r\nDialogue: 0,1:00:54.40,1:00:56.54,yin,,0,0,0,,我还是要做相同的事情\\N{\\fs12}So again I'm going to do the same,\r\nDialogue: 0,1:00:56.54,1:00:59.60,yin,,0,0,0,,如果segue的标识符等于那个UNWIND常数\\N{\\fs12}if segue identifier is that unwind guy.\r\nDialogue: 0,1:00:59.60,1:01:02.56,yin,,0,0,0,,然后我要检查一些东西\\N{\\fs12}And then I'm just going to check some things\r\nDialogue: 0,1:01:02.56,1:01:09.24,yin,,0,0,0,,如果没有self.image 那么我就会警告\\N{\\fs12}to make sure things are okay like if not self dot image, then I'm going to complain.\r\nDialogue: 0,1:01:09.24,1:01:12.97,yin,,0,0,0,,这里我们说 尚未拍照\\N{\\fs12}So let's say no photo taken.\r\nDialogue: 0,1:01:14.41,1:01:19.00,yin,,0,0,0,,我可以说 否则\\N{\\fs12}Okay or I might say or else\r\nDialogue: 0,1:01:19.00,1:01:27.27,yin,,0,0,0,,如果self.titleTextField.text length\\N{\\fs12}if self dot title text field dot text length\r\nDialogue: 0,1:01:27.27,1:01:31.26,yin,,0,0,0,,非 这里我强制要求标题存在\\N{\\fs12}not-- so if, I'll force a title here\r\nDialogue: 0,1:01:31.26,1:01:37.01,yin,,0,0,0,,这时我也要self alert说 必须有标题\\N{\\fs12}and I'll say self alert title required.\r\nDialogue: 0,1:01:37.01,1:01:38.74,yin,,0,0,0,,这里叹号好多\\N{\\fs12}Too many exclamation points there.\r\nDialogue: 0,1:01:38.74,1:01:40.42,yin,,0,0,0,,否则 返回YES\\N{\\fs12}Otherwise, we'll return yes.\r\nDialogue: 0,1:01:40.42,1:01:45.61,yin,,0,0,0,,这两种情况下我们都应返回NO 不应segue\\N{\\fs12}In both of these cases we want to return no that we should not segue.\r\nDialogue: 0,1:01:45.61,1:01:52.31,yin,,0,0,0,,在尝试这些segue之前 我们先来看这个\\N{\\fs12}Now before we go on and try all this segueing stuff, let's talk about this okay?\r\nDialogue: 0,1:01:52.31,1:01:56.41,yin,,0,0,0,,看到这个方法了吗 alert 我还没有定义\\N{\\fs12}See this little method alert which I haven't defined yet?\r\nDialogue: 0,1:01:56.41,1:01:57.75,yin,,0,0,0,,让我们来实现这个\\N{\\fs12}Let's go ahead and implement that.\r\nDialogue: 0,1:01:57.75,1:02:01.18,yin,,0,0,0,,这对于我们讨论警告视图是个不错的例子\\N{\\fs12}This is a good aside for us to talk about alert view here.\r\nDialogue: 0,1:02:01.18,1:02:07.41,yin,,0,0,0,,我们这样 (void)alert:(NSString *)msg\\N{\\fs12}So let's do void alert NS string, message.\r\nDialogue: 0,1:02:07.41,1:02:12.94,yin,,0,0,0,,我们这里会显示一个警告框 给出这个消息\\N{\\fs12}What we want to do here is put up an alert that says whatever that message is.\r\nDialogue: 0,1:02:12.94,1:02:14.24,yin,,0,0,0,,如何做到呢\\N{\\fs12}So how do we do that?\r\nDialogue: 0,1:02:14.24,1:02:20.17,yin,,0,0,0,,UIAlertVIew alloc init这一长串\\N{\\fs12}UI alert view, alloc init this long thing.\r\nDialogue: 0,1:02:20.18,1:02:21.47,yin,,0,0,0,,标题是什么\\N{\\fs12}What's the title?\r\nDialogue: 0,1:02:21.47,1:02:25.50,yin,,0,0,0,,我们正在添加照片 不妨设这个为警告框\\N{\\fs12}Well, we're adding a photo so we'll say the title of this alert.\r\nDialogue: 0,1:02:25.50,1:02:26.66,yin,,0,0,0,,顶部的标题\\N{\\fs12}That's the little title at the top.\r\nDialogue: 0,1:02:26.66,1:02:28.50,yin,,0,0,0,,不是消息 而是顶部标题\\N{\\fs12}Not the message but the title at the top.\r\nDialogue: 0,1:02:28.50,1:02:29.07,yin,,0,0,0,,添加照片\\N{\\fs12}Say add photo.\r\nDialogue: 0,1:02:29.07,1:02:32.14,yin,,0,0,0,,消息则是我们想在这里显示的消息\\N{\\fs12}The message is the message that we want to give right here.\r\nDialogue: 0,1:02:32.14,1:02:35.51,yin,,0,0,0,,委托 这个我设为不要委托\\N{\\fs12}Delegate, I'm going to make this one have no delegate.\r\nDialogue: 0,1:02:35.51,1:02:37.26,yin,,0,0,0,,等下再来看委托\\N{\\fs12}Show it with a delegate in a minute.\r\nDialogue: 0,1:02:37.26,1:02:38.28,yin,,0,0,0,,取消按钮\\N{\\fs12}Cancel button.\r\nDialogue: 0,1:02:38.28,1:02:40.05,yin,,0,0,0,,没有取消\\N{\\fs12}There's no cancel.\r\nDialogue: 0,1:02:40.05,1:02:43.57,yin,,0,0,0,,唯一的按钮是OK\\N{\\fs12}And the only button is okay.\r\nDialogue: 0,1:02:43.57,1:02:50.53,yin,,0,0,0,,我创建了这个警告视图 下面我要显示它\\N{\\fs12}So I've created this alert view, now I'm going to show it.\r\nDialogue: 0,1:02:50.53,1:02:52.42,yin,,0,0,0,,都理解了吗\\N{\\fs12}Everyone understand that?\r\nDialogue: 0,1:02:52.42,1:02:54.44,yin,,0,0,0,,这里不过是显示\\N{\\fs12}So that's just showing.\r\nDialogue: 0,1:02:54.44,1:02:57.96,yin,,0,0,0,,我们来看看这个\\N{\\fs12}So let's go ahead and take a look at this.\r\nDialogue: 0,1:02:57.96,1:02:59.49,yin,,0,0,0,,看看这里怎么了\\N{\\fs12}What have we got here?\r\nDialogue: 0,1:02:59.49,1:03:04.46,yin,,0,0,0,,抱歉 这里只是一个标识符\\N{\\fs12}Oh sorry, this is just the identifier.\r\nDialogue: 0,1:03:07.59,1:03:09.03,yin,,0,0,0,,看看还有什么\\N{\\fs12}Yeah what else have we got here?\r\nDialogue: 0,1:03:09.03,1:03:16.54,yin,,0,0,0,,这里是否则 返回super should…\\N{\\fs12}Okay this else return super should okay?\r\nDialogue: 0,1:03:16.54,1:03:19.88,yin,,0,0,0,,这里是说 如果这不是我们的标识符\\N{\\fs12}That's if we don't, if it's not our identifier,\r\nDialogue: 0,1:03:19.88,1:03:23.28,yin,,0,0,0,,而是别的 那么我们就用super\\N{\\fs12}it's some other one, then we'll do super.\r\nDialogue: 0,1:03:23.28,1:03:24.57,yin,,0,0,0,,让我们这样做\\N{\\fs12}So let's do that.\r\nDialogue: 0,1:03:24.59,1:03:26.53,yin,,0,0,0,,进入照片\\N{\\fs12}All right so we'll go to photos.\r\nDialogue: 0,1:03:26.53,1:03:27.48,yin,,0,0,0,,到这里\\N{\\fs12}We go here.\r\nDialogue: 0,1:03:27.48,1:03:29.50,yin,,0,0,0,,下面尝试unwind\\N{\\fs12}Now let's try to unwind.\r\nDialogue: 0,1:03:29.50,1:03:30.89,yin,,0,0,0,,尚未拍照\\N{\\fs12}No photo taken.\r\nDialogue: 0,1:03:30.89,1:03:33.46,yin,,0,0,0,,shouldPerform方法给出了警告\\N{\\fs12}So did our should perform put up an alert?\r\nDialogue: 0,1:03:33.46,1:03:35.09,yin,,0,0,0,,尚未拍照\\N{\\fs12}No photo taken.\r\nDialogue: 0,1:03:35.09,1:03:37.46,yin,,0,0,0,,看到了吗 这很好\\N{\\fs12}See that? So that's good.\r\nDialogue: 0,1:03:37.46,1:03:40.83,yin,,0,0,0,,我们尝试unwind 这样unwind就快搞定了\\N{\\fs12}So we're trying to unwind so we're getting closer to unwinding.\r\nDialogue: 0,1:03:40.83,1:03:45.63,yin,,0,0,0,,我们还需要得到照片 并确保设置了标题\\N{\\fs12}We still have to get an image and we have to make sure we set our title.\r\nDialogue: 0,1:03:45.63,1:03:46.87,yin,,0,0,0,,我们很近了\\N{\\fs12}So we're getting closer.\r\nDialogue: 0,1:03:46.87,1:03:48.71,yin,,0,0,0,,这里我还想讲点题外话\\N{\\fs12}I'm going to take another little aside\r\nDialogue: 0,1:03:48.71,1:03:51.47,yin,,0,0,0,,也就是使用委托来进行警告\\N{\\fs12}to show you doing an alert with a delegate.\r\nDialogue: 0,1:03:51.47,1:03:53.65,yin,,0,0,0,,如果应用程序中\\N{\\fs12}What if I had something in my application\r\nDialogue: 0,1:03:53.65,1:03:59.14,yin,,0,0,0,,我得到了一个致命错误 致命警告 这会怎样\\N{\\fs12}which was a fatal error, fatal alert.\r\nDialogue: 0,1:03:59.14,1:04:02.98,yin,,0,0,0,,这个警告很糟糕 我需要立刻取消\\N{\\fs12}So this is some alert that's so bad I got to cancel right away.\r\nDialogue: 0,1:04:02.98,1:04:04.79,yin,,0,0,0,,直接取消\\N{\\fs12}Just do cancel.\r\nDialogue: 0,1:04:04.79,1:04:05.71,yin,,0,0,0,,如何实现这个\\N{\\fs12}How would I implement that?\r\nDialogue: 0,1:04:05.71,1:04:10.04,yin,,0,0,0,,我可以使用和这里相同的警告\\N{\\fs12}Well, I would do the same alert that I'm doing here.\r\nDialogue: 0,1:04:10.04,1:04:12.32,yin,,0,0,0,,但委托不为nil\\N{\\fs12}But instead of having the delegate be nil,\r\nDialogue: 0,1:04:12.32,1:04:16.87,yin,,0,0,0,,而为self 这样我就能在用户点OK时\\N{\\fs12}I'm going to have the delegate be self so that I can find out when the user clicks okay.\r\nDialogue: 0,1:04:16.87,1:04:19.43,yin,,0,0,0,,直接取消掉\\N{\\fs12}And when they click okay, I'm going to cancel.\r\nDialogue: 0,1:04:19.43,1:04:21.71,yin,,0,0,0,,我要消掉自己\\N{\\fs12}I'm going to dismiss myself.\r\nDialogue: 0,1:04:21.71,1:04:26.00,yin,,0,0,0,,要做这个 我需要是一个UIAlertViewDelegate\\N{\\fs12}So to do this, I need to be a UI alert view delegate.\r\nDialogue: 0,1:04:28.57,1:04:31.61,yin,,0,0,0,,然后 我要实现alertView\\N{\\fs12}And then I'm going to implement the alert view.\r\nDialogue: 0,1:04:31.61,1:04:34.90,yin,,0,0,0,,这里有不少 我要用的是\\N{\\fs12}I'm going to do the one dis- you can see there's a few here--\r\nDialogue: 0,1:04:34.90,1:04:37.68,yin,,0,0,0,,didDismissWithButtonIndex\\N{\\fs12}did dismiss with button index. That's the one I'm going to do.\r\nDialogue: 0,1:04:37.68,1:04:41.84,yin,,0,0,0,,这里我只有一个按钮 因此无需考察按钮索引\\N{\\fs12}And I only have this one button so I didn't even need to look at the button index.\r\nDialogue: 0,1:04:41.84,1:04:45.52,yin,,0,0,0,,我知道这里我需要取消\\N{\\fs12}I know that in this case I want to cancel.\r\nDialogue: 0,1:04:45.52,1:04:48.10,yin,,0,0,0,,我没有将自己设置为这个的委托\\N{\\fs12}Now I didn't set myself as the delegate for this one,\r\nDialogue: 0,1:04:48.10,1:04:50.00,yin,,0,0,0,,因此对于常规警告我不打算取消\\N{\\fs12}so I'm not going to cancel for a normal alert.\r\nDialogue: 0,1:04:50.00,1:04:53.71,yin,,0,0,0,,只在致命警告时 我才会取消\\N{\\fs12}Only for a fatal alert am I going to cancel.\r\nDialogue: 0,1:04:53.71,1:04:55.53,yin,,0,0,0,,什么叫致命呢\\N{\\fs12}Now what would be fatal?\r\nDialogue: 0,1:04:55.53,1:04:57.91,yin,,0,0,0,,这里什么情况才会致命呢\\N{\\fs12}What kind of things would be fatal in this?\r\nDialogue: 0,1:04:57.91,1:05:00.91,yin,,0,0,0,,如果我的设备没有摄像头\\N{\\fs12}Well, what if my device has no camera?\r\nDialogue: 0,1:05:00.91,1:05:02.06,yin,,0,0,0,,这就是致命了\\N{\\fs12}Okay that's fatal.\r\nDialogue: 0,1:05:02.06,1:05:05.13,yin,,0,0,0,,没有摄像头 这些东西都只是浪费时间\\N{\\fs12}It's just a waste of time to have this thing up if my device has no camera.\r\nDialogue: 0,1:05:05.13,1:05:09.09,yin,,0,0,0,,另外 Photomania的本质是照片位置\\N{\\fs12}Or, since this PhotoMania is fundamentally locations\r\nDialogue: 0,1:05:09.09,1:05:12.67,yin,,0,0,0,,如果我无法获知位置 那也会没有意义\\N{\\fs12}of photos, what if I can't get the location?\r\nDialogue: 0,1:05:12.67,1:05:15.66,yin,,0,0,0,,或许用户不允许我获得位置信息\\N{\\fs12}Okay the user maybe doesn't allow me to get the location.\r\nDialogue: 0,1:05:15.66,1:05:20.25,yin,,0,0,0,,因此 我们这里再加个方法 canAddPhoto\\N{\\fs12}So let's go ahead and put a method up here called can add photo.\r\nDialogue: 0,1:05:20.25,1:05:23.19,yin,,0,0,0,,这里需要导入一些东西\\N{\\fs12}We've got to import some stuff here.\r\nDialogue: 0,1:05:23.19,1:05:26.55,yin,,0,0,0,,canAddPhoto会检查是否能添加照片\\N{\\fs12}So this can add photo method is going to check some\r\nDialogue: 0,1:05:26.55,1:05:31.08,yin,,0,0,0,,这些致命错误包括 我有没有摄像头\\N{\\fs12}of these fatal errors like do I have a camera available?\r\nDialogue: 0,1:05:31.08,1:05:34.53,yin,,0,0,0,,我问UIImagePickerController 有没摄像头可用\\N{\\fs12}I'm asking the UI image picker controller, is there a camera available?\r\nDialogue: 0,1:05:34.53,1:05:36.58,yin,,0,0,0,,我还要确保我能得到一张图像\\N{\\fs12}I'm also making sure I can get an image\r\nDialogue: 0,1:05:36.58,1:05:38.58,yin,,0,0,0,,一般你可能不会检查这个\\N{\\fs12}which really you usually don't have to check this.\r\nDialogue: 0,1:05:38.58,1:05:41.22,yin,,0,0,0,,多数时候 你只需检查能否录视频\\N{\\fs12}Mostly you're checking this to see if it'll do video.\r\nDialogue: 0,1:05:41.22,1:05:43.36,yin,,0,0,0,,所有摄像头都能拍摄图像\\N{\\fs12}All cameras can do image,\r\nDialogue: 0,1:05:43.36,1:05:45.46,yin,,0,0,0,,这里我就演示一下这些检查\\N{\\fs12}but just to show you what it looks like to check it.\r\nDialogue: 0,1:05:45.46,1:05:48.25,yin,,0,0,0,,然后我还要检查位置管理器\\N{\\fs12}And then I'm also going to check my location manager\r\nDialogue: 0,1:05:48.25,1:05:51.20,yin,,0,0,0,,确保我的授权状态不是受限\\N{\\fs12}to make sure my authorization status is not restricted.\r\nDialogue: 0,1:05:51.20,1:05:56.06,yin,,0,0,0,,也就是说 我的授权状态要么是允许 要么是拒绝\\N{\\fs12}So that means my authorization status is either you're authorized, or denied.\r\nDialogue: 0,1:05:56.06,1:05:58.44,yin,,0,0,0,,为什么这里我只检查受限呢\\N{\\fs12}Now why am I only checking restricted here?\r\nDialogue: 0,1:05:58.44,1:06:00.77,yin,,0,0,0,,因为这是致命错误\\N{\\fs12}Because this is going to be a fatal error.\r\nDialogue: 0,1:06:00.77,1:06:02.47,yin,,0,0,0,,成为致命错误的情况\\N{\\fs12}It's only going to be fatal\r\nDialogue: 0,1:06:02.47,1:06:07.97,yin,,0,0,0,,只包括用户无法控制app能否找到其位置的情况\\N{\\fs12}if the user can't control whether my app can find its location.\r\nDialogue: 0,1:06:07.97,1:06:12.08,yin,,0,0,0,,用户无法设置这些 这就是致命错误\\N{\\fs12}All right, they can't go to settings and set it, so it's fatal.\r\nDialogue: 0,1:06:12.08,1:06:15.09,yin,,0,0,0,,后面我还会检查 用户是否只是拒绝\\N{\\fs12}Later I'll check to see if they've just denied it\r\nDialogue: 0,1:06:15.09,1:06:17.45,yin,,0,0,0,,我会建议用户回到设置\\N{\\fs12}and I'm going to suggest to them they go back to settings\r\nDialogue: 0,1:06:17.45,1:06:19.63,yin,,0,0,0,,取消拒绝 这样它就可以工作了\\N{\\fs12}and undeny it and then it'll work.\r\nDialogue: 0,1:06:19.63,1:06:21.84,yin,,0,0,0,,这并不是致命错误\\N{\\fs12}So it's not a fatal error in that case.\r\nDialogue: 0,1:06:21.84,1:06:24.82,yin,,0,0,0,,这就是这里只考虑受限这一状态的原因\\N{\\fs12}So that's the difference why we're doing restricted here, okay?\r\nDialogue: 0,1:06:24.82,1:06:27.64,yin,,0,0,0,,如果所有这些都没问题 那就很好了\\N{\\fs12}So if any, if all this is true, then we're good to go.\r\nDialogue: 0,1:06:27.64,1:06:28.93,yin,,0,0,0,,我们可以拍照\\N{\\fs12}We can take a photo.\r\nDialogue: 0,1:06:28.93,1:06:30.89,yin,,0,0,0,,否则我们就无法拍照\\N{\\fs12}Otherwise, we can't take a photo.\r\nDialogue: 0,1:06:30.89,1:06:34.65,yin,,0,0,0,,下面 在我们的viewDidAppear中\\N{\\fs12}So now let's, in our view will appear or view did appear--\r\nDialogue: 0,1:06:37.49,1:06:39.85,yin,,0,0,0,,super viewDidAppear\\N{\\fs12}super, view did appear--\r\nDialogue: 0,1:06:39.85,1:06:47.63,yin,,0,0,0,,我要说 if ([[self class] canAddPhoto])\\N{\\fs12}I'm going to say if self class can add photo--\r\nDialogue: 0,1:06:47.63,1:06:51.97,yin,,0,0,0,,这里应该是非 如果我不能添加照片\\N{\\fs12}actually I'm going to say if not-- if I can't add a photo,\r\nDialogue: 0,1:06:51.97,1:06:56.75,yin,,0,0,0,,那么 我就要self fatalAlert说\\N{\\fs12}then I'm going to self fatal alert\r\nDialogue: 0,1:06:56.75,1:07:01.70,yin,,0,0,0,,抱歉 本设备无法添加照片\\N{\\fs12}sorry this device cannot add a photo.\r\nDialogue: 0,1:07:01.70,1:07:04.98,yin,,0,0,0,,注意 我在致命错误中并没有说\\N{\\fs12}Notice I'm not saying anything in this fatal error like\r\nDialogue: 0,1:07:05.00,1:07:11.40,yin,,0,0,0,,你无权获得你的位置信息\\N{\\fs12}you are not authorized to do, get your location\r\nDialogue: 0,1:07:11.40,1:07:13.85,yin,,0,0,0,,因为用户对此无能为力\\N{\\fs12}because there's nothing they can do about it.\r\nDialogue: 0,1:07:13.85,1:07:16.49,yin,,0,0,0,,如果没有摄像头\\N{\\fs12}If they have no camera or they can't do it, they can't go\r\nDialogue: 0,1:07:16.49,1:07:19.90,yin,,0,0,0,,用户不能去找一个摄像头\\N{\\fs12}out of camera or, you know, do something\r\nDialogue: 0,1:07:19.90,1:07:21.86,yin,,0,0,0,,权限受限用户也没辙\\N{\\fs12}about their being restricted from doing the location.\r\nDialogue: 0,1:07:21.86,1:07:24.14,yin,,0,0,0,,所以这里我也不需要建议用户做任何事\\N{\\fs12}They can't do anything so I'm not going to suggest they do anything.\r\nDialogue: 0,1:07:24.14,1:07:26.94,yin,,0,0,0,,我只打算说 抱歉 你做不了这个\\N{\\fs12}I'm just going to say sorry, you can't do it.\r\nDialogue: 0,1:07:26.94,1:07:30.96,yin,,0,0,0,,当然 我也可以说 抱歉 本设备不能拍照\\N{\\fs12}I could imagine maybe saying here, sorry this device cannot have a photo\r\nDialogue: 0,1:07:30.96,1:07:33.80,yin,,0,0,0,,因为你没有摄像头\\N{\\fs12}because you have no camera.\r\nDialogue: 0,1:07:33.80,1:07:37.32,yin,,0,0,0,,但我肯定不打算说 因为你无法获得位置信息\\N{\\fs12}I definitely wouldn't want to say because you cannot get your location.\r\nDialogue: 0,1:07:37.32,1:07:38.79,yin,,0,0,0,,或者 如果我想说这个\\N{\\fs12}Or if I do say that, I want\r\nDialogue: 0,1:07:38.79,1:07:42.73,yin,,0,0,0,,我可以说 同系统管理员联系 尝试获得权限\\N{\\fs12}to say contact your system administrator or something like that to get yourself there.\r\nDialogue: 0,1:07:42.73,1:07:44.41,yin,,0,0,0,,你知道的 不过我只说\\N{\\fs12}It's, you know, but here I'm just going\r\nDialogue: 0,1:07:44.41,1:07:46.09,yin,,0,0,0,,抱歉 你无法拍照\\N{\\fs12}to say sorry you can't take a photo, and it's going\r\nDialogue: 0,1:07:46.09,1:07:48.87,yin,,0,0,0,,这是致命的 因此我会立刻取消\\N{\\fs12}to be fatal so I'm going to immediately drop out of there.\r\nDialogue: 0,1:07:48.87,1:07:51.03,yin,,0,0,0,,我们来看看这个\\N{\\fs12}So let's take a look at that.\r\nDialogue: 0,1:07:51.03,1:07:54.01,yin,,0,0,0,,进入照片 然后到这里\\N{\\fs12}All right there's photos, and I'm going to bring this up.\r\nDialogue: 0,1:07:54.01,1:07:57.08,yin,,0,0,0,,果然 这里显示出\"本设备无法拍照\"\\N{\\fs12}And sure enough sorry, this device cannot add a photo.\r\nDialogue: 0,1:07:57.08,1:07:59.22,yin,,0,0,0,,为什么 因为这是模拟器\\N{\\fs12}Why? Because it's the simulator.\r\nDialogue: 0,1:07:59.22,1:08:01.32,yin,,0,0,0,,模拟器无法添加照片\\N{\\fs12}The simulator cannot add a photo.\r\nDialogue: 0,1:08:01.32,1:08:03.99,yin,,0,0,0,,这很好地告诉了我 我无法拍照\\N{\\fs12}So it's properly telling me I can't add a photo\r\nDialogue: 0,1:08:03.99,1:08:08.14,yin,,0,0,0,,如果我点OK 它就会取消\\N{\\fs12}and if I click okay, cancel.\r\nDialogue: 0,1:08:08.14,1:08:10.33,yin,,0,0,0,,这是致命错误\\N{\\fs12}Okay so fatal error.\r\nDialogue: 0,1:08:10.33,1:08:13.34,yin,,0,0,0,,下面 我们将继续后面的内容\\N{\\fs12}Okay so now we're going to continue, we're going to switch\r\nDialogue: 0,1:08:13.34,1:08:16.89,yin,,0,0,0,,转到一个可以拍照的设备上\\N{\\fs12}over and do it on a device where we actually can do this stuff.\r\nDialogue: 0,1:08:16.89,1:08:21.33,yin,,0,0,0,,要做到这个 下面我们需要用到位置管理器\\N{\\fs12}But to do that, the next thing we want to do is location manager.\r\nDialogue: 0,1:08:21.33,1:08:24.75,yin,,0,0,0,,我从没演示过如何使用位置这些\\N{\\fs12}So I never showed you how to do the location stuff\r\nDialogue: 0,1:08:24.75,1:08:26.94,yin,,0,0,0,,这里是一个很好的例子\\N{\\fs12}and so this is a good example of how to show that.\r\nDialogue: 0,1:08:26.94,1:08:30.08,yin,,0,0,0,,我想把这个self.location设为某个东西\\N{\\fs12}So I want to set this self dot location to something.\r\nDialogue: 0,1:08:30.08,1:08:32.00,yin,,0,0,0,,因为现在 它是nil\\N{\\fs12}Because right now it's going to be nil, right?\r\nDialogue: 0,1:08:32.00,1:08:35.13,yin,,0,0,0,,因为我刚创建了这个属性 从未设置它\\N{\\fs12}Because I just created that property and I never set it,\r\nDialogue: 0,1:08:35.13,1:08:36.30,yin,,0,0,0,,而这里我在看它\\N{\\fs12}and then here I'm looking at it.\r\nDialogue: 0,1:08:36.30,1:08:38.05,yin,,0,0,0,,我们的经纬度都是0\\N{\\fs12}So our latitude and longitude would be zero so we're going\r\nDialogue: 0,1:08:38.05,1:08:41.93,yin,,0,0,0,,我们可能位于非洲西面的海洋中\\N{\\fs12}to be somewhere out in the ocean somewhere west of Africa or something.\r\nDialogue: 0,1:08:41.93,1:08:44.15,yin,,0,0,0,,或许还有海盗在追我们\\N{\\fs12}Probably have pirates after us over there.\r\nDialogue: 0,1:08:44.15,1:08:45.46,yin,,0,0,0,,我们不想这样\\N{\\fs12}So we don't want to do that.\r\nDialogue: 0,1:08:45.48,1:08:47.16,yin,,0,0,0,,我们要设置self.location\\N{\\fs12}We want to set this self.location.\r\nDialogue: 0,1:08:47.16,1:08:47.93,yin,,0,0,0,,怎么做呢\\N{\\fs12}So how are we going to do that?\r\nDialogue: 0,1:08:47.93,1:08:52.12,yin,,0,0,0,,要做到这个 我需要一个位置管理器\\N{\\fs12}Well, to do that I need a location manager.\r\nDialogue: 0,1:08:52.12,1:08:53.81,yin,,0,0,0,,找个地方放这些东西\\N{\\fs12}So let's find a good place to put all this.\r\nDialogue: 0,1:08:53.81,1:08:56.35,yin,,0,0,0,,放到下面这里\\N{\\fs12}Let's put it down here.\r\nDialogue: 0,1:08:56.35,1:08:58.84,yin,,0,0,0,,我需要一个位置管理器\\N{\\fs12}So I need a location manager and I,\r\nDialogue: 0,1:08:58.84,1:09:02.23,yin,,0,0,0,,为了提高速度 我准备了这些\\N{\\fs12}for speed here I have this to show you how to do that.\r\nDialogue: 0,1:09:02.25,1:09:06.46,yin,,0,0,0,,我只需要添加这个属性\\N{\\fs12}So I'm just going to add this property right?\r\nDialogue: 0,1:09:06.46,1:09:09.01,yin,,0,0,0,,CLLocationManager *locationManager\\N{\\fs12}CL location manager, location manager,\r\nDialogue: 0,1:09:09.01,1:09:10.91,yin,,0,0,0,,记得吧 我们会要求\\N{\\fs12}remember this is the thing we ask\r\nDialogue: 0,1:09:10.91,1:09:13.80,yin,,0,0,0,,这个东西开始给我们位置的更新\\N{\\fs12}to start giving us updates on the location.\r\nDialogue: 0,1:09:13.80,1:09:16.93,yin,,0,0,0,,然后我要惰性实例化它\\N{\\fs12}And then I'm going to lazily instantiate it.\r\nDialogue: 0,1:09:16.93,1:09:19.01,yin,,0,0,0,,这里 惰性实例化\\N{\\fs12}Here it is here, lazy instantiation.\r\nDialogue: 0,1:09:19.01,1:09:21.83,yin,,0,0,0,,如果没有创建 我将alloc init\\N{\\fs12}If we haven't created one, then I'm going to alloc init it.\r\nDialogue: 0,1:09:21.83,1:09:24.62,yin,,0,0,0,,我将把self设为委托\\N{\\fs12}I'm going to set myself as the delegate.\r\nDialogue: 0,1:09:24.62,1:09:27.54,yin,,0,0,0,,这里有警告 因为我还没有说我是哪类委托\\N{\\fs12}Obviously warning because I haven't said that I'm that kind of delegate yet.\r\nDialogue: 0,1:09:27.56,1:09:30.22,yin,,0,0,0,,然后我要把精度设为最佳\\N{\\fs12}And then I'm going to set my accuracy to best.\r\nDialogue: 0,1:09:30.22,1:09:31.61,yin,,0,0,0,,为什么设为最佳呢\\N{\\fs12}Why am I doing best?\r\nDialogue: 0,1:09:31.61,1:09:33.86,yin,,0,0,0,,因为我想准确知道这张照片拍自哪里\\N{\\fs12}Because I want to know exactly where this photo was taken?\r\nDialogue: 0,1:09:33.86,1:09:37.25,yin,,0,0,0,,我只是模态的 我只会在屏幕上待几秒钟\\N{\\fs12}And I'm modal anyway so I'm only going to be on screen for a few moments.\r\nDialogue: 0,1:09:37.25,1:09:40.24,yin,,0,0,0,,只是找到我在哪 并不会用掉很多电量\\N{\\fs12}I'm not going to use up the whole battery just finding out where I am.\r\nDialogue: 0,1:09:40.24,1:09:42.69,yin,,0,0,0,,然后这里 我们设置位置管理器\\N{\\fs12}And then here we set the location manager.\r\nDialogue: 0,1:09:42.69,1:09:45.52,yin,,0,0,0,,然后这是我要使用的委托方法\\N{\\fs12}And then here's the delegate method I'm going to use.\r\nDialogue: 0,1:09:45.52,1:09:48.30,yin,,0,0,0,,我是委托 我将获取委托方法\\N{\\fs12}I'm the delegate, so I'm going to get the delegate method.\r\nDialogue: 0,1:09:48.30,1:09:51.11,yin,,0,0,0,,它叫locationManager didUpdateLocations\\N{\\fs12}It's called location manager did update locations.\r\nDialogue: 0,1:09:51.11,1:09:53.71,yin,,0,0,0,,它会给我一个数组 其中是它找到的所有位置\\N{\\fs12}It gives me an array of all the locations it's found\r\nDialogue: 0,1:09:53.71,1:09:56.50,yin,,0,0,0,,自该方法上次调用这条消息以来\\N{\\fs12}since the last time it called this message, this method.\r\nDialogue: 0,1:09:56.50,1:09:58.45,yin,,0,0,0,,我将抓取最后一个\\N{\\fs12}And I'm just going to grab the last one.\r\nDialogue: 0,1:09:58.45,1:10:03.31,yin,,0,0,0,,最后一个总会是最新的一个 最准确的一个\\N{\\fs12}The last one is always the most current one, the most up to date, the most accurate.\r\nDialogue: 0,1:10:03.31,1:10:06.24,yin,,0,0,0,,这里我们要的总会是它\\N{\\fs12}That's the one you always want there.\r\nDialogue: 0,1:10:06.24,1:10:07.92,yin,,0,0,0,,想找当前位置就该这么做\\N{\\fs12}If you're just trying to get your current location.\r\nDialogue: 0,1:10:07.92,1:10:10.55,yin,,0,0,0,,我将把这个放到self.location\\N{\\fs12}And I'm just going to put that in self dot location so that\r\nDialogue: 0,1:10:10.55,1:10:15.08,yin,,0,0,0,,这样一来 到这里就会是正确的位置\\N{\\fs12}when I pop it in here it'll be the right location.\r\nDialogue: 0,1:10:15.08,1:10:17.50,yin,,0,0,0,,这还没完\\N{\\fs12}Now, we're not done here\r\nDialogue: 0,1:10:17.50,1:10:21.95,yin,,0,0,0,,因为这个位置管理器 我们需要开启它\\N{\\fs12}because this location manager, we have to start it up.\r\nDialogue: 0,1:10:21.95,1:10:24.05,yin,,0,0,0,,记得吧 创建一个位置管理器…\\N{\\fs12}Okay remember, just because you create a location manager--\r\nDialogue: 0,1:10:24.05,1:10:26.96,yin,,0,0,0,,让我先来处理这个委托\\N{\\fs12}let me go ahead and do this delegate thing first,\r\nDialogue: 0,1:10:26.96,1:10:33.09,yin,,0,0,0,,让我自己成为CLLocationManagerDelegate\\N{\\fs12}make myself be a CL location manager delegate.\r\nDialogue: 0,1:10:33.09,1:10:34.36,yin,,0,0,0,,我需要开启它\\N{\\fs12}I need to start it up.\r\nDialogue: 0,1:10:34.36,1:10:35.34,yin,,0,0,0,,在哪做呢\\N{\\fs12}And where am I going to start it up?\r\nDialogue: 0,1:10:35.34,1:10:37.51,yin,,0,0,0,,在viewDidAppear中\\N{\\fs12}I'm going to start it up in view did appear.\r\nDialogue: 0,1:10:37.51,1:10:42.03,yin,,0,0,0,,我要说 否则 因为这里是不能添加照片的情况\\N{\\fs12}So I'm going to say else-- okay this is I can't add a photo.\r\nDialogue: 0,1:10:42.03,1:10:45.69,yin,,0,0,0,,否则 我要说 self.locationManager\\N{\\fs12}So else, I'm going to say self dot location manager--\r\nDialogue: 0,1:10:45.69,1:10:49.93,yin,,0,0,0,,这会惰性实例化它 开始更新位置\\N{\\fs12}that's going to lazily instantiate it starts updating location.\r\nDialogue: 0,1:10:49.93,1:10:55.26,yin,,0,0,0,,这就会开始向我发送位置的委托方法\\N{\\fs12}And that's going to start sending me those delegate methods of my location, all right?\r\nDialogue: 0,1:10:55.26,1:10:58.43,yin,,0,0,0,,也许马上 它就会发送一个很不准确的给我\\N{\\fs12}It's probably going to send me one right away that's pretty inaccurate,\r\nDialogue: 0,1:10:58.43,1:11:00.23,yin,,0,0,0,,例如基于wifi的 或是别的什么\\N{\\fs12}like WiFi based or something,\r\nDialogue: 0,1:11:00.23,1:11:02.40,yin,,0,0,0,,然后它可能会发送另一个使用GPS的消息\\N{\\fs12}then it'll probably send me another one with GPS\r\nDialogue: 0,1:11:02.40,1:11:04.94,yin,,0,0,0,,如果我在外面 可以和卫星通讯的话\\N{\\fs12}if I'm outside or I can, you know, see the satellites.\r\nDialogue: 0,1:11:04.94,1:11:06.54,yin,,0,0,0,,这可能会多于一个 这没问题\\N{\\fs12}So it might send me more than one. That's okay.\r\nDialogue: 0,1:11:06.54,1:11:10.19,yin,,0,0,0,,随时间推移 我希望它持续发送越来越准确的信息\\N{\\fs12}I want it to keep sending me more and more accurate ones as time goes on.\r\nDialogue: 0,1:11:10.19,1:11:15.20,yin,,0,0,0,,这样做时 你几乎总要在viewWillDisappear中\\N{\\fs12}If you do this, you almost always, in view will disappear,\r\nDialogue: 0,1:11:15.20,1:11:17.52,yin,,0,0,0,,将这个关闭掉\\N{\\fs12}want to turn this back off.\r\nDialogue: 0,1:11:17.52,1:11:20.67,yin,,0,0,0,,这里问题其实并不大\\N{\\fs12}Now it's not that huge a deal here\r\nDialogue: 0,1:11:20.67,1:11:25.64,yin,,0,0,0,,因为这个是模态方式present的\\N{\\fs12}because this thing is presented modally.\r\nDialogue: 0,1:11:25.64,1:11:28.91,yin,,0,0,0,,这里是停止更新位置\\N{\\fs12}Oops, stop updating location.\r\nDialogue: 0,1:11:28.91,1:11:32.99,yin,,0,0,0,,这是模态方式present的 因此当这个unwind时\\N{\\fs12}This is presented modally and so when this thing unwinds,\r\nDialogue: 0,1:11:32.99,1:11:34.86,yin,,0,0,0,,它会从堆中被释放\\N{\\fs12}it's going to get released from the heap.\r\nDialogue: 0,1:11:34.86,1:11:36.33,yin,,0,0,0,,从堆中被释放时\\N{\\fs12}And when it gets released from the heap,\r\nDialogue: 0,1:11:36.33,1:11:39.66,yin,,0,0,0,,这个位置管理器也会被释放 并停止更新\\N{\\fs12}this location manager's going to get released and it's going to stop updating.\r\nDialogue: 0,1:11:39.66,1:11:41.41,yin,,0,0,0,,因此这里问题不大\\N{\\fs12}So it's really not that big a deal,\r\nDialogue: 0,1:11:41.41,1:11:43.63,yin,,0,0,0,,不过有些情况下\\N{\\fs12}but if for some reason we ever figured out how\r\nDialogue: 0,1:11:43.63,1:11:46.83,yin,,0,0,0,,这个会以非模态方式呈现出来\\N{\\fs12}to make this thing not be modal, put it up in a non modal way,\r\nDialogue: 0,1:11:46.83,1:11:48.30,yin,,0,0,0,,我们希望养成好习惯\\N{\\fs12}we just want to be in the good habit\r\nDialogue: 0,1:11:48.30,1:11:51.71,yin,,0,0,0,,每次开启这个时 都要再找地方将它关闭\\N{\\fs12}of every time we turn this thing on, turn it off somewhere.\r\nDialogue: 0,1:11:51.71,1:11:55.06,yin,,0,0,0,,哪怕它会自动被从堆中丢出来\\N{\\fs12}Even if it's, you know, turns it off right before it gets thrown out of the heap.\r\nDialogue: 0,1:11:55.06,1:11:57.23,yin,,0,0,0,,总记得关掉它\\N{\\fs12}Still, turn it off.\r\nDialogue: 0,1:11:57.23,1:11:59.66,yin,,0,0,0,,使用位置更新代价很大\\N{\\fs12}Using location updates is expensive.\r\nDialogue: 0,1:11:59.66,1:12:01.71,yin,,0,0,0,,这个还在时我们可以运行它\\N{\\fs12}Fine to run while this thing is up,\r\nDialogue: 0,1:12:01.71,1:12:06.17,yin,,0,0,0,,但最后 我们需要确保将它关闭了\\N{\\fs12}but we want to make sure we turn it off.\r\nDialogue: 0,1:12:06.17,1:12:13.96,yin,,0,0,0,,好 下面再来看还有什么要做\\N{\\fs12}Okay let's go ahead and, let's see what else can we do here?\r\nDialogue: 0,1:12:13.96,1:12:20.99,yin,,0,0,0,,好 让我们把这两个方法丢入到图像URL和缩略图URL\\N{\\fs12}Yeah, let's go ahead and throw these two methods into image URL and thumbnail URL.\r\nDialogue: 0,1:12:20.99,1:12:24.26,yin,,0,0,0,,这里对于图像URL和缩略图URL\\N{\\fs12}So all I need to do here with the image URL and thumbnail URL\r\nDialogue: 0,1:12:24.27,1:12:28.60,yin,,0,0,0,,我只需要把图像视图中的图像放到磁盘上\\N{\\fs12}is I'm just going to take the image that's in my image view, put it on disk,\r\nDialogue: 0,1:12:28.60,1:12:30.38,yin,,0,0,0,,然后返回URL\\N{\\fs12}and return the URL.\r\nDialogue: 0,1:12:30.38,1:12:31.94,yin,,0,0,0,,放到磁盘上的哪里呢\\N{\\fs12}Where am I going to put it on disk?\r\nDialogue: 0,1:12:31.94,1:12:35.07,yin,,0,0,0,,放到一个随机命名的文件中\\N{\\fs12}I'm just going to put it in a randomly named file.\r\nDialogue: 0,1:12:35.07,1:12:37.30,yin,,0,0,0,,随机取个名字\\N{\\fs12}I'm just going to pick a name, I'm going to pick,\r\nDialogue: 0,1:12:37.30,1:12:40.48,yin,,0,0,0,,名字将是某个参考日期之后的秒数\\N{\\fs12}the name is going to be the number of seconds since some reference date in\r\nDialogue: 0,1:12:40.48,1:12:42.48,yin,,0,0,0,,参考日期可以是2001这些\\N{\\fs12}2001 or something like that.\r\nDialogue: 0,1:12:42.48,1:12:43.79,yin,,0,0,0,,这是唯一的\\N{\\fs12}That's pretty unique.\r\nDialogue: 0,1:12:43.79,1:12:47.48,yin,,0,0,0,,除非两个设备完全同时使用\\N{\\fs12}It's not likely, I mean unless somehow you did two different\r\nDialogue: 0,1:12:47.48,1:12:49.45,yin,,0,0,0,,而这是在iCloud中\\N{\\fs12}devices identically and this was over iCloud,\r\nDialogue: 0,1:12:49.45,1:12:54.22,yin,,0,0,0,,这时就可能会有冲突 不过我们就这样做\\N{\\fs12}you could conceivably get a conflict there but we're just going to do that.\r\nDialogue: 0,1:12:54.22,1:12:56.91,yin,,0,0,0,,或许有更好的办法 反正这里\\N{\\fs12}Probably better ways but we're going\r\nDialogue: 0,1:12:56.91,1:13:02.88,yin,,0,0,0,,我们将创建图像URL和缩略图URL 放到下面这里\\N{\\fs12}to create both the image URL and the thumbnail URL. Let's put those down here.\r\nDialogue: 0,1:13:02.88,1:13:08.49,yin,,0,0,0,,图像URL NSURL imageURL是这样的\\N{\\fs12}So the image URL, NS URL, image URL looks like this.\r\nDialogue: 0,1:13:09.60,1:13:11.87,yin,,0,0,0,,这是方法的getter\\N{\\fs12}Okay so this is the getter for that method,\r\nDialogue: 0,1:13:11.87,1:13:14.04,yin,,0,0,0,,我将按惰性方式创建文件\\N{\\fs12}so I'm going lazily create that file.\r\nDialogue: 0,1:13:14.04,1:13:15.90,yin,,0,0,0,,一旦有人想要它的URL\\N{\\fs12}As soon as someone wants the URL for it,\r\nDialogue: 0,1:13:15.90,1:13:18.44,yin,,0,0,0,,我就会创建文件\\N{\\fs12}I'm going to go create the file.\r\nDialogue: 0,1:13:18.44,1:13:21.32,yin,,0,0,0,,换言之 如果!_imageURL\\N{\\fs12}So if not image URL-- in other words,\r\nDialogue: 0,1:13:21.32,1:13:22.93,yin,,0,0,0,,我就会惰性实例化它\\N{\\fs12}I'm going to lazily instantiate it.\r\nDialogue: 0,1:13:22.93,1:13:25.07,yin,,0,0,0,,且我们有图像\\N{\\fs12}And we have an image,\r\nDialogue: 0,1:13:25.07,1:13:27.62,yin,,0,0,0,,显然 没有图像 我们就无法创建文件\\N{\\fs12}okay because we can't create the file if we don't have an image,\r\nDialogue: 0,1:13:27.62,1:13:31.67,yin,,0,0,0,,不过如果有图像 我们就会这样做\\N{\\fs12}but if we do have the image then we'll do it.\r\nDialogue: 0,1:13:31.67,1:13:36.47,yin,,0,0,0,,让我们这样做 我们说NSURL\\N{\\fs12}Let's do this, let's say NS URL,\r\nDialogue: 0,1:13:36.49,1:13:42.53,yin,,0,0,0,,url = self uniqueDocumentURL\\N{\\fs12}URL equals self unique document URL.\r\nDialogue: 0,1:13:42.53,1:13:46.91,yin,,0,0,0,,这将是文档目录下唯一的URL\\N{\\fs12}Okay so this is just going to be a unique URL in my documents directory.\r\nDialogue: 0,1:13:46.91,1:13:50.20,yin,,0,0,0,,我写到了这里 你们有时间可以看\\N{\\fs12}I have that one here for you, you can look at it at your leisure.\r\nDialogue: 0,1:13:50.20,1:13:52.97,yin,,0,0,0,,你们已经知道如何做这些东西\\N{\\fs12}It just does, you know how to do all these things already\r\nDialogue: 0,1:13:52.97,1:13:54.98,yin,,0,0,0,,我没必要再讲一次\\N{\\fs12}so there's no use going over them again.\r\nDialogue: 0,1:13:54.98,1:13:57.62,yin,,0,0,0,,我有了这个唯一的URL\\N{\\fs12}So I got this unique URL.\r\nDialogue: 0,1:13:57.62,1:13:59.40,yin,,0,0,0,,如果这能成功\\N{\\fs12}If that was successful,\r\nDialogue: 0,1:13:59.40,1:14:04.01,yin,,0,0,0,,那么我就要从图像视图中获取图像数据\\N{\\fs12}then I'm going to get the image data out of my image view\r\nDialogue: 0,1:14:04.01,1:14:06.83,yin,,0,0,0,,我打算通过这个很酷的函数来做到这一点\\N{\\fs12}and I'm going to do that through this kind of cool function,\r\nDialogue: 0,1:14:06.83,1:14:09.51,yin,,0,0,0,,UIImageJPEGRepresentation\\N{\\fs12}UI image jpeg representation.\r\nDialogue: 0,1:14:09.51,1:14:11.63,yin,,0,0,0,,它的参数是一个UIImage\\N{\\fs12}It will take a UI image\r\nDialogue: 0,1:14:11.63,1:14:15.46,yin,,0,0,0,,返回的是NSData 带有它的JPEG\\N{\\fs12}and give you back an NS data with a Jpeg of that thing.\r\nDialogue: 0,1:14:15.47,1:14:16.89,yin,,0,0,0,,很酷 不是吗\\N{\\fs12}Pretty cool, huh?\r\nDialogue: 0,1:14:16.89,1:14:19.33,yin,,0,0,0,,不是所有图像都能这样做\\N{\\fs12}Not all images can do this but,\r\nDialogue: 0,1:14:19.33,1:14:22.36,yin,,0,0,0,,不过摄像头拍摄的图像都没问题\\N{\\fs12}you know, the kind of images that we load from the camera can, for example.\r\nDialogue: 0,1:14:22.36,1:14:24.52,yin,,0,0,0,,这将是self.image\\N{\\fs12}So this would be self dot image,\r\nDialogue: 0,1:14:24.52,1:14:26.80,yin,,0,0,0,,然后这是压缩程度\\N{\\fs12}and then this is how much you want to compress it,\r\nDialogue: 0,1:14:26.80,1:14:29.90,yin,,0,0,0,,我希望压缩尽可能少\\N{\\fs12}and I'm going to compress it as little as possible.\r\nDialogue: 0,1:14:29.90,1:14:33.75,yin,,0,0,0,,因为我希望照片跟刚拍的时候差别尽可能小\\N{\\fs12}Because I want the image to be as close to what you took of the camera as possible.\r\nDialogue: 0,1:14:33.75,1:14:35.96,yin,,0,0,0,,我不希望压缩毁掉图片的原样\\N{\\fs12}I don't want any compression artifacts or any of that stuff\r\nDialogue: 0,1:14:35.96,1:14:37.63,yin,,0,0,0,,因为这就是你实际拍的照片\\N{\\fs12}because this is the actual image you took.\r\nDialogue: 0,1:14:37.63,1:14:40.45,yin,,0,0,0,,有了这个以后 我想说\\N{\\fs12}So now that I have this, I'm going to say if I'm able\r\nDialogue: 0,1:14:40.45,1:14:43.45,yin,,0,0,0,,如果我能把这个写出 那就写到URL\\N{\\fs12}to write this thing out, write to URLs.\r\nDialogue: 0,1:14:43.45,1:14:47.87,yin,,0,0,0,,writeToURL是一个USData方法 我将指定URL\\N{\\fs12}So write to URL is an NS data method and I'm going to specify that URL,\r\nDialogue: 0,1:14:47.88,1:14:49.38,yin,,0,0,0,,YES 这里我要按原子方式来\\N{\\fs12}and yes I'm going to do it atomically\r\nDialogue: 0,1:14:49.38,1:14:51.38,yin,,0,0,0,,意味着会写入到一个临时文件\\N{\\fs12}which means it's going to write it to a temporary file,\r\nDialogue: 0,1:14:51.38,1:14:56.17,yin,,0,0,0,,删除已有的 在一个原子事务中移过来\\N{\\fs12}delete any existing one, move it over in one atomic transaction\r\nDialogue: 0,1:14:56.17,1:14:58.38,yin,,0,0,0,,如果手机在过程中崩溃\\N{\\fs12}so if the phone crashes in the middle, you won't get,\r\nDialogue: 0,1:14:58.38,1:15:01.36,yin,,0,0,0,,旧文件就还会在那里\\N{\\fs12}you'll still have an old file if it were still there.\r\nDialogue: 0,1:15:01.36,1:15:04.80,yin,,0,0,0,,如果它成功做到了 那么这就是图像URL\\N{\\fs12}If it successfully does that, then now this is the image URL.\r\nDialogue: 0,1:15:04.80,1:15:08.96,yin,,0,0,0,,记住 这是图像URL的getter 我在设置这个\\N{\\fs12}Remember this is the getter for image URL so I'm setting that.\r\nDialogue: 0,1:15:08.96,1:15:11.26,yin,,0,0,0,,现在 我们可以返回图像URL\\N{\\fs12}And now we can return our image URL.\r\nDialogue: 0,1:15:11.26,1:15:14.06,yin,,0,0,0,,每次你要图像URL时\\N{\\fs12}Now one thing is, every time you ask for the image URL,\r\nDialogue: 0,1:15:14.06,1:15:16.46,yin,,0,0,0,,我都会把它写出到磁盘\\N{\\fs12}I'm writing it out to disk.\r\nDialogue: 0,1:15:16.46,1:15:19.73,yin,,0,0,0,,不是每次 而是首次要的时候\\N{\\fs12}Well not every time but the first time you ask for it.\r\nDialogue: 0,1:15:19.73,1:15:23.23,yin,,0,0,0,,我需要小心 如果有人把照片换了\\N{\\fs12}I better be careful here if someone changes the image,\r\nDialogue: 0,1:15:23.23,1:15:25.31,yin,,0,0,0,,我就需要重新生成这个URL\\N{\\fs12}I'm going to have to regenerate this URL.\r\nDialogue: 0,1:15:25.31,1:15:28.78,yin,,0,0,0,,我还需要从磁盘上删除文件\\N{\\fs12}I also want to delete that file off of disk.\r\nDialogue: 0,1:15:28.78,1:15:31.17,yin,,0,0,0,,这里我要说 如果有人将图像\\N{\\fs12}So here I'm going to say, if anyone sets the image\r\nDialogue: 0,1:15:31.17,1:15:34.17,yin,,0,0,0,,设置为新图片 我要说NSFileManager\\N{\\fs12}to something new, I'm going to say NS file manager,\r\nDialogue: 0,1:15:34.17,1:15:35.61,yin,,0,0,0,,defaultManager\\N{\\fs12}default manager,\r\nDialogue: 0,1:15:35.61,1:15:38.87,yin,,0,0,0,,removeItemAtURL: 我们的imageURL\\N{\\fs12}remove item at URL our image URL.\r\nDialogue: 0,1:15:38.87,1:15:41.76,yin,,0,0,0,,注意这里我没有调用self.imageURL\\N{\\fs12}Notice I'm not calling self dot image URL here\r\nDialogue: 0,1:15:41.76,1:15:44.24,yin,,0,0,0,,因为那会创建文件\\N{\\fs12}because that would create the file.\r\nDialogue: 0,1:15:44.24,1:15:46.82,yin,,0,0,0,,这里有些奇特\\N{\\fs12}So this is a little bit weird.\r\nDialogue: 0,1:15:46.82,1:15:49.62,yin,,0,0,0,,我说过 除了setter和getter里面\\N{\\fs12}I told you never use underbar\r\nDialogue: 0,1:15:49.62,1:15:51.70,yin,,0,0,0,,都不要使用带下划线的\\N{\\fs12}in anything but a setter or a getter.\r\nDialogue: 0,1:15:51.70,1:15:56.30,yin,,0,0,0,,这里我违反了自己说的 不过这是出于性能考虑\\N{\\fs12}I'm violating that but it's, you know, kind of for performance reasons here\r\nDialogue: 0,1:15:56.30,1:15:57.98,yin,,0,0,0,,我们不关心这里有没有错误\\N{\\fs12}and we don't care if there's an error.\r\nDialogue: 0,1:15:57.98,1:16:00.35,yin,,0,0,0,,如果它不能删除 它就不能删除\\N{\\fs12}If it couldn't delete it, it couldn't delete it.\r\nDialogue: 0,1:16:00.35,1:16:04.00,yin,,0,0,0,,而且我还要将imageURL设为nil\\N{\\fs12}And also I'm going to set my image URL to nil\r\nDialogue: 0,1:16:04.00,1:16:05.86,yin,,0,0,0,,以后再有人问\\N{\\fs12}so that the next time someone asks,\r\nDialogue: 0,1:16:05.86,1:16:07.49,yin,,0,0,0,,因为我有一张新图片\\N{\\fs12}because I have a new image,\r\nDialogue: 0,1:16:07.49,1:16:09.77,yin,,0,0,0,,以后再有人问 它就会重新生成\\N{\\fs12}the next time someone asks, it'll regenerate.\r\nDialogue: 0,1:16:09.77,1:16:14.01,yin,,0,0,0,,我要对缩略图做完全相同的事情\\N{\\fs12}So I'm going to do the exact same thing for the thumbnail.\r\nDialogue: 0,1:16:14.01,1:16:16.30,yin,,0,0,0,,我创建了这个文件\\N{\\fs12}I created this file here.\r\nDialogue: 0,1:16:16.30,1:16:19.33,yin,,0,0,0,,我要拖入一点category\\N{\\fs12}I'm going to drag in a little category\r\nDialogue: 0,1:16:19.33,1:16:22.49,yin,,0,0,0,,这是我之前创建的\\N{\\fs12}that I created\r\nDialogue: 0,1:16:22.49,1:16:26.74,yin,,0,0,0,,使用了上周五辅导课上的一些代码\\N{\\fs12}using some of the code from last Friday's section\r\nDialogue: 0,1:16:26.74,1:16:31.25,yin,,0,0,0,,还有一些我写的代码 在这里\\N{\\fs12}and also some of the little code that I wrote. So here it is right here.\r\nDialogue: 0,1:16:31.25,1:16:32.46,yin,,0,0,0,,拖入这里\\N{\\fs12}Put it in here.\r\nDialogue: 0,1:16:32.46,1:16:34.54,yin,,0,0,0,,到这里来 这样你们就能看到我在做什么\\N{\\fs12}Oops, let's go here so you can see what I'm doing.\r\nDialogue: 0,1:16:34.54,1:16:37.00,yin,,0,0,0,,把这个放到这里\\N{\\fs12}Going to put this right here.\r\nDialogue: 0,1:16:37.00,1:16:39.37,yin,,0,0,0,,这段代码很简单\\N{\\fs12}This code is quite simple.\r\nDialogue: 0,1:16:39.37,1:16:40.74,yin,,0,0,0,,它只有两个方法\\N{\\fs12}It just has two methods.\r\nDialogue: 0,1:16:40.74,1:16:44.93,yin,,0,0,0,,一个是取图像 并获得调整尺寸后的新图像\\N{\\fs12}One takes the image and gets a new image by resizing it.\r\nDialogue: 0,1:16:44.93,1:16:46.18,yin,,0,0,0,,缩略图就是这个了\\N{\\fs12}That's what we want for a thumbnail.\r\nDialogue: 0,1:16:46.18,1:16:50.29,yin,,0,0,0,,而这个应用了一个过滤器 基于周五辅导课上的内容\\N{\\fs12}And this one applies a filter based on what we saw at Friday's section.\r\nDialogue: 0,1:16:50.29,1:16:52.48,yin,,0,0,0,,没上周五辅导课的人 可能看不懂这段代码\\N{\\fs12}So if you miss Friday's section you won't understand this code,\r\nDialogue: 0,1:16:52.48,1:16:53.84,yin,,0,0,0,,上了的人肯定知道\\N{\\fs12}but if you were there you will.\r\nDialogue: 0,1:16:53.84,1:16:56.42,yin,,0,0,0,,这段代码很简单 使用drawInRect\\N{\\fs12}And this is pretty straightforward code using draw in rect\r\nDialogue: 0,1:16:56.42,1:16:59.22,yin,,0,0,0,,还有这个GraphicsBeginImageContextWithOption\\N{\\fs12}and this nice graphics begin image context with option\r\nDialogue: 0,1:16:59.22,1:17:02.50,yin,,0,0,0,,你们可以离线看看这些\\N{\\fs12}so you can look at that offline as well.\r\nDialogue: 0,1:17:02.50,1:17:04.89,yin,,0,0,0,,下面回到这里\\N{\\fs12}And so now let's go back here,\r\nDialogue: 0,1:17:04.89,1:17:08.92,yin,,0,0,0,,有了这个以后… 我到哪里了\\N{\\fs12}and now that I have that, let u- where was I?\r\nDialogue: 0,1:17:08.92,1:17:10.05,yin,,0,0,0,,我来找找\\N{\\fs12}Let's find this thing.\r\nDialogue: 0,1:17:10.05,1:17:11.29,yin,,0,0,0,,下面吧\\N{\\fs12}It's way down here.\r\nDialogue: 0,1:17:11.29,1:17:11.92,yin,,0,0,0,,这里\\N{\\fs12}Here it is.\r\nDialogue: 0,1:17:11.92,1:17:15.73,yin,,0,0,0,,我们获得缩略图 缩略图使用图像相同的URL\\N{\\fs12}So we've got the thumbnail, so the thumbnail uses the same URL as the image\r\nDialogue: 0,1:17:15.73,1:17:17.74,yin,,0,0,0,,不过加上了.thumbnail\\N{\\fs12}but adds dot thumbnail to it\r\nDialogue: 0,1:17:17.74,1:17:20.42,yin,,0,0,0,,然后缩放了 其它都完全相同\\N{\\fs12}and then scales it and then does exactly the same thing.\r\nDialogue: 0,1:17:20.42,1:17:21.42,yin,,0,0,0,,这是缩略图\\N{\\fs12}So now thumbnail,\r\nDialogue: 0,1:17:21.42,1:17:23.50,yin,,0,0,0,,我们要对缩略图做相同的事\\N{\\fs12}so we want to do the same thing here for the thumbnail.\r\nDialogue: 0,1:17:23.50,1:17:28.83,yin,,0,0,0,,我们需要删除缩略图文件 我们还要self.thumbnail\\N{\\fs12}We better remove our thumbnail file and we want to self dot thumbnail.\r\nDialogue: 0,1:17:28.83,1:17:31.48,yin,,0,0,0,,严格来讲 这不是必需的 不过这里就这样\\N{\\fs12}That's not strictly necessary but we'll do it.\r\nDialogue: 0,1:17:31.48,1:17:35.60,yin,,0,0,0,,现在 我们有了缩略图URL和图像URL\\N{\\fs12}Okay, so now that we have thumbnail URL and image URL,\r\nDialogue: 0,1:17:35.60,1:17:40.92,yin,,0,0,0,,上面这个照片创建就能完整地创建照片了\\N{\\fs12}this photo creation up here will be able to fully create the photo.\r\nDialogue: 0,1:17:40.92,1:17:43.75,yin,,0,0,0,,我们还没有摄像头 不过最后\\N{\\fs12}Now we don't have the camera, but I want to end this thing\r\nDialogue: 0,1:17:43.75,1:17:46.07,yin,,0,0,0,,我打算演示一下目前的进展\\N{\\fs12}by showing you this working so far.\r\nDialogue: 0,1:17:46.07,1:17:49.62,yin,,0,0,0,,我打算拖入一个图像 一朵小花\\N{\\fs12}So I'm going to drag an image, a little flower--\r\nDialogue: 0,1:17:49.62,1:17:52.13,yin,,0,0,0,,这朵花我们之前就看到过\\N{\\fs12}this is the flower we saw earlier in the quarter--\r\nDialogue: 0,1:17:52.13,1:17:56.76,yin,,0,0,0,,我打算把这朵小花当成我们的照片\\N{\\fs12}and I'm going to make this little flower be our photo, okay?\r\nDialogue: 0,1:17:56.76,1:18:02.02,yin,,0,0,0,,我打算在viewDidLoad中这样做\\N{\\fs12}So I'm just going to do that right here in view did load of this guy.\r\nDialogue: 0,1:18:02.02,1:18:04.56,yin,,0,0,0,,viewDidLoad\\N{\\fs12}View did load.\r\nDialogue: 0,1:18:06.21,1:18:10.29,yin,,0,0,0,,super viewDidLoad\\N{\\fs12}Super view did load and I'm going\r\nDialogue: 0,1:18:10.29,1:18:16.28,yin,,0,0,0,,然后是self.image = UIImage imageNamed\\N{\\fs12}to say self dot image equals UI image image named\r\nDialogue: 0,1:18:16.28,1:18:18.39,yin,,0,0,0,,flower.jpeg\\N{\\fs12}flower dot jpeg.\r\nDialogue: 0,1:18:18.41,1:18:22.04,yin,,0,0,0,,这里我要讲讲我刚做的事 这很酷\\N{\\fs12}This is an opportunity to show you another cool thing that we, I just did.\r\nDialogue: 0,1:18:22.04,1:18:26.43,yin,,0,0,0,,你们看到 我将文件拖入到Photomania的顶层\\N{\\fs12}What you see, I dragged the file right into my top level of PhotoMania\r\nDialogue: 0,1:18:26.43,1:18:31.07,yin,,0,0,0,,然后我可以使用imageNamed这些直接访问它\\N{\\fs12}and then I can access it directly using something like image named.\r\nDialogue: 0,1:18:31.07,1:18:33.28,yin,,0,0,0,,你并不一定要把文件放到asset中\\N{\\fs12}So you don't actually have to put things in that asset,\r\nDialogue: 0,1:18:33.28,1:18:36.57,yin,,0,0,0,,你可以放到顶层 然后像这样访问它们\\N{\\fs12}so you can put them right in the top level if you want and access them that way.\r\nDialogue: 0,1:18:36.57,1:18:40.14,yin,,0,0,0,,好 但愿… 哦 这不行\\N{\\fs12}All right, so hopefully-- oops, this is not going to work\r\nDialogue: 0,1:18:40.14,1:18:43.03,yin,,0,0,0,,因为我们需要用真正的设备\\N{\\fs12}because we need to be on a real device.\r\nDialogue: 0,1:18:43.24,1:18:47.51,yin,,0,0,0,,这里是iPad和iPhone模拟模式\\N{\\fs12}There we go. I've got this iPad and iPhone simulation mode here.\r\nDialogue: 0,1:18:55.59,1:18:58.04,yin,,0,0,0,,好 到My Photos里面\\N{\\fs12}All right so we'll go to my photos.\r\nDialogue: 0,1:18:58.04,1:19:00.71,yin,,0,0,0,,这里显示了我的所有照片 我一张都没有\\N{\\fs12}Here's showing all my photos. I don't have any yet.\r\nDialogue: 0,1:19:00.71,1:19:02.35,yin,,0,0,0,,点相机按钮\\N{\\fs12}We'll press the little camera.\r\nDialogue: 0,1:19:02.35,1:19:04.56,yin,,0,0,0,,这是相机拍摄的照片\\N{\\fs12}Here's our photo that we took with our camera.\r\nDialogue: 0,1:19:04.56,1:19:08.36,yin,,0,0,0,,真正的拍照周三再讲 这里就用了一张图像\\N{\\fs12}We'll do that on Wednesday so for now we got photo.\r\nDialogue: 0,1:19:08.36,1:19:10.27,yin,,0,0,0,,我们可以按完成\\N{\\fs12}We could actually hit done here.\r\nDialogue: 0,1:19:10.27,1:19:11.39,yin,,0,0,0,,看看会怎样\\N{\\fs12}Watch what happened if we hit done.\r\nDialogue: 0,1:19:11.39,1:19:12.74,yin,,0,0,0,,它说 必需有标题\\N{\\fs12}It says title required.\r\nDialogue: 0,1:19:12.74,1:19:16.11,yin,,0,0,0,,记得shouldPerform方法吗 这很好 我们需要这个\\N{\\fs12}Remember we had that should perform so that's good that it requires that.\r\nDialogue: 0,1:19:16.11,1:19:20.25,yin,,0,0,0,,我们把这个称作Flower\\N{\\fs12}So we'll call this flower\r\nDialogue: 0,1:19:20.25,1:19:25.49,yin,,0,0,0,,然后是副标题 Pretty\\N{\\fs12}and then we'll have a little subtitle, pretty.\r\nDialogue: 0,1:19:25.49,1:19:26.65,yin,,0,0,0,,这就好了\\N{\\fs12}So we're ready to go.\r\nDialogue: 0,1:19:26.65,1:19:29.56,yin,,0,0,0,,点完成 它就会unwind 然后创建照片\\N{\\fs12}Now we hit done, it unwinds, it creates it.\r\nDialogue: 0,1:19:29.56,1:19:31.38,yin,,0,0,0,,它找到了我们的位置\\N{\\fs12}It found our location.\r\nDialogue: 0,1:19:31.38,1:19:33.84,yin,,0,0,0,,点它 我们会看到缩略图\\N{\\fs12}If we click on it, we see it's got a thumbnail.\r\nDialogue: 0,1:19:33.84,1:19:36.07,yin,,0,0,0,,我们可以点击查看照片\\N{\\fs12}We can click to see the photo.\r\nDialogue: 0,1:19:36.07,1:19:38.61,yin,,0,0,0,,这就是我们的照片\\N{\\fs12}Here's our photo, etcetera.\r\nDialogue: 0,1:19:39.73,1:19:41.54,yin,,0,0,0,,明白了吗\\N{\\fs12}Got all that?\r\nDialogue: 0,1:19:41.54,1:19:45.87,yin,,0,0,0,,好 周三 我们将继续这个 讲解实际拍照\\N{\\fs12}Okay, so on Wednesday we will continue by actually getting the photo in here.\r\nDialogue: 0,1:19:45.87,1:19:47.41,yin,,0,0,0,,我还会演示动作表单\\N{\\fs12}I'll also show you an action sheet.\r\nDialogue: 0,1:19:47.41,1:19:49.15,yin,,0,0,0,,我们将使用过滤那些\\N{\\fs12}We'll use that filtering thing\r\nDialogue: 0,1:19:49.15,1:19:52.57,yin,,0,0,0,,创建出过滤照片用的动作表单\\N{\\fs12}to put an action sheet up that filters our photo.\r\nDialogue: 0,1:19:52.57,1:19:55.30,yin,,0,0,0,,有问题的可以来提\\N{\\fs12}If you have questions I'm here.\r\nDialogue: 0,1:19:56.80,1:20:00.28,yin,,0,0,0,,更多内容 请访问我校官网stanford.edu\\N{\\fs12}> For more, please visit us at Stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/17. Camera, Core Motion, Application Lifecycle.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.2.0\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage]\r\nLast Style Storage: Default\r\nActive Line: 7\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.33,0:00:07.74,yin,,0,0,0,,斯坦福大学\\N{\\fs12}> Stanford University.\r\nDialogue: 0,0:00:07.74,0:00:14.52,yin,,0,0,0,,欢迎来到CS193P课程 2013-14秋季第17讲\\N{\\fs12}> Alright, well welcome to lecture 17 of CS193P, Fall 2013/14.\r\nDialogue: 0,0:00:14.52,0:00:17.44,yin,,0,0,0,,今天我将先花几分钟时间\\N{\\fs12}And today I'm going to spend just a couple minutes typing\r\nDialogue: 0,0:00:17.44,0:00:20.51,yin,,0,0,0,,对周一的demo进行一些查漏补缺\\N{\\fs12}up some loose ends from the demo we had on Monday,\r\nDialogue: 0,0:00:20.51,0:00:24.88,yin,,0,0,0,,然后再来讨论摄像头拍照\\N{\\fs12}and then I'm going to talk about taking pictures with the camera.\r\nDialogue: 0,0:00:24.88,0:00:28.69,yin,,0,0,0,,然后这方面也有一个demo\\N{\\fs12}And then we'll do a demo about that.\r\nDialogue: 0,0:00:28.69,0:00:33.23,yin,,0,0,0,,继续用Photomania 继续上次的demo来\\N{\\fs12}And that's basically PhotoMania, what we kind of set this all up for in our last demo.\r\nDialogue: 0,0:00:33.23,0:00:35.01,yin,,0,0,0,,然后我们会谈到Core Motion\\N{\\fs12}Then we'll talk about core motion,\r\nDialogue: 0,0:00:35.01,0:00:38.59,yin,,0,0,0,,也就是加速计 陀螺仪这些东西\\N{\\fs12}which is the accelerometer and the gyro and all that business,\r\nDialogue: 0,0:00:38.59,0:00:40.26,yin,,0,0,0,,然后我会演示这个\\N{\\fs12}and I'll have a demo of that.\r\nDialogue: 0,0:00:40.26,0:00:42.18,yin,,0,0,0,,最后如果时间允许\\N{\\fs12}And if time permitting at the end here,\r\nDialogue: 0,0:00:42.18,0:00:45.51,yin,,0,0,0,,我们还会简要讨论应用程序生命周期\\N{\\fs12}we'll talk a little bit about the application life cycle.\r\nDialogue: 0,0:00:45.51,0:00:48.24,yin,,0,0,0,,我们讨论过视图控制器生命周期\\N{\\fs12}We talked about the view controller life cycle\r\nDialogue: 0,0:00:48.24,0:00:50.30,yin,,0,0,0,,它什么时候出现 什么时候消失 等等\\N{\\fs12}where it appears and disappears and all those things,\r\nDialogue: 0,0:00:50.30,0:00:52.39,yin,,0,0,0,,应用程序也有生命周期\\N{\\fs12}well the application kind of, you know,\r\nDialogue: 0,0:00:52.39,0:00:55.04,yin,,0,0,0,,你到前台 你运行 然后你消失\\N{\\fs12}you come into the foreground, you run, then you go away,\r\nDialogue: 0,0:00:55.04,0:00:58.48,yin,,0,0,0,,你到后台 然后回来 这里也有生命周期\\N{\\fs12}then you go the background, you come back, so there's kind of a life cycle there too,\r\nDialogue: 0,0:00:58.48,0:01:00.58,yin,,0,0,0,,我们可以简要谈下这个\\N{\\fs12}which we can talk about briefly,\r\nDialogue: 0,0:01:00.58,0:01:04.97,yin,,0,0,0,,有时间的话 这个我也可以演示一下\\N{\\fs12}and I could even demo some of that if we have time.\r\nDialogue: 0,0:01:04.97,0:01:07.94,yin,,0,0,0,,先来看看上次的demo\\N{\\fs12}Alright, so let's talk about the demo.\r\nDialogue: 0,0:01:07.94,0:01:12.35,yin,,0,0,0,,我要快速看看这个demo 并讲两点\\N{\\fs12}I'm going to go back to the demo here real quick and talk about two things.\r\nDialogue: 0,0:01:12.35,0:01:15.75,yin,,0,0,0,,一是清理imageURL\\N{\\fs12}One was cleaning up image URLs\r\nDialogue: 0,0:01:15.75,0:01:19.76,yin,,0,0,0,,因为对于imageURL 我们有这个getter\\N{\\fs12}because the way we do our URLs is we have this \"getter\" for image URL,\r\nDialogue: 0,0:01:19.76,0:01:23.61,yin,,0,0,0,,只要有人想要图像视图中图像的URL\\N{\\fs12}and any time someone wants a URL for the image that's in our image view,\r\nDialogue: 0,0:01:23.61,0:01:26.59,yin,,0,0,0,,我们就会创建一个文件到磁盘上 并返回URL\\N{\\fs12}why we just create a file on disc and return the URL.\r\nDialogue: 0,0:01:26.59,0:01:28.25,yin,,0,0,0,,这是请求式的\\N{\\fs12}So it's kind of on-demand.\r\nDialogue: 0,0:01:28.25,0:01:31.16,yin,,0,0,0,,问题在于 如果拍了另外一张照片\\N{\\fs12}Well, the problem is, what if they then take a different photo\r\nDialogue: 0,0:01:31.16,0:01:35.17,yin,,0,0,0,,或者如果视图控制器离开屏幕然后回到屏幕\\N{\\fs12}or if this view controller goes off screen and back on screen,\r\nDialogue: 0,0:01:35.17,0:01:36.67,yin,,0,0,0,,有人选了别的什么\\N{\\fs12}and someone picked something else,\r\nDialogue: 0,0:01:36.67,0:01:39.44,yin,,0,0,0,,你不希望原来的URL还在那里\\N{\\fs12}you don't want any old URLs lying around.\r\nDialogue: 0,0:01:39.44,0:01:42.09,yin,,0,0,0,,我们需要清理那些老旧的URL\\N{\\fs12}So we need to clean up those old URLs.\r\nDialogue: 0,0:01:42.09,0:01:44.86,yin,,0,0,0,,另外我还要简单讲一点\\N{\\fs12}And the other thing I'm going to show you, just a brief bit more\r\nDialogue: 0,0:01:44.86,0:01:47.49,yin,,0,0,0,,关于在Core Location检查错误\\N{\\fs12}about checking for errors in core location.\r\nDialogue: 0,0:01:47.49,0:01:50.08,yin,,0,0,0,,我们已经做了一些错误检查\\N{\\fs12}Because we did some error checking already,\r\nDialogue: 0,0:01:50.08,0:01:51.53,yin,,0,0,0,,不过我们还可以做更多一些\\N{\\fs12}but we could do just slightly a bit more.\r\nDialogue: 0,0:01:51.53,0:01:56.19,yin,,0,0,0,,让我们回到Photomania\\N{\\fs12}So let's go back to PhotoMania.\r\nDialogue: 0,0:01:56.19,0:01:58.51,yin,,0,0,0,,看看这个\\N{\\fs12}And let's look at that.\r\nDialogue: 0,0:01:58.51,0:02:01.28,yin,,0,0,0,,imageURL的清理其实有两件事\\N{\\fs12}The cleaning up the image stuff is really two things.\r\nDialogue: 0,0:02:01.28,0:02:03.94,yin,,0,0,0,,一是在取消时\\N{\\fs12}One, when we cancel.\r\nDialogue: 0,0:02:03.94,0:02:08.18,yin,,0,0,0,,当我们取消 从模态视图控制器中退出时\\N{\\fs12}When we do our cancel to get out of our modal view controller,\r\nDialogue: 0,0:02:08.18,0:02:11.48,yin,,0,0,0,,我们会将图像设为nil 为什么要这样做呢\\N{\\fs12}we're going to set our image to nil, and why are we going to do that?\r\nDialogue: 0,0:02:11.48,0:02:15.09,yin,,0,0,0,,原因是这样 你可以看我们的设置图像方法 下面这里\\N{\\fs12}That's because if you look at our set image, down here,\r\nDialogue: 0,0:02:15.09,0:02:17.70,yin,,0,0,0,,我们会删除URL\\N{\\fs12}we delete the URLs, right?\r\nDialogue: 0,0:02:17.70,0:02:21.22,yin,,0,0,0,,只要图像视图中的图像改变了\\N{\\fs12}So whenever we change the image that's in our image view, right?\r\nDialogue: 0,0:02:21.22,0:02:23.32,yin,,0,0,0,,我们就会删除URL\\N{\\fs12}We delete the URLs. This is something we did,\r\nDialogue: 0,0:02:23.32,0:02:26.52,yin,,0,0,0,,上次课最后可能做得有些匆忙\\N{\\fs12}kind of it was a little rushed maybe at the end,\r\nDialogue: 0,0:02:26.52,0:02:29.25,yin,,0,0,0,,不过我们的确删除了URL\\N{\\fs12}but we do delete our URLs there.\r\nDialogue: 0,0:02:29.25,0:02:31.69,yin,,0,0,0,,这是因为我们有了新图像\\N{\\fs12}And that's because we've got a new image, so we're going\r\nDialogue: 0,0:02:31.69,0:02:34.44,yin,,0,0,0,,我们于是想删掉旧图像的URL\\N{\\fs12}to delete the URLs for the old image, and that will make,\r\nDialogue: 0,0:02:34.44,0:02:37.64,yin,,0,0,0,,这就将URL设为nil 我们会创建新URL\\N{\\fs12}we'll set our URL to nil, so that we'll make new URLs, right?\r\nDialogue: 0,0:02:37.64,0:02:39.10,yin,,0,0,0,,这就是我们要清理的地方\\N{\\fs12}So this is where we're going to clean up.\r\nDialogue: 0,0:02:39.10,0:02:42.01,yin,,0,0,0,,在取消时 我们显然需要把图像设为nil\\N{\\fs12}So we definitely want to set that image to nil when we cancel.\r\nDialogue: 0,0:02:42.01,0:02:44.47,yin,,0,0,0,,另一点是 不取消时\\N{\\fs12}And the other thing is, when we don't cancel,\r\nDialogue: 0,0:02:44.47,0:02:48.03,yin,,0,0,0,,如果我们要实际准备segue并创建照片\\N{\\fs12}when we actually prepare for segue and make a photo,\r\nDialogue: 0,0:02:48.03,0:02:53.36,yin,,0,0,0,,那我们就希望将URL设为nil 让它们不被删除\\N{\\fs12}then we want to set the URLs to nil, so that they don't get deleted.\r\nDialogue: 0,0:02:53.36,0:02:56.64,yin,,0,0,0,,因为这里 我们在照片中将URL汇报回去\\N{\\fs12}Because here, we're reporting that URL back in the photo,\r\nDialogue: 0,0:02:56.64,0:02:58.36,yin,,0,0,0,,我们不希望这个URL被删除\\N{\\fs12}so we do not want that URL to delete.\r\nDialogue: 0,0:02:58.36,0:02:59.99,yin,,0,0,0,,因此我们把这些设为nil\\N{\\fs12}So we're going to set these to nil.\r\nDialogue: 0,0:02:59.99,0:03:03.72,yin,,0,0,0,,这样它们就不会在任何时候被删掉了\\N{\\fs12}So that they won't get deleted at any point.\r\nDialogue: 0,0:03:03.72,0:03:06.78,yin,,0,0,0,,我们用它们 我们用那个URL\\N{\\fs12}It's kind of like we use them, we use that URL,\r\nDialogue: 0,0:03:06.78,0:03:09.19,yin,,0,0,0,,我们现在只将它设为nil\\N{\\fs12}so now we don't want to-- we want to just set it to nil.\r\nDialogue: 0,0:03:09.19,0:03:12.68,yin,,0,0,0,,这就是这里涉及到的一些清理任务\\N{\\fs12}So that was that, that's the only clean-up there that was involved.\r\nDialogue: 0,0:03:12.68,0:03:16.43,yin,,0,0,0,,另外一点是Core Location错误检查\\N{\\fs12}The other thing was this core location error checking,\r\nDialogue: 0,0:03:16.43,0:03:19.56,yin,,0,0,0,,可以看到 在shouldPerformForSegue中\\N{\\fs12}and you can see, for example in our should perform for segue,\r\nDialogue: 0,0:03:19.56,0:03:23.30,yin,,0,0,0,,我在这里加了注释 \"应该检查位置和imageURL\"\\N{\\fs12}I put a comment in here, \"should check location and image URL\" too, right?\r\nDialogue: 0,0:03:23.30,0:03:25.98,yin,,0,0,0,,因为我已经检查了 确保我们已经拍了照\\N{\\fs12}Because I already checked to make sure we actually took a photo,\r\nDialogue: 0,0:03:25.98,0:03:30.34,yin,,0,0,0,,而且用户提供了标题 我还应该检查\\N{\\fs12}and that the person provided a title, so I should also check\r\nDialogue: 0,0:03:30.34,0:03:33.12,yin,,0,0,0,,我们是否位置信息\\N{\\fs12}that the location, that we got a location, right?\r\nDialogue: 0,0:03:33.12,0:03:35.81,yin,,0,0,0,,因为我们在后台获得的位置信息\\N{\\fs12}Because remember that location we're kind of getting in the background\r\nDialogue: 0,0:03:35.81,0:03:38.87,yin,,0,0,0,,正在异步地从GPS\\N{\\fs12}is asynchronously looking at GPS\r\nDialogue: 0,0:03:38.87,0:03:40.65,yin,,0,0,0,,wifi这些那里获取\\N{\\fs12}or wi-fi or something to get that location.\r\nDialogue: 0,0:03:40.65,0:03:44.64,yin,,0,0,0,,这里 点完成时 我们要确保确实获得了位置信息\\N{\\fs12}So here, when we hit \"done,\" we've got to make sure we actually got one.\r\nDialogue: 0,0:03:44.64,0:03:47.34,yin,,0,0,0,,除了确保我们获得了位置信息之外\\N{\\fs12}And more than just determining that we got it,\r\nDialogue: 0,0:03:47.34,0:03:49.86,yin,,0,0,0,,我们还要保证没有特定错误\\N{\\fs12}let's make sure there wasn't a particular error.\r\nDialogue: 0,0:03:49.86,0:03:51.70,yin,,0,0,0,,这里有个办法可以监视错误\\N{\\fs12}And so there's a way to watch for errors.\r\nDialogue: 0,0:03:51.70,0:03:54.04,yin,,0,0,0,,这里是我们创建位置管理器的地方\\N{\\fs12}Here's where we create our location manager,\r\nDialogue: 0,0:03:54.04,0:03:58.34,yin,,0,0,0,,我们这里只使用了这一个委托方法\\N{\\fs12}and we only use this one delegate method right here.\r\nDialogue: 0,0:03:58.34,0:04:02.15,yin,,0,0,0,,不过还有一点我们可以做\\N{\\fs12}But there is another thing we could do,\r\nDialogue: 0,0:04:02.15,0:04:05.49,yin,,0,0,0,,也就是 我们可以实现这个委托方法\\N{\\fs12}which is we could implement this delegate method,\r\nDialogue: 0,0:04:05.49,0:04:06.79,yin,,0,0,0,,didFailWithError\\N{\\fs12}didFailWithError\r\nDialogue: 0,0:04:06.79,0:04:09.75,yin,,0,0,0,,位置管理器失败时 它就会告诉我们\\N{\\fs12}and that will tell us any time the location manager fails.\r\nDialogue: 0,0:04:09.75,0:04:11.20,yin,,0,0,0,,位置信息获取失败\\N{\\fs12}Fails to get a location.\r\nDialogue: 0,0:04:11.20,0:04:14.99,yin,,0,0,0,,我将把这些进入到NSError的错误代码存起来\\N{\\fs12}And I'm just going to salt away the error code that comes in this NS error\r\nDialogue: 0,0:04:14.99,0:04:17.43,yin,,0,0,0,,存入到这个locationErrorCode\\N{\\fs12}into this location error code,\r\nDialogue: 0,0:04:17.43,0:04:19.56,yin,,0,0,0,,我把这设为一个属性\\N{\\fs12}which I'm going to make a property.\r\nDialogue: 0,0:04:19.56,0:04:20.85,yin,,0,0,0,,这只是一个整数\\N{\\fs12}Okay so it's just an integer.\r\nDialogue: 0,0:04:20.85,0:04:22.53,yin,,0,0,0,,我将保存这个错误代码\\N{\\fs12}So I'm going to keep that error code,\r\nDialogue: 0,0:04:22.53,0:04:25.88,yin,,0,0,0,,然后在下面这里的完成中\\N{\\fs12}and then down in done right here, okay,\r\nDialogue: 0,0:04:25.88,0:04:30.97,yin,,0,0,0,,除了检查是否有标题和是否拍过照之外\\N{\\fs12}I am going to, in addition to checking the title and whether a photo was taken,\r\nDialogue: 0,0:04:30.97,0:04:33.76,yin,,0,0,0,,这里我还要检查是否获得了位置\\N{\\fs12}here I'm going to check the location.\r\nDialogue: 0,0:04:33.76,0:04:36.92,yin,,0,0,0,,如果我没获得位置 如果位置为nil\\N{\\fs12}And so if I didn't get a location, if location is nil,\r\nDialogue: 0,0:04:36.92,0:04:39.91,yin,,0,0,0,,那我就会去看我获得的错误代码\\N{\\fs12}then I'm going to look at that error code that I got.\r\nDialogue: 0,0:04:39.91,0:04:43.52,yin,,0,0,0,,这里可能是0 也就是错误位置未知\\N{\\fs12}Now, it might be zero, which is error location unknown,\r\nDialogue: 0,0:04:43.52,0:04:45.82,yin,,0,0,0,,这是什么意思呢\\N{\\fs12}in which case, what does that mean if the location--\r\nDialogue: 0,0:04:45.82,0:04:48.77,yin,,0,0,0,,这里的错误是说\\N{\\fs12}if either I've never gotten an error, or I got an error\r\nDialogue: 0,0:04:48.77,0:04:51.45,yin,,0,0,0,,错误位置未知 这里也就是0\\N{\\fs12}and it said location unknown, which is zero,\r\nDialogue: 0,0:04:51.45,0:04:53.73,yin,,0,0,0,,这意味着它还在尝试\\N{\\fs12}well, that means that it's still trying.\r\nDialogue: 0,0:04:53.73,0:04:55.35,yin,,0,0,0,,它还没得到错误说\\N{\\fs12}It hasn't gotten an error\r\nDialogue: 0,0:04:55.35,0:04:58.77,yin,,0,0,0,,我无法获得位置 它还在尝试\\N{\\fs12}that says I can't get the location, but it's still trying,\r\nDialogue: 0,0:04:58.77,0:05:00.34,yin,,0,0,0,,这时我们告诉用户\\N{\\fs12}so that's what we're going to tell the user.\r\nDialogue: 0,0:05:00.34,0:05:04.10,yin,,0,0,0,,我现在还没弄清这张照片是在哪拍的\\N{\\fs12}It's like I couldn't figure out where this photo was taken, yet.\r\nDialogue: 0,0:05:04.10,0:05:07.90,yin,,0,0,0,,用户看到这个警告会点OK\\N{\\fs12}And if they say this is an alert, so they'll click \"ok\"\r\nDialogue: 0,0:05:07.90,0:05:09.30,yin,,0,0,0,,回到之前的位置\\N{\\fs12}and they'll be back where they started,\r\nDialogue: 0,0:05:09.30,0:05:12.59,yin,,0,0,0,,用户可以再次点完成 他可以一直点下去\\N{\\fs12}they can try hitting done again, and they just keep hitting done\r\nDialogue: 0,0:05:12.59,0:05:16.07,yin,,0,0,0,,看能不能得到 直到感到厌倦 然后点取消\\N{\\fs12}and seeing if this keeps coming up until they get tired of it and they hit cancel.\r\nDialogue: 0,0:05:16.07,0:05:18.12,yin,,0,0,0,,这是一种错误情形\\N{\\fs12}So that's one error situation.\r\nDialogue: 0,0:05:18.12,0:05:19.40,yin,,0,0,0,,另一种是被拒绝\\N{\\fs12}Another one is \"denied.\"\r\nDialogue: 0,0:05:19.40,0:05:22.21,yin,,0,0,0,,这个不应当发生 因为一开始我们就\\N{\\fs12}This shouldn't happen because we checked whether we were\r\nDialogue: 0,0:05:22.21,0:05:24.29,yin,,0,0,0,,检验过是否有授权 记得吗\\N{\\fs12}authorized before, at the very beginning remember?\r\nDialogue: 0,0:05:24.29,0:05:27.22,yin,,0,0,0,,如果没有授权 我们有一个致命警告\\N{\\fs12}And we put a fatal alert up if you weren't authorized.\r\nDialogue: 0,0:05:27.22,0:05:29.89,yin,,0,0,0,,不过用户在看到这个警告后\\N{\\fs12}But it's actually possible they could put this alert up,\r\nDialogue: 0,0:05:29.89,0:05:33.46,yin,,0,0,0,,有可能去设置 禁用它 回来 再点完成\\N{\\fs12}go to settings, disable it, come back, and click \"done,\"\r\nDialogue: 0,0:05:33.47,0:05:35.48,yin,,0,0,0,,然后被拒绝\\N{\\fs12}and then they'd be denied.\r\nDialogue: 0,0:05:35.48,0:05:39.13,yin,,0,0,0,,这很罕见 不过我们还是可以检查一下\\N{\\fs12}So that's pretty rare, but let's check for it anyway.\r\nDialogue: 0,0:05:39.13,0:05:40.96,yin,,0,0,0,,如果用户这样做 我们可以告诉他\\N{\\fs12}And if they do that, then we'll just tell them,\r\nDialogue: 0,0:05:40.96,0:05:43.93,yin,,0,0,0,,到隐私里面 把这个重新开启\\N{\\fs12}go back into privacy and turn that thing back on.\r\nDialogue: 0,0:05:43.93,0:05:47.71,yin,,0,0,0,,我们可能被拒绝 很罕见 另一点是网络\\N{\\fs12}So we could get a denied, rare, the other one is network,\r\nDialogue: 0,0:05:47.71,0:05:50.42,yin,,0,0,0,,我们尝试找到位置\\N{\\fs12}so this is-- we're trying to find the location,\r\nDialogue: 0,0:05:50.42,0:05:53.52,yin,,0,0,0,,我们无法连上GPS 而且设备没有联网\\N{\\fs12}we can't get any GPS, and they're not connected to the network,\r\nDialogue: 0,0:05:53.52,0:05:55.23,yin,,0,0,0,,我们不能使用wifi\\N{\\fs12}so we can't use wi-fi either.\r\nDialogue: 0,0:05:55.23,0:05:58.09,yin,,0,0,0,,而且这里没有蜂窝网络\\N{\\fs12}Or a cell site for that matter, okay,\r\nDialogue: 0,0:05:58.09,0:06:01.13,yin,,0,0,0,,这时 我们就真的碰到麻烦了\\N{\\fs12}so now we're really stuck and the thing is\r\nDialogue: 0,0:06:01.13,0:06:04.48,yin,,0,0,0,,位置服务可以探测这种情况\\N{\\fs12}that the location services can detect that case,\r\nDialogue: 0,0:06:04.48,0:06:06.83,yin,,0,0,0,,它会汇报这个错误 网络\\N{\\fs12}and they'll actually report this error, network,\r\nDialogue: 0,0:06:06.83,0:06:10.34,yin,,0,0,0,,我们于是可以告诉用户 还是相同的基本错误\\N{\\fs12}and we can tell the person still we can't-- same basic error,\r\nDialogue: 0,0:06:10.34,0:06:12.70,yin,,0,0,0,,我们无法获悉照片是在哪拍的 但至少我们可以建议\\N{\\fs12}we can't figure out where the photo was taken, but at least we can suggest\r\nDialogue: 0,0:06:12.70,0:06:14.86,yin,,0,0,0,,请检验一下同网络的连接\\N{\\fs12}that they verify your connection to the network.\r\nDialogue: 0,0:06:14.86,0:06:17.89,yin,,0,0,0,,用户可能发现自己忘记开wifi了 然后打开wifi\\N{\\fs12}And oh, I forgot to turn wi-fi on, they turn wi-fi on, and oh,\r\nDialogue: 0,0:06:17.89,0:06:20.63,yin,,0,0,0,,这时就能找到位置了\\N{\\fs12}now it's able to figure out their location.\r\nDialogue: 0,0:06:20.63,0:06:24.28,yin,,0,0,0,,否则 我们就只打算一般性地警告一下\\N{\\fs12}And otherwise, we're just going to generically complain.\r\nDialogue: 0,0:06:24.28,0:06:26.48,yin,,0,0,0,,我们无法弄清位置\\N{\\fs12}That we couldn't figure it out.\r\nDialogue: 0,0:06:26.48,0:06:28.59,yin,,0,0,0,,我这里只是想讲一下\\N{\\fs12}So I just wanted to show you a little bit about getting\r\nDialogue: 0,0:06:28.59,0:06:32.67,yin,,0,0,0,,使用didFailWithError获得错误代码\\N{\\fs12}that error code using this didFailWithError thing.\r\nDialogue: 0,0:06:32.67,0:06:34.91,yin,,0,0,0,,一般而言 课上的demo中\\N{\\fs12}And in general, in demos that I do in this class,\r\nDialogue: 0,0:06:34.91,0:06:38.33,yin,,0,0,0,,我不会检查任何错误 这是出于时间考虑\\N{\\fs12}obviously I hardly check any errors, it's just a time thing.\r\nDialogue: 0,0:06:38.33,0:06:40.46,yin,,0,0,0,,你们应该在任何获得NSError的时候\\N{\\fs12}You should, any time you get an NS error back,\r\nDialogue: 0,0:06:40.46,0:06:41.82,yin,,0,0,0,,检查它到底是什么\\N{\\fs12}you should go check it and see what it is,\r\nDialogue: 0,0:06:41.82,0:06:43.51,yin,,0,0,0,,去查查说明文档\\N{\\fs12}and go look in the documentation and see what kind\r\nDialogue: 0,0:06:43.51,0:06:45.74,yin,,0,0,0,,看你得到什么错误 怎么处理它们\\N{\\fs12}of errors you could get back and what you should do about them.\r\nDialogue: 0,0:06:45.74,0:06:46.42,yin,,0,0,0,,总记得这样做\\N{\\fs12}Should always do that.\r\nDialogue: 0,0:06:46.42,0:06:49.86,yin,,0,0,0,,我在幻灯片中强调过 错误检查非常重要\\N{\\fs12}I try to emphasize in the slides when errors are really important to check,\r\nDialogue: 0,0:06:49.87,0:06:53.46,yin,,0,0,0,,一般而言 我们总应该检查错误\\N{\\fs12}but in general, we should always be checking those.\r\nDialogue: 0,0:06:53.46,0:06:55.97,yin,,0,0,0,,这就是这里我要讲的了\\N{\\fs12}So that's it, that's all I wanted to show you there.\r\nDialogue: 0,0:06:55.97,0:06:57.77,yin,,0,0,0,,回到幻灯片\\N{\\fs12}So back to our slides.\r\nDialogue: 0,0:06:57.77,0:06:59.31,yin,,0,0,0,,这方面有问题吗\\N{\\fs12}Any questions about that?\r\nDialogue: 0,0:06:59.31,0:06:59.84,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,0:07:07.33,0:07:09.96,yin,,0,0,0,,问题是 苹果是否提供服务\\N{\\fs12}So the question is, does Apple provide a service\r\nDialogue: 0,0:07:09.96,0:07:13.78,yin,,0,0,0,,让你能够对你获得的错误记录日志\\N{\\fs12}where you can like log the errors you get, for what purpose,\r\nDialogue: 0,0:07:13.78,0:07:17.31,yin,,0,0,0,,这样你就知道…\\N{\\fs12}to kind of so that they know what errors people are-- ?\r\nDialogue: 0,0:07:19.11,0:07:20.99,yin,,0,0,0,,哦 我懂你的意思了\\N{\\fs12}Oh, I see what you mean, so you want to--\r\nDialogue: 0,0:07:20.99,0:07:23.87,yin,,0,0,0,,你的app的用户有了错误\\N{\\fs12}you have customers for your app, and they're having errors,\r\nDialogue: 0,0:07:23.87,0:07:25.46,yin,,0,0,0,,你想知道这些\\N{\\fs12}and you want to find out about them.\r\nDialogue: 0,0:07:25.46,0:07:27.15,yin,,0,0,0,,苹果没有提供这种功能\\N{\\fs12}Apple doesn't provide that infrastructure,\r\nDialogue: 0,0:07:27.15,0:07:29.09,yin,,0,0,0,,不过有些第三方做了这个\\N{\\fs12}but there are plenty of third parties who do.\r\nDialogue: 0,0:07:29.09,0:07:32.18,yin,,0,0,0,,这些第三方的代码可以放到你的app中\\N{\\fs12}That basically provide code you put into your app\r\nDialogue: 0,0:07:32.18,0:07:34.22,yin,,0,0,0,,为此提供测量 不仅仅是错误\\N{\\fs12}that provide metrics, not just errors,\r\nDialogue: 0,0:07:34.22,0:07:36.02,yin,,0,0,0,,还有用户点某个键多少次\\N{\\fs12}but how many times did people click on this button?\r\nDialogue: 0,0:07:36.02,0:07:38.37,yin,,0,0,0,,用户去某个页面多少次 等等\\N{\\fs12}How many times did they go to this page, you know, et cetera,\r\nDialogue: 0,0:07:38.37,0:07:40.67,yin,,0,0,0,,你可以看到用户如何在使用你的app\\N{\\fs12}so you can see how people are using your app.\r\nDialogue: 0,0:07:40.67,0:07:42.46,yin,,0,0,0,,这其实很重要\\N{\\fs12}That's actually quite important.\r\nDialogue: 0,0:07:42.46,0:07:45.96,yin,,0,0,0,,不过显然 这不是这堂课的讨论范围\\N{\\fs12}Obviously beyond the scope of this app, or of this lecture,\r\nDialogue: 0,0:07:45.96,0:07:49.06,yin,,0,0,0,,不过我强烈建议app中进行一些测量\\N{\\fs12}to talk about it, but I really highly recommend putting metrics\r\nDialogue: 0,0:07:49.06,0:07:52.86,yin,,0,0,0,,这样你就能理解真正的用户如何使用你的app\\N{\\fs12}in your app so you really understand how your real users are actually using your app.\r\nDialogue: 0,0:07:52.86,0:07:56.21,yin,,0,0,0,,这样做工作量稍大一些 但很值得\\N{\\fs12}It's a little more work for you, but it's really worth it.\r\nDialogue: 0,0:07:56.21,0:08:00.26,yin,,0,0,0,,好 再来看摄像头\\N{\\fs12}Um, okay, so...the camera.\r\nDialogue: 0,0:08:00.26,0:08:05.86,yin,,0,0,0,,所有这些摄像头工作 以及将图像获取到app中\\N{\\fs12}So all this camera business and basically getting images\r\nDialogue: 0,0:08:05.86,0:08:09.36,yin,,0,0,0,,都由这个类完成 UIImagePickerController\\N{\\fs12}into your app is done with this class UIImagePickerController,\r\nDialogue: 0,0:08:09.36,0:08:10.57,yin,,0,0,0,,这是一个视图控制器\\N{\\fs12}which is a view controller.\r\nDialogue: 0,0:08:10.57,0:08:13.38,yin,,0,0,0,,一个UIViewController 你会把它放到屏幕上\\N{\\fs12}It's a UI view controller that you're going to put on screen,\r\nDialogue: 0,0:08:13.38,0:08:15.78,yin,,0,0,0,,可以是用模态 也可以是用弹窗\\N{\\fs12}either modally or in a popover,\r\nDialogue: 0,0:08:15.78,0:08:20.14,yin,,0,0,0,,取决于你是在iPad还是iPhone上\\N{\\fs12}depending on whether you're in iPad or iPhone, and you're--\r\nDialogue: 0,0:08:20.14,0:08:22.17,yin,,0,0,0,,这是你们第一次使用这样的视图控制器\\N{\\fs12}so this is the first time you're going to have a view controller\r\nDialogue: 0,0:08:22.17,0:08:24.11,yin,,0,0,0,,它不来自于故事板\\N{\\fs12}that didn't come out of a storyboard.\r\nDialogue: 0,0:08:24.11,0:08:26.28,yin,,0,0,0,,这个视图控制器你将需要alloc init\\N{\\fs12}This view controller you're going to alloc init, alright?\r\nDialogue: 0,0:08:26.28,0:08:28.46,yin,,0,0,0,,然后你想把它放到屏幕上\\N{\\fs12}And then you're going to want to put it on screen,\r\nDialogue: 0,0:08:28.46,0:08:31.22,yin,,0,0,0,,你需要使用几周前我讲过的这个方法\\N{\\fs12}so you're going to have to use this method that we did talk about weeks ago\r\nDialogue: 0,0:08:31.22,0:08:33.52,yin,,0,0,0,,当时我们讲到presenting view controller\\N{\\fs12}when we talked about presenting view controllers called\r\nDialogue: 0,0:08:33.52,0:08:35.74,yin,,0,0,0,,也就是presentViewController animated\\N{\\fs12}\"present view controller, animated.\"\r\nDialogue: 0,0:08:35.74,0:08:36.65,yin,,0,0,0,,completion\\N{\\fs12}Completion.\r\nDialogue: 0,0:08:36.65,0:08:38.49,yin,,0,0,0,,它还有一个完成block\\N{\\fs12}It's got a completion block as well.\r\nDialogue: 0,0:08:38.49,0:08:41.74,yin,,0,0,0,,这就是我们把这个放到屏幕上的方式\\N{\\fs12}And so that's how we're going to put this thing on screen.\r\nDialogue: 0,0:08:41.74,0:08:44.81,yin,,0,0,0,,present视图控制器的参数是一个视图控制器\\N{\\fs12}And the argument to present view controller is a view controller,\r\nDialogue: 0,0:08:44.81,0:08:47.13,yin,,0,0,0,,不是视图控制器的故事板标识符\\N{\\fs12}not a storyboard identifier for a view controller,\r\nDialogue: 0,0:08:47.13,0:08:49.98,yin,,0,0,0,,而是视图控制器的实例\\N{\\fs12}but an actual instance of a view controller.\r\nDialogue: 0,0:08:49.98,0:08:52.29,yin,,0,0,0,,然后iPad上\\N{\\fs12}And then the iPad you're probably going to put\r\nDialogue: 0,0:08:52.29,0:08:56.24,yin,,0,0,0,,使用摄像头时可能需要模态全屏\\N{\\fs12}the camera-- actually the iPad you probably put the camera up full-screen modally,\r\nDialogue: 0,0:08:56.24,0:08:58.05,yin,,0,0,0,,如果只是查照片库\\N{\\fs12}if you're just looking at the photo library, you're going\r\nDialogue: 0,0:08:58.05,0:09:00.42,yin,,0,0,0,,你可能就只需要弹窗\\N{\\fs12}to probably put that up in a popover.\r\nDialogue: 0,0:09:00.42,0:09:02.63,yin,,0,0,0,,这如何工作呢\\N{\\fs12}Alright, so how does this work?\r\nDialogue: 0,0:09:02.63,0:09:05.62,yin,,0,0,0,,你alloc init这个UIImagePickerController\\N{\\fs12}You alloc and init this UIImagePickerController,\r\nDialogue: 0,0:09:05.62,0:09:07.68,yin,,0,0,0,,设置它的委托 这是必需的\\N{\\fs12}you set it's delegate, you have to set it's delegate\r\nDialogue: 0,0:09:07.68,0:09:09.85,yin,,0,0,0,,否则什么信息都无法得到\\N{\\fs12}or you're not going to get any information out of it.\r\nDialogue: 0,0:09:09.85,0:09:12.74,yin,,0,0,0,,然后你可以进行配置 包括摄像头\\N{\\fs12}Then you configure it for what you want, the camera,\r\nDialogue: 0,0:09:12.74,0:09:14.38,yin,,0,0,0,,或照片库这些\\N{\\fs12}or photo library, things like that,\r\nDialogue: 0,0:09:14.38,0:09:17.37,yin,,0,0,0,,是否让用户在拍照后进行编辑\\N{\\fs12}whether you're going to let the user edit the photo after they take it.\r\nDialogue: 0,0:09:17.37,0:09:21.05,yin,,0,0,0,,然后present它 监听委托 当委托告诉你\\N{\\fs12}Then you present it, and listen to the delegate, and when the delegate tells you\r\nDialogue: 0,0:09:21.05,0:09:24.02,yin,,0,0,0,,用户取消了或拍了照片\\N{\\fs12}that the user has either canceled or taken a photo,\r\nDialogue: 0,0:09:24.02,0:09:26.52,yin,,0,0,0,,如果拍了照片 你就能获得图像数据\\N{\\fs12}then you, if they've taken a photo you get the image data,\r\nDialogue: 0,0:09:26.52,0:09:29.52,yin,,0,0,0,,如果取消了 你就知道事情完了\\N{\\fs12}and if they cancel you're like \"Okay well they're done.\"\r\nDialogue: 0,0:09:29.52,0:09:34.11,yin,,0,0,0,,在UIImagePickerController 用户可以做什么\\N{\\fs12}Alright? What the user can do in this UIImagePickerController,\r\nDialogue: 0,0:09:34.11,0:09:36.62,yin,,0,0,0,,取决于其硬件能做什么\\N{\\fs12}it depends on what their hardware can do.\r\nDialogue: 0,0:09:36.62,0:09:40.14,yin,,0,0,0,,几乎所有设备现在都有摄像头了\\N{\\fs12}Almost everything has a camera now, so you're usually--\r\nDialogue: 0,0:09:40.14,0:09:42.59,yin,,0,0,0,,这不成问题 isSourceTypeAvailable\\N{\\fs12}if this is going to be no problem, source type available,\r\nDialogue: 0,0:09:42.59,0:09:45.46,yin,,0,0,0,,摄像头 你将能够找到它\\N{\\fs12}camera, you're going to find it,\r\nDialogue: 0,0:09:45.46,0:09:47.74,yin,,0,0,0,,不过这个还是应该检查\\N{\\fs12}but you should always check this anyway.\r\nDialogue: 0,0:09:47.76,0:09:49.97,yin,,0,0,0,,养成好的习惯很有必要\\N{\\fs12}Just to kind of, to be good code,\r\nDialogue: 0,0:09:49.97,0:09:52.84,yin,,0,0,0,,你要调用UIImagePickerController\\N{\\fs12}you want to call this UIImagePickerController,\r\nDialogue: 0,0:09:52.84,0:09:54.59,yin,,0,0,0,,类方法是isSourceTypeAvailable\\N{\\fs12}class method is source type available,\r\nDialogue: 0,0:09:54.59,0:09:56.11,yin,,0,0,0,,上次的demo中我们其实做过\\N{\\fs12}and we actually did that in our demo last time.\r\nDialogue: 0,0:09:56.11,0:09:59.96,yin,,0,0,0,,记得吧 我们有一个类方法canAddPhoto\\N{\\fs12}Remember? We had that class method can add photo,\r\nDialogue: 0,0:09:59.96,0:10:01.54,yin,,0,0,0,,其中 我们检查以确保\\N{\\fs12}and in there we checked to make sure\r\nDialogue: 0,0:10:01.54,0:10:03.11,yin,,0,0,0,,摄像头实际可用\\N{\\fs12}that the camera was actually available,\r\nDialogue: 0,0:10:03.11,0:10:05.29,yin,,0,0,0,,这就是做法 用这个类方法\\N{\\fs12}so this is how you do it, just this class method,\r\nDialogue: 0,0:10:05.29,0:10:07.63,yin,,0,0,0,,来自UIImagePickerController\\N{\\fs12}UIImagePickerController.\r\nDialogue: 0,0:10:07.63,0:10:11.13,yin,,0,0,0,,知道摄像头可用之后 如果你想拍摄视频\\N{\\fs12}Once you know the camera is available, then if you want to take video,\r\nDialogue: 0,0:10:11.14,0:10:13.95,yin,,0,0,0,,那你就需要确保其摄像头可以拍视频\\N{\\fs12}you need to be able to make sure that camera can do video,\r\nDialogue: 0,0:10:13.95,0:10:17.10,yin,,0,0,0,,因为有些老设备上的摄像头不能拍视频\\N{\\fs12}because there are cameras in older devices that can't take video,\r\nDialogue: 0,0:10:17.10,0:10:18.44,yin,,0,0,0,,只能拍照片\\N{\\fs12}they can only take images.\r\nDialogue: 0,0:10:18.44,0:10:20.44,yin,,0,0,0,,做法是通过这个类方法\\N{\\fs12}And you do that with this class method,\r\nDialogue: 0,0:10:20.44,0:10:22.20,yin,,0,0,0,,availableMediaTypesForSourceType\\N{\\fs12}\"available media types for source type,\"\r\nDialogue: 0,0:10:22.20,0:10:23.83,yin,,0,0,0,,sourceType是摄像头\\N{\\fs12}and the source type is the camera.\r\nDialogue: 0,0:10:23.83,0:10:27.45,yin,,0,0,0,,它会告诉你 它会返回一个数组\\N{\\fs12}So it's going to tell you, what are, it's going to give you an array back\r\nDialogue: 0,0:10:27.45,0:10:29.28,yin,,0,0,0,,涉及到这个摄像头能做什么\\N{\\fs12}of what things this camera can do.\r\nDialogue: 0,0:10:29.28,0:10:32.34,yin,,0,0,0,,你会得到这两个常量或其中之一\\N{\\fs12}And you're only going to have one of two or both\r\nDialogue: 0,0:10:32.34,0:10:36.83,yin,,0,0,0,,一个是kUTTypeImage 一个是kUTTypeMovie\\N{\\fs12}of these two constants, UT type image, and UT type movie,\r\nDialogue: 0,0:10:36.83,0:10:38.76,yin,,0,0,0,,很不幸 这两个常量来自于\\N{\\fs12}unfortunately, these two constants come\r\nDialogue: 0,0:10:38.76,0:10:41.93,yin,,0,0,0,,MobileCoreServices/MobileCoreServices.h\\N{\\fs12}from MobileCoreServices, MobileCoreServices.h,\r\nDialogue: 0,0:10:41.94,0:10:43.49,yin,,0,0,0,,它们不在Foundation或UIKit中\\N{\\fs12}they're not in foundation or UI kits,\r\nDialogue: 0,0:10:43.49,0:10:46.14,yin,,0,0,0,,因此你需要明确导入这个\\N{\\fs12}so you have to explicitly import this thing.\r\nDialogue: 0,0:10:46.14,0:10:49.96,yin,,0,0,0,,你需要连入MobileCoreServices\\N{\\fs12}You've got to link in the MobileCoreServices,\r\nDialogue: 0,0:10:49.96,0:10:52.18,yin,,0,0,0,,不过在iOS7的新机制中\\N{\\fs12}but with the new mechanism in iOS7,\r\nDialogue: 0,0:10:52.18,0:10:55.00,yin,,0,0,0,,这个会自动地为你连入\\N{\\fs12}that should get linked in for you automatically.\r\nDialogue: 0,0:10:55.00,0:11:00.39,yin,,0,0,0,,很不幸 kUTTypeImage和kUTTypeMovie这两个常量\\N{\\fs12}And unfortunately, those two things, kUTType image and kUTType movie\r\nDialogue: 0,0:11:00.39,0:11:02.36,yin,,0,0,0,,并不是NSString\\N{\\fs12}are not NS strings,\r\nDialogue: 0,0:11:02.36,0:11:03.67,yin,,0,0,0,,它们是Core Foundation字符串\\N{\\fs12}they are core foundation strings,\r\nDialogue: 0,0:11:03.67,0:11:07.77,yin,,0,0,0,,几张幻灯片后 我们就会谈到如何在代码中处理这个\\N{\\fs12}so we'll talk about how we deal with that in our code in a couple slides here.\r\nDialogue: 0,0:11:07.77,0:11:11.68,yin,,0,0,0,,你还可以查到前置和后置摄像头\\N{\\fs12}You can also find out about front-facing versus rear-facing cameras,\r\nDialogue: 0,0:11:11.68,0:11:15.39,yin,,0,0,0,,硬件的各种细节内容都可以从\\N{\\fs12}all kinds of details about what your hardware has, just take a look\r\nDialogue: 0,0:11:15.39,0:11:18.88,yin,,0,0,0,,UIImagePickerController的说明文档中查到\\N{\\fs12}at the documentation for UIImagePickerController and you can find that all out.\r\nDialogue: 0,0:11:18.88,0:11:19.75,yin,,0,0,0,,有问题\\N{\\fs12}Is that a question?\r\nDialogue: 0,0:11:28.47,0:11:31.81,yin,,0,0,0,,视图控制器会提供UI\\N{\\fs12}Uh, the view controller will provide UI\r\nDialogue: 0,0:11:31.81,0:11:33.64,yin,,0,0,0,,让其从前置摄像头或后置摄像头选取\\N{\\fs12}for them to pick front camera or back camera,\r\nDialogue: 0,0:11:33.64,0:11:36.22,yin,,0,0,0,,不过你可以说 只让其自拍\\N{\\fs12}but you can also say only let them take a selfie, right?\r\nDialogue: 0,0:11:36.22,0:11:37.97,yin,,0,0,0,,你知道我说的什么吗\\N{\\fs12}Only for, or whatever, you know what I'm saying?\r\nDialogue: 0,0:11:37.97,0:11:40.19,yin,,0,0,0,,你可以这样决定 不过他们也有…\\N{\\fs12}You can just determine it, but they also have the--\r\nDialogue: 0,0:11:40.19,0:11:42.44,yin,,0,0,0,,如果你不决定 那么他们就能选择\\N{\\fs12}if you don't determine it, then they can choose.\r\nDialogue: 0,0:11:42.44,0:11:44.18,yin,,0,0,0,,答案是肯定的\\N{\\fs12}So the answer is yes.\r\nDialogue: 0,0:11:44.18,0:11:46.29,yin,,0,0,0,,好 下面这是\\N{\\fs12}Alright, so this is what it looks\r\nDialogue: 0,0:11:46.29,0:11:49.47,yin,,0,0,0,,ImagePickerController的配置\\N{\\fs12}like to configure the ImagePickerController here,\r\nDialogue: 0,0:11:49.47,0:11:51.97,yin,,0,0,0,,我创建了一个 设置了委托\\N{\\fs12}so I'm creating one, I'm setting my delegate,\r\nDialogue: 0,0:11:51.97,0:11:54.20,yin,,0,0,0,,检查源类型 看摄像头能不能…\\N{\\fs12}I'm checking the source type to see if the camera,\r\nDialogue: 0,0:11:54.20,0:11:57.42,yin,,0,0,0,,这里我要用视频 因此我要确保\\N{\\fs12}I want to do video here, so I'm going to make sure\r\nDialogue: 0,0:11:57.42,0:12:00.34,yin,,0,0,0,,它能拍视频 如果能拍 那就好了\\N{\\fs12}that it does video, and if it does, I'm ready to go.\r\nDialogue: 0,0:12:00.34,0:12:02.22,yin,,0,0,0,,这里是用一些代码\\N{\\fs12}So that's a summary of what I just said,\r\nDialogue: 0,0:12:02.22,0:12:05.49,yin,,0,0,0,,总结了一下我刚讲的几张幻灯片\\N{\\fs12}kind of in-code what I just said on the last few slides.\r\nDialogue: 0,0:12:05.49,0:12:11.49,yin,,0,0,0,,下面我们来谈谈kUTTypeImage和kUTTypeMovie\\N{\\fs12}Um, so let's talk about that kUTType movie and kUTType image,\r\nDialogue: 0,0:12:11.49,0:12:13.71,yin,,0,0,0,,它们是CFString\\N{\\fs12}they are CF strings.\r\nDialogue: 0,0:12:13.71,0:12:16.31,yin,,0,0,0,,你可以把它们转为NSString\\N{\\fs12}You can just cast them to NS strings.\r\nDialogue: 0,0:12:16.31,0:12:21.94,yin,,0,0,0,,Core Foundation和你们更熟悉的Foundation间\\N{\\fs12}There is a bridging mechanism between core foundation and foundation,\r\nDialogue: 0,0:12:21.94,0:12:23.18,yin,,0,0,0,,有很好的桥梁机制\\N{\\fs12}which is what you're used to.\r\nDialogue: 0,0:12:23.18,0:12:26.86,yin,,0,0,0,,这里在iOS6或7中 你可以进行强制类型转换\\N{\\fs12}And so you can just put this cast in here, and in iOS6 or 7,\r\nDialogue: 0,0:12:26.86,0:12:29.03,yin,,0,0,0,,这里可以自动给你转换类型\\N{\\fs12}they introduced a thing where it will even do this bridging\r\nDialogue: 0,0:12:29.03,0:12:32.55,yin,,0,0,0,,这里可以自动给你转换类型\\N{\\fs12}for you automatically in terms of arc and all that,\r\nDialogue: 0,0:12:32.55,0:12:34.64,yin,,0,0,0,,这里可以直接转换\\N{\\fs12}so you just need to cast that, it's just something you need\r\nDialogue: 0,0:12:34.64,0:12:39.81,yin,,0,0,0,,只需要将NSString *放到那两个之前即可\\N{\\fs12}to know, is to put the NS string star in front of those two types.\r\nDialogue: 0,0:12:39.81,0:12:42.86,yin,,0,0,0,,可编辑性 用户用摄像头拍照时\\N{\\fs12}Alright, editability-- so when someone takes a picture with the camera,\r\nDialogue: 0,0:12:42.86,0:12:44.21,yin,,0,0,0,,可以放大\\N{\\fs12}they can actually zoom in on it,\r\nDialogue: 0,0:12:44.21,0:12:47.06,yin,,0,0,0,,选择图像的某一部分\\N{\\fs12}and move around and pick what part of the image they want\r\nDialogue: 0,0:12:47.06,0:12:49.78,yin,,0,0,0,,并汇报回app 如果你允许的话\\N{\\fs12}to report back to your app, if you allow that.\r\nDialogue: 0,0:12:49.78,0:12:52.05,yin,,0,0,0,,允许这个需要使用allowsEditing\\N{\\fs12}And you have to allow that by saying allows editing\r\nDialogue: 0,0:12:52.05,0:12:54.65,yin,,0,0,0,,用到UIImagePickerController实例\\N{\\fs12}to your UIImagePickerController instance,\r\nDialogue: 0,0:12:54.65,0:12:57.87,yin,,0,0,0,,你还可以限制视频捕捉\\N{\\fs12}and you can also do things like limit the video capture\r\nDialogue: 0,0:12:57.87,0:13:01.92,yin,,0,0,0,,让其只能低画质拍摄 或是只能拍摄特定秒数\\N{\\fs12}to be low resolution or only a certain number of seconds, things like that.\r\nDialogue: 0,0:13:01.92,0:13:05.70,yin,,0,0,0,,UIImagePicker中的细节我不打算一一讲到\\N{\\fs12}So I'm not going to go through every single thing you can do in UIImagePicker,\r\nDialogue: 0,0:13:05.70,0:13:08.26,yin,,0,0,0,,不过flash方面 还有很多事情你可以做\\N{\\fs12}but there's tons and tons of stuff you can do with flash,\r\nDialogue: 0,0:13:08.26,0:13:10.83,yin,,0,0,0,,你可以控制很多东西\\N{\\fs12}all these other things you can control.\r\nDialogue: 0,0:13:10.83,0:13:14.83,yin,,0,0,0,,有了这个UIImagePickerController\\N{\\fs12}So then, you have this UIImagePickerController\r\nDialogue: 0,0:13:14.83,0:13:19.61,yin,,0,0,0,,你可以将自己实例化为它的委托 然后你可以present它\\N{\\fs12}that you've instantiated yourself as the delegate of, now you present it.\r\nDialogue: 0,0:13:19.61,0:13:24.17,yin,,0,0,0,,在iPad上 如果你没有提供摄像头\\N{\\fs12}And so on the iPad, if you're not offering the camera,\r\nDialogue: 0,0:13:24.17,0:13:27.26,yin,,0,0,0,,如果你… 抱歉 这里我们有些掩盖了真相\\N{\\fs12}so if you're-- sorry, we kind of glossed over this a little bit--\r\nDialogue: 0,0:13:27.26,0:13:30.46,yin,,0,0,0,,你可以让用户用摄像头拍照\\N{\\fs12}you can offer to get a picture from the camera,\r\nDialogue: 0,0:13:30.46,0:13:35.18,yin,,0,0,0,,也可以让用户从照片库中选照片\\N{\\fs12}or you can also offer the user to have a picture come from their photo library.\r\nDialogue: 0,0:13:35.18,0:13:39.38,yin,,0,0,0,,这就是设备上app中的管理方式\\N{\\fs12}Which is this thing they manage in app on their device.\r\nDialogue: 0,0:13:39.38,0:13:41.24,yin,,0,0,0,,你可以选两者或其中之一\\N{\\fs12}And so you can kind of pick either or both.\r\nDialogue: 0,0:13:41.24,0:13:43.40,yin,,0,0,0,,在iPhone上 你可以同时要两者\\N{\\fs12}On the iPhone, you can ask for both at the same time,\r\nDialogue: 0,0:13:43.40,0:13:47.49,yin,,0,0,0,,它会给出一个UI 用户可以在两者中进行选择\\N{\\fs12}so it will put up a UI where you can kind of-- the user can pick between the two.\r\nDialogue: 0,0:13:47.49,0:13:49.33,yin,,0,0,0,,在iPad上 你不会这样做\\N{\\fs12}On the iPad you don't do it that way.\r\nDialogue: 0,0:13:49.33,0:13:51.85,yin,,0,0,0,,在iPad上 要么是摄像头 要么是照片库\\N{\\fs12}On the iPad it's camera or photo library\r\nDialogue: 0,0:13:51.85,0:13:54.43,yin,,0,0,0,,因为照片库会放到弹窗中\\N{\\fs12}because the photo library you're going to bring up in a popover,\r\nDialogue: 0,0:13:54.43,0:13:57.00,yin,,0,0,0,,而摄像头则是全屏模态\\N{\\fs12}the camera you're probably going to do full-screen modal.\r\nDialogue: 0,0:13:57.00,0:14:00.87,yin,,0,0,0,,这就是通常不把两者同时混起来的原因\\N{\\fs12}So that's why you're usually not mixing them at the same time.\r\nDialogue: 0,0:14:00.87,0:14:04.88,yin,,0,0,0,,用户用摄像头拍照或是从照片库中选择照片后\\N{\\fs12}After the user has chosen a photo from by using the camera\r\nDialogue: 0,0:14:04.88,0:14:06.46,yin,,0,0,0,,用户用摄像头拍照或是从照片库中选择照片后\\N{\\fs12}or from their photo library,\r\nDialogue: 0,0:14:06.46,0:14:09.32,yin,,0,0,0,,你就会得到这个委托方法 imagePickerController\\N{\\fs12}you're going to get this delegate method, ImagePickerController,\r\nDialogue: 0,0:14:09.32,0:14:11.67,yin,,0,0,0,,didFinishPickingMediaWithInfo\\N{\\fs12}didFinishPickingMediaWithInfo.\r\nDialogue: 0,0:14:11.67,0:14:16.01,yin,,0,0,0,,然后你就要消掉那个视图控制器\\N{\\fs12}And you are then going to dismiss that view controller.\r\nDialogue: 0,0:14:16.01,0:14:20.22,yin,,0,0,0,,你需要手动消掉它\\N{\\fs12}So you have to manually dismiss it right here,\r\nDialogue: 0,0:14:20.22,0:14:21.96,yin,,0,0,0,,在消掉它之前\\N{\\fs12}but before you dismiss it, you're going to look\r\nDialogue: 0,0:14:21.96,0:14:25.35,yin,,0,0,0,,你需要看刚刚传递的信息字典\\N{\\fs12}into that dictionary that just passed, this info dictionary,\r\nDialogue: 0,0:14:25.35,0:14:30.32,yin,,0,0,0,,并获得关于摄像头的信息 关于用户拍了什么照片等等\\N{\\fs12}and get the information about what camera, what picture they took or whatever.\r\nDialogue: 0,0:14:30.32,0:14:32.92,yin,,0,0,0,,如果用户点了摄像头上的取消\\N{\\fs12}If they didn't, if they hit cancel on the camera,\r\nDialogue: 0,0:14:32.92,0:14:35.70,yin,,0,0,0,,那你就会得到imagePickerControllerDidCancel\\N{\\fs12}then you're just going to get this imagePickerControllerDidCancel,\r\nDialogue: 0,0:14:35.70,0:14:37.46,yin,,0,0,0,,这样就没有信息字典\\N{\\fs12}and there's no info dictionary there,\r\nDialogue: 0,0:14:37.46,0:14:39.54,yin,,0,0,0,,你无法获悉任何关于照片的信息\\N{\\fs12}so you don't get to find anything about the photo.\r\nDialogue: 0,0:14:40.48,0:14:42.95,yin,,0,0,0,,如果是在弹窗中 你就需要使用\\N{\\fs12}Again, if you're in a popover, you're going to use the\r\nDialogue: 0,0:14:42.95,0:14:45.68,yin,,0,0,0,,弹窗的didDismissPopover…委托方法\\N{\\fs12}popover did dismiss popover business,\r\nDialogue: 0,0:14:45.68,0:14:48.45,yin,,0,0,0,,你会做相同的事情\\N{\\fs12}you'll do the same thing.\r\nDialogue: 0,0:14:48.45,0:14:50.95,yin,,0,0,0,,返回的字典中有些什么呢\\N{\\fs12}So what's in that dictionary that you get back?\r\nDialogue: 0,0:14:50.95,0:14:53.44,yin,,0,0,0,,如果用户didFinishPickingMediaWithInfo\\N{\\fs12}So if the user did finish picking with info,\r\nDialogue: 0,0:14:53.44,0:14:54.62,yin,,0,0,0,,其中有什么呢\\N{\\fs12}what's in it,\r\nDialogue: 0,0:14:54.62,0:14:56.41,yin,,0,0,0,,有用户拍的照片\\N{\\fs12}there's the image that they took.\r\nDialogue: 0,0:14:56.41,0:14:59.45,yin,,0,0,0,,包括放大和裁剪后的图像\\N{\\fs12}Both the edited image, if they zoomed in and cropped it,\r\nDialogue: 0,0:14:59.45,0:15:01.36,yin,,0,0,0,,和没有编辑的原图\\N{\\fs12}and the original image, if they didn't--\r\nDialogue: 0,0:15:01.36,0:15:03.63,yin,,0,0,0,,和没有编辑的原图\\N{\\fs12}whether they did or not, the original image is in there.\r\nDialogue: 0,0:15:03.63,0:15:08.28,yin,,0,0,0,,如果有裁剪 它会告诉你是沿图像内哪个矩形裁剪的\\N{\\fs12}If they cropped it, it will tell you the rectangle inside the image that they cropped to.\r\nDialogue: 0,0:15:08.28,0:15:13.95,yin,,0,0,0,,如果是视频 你会得到视频文件的URL\\N{\\fs12}If it's a video, you're going to get a URL to a file, with the video in there.\r\nDialogue: 0,0:15:13.95,0:15:17.39,yin,,0,0,0,,这就是你得到视频的方式 文件URL\\N{\\fs12}So that's how video comes back to you, as a URL to some file.\r\nDialogue: 0,0:15:17.39,0:15:21.25,yin,,0,0,0,,得到了这些图像 如果你想保存它们\\N{\\fs12}And you can, if you get these images, and you want\r\nDialogue: 0,0:15:21.25,0:15:23.72,yin,,0,0,0,,例如存到用户的照片库\\N{\\fs12}to save them, like in the user's photo library,\r\nDialogue: 0,0:15:23.72,0:15:26.48,yin,,0,0,0,,这是ALAssetsLibrary中的API\\N{\\fs12}that's--  API is in AL assets library.\r\nDialogue: 0,0:15:26.48,0:15:28.46,yin,,0,0,0,,我不打算讲这个 不过API就在这里\\N{\\fs12}Not going to cover that, but that's where the API is,\r\nDialogue: 0,0:15:28.46,0:15:32.39,yin,,0,0,0,,如果你想把用户拍的照片存入到照片库\\N{\\fs12}if you want to save it into their photo library. Some picture they've taken.\r\nDialogue: 0,0:15:32.39,0:15:33.86,yin,,0,0,0,,和Photomania中一样 我们不打算做这个\\N{\\fs12}Like in PhotoMania, we're not going to do that,\r\nDialogue: 0,0:15:33.86,0:15:37.20,yin,,0,0,0,,我们会把它存入我们自己的数据库\\N{\\fs12}we're actually going to save it into our own database, but--\r\nDialogue: 0,0:15:37.20,0:15:40.55,yin,,0,0,0,,而且我们会把图像存入我们的文档目录\\N{\\fs12}and we're going to save our image into our documents directory,\r\nDialogue: 0,0:15:40.55,0:15:43.78,yin,,0,0,0,,不过我们也可以在照片库中做些什么\\N{\\fs12}but we could put things in the photo library as well.\r\nDialogue: 0,0:15:43.78,0:15:48.55,yin,,0,0,0,,摄像头可以有一个覆盖视图在它之上\\N{\\fs12}The camera can have an overlay view on top of it.\r\nDialogue: 0,0:15:48.55,0:15:50.46,yin,,0,0,0,,这是在它之上的视图\\N{\\fs12}This is a view that sits on top of it.\r\nDialogue: 0,0:15:50.46,0:15:52.55,yin,,0,0,0,,你还可以提供你自己的按钮\\N{\\fs12}You can even provide your own buttons for like\r\nDialogue: 0,0:15:52.55,0:15:55.28,yin,,0,0,0,,用于\"拍照\"这些\\N{\\fs12}\"take picture\" and things like that.\r\nDialogue: 0,0:15:55.28,0:15:57.98,yin,,0,0,0,,这只是一个视图\\N{\\fs12}This is just a view,\r\nDialogue: 0,0:15:57.98,0:16:01.27,yin,,0,0,0,,你还可以得到这个变形 看到底部了吗\\N{\\fs12}and you also are going to get this transform, see at the bottom there?\r\nDialogue: 0,0:16:01.27,0:16:03.47,yin,,0,0,0,,cameraViewTransform\\N{\\fs12}Camera view transform,\r\nDialogue: 0,0:16:03.47,0:16:09.25,yin,,0,0,0,,有时你可能希望用户拍的照片放大到全屏\\N{\\fs12}in case you want the image that the person's taking, for example, to be scaled\r\nDialogue: 0,0:16:09.25,0:16:13.92,yin,,0,0,0,,因为手机本身的纵横比有可能不同于照片\\N{\\fs12}up to full screen, because the aspect ratio of the phone\r\nDialogue: 0,0:16:13.92,0:16:16.94,yin,,0,0,0,,这样它就不能全屏显示\\N{\\fs12}itself is not the same as the camera, so it won't be full screen.\r\nDialogue: 0,0:16:16.94,0:16:18.65,yin,,0,0,0,,旁边会看到边框\\N{\\fs12}You'll see there will kind of be some borders around it,\r\nDialogue: 0,0:16:18.65,0:16:22.72,yin,,0,0,0,,有些人喜欢放大到全屏 这时可以变形\\N{\\fs12}when people like to zoom it up to full screen, you could do the transform to do that.\r\nDialogue: 0,0:16:22.72,0:16:24.43,yin,,0,0,0,,如果在覆盖视图中\\N{\\fs12}If, in your overlay view,\r\nDialogue: 0,0:16:24.43,0:16:26.32,yin,,0,0,0,,你要提供\"拍照\"按钮\\N{\\fs12}you provide the \"take picture\" button,\r\nDialogue: 0,0:16:26.32,0:16:28.88,yin,,0,0,0,,那么你就要说 \"显示摄像头控制 不\"\\N{\\fs12}then you want to say \"show camera controls, no\"\r\nDialogue: 0,0:16:28.88,0:16:31.44,yin,,0,0,0,,否则你就会从iOS获得拍照按钮\\N{\\fs12}otherwise you'll have the take picture button from iOS\r\nDialogue: 0,0:16:31.44,0:16:33.84,yin,,0,0,0,,还有你自己的拍照按钮\\N{\\fs12}and also your own take picture button.\r\nDialogue: 0,0:16:33.84,0:16:37.53,yin,,0,0,0,,覆盖 你们也可以离线去看这些\\N{\\fs12}So overlays, you can look those up offline as well.\r\nDialogue: 0,0:16:37.53,0:16:39.58,yin,,0,0,0,,demo中我不打算考虑\\N{\\fs12}We're not going to do those in the demo.\r\nDialogue: 0,0:16:39.58,0:16:43.64,yin,,0,0,0,,让我们把拍照这个环节加到Photomania中\\N{\\fs12}Let's go ahead and add this photo taking to PhotoMania.\r\nDialogue: 0,0:16:43.64,0:16:49.93,yin,,0,0,0,,这个动作表单 看看时间够不够再作考虑\\N{\\fs12}And this action sheet thing, we'll see how the time goes, whether we do the action sheet.\r\nDialogue: 0,0:16:49.93,0:16:51.93,yin,,0,0,0,,这是我们的Photomania\\N{\\fs12}Alright, so here we are in PhotoMania,\r\nDialogue: 0,0:16:51.93,0:16:57.11,yin,,0,0,0,,记得吧 让我们到这里\\N{\\fs12}and if you remember here, let's go ahead and go over here...\r\nDialogue: 0,0:16:57.12,0:17:02.29,yin,,0,0,0,,回想一下它是怎样的\\N{\\fs12}and remind ourselves what it looked like right now...\r\nDialogue: 0,0:17:11.45,0:17:16.50,yin,,0,0,0,,这是My Photos 我们还没有拍任何照片\\N{\\fs12}So we have our photos here, we haven't taken any photos yet.\r\nDialogue: 0,0:17:16.50,0:17:18.81,yin,,0,0,0,,但愿这是在后台加载\\N{\\fs12}Hopefully, this is probably loading in the background\r\nDialogue: 0,0:17:18.81,0:17:21.38,yin,,0,0,0,,好 有了 从Flickr\\N{\\fs12}as well, yeah, there it is, from Flickr.\r\nDialogue: 0,0:17:21.38,0:17:24.56,yin,,0,0,0,,看My Photos 里面什么都还没有\\N{\\fs12}But if I look at my photos, I can see I don't have any,\r\nDialogue: 0,0:17:24.56,0:17:26.02,yin,,0,0,0,,不过右上角有相机\\N{\\fs12}but I have the camera in the corner, so I'm going\r\nDialogue: 0,0:17:26.02,0:17:28.51,yin,,0,0,0,,点它 我们把照片放进来\\N{\\fs12}to press the camera, we put that photo in.\r\nDialogue: 0,0:17:28.51,0:17:30.28,yin,,0,0,0,,这里可以看到提示说\\N{\\fs12}And see you notice it saying \"PhotoMania would\r\nDialogue: 0,0:17:30.28,0:17:32.56,yin,,0,0,0,,Photomania要使用当前位置\\N{\\fs12}like to use your current location\" okay?\r\nDialogue: 0,0:17:32.56,0:17:34.86,yin,,0,0,0,,我点OK 如果我说不\\N{\\fs12}And I'm going to say \"Ok,\" if I said \"no,\"\r\nDialogue: 0,0:17:34.86,0:17:39.84,yin,,0,0,0,,这里或许就会出现致命错误 说我无法拍照\\N{\\fs12}we probably would have to put up this fatal error that says you can't take a picture.\r\nDialogue: 0,0:17:39.84,0:17:42.84,yin,,0,0,0,,这里我们想这样 看到拍照按钮了吗\\N{\\fs12}And what we want to do here is you see the \"take photo\" button?\r\nDialogue: 0,0:17:42.84,0:17:44.97,yin,,0,0,0,,我想按那个拍照按钮时\\N{\\fs12}I want to be able to press that \"take photo\" button\r\nDialogue: 0,0:17:44.97,0:17:47.92,yin,,0,0,0,,UIImagePickerController出现\\N{\\fs12}and have this UIImagePickerController come up.\r\nDialogue: 0,0:17:47.92,0:17:52.41,yin,,0,0,0,,这就是我们接下来要做的事\\N{\\fs12}So that's what we're going to do next.\r\nDialogue: 0,0:17:52.41,0:17:55.46,yin,,0,0,0,,拍照 我们其实已经关联起来了\\N{\\fs12}Alright, so take photo, we actually wired that up\r\nDialogue: 0,0:17:55.46,0:17:59.25,yin,,0,0,0,,在我们最开始的时候 放到哪里了\\N{\\fs12}when we very first started here, where did we put it?\r\nDialogue: 0,0:17:59.25,0:18:01.98,yin,,0,0,0,,在这里\\N{\\fs12}It is right...here.\r\nDialogue: 0,0:18:01.98,0:18:04.05,yin,,0,0,0,,它现在什么都做不了\\N{\\fs12}And it doesn't do anything right now.\r\nDialogue: 0,0:18:04.05,0:18:05.51,yin,,0,0,0,,这里我们需要做什么呢\\N{\\fs12}So what do we need to do here?\r\nDialogue: 0,0:18:05.51,0:18:07.50,yin,,0,0,0,,刚才幻灯片里我讲的所有那些事情\\N{\\fs12}All those things I just told you in this slide.\r\nDialogue: 0,0:18:07.50,0:18:10.65,yin,,0,0,0,,我们说 UIImagePickerController\\N{\\fs12}So let's do a UIImagePickerController,\r\nDialogue: 0,0:18:10.65,0:18:13.21,yin,,0,0,0,,uiipc\\N{\\fs12}UIImagePickerController, UI,\r\nDialogue: 0,0:18:13.21,0:18:18.44,yin,,0,0,0,,= UIImagePickerController alloc init\\N{\\fs12}image picker controller equals UIImagePickerController, alloc init.\r\nDialogue: 0,0:18:18.44,0:18:20.27,yin,,0,0,0,,这里只是alloc init\\N{\\fs12}So we just alloc init,\r\nDialogue: 0,0:18:20.27,0:18:23.95,yin,,0,0,0,,不需在初始化时指定任何其它东西\\N{\\fs12}there is no other thing we specify when we initialize it,\r\nDialogue: 0,0:18:23.95,0:18:25.57,yin,,0,0,0,,我们只需要做这些\\N{\\fs12}that's all we need to do.\r\nDialogue: 0,0:18:25.59,0:18:29.85,yin,,0,0,0,,然后 我们只需要设置这个UIImagePickerController\\N{\\fs12}And then we just need to set up this UIImagePickerController\r\nDialogue: 0,0:18:29.85,0:18:32.63,yin,,0,0,0,,来指定我们的选项\\N{\\fs12}to specify any options we have.\r\nDialogue: 0,0:18:32.63,0:18:37.19,yin,,0,0,0,,我们还需要把自己设置为委托\\N{\\fs12}And we also need to set ourselves as the delegate.\r\nDialogue: 0,0:18:37.19,0:18:38.55,yin,,0,0,0,,首先来做这个\\N{\\fs12}So I'm going to do that first.\r\nDialogue: 0,0:18:38.55,0:18:40.94,yin,,0,0,0,,你会看到这里很有趣\\N{\\fs12}And you're going to see something interesting about this.\r\nDialogue: 0,0:18:40.94,0:18:43.38,yin,,0,0,0,,我们知道 将自己设为委托后\\N{\\fs12}So we know that as soon as we set ourselves as a delegate,\r\nDialogue: 0,0:18:43.38,0:18:45.65,yin,,0,0,0,,我们会得到这个警告说\\N{\\fs12}we're going to get this warning that says\r\nDialogue: 0,0:18:45.66,0:18:49.10,yin,,0,0,0,,我们没有实现UIImagePickerControllerDelegate方法\\N{\\fs12}we don't implement the UIImagePickerControllerDelegate method.\r\nDialogue: 0,0:18:49.10,0:18:51.46,yin,,0,0,0,,注意 它还说 我们没有实现\\N{\\fs12}Notice it also says we don't implement the\r\nDialogue: 0,0:18:51.46,0:18:54.25,yin,,0,0,0,,UINavigationControllerDelegate\\N{\\fs12}UINavigationControllerDelegate.\r\nDialogue: 0,0:18:54.25,0:18:57.65,yin,,0,0,0,,对于UIImagePickerController 这很奇怪\\N{\\fs12}This is kind of a weird thing about the UIImagePickerController,\r\nDialogue: 0,0:18:57.65,0:19:00.78,yin,,0,0,0,,它继承自UINavigationController\\N{\\fs12}it inherits from UINavigationController,\r\nDialogue: 0,0:19:00.78,0:19:04.38,yin,,0,0,0,,因此它继承了那个委托方法 因此它需要\\N{\\fs12}so it inherits that delegate method, and so it requires\r\nDialogue: 0,0:19:04.38,0:19:07.67,yin,,0,0,0,,你成为两者的委托\\N{\\fs12}that you be a delegate for both.\r\nDialogue: 0,0:19:07.67,0:19:10.60,yin,,0,0,0,,因此我需要是NavigationControllerDelegate\\N{\\fs12}So I have to be NavigationControllerDelegate,\r\nDialogue: 0,0:19:10.60,0:19:13.83,yin,,0,0,0,,同时还是ImagePickerControllerDelegate\\N{\\fs12}and I have to be the ImagePickerControllerDelegate.\r\nDialogue: 0,0:19:13.83,0:19:17.15,yin,,0,0,0,,这两者都没有任何必需的方法\\N{\\fs12}Now neither of those things have any mandatory methods,\r\nDialogue: 0,0:19:17.15,0:19:21.08,yin,,0,0,0,,义务并不繁重 不过对于这个错误 很多人都会说\\N{\\fs12}so it's not that onerous but this is just an error that a lot of people are like, \"Huh?\r\nDialogue: 0,0:19:21.08,0:19:22.26,yin,,0,0,0,,为什么要说这个\\N{\\fs12}Why is it saying that?\"\r\nDialogue: 0,0:19:22.26,0:19:24.98,yin,,0,0,0,,这是UIImagePickerController方面很奇特的一点\\N{\\fs12}It's just a weird thing about UIImagePickerController,\r\nDialogue: 0,0:19:24.98,0:19:27.10,yin,,0,0,0,,你需要成为NavigationControllerDelegate\\N{\\fs12}you have to be a NavigationControllerDelegate.\r\nDialogue: 0,0:19:27.10,0:19:28.86,yin,,0,0,0,,你不需要实现任何方法\\N{\\fs12}You're not going to implement any of those methods,\r\nDialogue: 0,0:19:28.86,0:19:32.88,yin,,0,0,0,,你只需要实现那个协议\\N{\\fs12}just have to say you do implement that protocol.\r\nDialogue: 0,0:19:32.88,0:19:34.85,yin,,0,0,0,,现在 我们是委托\\N{\\fs12}So now we're the delegate, and we're going\r\nDialogue: 0,0:19:34.85,0:19:37.78,yin,,0,0,0,,我们等下会实现一些方法\\N{\\fs12}to implement a couple of those methods in a minute, but first,\r\nDialogue: 0,0:19:37.78,0:19:40.75,yin,,0,0,0,,不过首先 我要完成这个的配置\\N{\\fs12}I'm going to finish configuring this thing.\r\nDialogue: 0,0:19:40.75,0:19:41.72,yin,,0,0,0,,我还要做什么\\N{\\fs12}So what else am I going to do?\r\nDialogue: 0,0:19:41.72,0:19:44.86,yin,,0,0,0,,我要说 我想要怎样的媒体类型\\N{\\fs12}Well, I'm going to say what media types I want,\r\nDialogue: 0,0:19:44.86,0:19:48.54,yin,,0,0,0,,我唯一想要的媒体类型是图像\\N{\\fs12}and the only media type I want is an image.\r\nDialogue: 0,0:19:48.54,0:19:57.78,yin,,0,0,0,,我不需要视频 这里是kUTTypeImage\\N{\\fs12}I don't want video, so, kUTType what's it called, image? Image. Yeah.\r\nDialogue: 0,0:19:57.78,0:19:59.82,yin,,0,0,0,,这是一个数组\\N{\\fs12}So this is an array,\r\nDialogue: 0,0:19:59.83,0:20:04.00,yin,,0,0,0,,不过这里只有这一个东西 我进行了这个奇特的类型转换\\N{\\fs12}but the only one I'm putting in there is this one thing, and I'm doing this weird cast.\r\nDialogue: 0,0:20:04.00,0:20:07.62,yin,,0,0,0,,然后 这里我还要设置什么呢\\N{\\fs12}And then what else do I want to set up here?\r\nDialogue: 0,0:20:07.62,0:20:11.90,yin,,0,0,0,,我想要设置源类型 这里我要的是摄像头\\N{\\fs12}I want to set up the source type, which is I want the camera.\r\nDialogue: 0,0:20:11.90,0:20:17.95,yin,,0,0,0,,这是ImagePickerControllerSourceTypeCamera\\N{\\fs12}So this is ImagePickerController, SourceType, Camera.\r\nDialogue: 0,0:20:17.95,0:20:21.19,yin,,0,0,0,,这里我还可以说 竖线\\N{\\fs12}Now, I could also say here vertical bar\r\nDialogue: 0,0:20:21.19,0:20:25.38,yin,,0,0,0,,UIImagePickerSourceTypePhotoLibrary\\N{\\fs12}UIImagePicker SourceType PhotoLibrary.\r\nDialogue: 0,0:20:25.38,0:20:27.01,yin,,0,0,0,,在iPhone上 这没问题\\N{\\fs12}On the iPhone this would be fine,\r\nDialogue: 0,0:20:27.01,0:20:29.72,yin,,0,0,0,,UI可以让我选择这两个地方的任一个\\N{\\fs12}where the UI would let me choose from either of these two places.\r\nDialogue: 0,0:20:29.72,0:20:31.95,yin,,0,0,0,,我的demo机器上没有照片库\\N{\\fs12}I don't have anything in my photo library on my demo\r\nDialogue: 0,0:20:31.95,0:20:33.54,yin,,0,0,0,,这里可以说是有些浪费\\N{\\fs12}machine, so it's kind of a waste.\r\nDialogue: 0,0:20:33.54,0:20:35.63,yin,,0,0,0,,iPad上 我就需要分开做两个UI了\\N{\\fs12}And on the iPad I would have to do two separate UIs,\r\nDialogue: 0,0:20:35.63,0:20:38.34,yin,,0,0,0,,我就不能这样做了\\N{\\fs12}so I couldn't really do that there anyway.\r\nDialogue: 0,0:20:38.34,0:20:42.24,yin,,0,0,0,,我还要允许编辑 为什么不呢\\N{\\fs12}I'm also going to allow editing, why not?\r\nDialogue: 0,0:20:42.24,0:20:44.92,yin,,0,0,0,,allowsEditing = YES\\N{\\fs12}Allows editing equals yes, so that allows me to crop\r\nDialogue: 0,0:20:44.92,0:20:48.37,yin,,0,0,0,,这让我能对图像进行裁剪和缩放\\N{\\fs12}and zoom in, allows the user to crop and zoom in on the image.\r\nDialogue: 0,0:20:48.37,0:20:49.09,yin,,0,0,0,,就这些了\\N{\\fs12}And that's it.\r\nDialogue: 0,0:20:49.09,0:20:55.53,yin,,0,0,0,,然后我只需要使用presentViewController\\N{\\fs12}And now I just do this PresentViewController.\r\nDialogue: 0,0:20:55.53,0:20:57.43,yin,,0,0,0,,animated:YES\\N{\\fs12}Animated, yes.\r\nDialogue: 0,0:20:57.43,0:20:59.71,yin,,0,0,0,,completion 这个完成block\\N{\\fs12}Completion-- completion block, again,\r\nDialogue: 0,0:20:59.71,0:21:04.57,yin,,0,0,0,,会在viewDidAppear发生时立刻被调用 换言之\\N{\\fs12}it would get called as soon as the view did appear happened, so in other words,\r\nDialogue: 0,0:21:04.57,0:21:06.22,yin,,0,0,0,,它一到屏幕上 这个就会被调用\\N{\\fs12}once it was on screen, this would get called,\r\nDialogue: 0,0:21:06.22,0:21:08.21,yin,,0,0,0,,我甚至不需要做任何事情\\N{\\fs12}I don't need to do anything then.\r\nDialogue: 0,0:21:08.21,0:21:09.89,yin,,0,0,0,,这就完成了\\N{\\fs12}So we're done.\r\nDialogue: 0,0:21:09.89,0:21:13.41,yin,,0,0,0,,这会导致一个模态视图控制器出现\\N{\\fs12}So this is going to cause a modal view controller\r\nDialogue: 0,0:21:13.41,0:21:17.38,yin,,0,0,0,,它会占据屏幕 这将是相机\\N{\\fs12}to appear, and it takes over the screen, and it's going to be the camera,\r\nDialogue: 0,0:21:17.39,0:21:21.40,yin,,0,0,0,,用户可以选择是使用拍摄的照片\\N{\\fs12}and the user's either going to have the option of using the photo they take\r\nDialogue: 0,0:21:21.40,0:21:22.70,yin,,0,0,0,,还是点取消\\N{\\fs12}or hitting cancel.\r\nDialogue: 0,0:21:22.70,0:21:24.20,yin,,0,0,0,,两种情况我们都要处理\\N{\\fs12}So we have to handle both those cases.\r\nDialogue: 0,0:21:24.20,0:21:28.23,yin,,0,0,0,,首先来看取消这种情况 因为这很简单\\N{\\fs12}So let's do the cancel case first, because it's really easy.\r\nDialogue: 0,0:21:28.23,0:21:33.92,yin,,0,0,0,,我们可以用这个来做到\\N{\\fs12}And we do that with this one right here...this is right here,\r\nDialogue: 0,0:21:33.92,0:21:35.36,yin,,0,0,0,,imagePickerControllerDidCancel\\N{\\fs12}ImagePickerController DidCancel.\r\nDialogue: 0,0:21:35.36,0:21:38.62,yin,,0,0,0,,这里只有两个方法 有一个已经过时\\N{\\fs12}You can see there's only two methods here, there's an old deprecated one there,\r\nDialogue: 0,0:21:38.62,0:21:39.65,yin,,0,0,0,,这里只有两个方法 有一个已经过时\\N{\\fs12}but there's only these two.\r\nDialogue: 0,0:21:39.65,0:21:41.55,yin,,0,0,0,,我们将会实现这两个\\N{\\fs12}Those are the two we're going to implement.\r\nDialogue: 0,0:21:41.55,0:21:45.43,yin,,0,0,0,,在取消中 我们只需要消掉这个东西\\N{\\fs12}So in cancel, our only responsibility is to dismiss this thing.\r\nDialogue: 0,0:21:45.43,0:21:47.98,yin,,0,0,0,,因为我们不打算使用照片这些\\N{\\fs12}Because we're not going to use the photo or anything like that,\r\nDialogue: 0,0:21:47.98,0:21:50.63,yin,,0,0,0,,因此这里说dismiss…:YES 还是completion\\N{\\fs12}so I'm going to say dismiss, yes, completion again,\r\nDialogue: 0,0:21:50.63,0:21:52.94,yin,,0,0,0,,这里我不需要完成处理器\\N{\\fs12}I don't need the completion handler there.\r\nDialogue: 0,0:21:52.94,0:21:54.62,yin,,0,0,0,,这个很简单\\N{\\fs12}So that's an easy one.\r\nDialogue: 0,0:21:54.62,0:21:57.11,yin,,0,0,0,,然后是另一个\\N{\\fs12}And then the other one,\r\nDialogue: 0,0:21:57.11,0:22:01.27,yin,,0,0,0,,这个 这是didFinishPickingMediaWithInfo\\N{\\fs12}this guy...this is the DidFinishPickingMedia WithInfo,\r\nDialogue: 0,0:22:01.27,0:22:03.64,yin,,0,0,0,,我们有这个字典\\N{\\fs12}so we've got this dictionary right here,\r\nDialogue: 0,0:22:03.65,0:22:07.15,yin,,0,0,0,,提供用户选择的照片的信息\\N{\\fs12}that provides the information about the photo that the user chose.\r\nDialogue: 0,0:22:07.15,0:22:09.19,yin,,0,0,0,,这里用户确实选择了照片\\N{\\fs12}So the user did choose a photo in this case.\r\nDialogue: 0,0:22:09.19,0:22:10.15,yin,,0,0,0,,这个也很简单\\N{\\fs12}So this one's easy too.\r\nDialogue: 0,0:22:10.15,0:22:12.46,yin,,0,0,0,,我们只需要说image =\\N{\\fs12}We're just going to say image equals\r\nDialogue: 0,0:22:12.46,0:22:18.71,yin,,0,0,0,,info[UIImagePickerControllerEditedImage]\\N{\\fs12}info UIImagePickerController, edited image.\r\nDialogue: 0,0:22:18.71,0:22:22.89,yin,,0,0,0,,这是到这个字典中的键\\N{\\fs12}So this is a key into this dictionary.\r\nDialogue: 0,0:22:22.89,0:22:27.76,yin,,0,0,0,,这是编辑过的图像 UIImage被用户编辑过\\N{\\fs12}Right? And that's the edited image, the UI image the user edited.\r\nDialogue: 0,0:22:27.76,0:22:30.92,yin,,0,0,0,,我还要说 if (!image)\\N{\\fs12}Now, I'm also going to say if not image,\r\nDialogue: 0,0:22:30.92,0:22:32.51,yin,,0,0,0,,那么image就等于\\N{\\fs12}then the image equals\r\nDialogue: 0,0:22:32.51,0:22:36.94,yin,,0,0,0,,info[UIImagePickerControllerOriginalImage]\\N{\\fs12}the info UIImagePickerController original image.\r\nDialogue: 0,0:22:36.94,0:22:38.41,yin,,0,0,0,,为什么这样做呢\\N{\\fs12}Why am I doing this?\r\nDialogue: 0,0:22:38.41,0:22:40.75,yin,,0,0,0,,因为这里我允许编辑\\N{\\fs12}Because I allow editing right here.\r\nDialogue: 0,0:22:40.75,0:22:43.11,yin,,0,0,0,,我知道我会得到这张编辑过的图像\\N{\\fs12}So I know I'm going to get this edited image.\r\nDialogue: 0,0:22:43.11,0:22:48.17,yin,,0,0,0,,以后我可能会把这转为NO 这时我的代码就会中断\\N{\\fs12}Well, someday I might turn this to no, and then my code here would break.\r\nDialogue: 0,0:22:48.17,0:22:50.97,yin,,0,0,0,,我只是希望我的代码在两种情况下都能使用\\N{\\fs12}So I'm just trying to make code here that would work in either case.\r\nDialogue: 0,0:22:50.97,0:22:53.98,yin,,0,0,0,,这一行代码对我而言很轻松就能搞定\\N{\\fs12}It costs no skin off my nose to put this line of code in here,\r\nDialogue: 0,0:22:53.98,0:22:57.65,yin,,0,0,0,,而且这能让它转变为NO时也能工作\\N{\\fs12}and it will make it so if it ever changes to no, then this is going to still work.\r\nDialogue: 0,0:22:57.65,0:23:00.00,yin,,0,0,0,,就算我不这样 也不会有什么损失\\N{\\fs12}Doesn't hurt me if I don't.\r\nDialogue: 0,0:23:00.00,0:23:03.87,yin,,0,0,0,,我有了图像 下面我说 self.image = image\\N{\\fs12}Alright, so I got the image, so I'm just going to self.image equals image,\r\nDialogue: 0,0:23:03.87,0:23:06.64,yin,,0,0,0,,记得吧 我们设置过这个属性\\N{\\fs12}remember that we have this property set\r\nDialogue: 0,0:23:06.64,0:23:10.85,yin,,0,0,0,,我们实现了setter和getter 在这里\\N{\\fs12}that we implement the setter and getter for, which is right here.\r\nDialogue: 0,0:23:10.85,0:23:13.69,yin,,0,0,0,,这里设置了图像视图的图像\\N{\\fs12}Which is just setting the image view's image.\r\nDialogue: 0,0:23:13.69,0:23:16.05,yin,,0,0,0,,如果我们设置新东西\\N{\\fs12}If we're setting it to something new,\r\nDialogue: 0,0:23:16.05,0:23:20.75,yin,,0,0,0,,那么旧URL就要被删除 今天我已经演示过了\\N{\\fs12}then it's deleting the old URL, we showed that already today.\r\nDialogue: 0,0:23:20.75,0:23:28.46,yin,,0,0,0,,我们设置好图像 然后dismiss\\N{\\fs12}So...we set our image, and then we dismiss.\r\nDialogue: 0,0:23:31.35,0:23:32.81,yin,,0,0,0,,就是这样了\\N{\\fs12}And that's it.\r\nDialogue: 0,0:23:32.81,0:23:34.79,yin,,0,0,0,,使用摄像头是很简单的\\N{\\fs12}So using the camera, quite straightforward.\r\nDialogue: 0,0:23:34.79,0:23:37.17,yin,,0,0,0,,只要你理解了委托这些东西\\N{\\fs12}Once you understand that you have to do this delegate thing\r\nDialogue: 0,0:23:37.17,0:23:40.45,yin,,0,0,0,,来获得这里的结果 这就非常简单了\\N{\\fs12}to get the results out of there, it's pretty straightforward.\r\nDialogue: 0,0:23:40.45,0:23:42.75,yin,,0,0,0,,我们来试试这个\\N{\\fs12}So let's try and see if we can make this work.\r\nDialogue: 0,0:23:46.67,0:23:49.79,yin,,0,0,0,,这里要拍张照片\\N{\\fs12}Here something to take a picture of here.\r\nDialogue: 0,0:23:49.79,0:23:53.67,yin,,0,0,0,,到My Photos 到这里 拍张照片\\N{\\fs12}Alright, so we'll go to My Photos, I'm going to go here, and I'm going to take a photo.\r\nDialogue: 0,0:23:53.67,0:23:56.03,yin,,0,0,0,,我们会得到这个ImagePickerController\\N{\\fs12}We're going to get this ImagePickerController that's\r\nDialogue: 0,0:23:56.03,0:23:59.13,yin,,0,0,0,,它会模态式地出现 这是我的照片控制器\\N{\\fs12}going to come up Modally, so here's my picture controller,\r\nDialogue: 0,0:23:59.13,0:24:05.18,yin,,0,0,0,,2002 这有些老了 拍张它的照片\\N{\\fs12}2002, that's kind of old, but take it. So I'm just going to take this picture.\r\nDialogue: 0,0:24:05.18,0:24:08.15,yin,,0,0,0,,有点模糊 重新拍一张\\N{\\fs12}Alright? That's a little blurry, so I'll take another one.\r\nDialogue: 0,0:24:08.15,0:24:09.65,yin,,0,0,0,,这个好些了\\N{\\fs12}That's a little better.\r\nDialogue: 0,0:24:09.65,0:24:11.76,yin,,0,0,0,,我还可以放大\\N{\\fs12}And I could zoom in here, if I want.\r\nDialogue: 0,0:24:11.76,0:24:14.43,yin,,0,0,0,,剪切 因为我允许用户编辑\\N{\\fs12}Crop it, because I've allowed user editing, right?\r\nDialogue: 0,0:24:14.43,0:24:15.45,yin,,0,0,0,,我们可以这样\\N{\\fs12}So we can do that.\r\nDialogue: 0,0:24:15.47,0:24:18.30,yin,,0,0,0,,拍完照之后 点使用照片\\N{\\fs12}And then once I got it the way I want it, hit \"use photo\"\r\nDialogue: 0,0:24:18.30,0:24:20.82,yin,,0,0,0,,它就会返回到图像视图中\\N{\\fs12}and it comes back and sets in our image view.\r\nDialogue: 0,0:24:20.82,0:24:23.43,yin,,0,0,0,,这里我们还需要输入标题\\N{\\fs12}One thing we also need to do is put in a title there,\r\nDialogue: 0,0:24:23.43,0:24:26.87,yin,,0,0,0,,快速输个名字\\N{\\fs12}but that's...let's do that real quick.\r\nDialogue: 0,0:24:26.87,0:24:33.75,yin,,0,0,0,,Giants 好 有了\\N{\\fs12}Giants. Alright. Okay. There we go.\r\nDialogue: 0,0:24:33.75,0:24:37.59,yin,,0,0,0,,这是照片 这是我们的缩略图\\N{\\fs12}So now hopefully our photo, there's our thumbnail,\r\nDialogue: 0,0:24:37.59,0:24:40.47,yin,,0,0,0,,点击 可以看到细节\\N{\\fs12}if we click, we can see the detail of it.\r\nDialogue: 0,0:24:40.47,0:24:43.59,yin,,0,0,0,,这方面有问题吗\\N{\\fs12}Any questions about that?\r\nDialogue: 0,0:24:43.59,0:24:46.14,yin,,0,0,0,,很简单 摄像头这些东西\\N{\\fs12}It's pretty straightforward, the camera thing.\r\nDialogue: 0,0:24:46.14,0:24:48.87,yin,,0,0,0,,看还有多少时间\\N{\\fs12}Alright. Let's see what time we've got.\r\nDialogue: 0,0:24:48.89,0:24:52.60,yin,,0,0,0,,最后我会回头讲动作表单\\N{\\fs12}I'm going to come back to doing the action sheet at the end,\r\nDialogue: 0,0:24:52.60,0:24:55.99,yin,,0,0,0,,因为我想首先讲Core Motion\\N{\\fs12}because I really want to show you this other stuff first, the core motion stuff,\r\nDialogue: 0,0:24:55.99,0:24:58.33,yin,,0,0,0,,而动作表单 你们大部分是懂的\\N{\\fs12}and the action sheet, I think you mostly understand that,\r\nDialogue: 0,0:24:58.33,0:25:02.24,yin,,0,0,0,,因此 我们最后再回来考虑\\N{\\fs12}so we'll come back to this later.\r\nDialogue: 0,0:25:02.64,0:25:08.47,yin,,0,0,0,,回到幻灯片\\N{\\fs12}So let's go keynote here, okay.\r\nDialogue: 0,0:25:09.64,0:25:12.41,yin,,0,0,0,,好 Core Motion\\N{\\fs12}Alright. So core motion.\r\nDialogue: 0,0:25:12.41,0:25:16.28,yin,,0,0,0,,Core Motion是用于访问设备硬件的API\\N{\\fs12}So, core motion is the API for accessing the hardware\r\nDialogue: 0,0:25:16.28,0:25:19.27,yin,,0,0,0,,告诉你关于运动的信息\\N{\\fs12}on your device that tells you about motion.\r\nDialogue: 0,0:25:19.27,0:25:21.73,yin,,0,0,0,,设备上感觉运动的硬件其实有很多\\N{\\fs12}And there's a lot of different pieces of hardware,\r\nDialogue: 0,0:25:21.73,0:25:24.07,yin,,0,0,0,,设备上感觉运动的硬件其实有很多\\N{\\fs12}actually, that senses motion on your device,\r\nDialogue: 0,0:25:24.07,0:25:26.70,yin,,0,0,0,,有些设备的硬件比其它更多\\N{\\fs12}and some devices have more hardware than others.\r\nDialogue: 0,0:25:26.70,0:25:31.25,yin,,0,0,0,,适当地使用Core Motion能让你\\N{\\fs12}So a lot of using core motion properly is kind\r\nDialogue: 0,0:25:31.25,0:25:34.17,yin,,0,0,0,,理解设备有些什么 如何使用\\N{\\fs12}of understanding what your device has, and how you're going to use it,\r\nDialogue: 0,0:25:34.17,0:25:36.86,yin,,0,0,0,,如果没有相关硬件 你是否仍能做你想做的事\\N{\\fs12}and if it doesn't have things, can you still do what you want to do?\r\nDialogue: 0,0:25:36.86,0:25:39.25,yin,,0,0,0,,也许不能做得原来那么好 等等\\N{\\fs12}Maybe not quite as nicely, et cetera.\r\nDialogue: 0,0:25:39.25,0:25:43.53,yin,,0,0,0,,设备运动的主要输入包括加速计\\N{\\fs12}But, the primary inputs to where--\r\nDialogue: 0,0:25:43.53,0:25:46.46,yin,,0,0,0,,设备运动的主要输入包括加速计\\N{\\fs12}to the motion of your device, are the accelerometer,\r\nDialogue: 0,0:25:46.46,0:25:49.82,yin,,0,0,0,,它会告诉你设备的加速度\\N{\\fs12}which is just telling you the acceleration of your device,\r\nDialogue: 0,0:25:49.82,0:25:51.32,yin,,0,0,0,,在x y和z方向\\N{\\fs12}in X, Y, and Z.\r\nDialogue: 0,0:25:51.32,0:25:56.06,yin,,0,0,0,,陀螺仪 让你知道什么时候设备在旋转\\N{\\fs12}A gyro, which is letting the device know when it's being rotated,\r\nDialogue: 0,0:25:56.06,0:25:58.21,yin,,0,0,0,,这是很重要的信息\\N{\\fs12}which is an important thing for it to know,\r\nDialogue: 0,0:25:58.21,0:26:01.88,yin,,0,0,0,,还有磁力计 告诉你真北在哪\\N{\\fs12}and magnetometer, which is telling it \"where is true north?\"\r\nDialogue: 0,0:26:01.88,0:26:05.33,yin,,0,0,0,,实际上 它知道磁北在哪\\N{\\fs12}So really it knows where magnetic north is,\r\nDialogue: 0,0:26:05.33,0:26:10.07,yin,,0,0,0,,不过只要它知道GPS位置 它也能知道真北\\N{\\fs12}but if it knows your GPS location, then it knows where true north is as well.\r\nDialogue: 0,0:26:10.07,0:26:15.07,yin,,0,0,0,,用于获得这些设备信息的类\\N{\\fs12}So...the class that you use to get this information\r\nDialogue: 0,0:26:15.07,0:26:18.62,yin,,0,0,0,,叫作CMMotionManager\\N{\\fs12}about your device is called CM Motion Manager, kind of similar\r\nDialogue: 0,0:26:18.62,0:26:21.08,yin,,0,0,0,,有些类似于CLLocationManager\\N{\\fs12}to this CL Location Manager,\r\nDialogue: 0,0:26:21.08,0:26:24.33,yin,,0,0,0,,CLLocationManager让我知道设备处于什么地方\\N{\\fs12}which is how we got where the device is in the world,\r\nDialogue: 0,0:26:24.33,0:26:26.50,yin,,0,0,0,,CMMotionManager可以通过alloc init来创建\\N{\\fs12}and you create it just with alloc init.\r\nDialogue: 0,0:26:26.50,0:26:28.67,yin,,0,0,0,,这个需要稍微小心一些\\N{\\fs12}You have to be a little careful with this thing,\r\nDialogue: 0,0:26:28.67,0:26:31.82,yin,,0,0,0,,因为你不能在app中有两个不同的地方\\N{\\fs12}because you can't really have two different places in your app\r\nDialogue: 0,0:26:31.82,0:26:33.45,yin,,0,0,0,,alloc init这种东西\\N{\\fs12}alloc initting one of these things\r\nDialogue: 0,0:26:33.45,0:26:37.56,yin,,0,0,0,,并要求不同的信息率这些\\N{\\fs12}and asking for different information rates or something like that,\r\nDialogue: 0,0:26:37.56,0:26:40.70,yin,,0,0,0,,因为它汇报信息的频率\\N{\\fs12}because the rate at which it's going to report its information\r\nDialogue: 0,0:26:40.70,0:26:46.39,yin,,0,0,0,,需要在整个应用程序中都达成一致\\N{\\fs12}really is something that your whole application needs to be on the same page about.\r\nDialogue: 0,0:26:46.39,0:26:48.72,yin,,0,0,0,,你不希望应用中一个地方\\N{\\fs12}So you wouldn't want one place\r\nDialogue: 0,0:26:48.72,0:26:50.72,yin,,0,0,0,,获得信息非常非常快\\N{\\fs12}in your application getting data really really fast,\r\nDialogue: 0,0:26:50.72,0:26:53.74,yin,,0,0,0,,做一些微调得很好的事 而另一个地方很慢\\N{\\fs12}because it's doing some really fine-tuned thing, and the other wants it really slow,\r\nDialogue: 0,0:26:53.74,0:26:54.75,yin,,0,0,0,,这就会不同步\\N{\\fs12}and then they're kind of out of sync.\r\nDialogue: 0,0:26:54.75,0:26:57.13,yin,,0,0,0,,有些人会认为\\N{\\fs12}So some people would argue\r\nDialogue: 0,0:26:57.13,0:26:59.31,yin,,0,0,0,,CMMotionManager应该是全局的\\N{\\fs12}that CM Motion Manager should just be global.\r\nDialogue: 0,0:26:59.31,0:27:01.74,yin,,0,0,0,,应该在全局某处 有些类变量\\N{\\fs12}You should have some global somewhere, some class variable,\r\nDialogue: 0,0:27:01.74,0:27:03.72,yin,,0,0,0,,或是app委托这些\\N{\\fs12}or your app delegate or something.\r\nDialogue: 0,0:27:03.72,0:27:06.21,yin,,0,0,0,,我不知道有没有必要那样\\N{\\fs12}I don't know that that's strictly necessary to go\r\nDialogue: 0,0:27:06.21,0:27:09.42,yin,,0,0,0,,不过这里确实是很有争议的地方\\N{\\fs12}that far, but it is something where they can fight each other,\r\nDialogue: 0,0:27:09.42,0:27:12.33,yin,,0,0,0,,做这个时需要小心\\N{\\fs12}so you've got to be careful about doing that.\r\nDialogue: 0,0:27:12.33,0:27:14.65,yin,,0,0,0,,这是因为只有一台设备\\N{\\fs12}And that's just really because there's only one device,\r\nDialogue: 0,0:27:14.65,0:27:18.18,yin,,0,0,0,,而且只有一个陀螺仪和一个加速计\\N{\\fs12}and there's only one gyro and one accelerometer,\r\nDialogue: 0,0:27:18.18,0:27:22.33,yin,,0,0,0,,某种意义上讲 作为全局资源是有意义的\\N{\\fs12}and so it makes sense that this is a global resource, in a sense.\r\nDialogue: 0,0:27:22.33,0:27:24.24,yin,,0,0,0,,如何使用MotionManager呢\\N{\\fs12}So how to use the Motion Manager?\r\nDialogue: 0,0:27:24.24,0:27:26.22,yin,,0,0,0,,同LocationManager类似\\N{\\fs12}Just like Location Manager,\r\nDialogue: 0,0:27:26.22,0:27:29.09,yin,,0,0,0,,首先检查有什么硬件可用\\N{\\fs12}you check to see what hardware is available, then you kind\r\nDialogue: 0,0:27:29.09,0:27:32.14,yin,,0,0,0,,然后具体怎么做 有两种选项\\N{\\fs12}of have two choices to how you want to do it.\r\nDialogue: 0,0:27:32.14,0:27:34.67,yin,,0,0,0,,你可以进行一些取样\\N{\\fs12}You can set some sampling going,\r\nDialogue: 0,0:27:34.67,0:27:37.78,yin,,0,0,0,,然后对MotionManager进行poll(探寻)\\N{\\fs12}and then poll the Motion Manager.\r\nDialogue: 0,0:27:37.78,0:27:40.82,yin,,0,0,0,,例如 三个方向上 基于重力的当前加速度是多少\\N{\\fs12}What's the current acceleration due to gravity\r\nDialogue: 0,0:27:40.82,0:27:43.07,yin,,0,0,0,,例如 三个方向上 基于重力的当前加速度是多少\\N{\\fs12}in these three directions, for example.\r\nDialogue: 0,0:27:43.07,0:27:44.32,yin,,0,0,0,,我不喜欢poll\\N{\\fs12}Polling we don't like.\r\nDialogue: 0,0:27:44.32,0:27:47.23,yin,,0,0,0,,我有一张幻灯片讲过 我不赞成这样\\N{\\fs12}I have a slide on that, but you can see I'm going to blast right\r\nDialogue: 0,0:27:47.23,0:27:49.41,yin,,0,0,0,,因为poll不是很好\\N{\\fs12}by it, because polling-- not so good--\r\nDialogue: 0,0:27:49.41,0:27:54.84,yin,,0,0,0,,第二种方式是在队列上放一个block\\N{\\fs12}as the second way, which is that you basically put a block on a queue\r\nDialogue: 0,0:27:54.84,0:27:58.52,yin,,0,0,0,,按照你指定的频率被调用\\N{\\fs12}that will get called every time, at whatever rate you say,\r\nDialogue: 0,0:27:58.52,0:28:01.21,yin,,0,0,0,,告诉你 基于重力的当前加速度是多少\\N{\\fs12}to tell you here's the current acceleration to gravity, here's the current...\r\nDialogue: 0,0:28:01.21,0:28:02.57,yin,,0,0,0,,它会不断告诉你\\N{\\fs12}just tell you over and over and over,\r\nDialogue: 0,0:28:02.57,0:28:06.05,yin,,0,0,0,,你可以设置这个发生的频率 这是更好的做法\\N{\\fs12}and you can set the rate at which that's happening-- much better way to do that.\r\nDialogue: 0,0:28:06.05,0:28:09.90,yin,,0,0,0,,尤其是你可以让那个block在另一个队列上执行\\N{\\fs12}Especially since you can have that block be executing on another queue.\r\nDialogue: 0,0:28:09.90,0:28:12.09,yin,,0,0,0,,收集数据 进行合并等等\\N{\\fs12}Collecting the data, coalescing it, whatever,\r\nDialogue: 0,0:28:12.09,0:28:14.28,yin,,0,0,0,,然后回头同主队列通信\\N{\\fs12}and then communicating back to the main queue,\r\nDialogue: 0,0:28:14.28,0:28:17.22,yin,,0,0,0,,也许是以较低频率 这里它在更新UI\\N{\\fs12}maybe at a lower rate, where it's updating the UI.\r\nDialogue: 0,0:28:17.22,0:28:20.14,yin,,0,0,0,,这就是我们主要要关注的\\N{\\fs12}So mostly that's what we're going to focus on,\r\nDialogue: 0,0:28:20.14,0:28:23.07,yin,,0,0,0,,也就是发布一个block到队列\\N{\\fs12}is the way of posting a block to a queue.\r\nDialogue: 0,0:28:23.07,0:28:26.45,yin,,0,0,0,,如何检查可用性呢\\N{\\fs12}So how do you check the availability?\r\nDialogue: 0,0:28:26.45,0:28:30.25,yin,,0,0,0,,CMMotionManager中有这样的属性\\N{\\fs12}There is this property in CMMotionManager\r\nDialogue: 0,0:28:30.25,0:28:32.93,yin,,0,0,0,,叫accelerometerAvailable\\N{\\fs12}called accelerometer available,\r\nDialogue: 0,0:28:32.93,0:28:35.53,yin,,0,0,0,,gyroAvailable magnetometerAvailable\\N{\\fs12}gyro available, magnetometer available,\r\nDialogue: 0,0:28:35.53,0:28:38.06,yin,,0,0,0,,然后是非常重要的deviceMotionAvailable\\N{\\fs12}and then the very important device motion available,\r\nDialogue: 0,0:28:38.06,0:28:40.11,yin,,0,0,0,,等下我们会谈到这个\\N{\\fs12}and we will talk about that in a second.\r\nDialogue: 0,0:28:40.11,0:28:42.32,yin,,0,0,0,,如何开启这些感应器呢\\N{\\fs12}How do you start up these sensors?\r\nDialogue: 0,0:28:42.32,0:28:45.43,yin,,0,0,0,,如果你不调用startAccelerometerUpdates\\N{\\fs12}If you don't call start accelerometer updates,\r\nDialogue: 0,0:28:45.43,0:28:46.92,yin,,0,0,0,,它就不会给你任何更新\\N{\\fs12}it will not give you any updates.\r\nDialogue: 0,0:28:46.92,0:28:51.41,yin,,0,0,0,,poll时 你就不会得到任何最新信息\\N{\\fs12}And when you poll, you won't get any update-- any information that's up to date.\r\nDialogue: 0,0:28:51.41,0:28:53.07,yin,,0,0,0,,你需要开启它\\N{\\fs12}So you have to start it.\r\nDialogue: 0,0:28:53.07,0:28:56.48,yin,,0,0,0,,一般 我们不会这样在poll中开启它\\N{\\fs12}Now, normally we're not going to start it this way in poll,\r\nDialogue: 0,0:28:56.48,0:28:58.66,yin,,0,0,0,,我们会通过给它一个block来开启\\N{\\fs12}we're going to start it by giving it a block\r\nDialogue: 0,0:28:58.66,0:29:02.27,yin,,0,0,0,,以我们规定的频率进行调用\\N{\\fs12}to go call us every time, you know, at whatever rate.\r\nDialogue: 0,0:29:04.19,0:29:07.36,yin,,0,0,0,,总之 我们需要开启它 理解这一点很重要\\N{\\fs12}But we do need to start it. It's important to understand you have to start it.\r\nDialogue: 0,0:29:07.36,0:29:09.32,yin,,0,0,0,,不开启就无法获得数据\\N{\\fs12}If you don't start it, you get no data.\r\nDialogue: 0,0:29:09.33,0:29:10.70,yin,,0,0,0,,你还可以弄清\\N{\\fs12}You can also find out,\r\nDialogue: 0,0:29:10.70,0:29:12.61,yin,,0,0,0,,硬件当前在没在收集数据\\N{\\fs12}is the hardware currently collecting data?\r\nDialogue: 0,0:29:12.61,0:29:15.75,yin,,0,0,0,,换言之 加速计是否开启并在收集数据\\N{\\fs12}In other words, is the accelerometer on and collecting data?\r\nDialogue: 0,0:29:15.75,0:29:17.56,yin,,0,0,0,,陀螺仪是否开启并在收集数据\\N{\\fs12}Is the gyro on and collecting data?\r\nDialogue: 0,0:29:17.56,0:29:20.02,yin,,0,0,0,,这些也可以知道\\N{\\fs12}So you can find out that as well.\r\nDialogue: 0,0:29:20.02,0:29:22.59,yin,,0,0,0,,很重要的是 你也可以终止它这样做\\N{\\fs12}And very importantly, you can stop it doing this.\r\nDialogue: 0,0:29:22.59,0:29:24.01,yin,,0,0,0,,为什么说重要呢\\N{\\fs12}Why is that important?\r\nDialogue: 0,0:29:24.01,0:29:27.03,yin,,0,0,0,,因为这些东西的耗电量很大\\N{\\fs12}These things aren't free when it comes to battery.\r\nDialogue: 0,0:29:27.03,0:29:32.41,yin,,0,0,0,,测量加速度 陀螺仪测量 测量位置 这些都会耗电\\N{\\fs12}Measuring the acceleration, measuring the gyro, position, all of that, it takes power.\r\nDialogue: 0,0:29:32.41,0:29:34.53,yin,,0,0,0,,不用的时候 你需要关掉它\\N{\\fs12}And so you want to turn it off when you're not using it.\r\nDialogue: 0,0:29:34.53,0:29:36.99,yin,,0,0,0,,同CLLocationManager一样\\N{\\fs12}Just exactly like the CLLocationManager, right?\r\nDialogue: 0,0:29:36.99,0:29:39.05,yin,,0,0,0,,不使用时关掉它\\N{\\fs12}Turn it off when you're not using it.\r\nDialogue: 0,0:29:39.05,0:29:41.07,yin,,0,0,0,,这是poll\\N{\\fs12}So here's the polling thing.\r\nDialogue: 0,0:29:41.07,0:29:43.25,yin,,0,0,0,,这张幻灯片我不打算细讲\\N{\\fs12}I have this slide, we're not really going to look at it,\r\nDialogue: 0,0:29:43.25,0:29:45.91,yin,,0,0,0,,不过对于这每个 加速计 陀螺仪\\N{\\fs12}but for each of the things, accelerometer, gyro,\r\nDialogue: 0,0:29:45.91,0:29:47.83,yin,,0,0,0,,磁力计和设备运动都可以poll\\N{\\fs12}magnetometer, and device motion,\r\nDialogue: 0,0:29:47.83,0:29:51.78,yin,,0,0,0,,设备运动这个很神奇 我马上会讲到\\N{\\fs12}which is the magic one I'm going to talk about in a moment here, you can poll\r\nDialogue: 0,0:29:51.78,0:29:53.49,yin,,0,0,0,,你都可以问 当前状态是什么\\N{\\fs12}and say \"what's the current state of this?\"\r\nDialogue: 0,0:29:53.49,0:29:55.80,yin,,0,0,0,,但一般我们不这样做\\N{\\fs12}But you don't usually do that.\r\nDialogue: 0,0:29:55.82,0:29:58.38,yin,,0,0,0,,然后我要讲那个神奇的东西\\N{\\fs12}And now I'm going to talk about the magic thing\r\nDialogue: 0,0:29:58.38,0:30:01.18,yin,,0,0,0,,然后再谈论将block发布到队列\\N{\\fs12}before we talk about posting the blocks on the queues,\r\nDialogue: 0,0:30:01.18,0:30:03.88,yin,,0,0,0,,这里我要讲的是CMDeviceMotion\\N{\\fs12}which is CMDeviceMotion.\r\nDialogue: 0,0:30:03.90,0:30:06.62,yin,,0,0,0,,有了陀螺仪 加速计\\N{\\fs12}If you had a gyro and an accelerometer\r\nDialogue: 0,0:30:06.62,0:30:11.67,yin,,0,0,0,,还有磁力计 你就对设备的位置很了解了\\N{\\fs12}and a magnetometer, you really know a lot about this device's position.\r\nDialogue: 0,0:30:11.67,0:30:13.19,yin,,0,0,0,,很了解\\N{\\fs12}Really a lot!\r\nDialogue: 0,0:30:13.19,0:30:17.07,yin,,0,0,0,,实际上 你可以同时使用多个设备\\N{\\fs12}And in fact, you can use multiple of those devices together\r\nDialogue: 0,0:30:17.07,0:30:18.80,yin,,0,0,0,,来获得更好的信息\\N{\\fs12}to get better information.\r\nDialogue: 0,0:30:18.80,0:30:21.66,yin,,0,0,0,,例如 我们考虑加速\\N{\\fs12}For example, let's talk about acceleration.\r\nDialogue: 0,0:30:21.66,0:30:23.34,yin,,0,0,0,,这里有个加速计\\N{\\fs12}Really, there's an accelerometer in there,\r\nDialogue: 0,0:30:23.34,0:30:26.34,yin,,0,0,0,,它总是在测量由于重力的加速\\N{\\fs12}it's always measuring the acceleration due to gravity,\r\nDialogue: 0,0:30:26.34,0:30:28.52,yin,,0,0,0,,也就是9.8米每秒平方\\N{\\fs12}which is 9.8 meters per second squared.\r\nDialogue: 0,0:30:28.52,0:30:33.57,yin,,0,0,0,,如果你问原始加速计 该设备的当前加速度是多少\\N{\\fs12}So if you ask the raw accelerometer what's the current acceleration of this device?\r\nDialogue: 0,0:30:33.57,0:30:37.90,yin,,0,0,0,,它总会回答你说是 1g 指向地球的中心\\N{\\fs12}It's always going to give you 1 G down toward the center of the earth.\r\nDialogue: 0,0:30:37.90,0:30:39.99,yin,,0,0,0,,无论发生了什么\\N{\\fs12}No matter what's actually happening.\r\nDialogue: 0,0:30:39.99,0:30:43.00,yin,,0,0,0,,如果你像这样握住设备\\N{\\fs12}Now, if you are holding your device like this,\r\nDialogue: 0,0:30:43.00,0:30:46.75,yin,,0,0,0,,然后像这样 其它方向也会有加速度\\N{\\fs12}and you're going like this, you're also going to have acceleration in these other axes,\r\nDialogue: 0,0:30:46.75,0:30:49.48,yin,,0,0,0,,但加速计还是只有指向下面的那个\\N{\\fs12}but you're always going to have that one pointing down.\r\nDialogue: 0,0:30:49.48,0:30:53.32,yin,,0,0,0,,这就让你很难弄清\\N{\\fs12}So it's kind of like it's a little bit difficult for you\r\nDialogue: 0,0:30:53.32,0:30:56.86,yin,,0,0,0,,用户实际在用设备做什么\\N{\\fs12}to then figure out what's the user actually doing with my device?\r\nDialogue: 0,0:30:56.86,0:31:00.46,yin,,0,0,0,,因为你需要使用低通过滤器来滤出\\N{\\fs12}You see? Because you kind of have to filter out with like a low pass filter,\r\nDialogue: 0,0:31:00.47,0:31:02.33,yin,,0,0,0,,来自于重力的加速度\\N{\\fs12}the acceleration due to gravity.\r\nDialogue: 0,0:31:02.33,0:31:06.26,yin,,0,0,0,,如果有陀螺仪 你就不需要这样\\N{\\fs12}Well, you don't have to do that if you have a gyro.\r\nDialogue: 0,0:31:06.26,0:31:08.01,yin,,0,0,0,,因为只要有陀螺仪\\N{\\fs12}Because if you have a gyro,\r\nDialogue: 0,0:31:08.01,0:31:11.90,yin,,0,0,0,,你就知道设备现在有没有倾斜\\N{\\fs12}you know whether the device is tilted now.\r\nDialogue: 0,0:31:11.90,0:31:14.20,yin,,0,0,0,,知道有没有倾斜 你就能够剔除\\N{\\fs12}And since you know whether it's tilted, you can factor\r\nDialogue: 0,0:31:14.20,0:31:17.60,yin,,0,0,0,,基于重力的加速度在哪 明白了吗\\N{\\fs12}out where the acceleration due to gravity is, you see?\r\nDialogue: 0,0:31:17.60,0:31:23.87,yin,,0,0,0,,CMDeviceMotion是另一个你可以询问的东西\\N{\\fs12}Right? And so the CMDeviceMotion is another thing you can ask\r\nDialogue: 0,0:31:23.87,0:31:26.70,yin,,0,0,0,,就像你可以询问加速计和陀螺仪一样\\N{\\fs12}for, just like you can ask for the accelerometer or you can ask for the gyro,\r\nDialogue: 0,0:31:26.71,0:31:29.14,yin,,0,0,0,,你也可以询问这个神奇的CMDeviceMotion\\N{\\fs12}you can ask for this magic CMDeviceMotion,\r\nDialogue: 0,0:31:29.14,0:31:32.28,yin,,0,0,0,,它实际上是其它那些东西的融合\\N{\\fs12}it's actually a conglomeration of those other things.\r\nDialogue: 0,0:31:32.28,0:31:35.32,yin,,0,0,0,,例如 它可以告诉你\\N{\\fs12}And so for example it can tell you what is the\r\nDialogue: 0,0:31:35.32,0:31:38.24,yin,,0,0,0,,剔除重力后 加速度是多少\\N{\\fs12}acceleration of the device with gravity taken out.\r\nDialogue: 0,0:31:38.24,0:31:41.45,yin,,0,0,0,,CMDeviceMotion中有个属性叫userAcceleration\\N{\\fs12}So there's a property in the CMDeviceMotion called User Acceleration,\r\nDialogue: 0,0:31:41.45,0:31:45.48,yin,,0,0,0,,这是设备的加速度 不包括重力\\N{\\fs12}which is the acceleration of the device, not including gravity.\r\nDialogue: 0,0:31:45.48,0:31:48.00,yin,,0,0,0,,你可以弄清重力指向哪里\\N{\\fs12}You can also find out where gravity is pointing based\r\nDialogue: 0,0:31:48.00,0:31:49.68,yin,,0,0,0,,基于设备的当前朝向\\N{\\fs12}on the device's current orientation.\r\nDialogue: 0,0:31:49.68,0:31:56.99,yin,,0,0,0,,类似地 设备的旋转会有偏差\\N{\\fs12}Similarly, there's bias in there for rotation of the device.\r\nDialogue: 0,0:31:56.99,0:31:59.32,yin,,0,0,0,,这来自于设备的电子特性\\N{\\fs12}Bias due to electronics of the device.\r\nDialogue: 0,0:31:59.32,0:32:01.88,yin,,0,0,0,,也可以通过加速计来剔除\\N{\\fs12}That can be taken out using the accelerometer.\r\nDialogue: 0,0:32:01.88,0:32:06.09,yin,,0,0,0,,陀螺仪汇报信息可以得到加速计的辅助\\N{\\fs12}So the gyros reported information can also be helped\r\nDialogue: 0,0:32:06.09,0:32:08.67,yin,,0,0,0,,它们之间可以互相帮助\\N{\\fs12}by the accelerometer, so they kind of help each other,\r\nDialogue: 0,0:32:08.67,0:32:13.23,yin,,0,0,0,,你还可以得到设备位置的更精密信息\\N{\\fs12}and you can also get more sophisticated answers about the position of the device,\r\nDialogue: 0,0:32:13.23,0:32:15.29,yin,,0,0,0,,例如横滚 俯仰和偏向\\N{\\fs12}like roll, pitch and yaw.\r\nDialogue: 0,0:32:15.29,0:32:17.28,yin,,0,0,0,,都知道横滚 俯仰和偏向吗\\N{\\fs12}You all know what roll, pitch and yaw is?\r\nDialogue: 0,0:32:17.28,0:32:21.93,yin,,0,0,0,,横滚是这样 偏向是这样 俯仰是这样\\N{\\fs12}Roll is this way, yaw is like this, pitch is like this.\r\nDialogue: 0,0:32:21.93,0:32:25.11,yin,,0,0,0,,你可以获得所有这些信息 这就像是一架飞机一样\\N{\\fs12}So now you really can find out where, like almost this is an airplane, right?\r\nDialogue: 0,0:32:25.11,0:32:28.01,yin,,0,0,0,,你可以发现空间中的横滚 俯仰和偏向\\N{\\fs12}You can find it's roll, pitch and yaw in space.\r\nDialogue: 0,0:32:28.01,0:32:31.79,yin,,0,0,0,,这些都能够知道 只要你知道重力在哪\\N{\\fs12}And those are all possible when you know where gravity is,\r\nDialogue: 0,0:32:31.79,0:32:33.06,yin,,0,0,0,,真北在哪\\N{\\fs12}if you know where true north is,\r\nDialogue: 0,0:32:33.06,0:32:35.45,yin,,0,0,0,,你有一个参考点 等等\\N{\\fs12}you kind of have a reference point, all those things.\r\nDialogue: 0,0:32:35.45,0:32:37.67,yin,,0,0,0,,CMDeviceMotion的作用就是\\N{\\fs12}So CMDeviceMotion, that's where you're going\r\nDialogue: 0,0:32:37.67,0:32:43.32,yin,,0,0,0,,在空间中进行精密的位置分析\\N{\\fs12}to do any sophisticated analysis of things to position in space.\r\nDialogue: 0,0:32:43.32,0:32:47.40,yin,,0,0,0,,你们可以去看说明文档 里面有各种属性\\N{\\fs12}And you can go look at the documentation, you can see already right there some\r\nDialogue: 0,0:32:47.40,0:32:51.75,yin,,0,0,0,,包括横滚 俯仰和偏向 旋转率 用户加速度\\N{\\fs12}of the properties you can get, roll, pitch and yaw, rotation rate, user acceleration.\r\nDialogue: 0,0:32:51.75,0:32:54.24,yin,,0,0,0,,所有这些都来自于CMDeviceMotion\\N{\\fs12}All those things come out of a CMDeviceMotion.\r\nDialogue: 0,0:32:54.24,0:32:57.19,yin,,0,0,0,,如果你在一个没有陀螺仪的设备上\\N{\\fs12}Now, if you're on a device that doesn't have a gyro,\r\nDialogue: 0,0:32:57.19,0:32:58.82,yin,,0,0,0,,CMDeviceMotion还在\\N{\\fs12}the CMDeviceMotion is going to be there,\r\nDialogue: 0,0:32:58.82,0:33:02.18,yin,,0,0,0,,有些东西会给你未确定的结果\\N{\\fs12}but some things are going to give you unspecified results,\r\nDialogue: 0,0:33:02.18,0:33:04.57,yin,,0,0,0,,例如用户加速度就无法确定\\N{\\fs12}like user acceleration can't be determined\r\nDialogue: 0,0:33:04.57,0:33:06.71,yin,,0,0,0,,没有陀螺仪的设备就是这样了\\N{\\fs12}on a device where there's no gyro.\r\nDialogue: 0,0:33:06.71,0:33:08.93,yin,,0,0,0,,它会给你重力加速度\\N{\\fs12}It will give you the acceleration due to gravity,\r\nDialogue: 0,0:33:08.93,0:33:11.35,yin,,0,0,0,,但你得不到用户加速度\\N{\\fs12}but can't give you the user acceleration.\r\nDialogue: 0,0:33:11.35,0:33:12.55,yin,,0,0,0,,你需要知道\\N{\\fs12}So you have to know.\r\nDialogue: 0,0:33:12.55,0:33:15.43,yin,,0,0,0,,这就是你需要检查设备有些什么的原因\\N{\\fs12}That's why you have to check what your device has.\r\nDialogue: 0,0:33:17.38,0:33:20.19,yin,,0,0,0,,如何做block这些呢\\N{\\fs12}So...how do we do this block thing?\r\nDialogue: 0,0:33:20.19,0:33:26.57,yin,,0,0,0,,我想要开启我的设备 检查加速计的情况\\N{\\fs12}So I want to start my device, checking what is going on with the accelerometer,\r\nDialogue: 0,0:33:26.57,0:33:29.54,yin,,0,0,0,,我想要它汇报给我 发生了什么\\N{\\fs12}and I want it to report to me what's going on.\r\nDialogue: 0,0:33:29.54,0:33:31.54,yin,,0,0,0,,做法是 我会给它一个block\\N{\\fs12}And the way I do that is I give it a block,\r\nDialogue: 0,0:33:31.54,0:33:35.01,yin,,0,0,0,,一个CMAccelerometerHandler block 这里\\N{\\fs12}a CM Accelerometer Handler block right there.\r\nDialogue: 0,0:33:35.01,0:33:37.82,yin,,0,0,0,,看它是如何定义的 它有一个参数\\N{\\fs12}You can see how it's defined, it takes an argument,\r\nDialogue: 0,0:33:37.82,0:33:42.46,yin,,0,0,0,,这是CMAcceleratorData 然后还有这个错误\\N{\\fs12}which is the CM Accelerator data, and in this error,\r\nDialogue: 0,0:33:42.46,0:33:47.00,yin,,0,0,0,,它会按照你指定的频率不断调用这个block\\N{\\fs12}and it just keeps calling that block over and over at whatever rate you tell it to.\r\nDialogue: 0,0:33:47.00,0:33:49.22,yin,,0,0,0,,下一张幻灯片上我会具体说明如何设置\\N{\\fs12}And we'll talk about how you set that on the next slide.\r\nDialogue: 0,0:33:49.22,0:33:50.89,yin,,0,0,0,,这可以用于加速计更新\\N{\\fs12}And you can do that for accelerometer updates,\r\nDialogue: 0,0:33:50.89,0:33:55.25,yin,,0,0,0,,可以用于陀螺仪更新 也可以用于设备运动\\N{\\fs12}you can do it for gyro updates, you can do it for device motion as well.\r\nDialogue: 0,0:33:55.25,0:33:58.89,yin,,0,0,0,,横滚 俯仰和偏向这些 也能通过这个得到\\N{\\fs12}That roll, pitch and yaw, all that, it will tell you that.\r\nDialogue: 0,0:33:58.89,0:34:02.41,yin,,0,0,0,,不能再简单了 你只用调用这个方法\\N{\\fs12}So couldn't be simpler, you just call this method\r\nDialogue: 0,0:34:02.41,0:34:06.16,yin,,0,0,0,,startAccelerometer或GyroUpdatesToQueue\\N{\\fs12}start, accelerometer or gyro, updates to queue,\r\nDialogue: 0,0:34:06.16,0:34:07.57,yin,,0,0,0,,你给它一个队列\\N{\\fs12}you give it a queue.\r\nDialogue: 0,0:34:07.57,0:34:12.33,yin,,0,0,0,,这个队列 如果你要它更新的频率很低\\N{\\fs12}Now, that queue, if your rate at which you're asking it\r\nDialogue: 0,0:34:12.33,0:34:15.41,yin,,0,0,0,,你可以把它设为主队列\\N{\\fs12}to tell you is pretty low, that can be the main queue.\r\nDialogue: 0,0:34:15.41,0:34:16.91,yin,,0,0,0,,什么叫低呢\\N{\\fs12}And what do I mean by low?\r\nDialogue: 0,0:34:16.91,0:34:20.39,yin,,0,0,0,,你可以自己判断 如果是60次每秒\\N{\\fs12}Well, use your best judgment, I mean 60 times a second?\r\nDialogue: 0,0:34:20.39,0:34:22.31,yin,,0,0,0,,这就会push主队列\\N{\\fs12}That's going to be pushing the main queue.\r\nDialogue: 0,0:34:22.31,0:34:24.18,yin,,0,0,0,,10次每秒 没问题\\N{\\fs12}Ten times a second, no problem.\r\nDialogue: 0,0:34:24.18,0:34:27.03,yin,,0,0,0,,取决于你在block中做什么\\N{\\fs12}It depends on what you're doing in that block.\r\nDialogue: 0,0:34:27.03,0:34:30.64,yin,,0,0,0,,但愿你没有做代价很高的图像运算\\N{\\fs12}Hopefully you're not doing some very, very expensive graphics operation.\r\nDialogue: 0,0:34:30.64,0:34:32.89,yin,,0,0,0,,不过 你可以把这设为主队列\\N{\\fs12}But you could make that the main queue.\r\nDialogue: 0,0:34:32.89,0:34:35.56,yin,,0,0,0,,你也可以把这设为别的队列\\N{\\fs12}Or you could make that be some other queue.\r\nDialogue: 0,0:34:35.56,0:34:38.64,yin,,0,0,0,,然后合并事件 然后派回到\\N{\\fs12}And then coalesce events, and then just dispatch back\r\nDialogue: 0,0:34:38.64,0:34:42.30,yin,,0,0,0,,主队列 来进行UI更新\\N{\\fs12}to the main queue whenever you want to do the UI updating.\r\nDialogue: 0,0:34:42.30,0:34:45.65,yin,,0,0,0,,这个block的调用有多频繁呢\\N{\\fs12}So how often does this block get called?\r\nDialogue: 0,0:34:45.65,0:34:48.24,yin,,0,0,0,,顺便提下 这是设备运动的那些\\N{\\fs12}This is the device motion ones, by the way.\r\nDialogue: 0,0:34:48.24,0:34:51.28,yin,,0,0,0,,设备运动知道很多信息 它还可以有\\N{\\fs12}Device Motion knows so much information it can actually have\r\nDialogue: 0,0:34:51.28,0:34:56.47,yin,,0,0,0,,一个关于z轴和xy轴在哪的参考系\\N{\\fs12}a reference frame about where's Z axis and X and Y axis,\r\nDialogue: 0,0:34:56.47,0:34:58.58,yin,,0,0,0,,你也可以自己去查这些\\N{\\fs12}and all that, so you can look that up as well.\r\nDialogue: 0,0:34:58.58,0:35:01.82,yin,,0,0,0,,不过这里方式还是一样的 放一个block在队列上\\N{\\fs12}But it's the same way, though, in terms of you just put a block on the queue\r\nDialogue: 0,0:35:01.82,0:35:05.04,yin,,0,0,0,,设备运动产生变化时 它就会告诉你\\N{\\fs12}and when device motion has changes, it's going to tell you.\r\nDialogue: 0,0:35:05.04,0:35:06.90,yin,,0,0,0,,所有这些情形下\\N{\\fs12}So in all these cases,\r\nDialogue: 0,0:35:06.90,0:35:09.58,yin,,0,0,0,,你都要设置block被调用的时间区间\\N{\\fs12}you set the interval at which it's going to call your block\r\nDialogue: 0,0:35:09.58,0:35:11.84,yin,,0,0,0,,使用这个UpdateInterval属性\\N{\\fs12}using this update interval property.\r\nDialogue: 0,0:35:11.84,0:35:14.11,yin,,0,0,0,,这个可以用于加速计 陀螺仪\\N{\\fs12}So whether you're doing accelerometer, gyro,\r\nDialogue: 0,0:35:14.11,0:35:16.70,yin,,0,0,0,,磁力计和设备运动 你只需要设置时间区间\\N{\\fs12}magnetometer, device motion, you just set the interval.\r\nDialogue: 0,0:35:16.70,0:35:19.90,yin,,0,0,0,,以秒计算 如果你希望是10次每秒\\N{\\fs12}This is in seconds, so if you want it 10 times a second,\r\nDialogue: 0,0:35:19.90,0:35:24.75,yin,,0,0,0,,这里就可以设为0.1 如果你想20次每秒 那就是0.05\\N{\\fs12}you would say 0.1, if you want 20 times a second, 0.05.\r\nDialogue: 0,0:35:24.75,0:35:27.07,yin,,0,0,0,,这些东西可以有多频繁呢\\N{\\fs12}How often can these things go?\r\nDialogue: 0,0:35:27.07,0:35:28.08,yin,,0,0,0,,这里有限制\\N{\\fs12}There are limits.\r\nDialogue: 0,0:35:28.08,0:35:31.17,yin,,0,0,0,,这些东西无法一秒钟汇报一千次\\N{\\fs12}These things can't report thousand times a second,\r\nDialogue: 0,0:35:31.17,0:35:33.95,yin,,0,0,0,,一秒钟一千次你可能也做不了什么\\N{\\fs12}probably you couldn't do much with 1,000 times a second,\r\nDialogue: 0,0:35:33.95,0:35:36.48,yin,,0,0,0,,你在UI中无法作出反应\\N{\\fs12}you couldn't respond in the UI or anything to that.\r\nDialogue: 0,0:35:36.48,0:35:40.22,yin,,0,0,0,,我想 这些东西只能到60赫兹\\N{\\fs12}I think most of these things are around 60 Hz.\r\nDialogue: 0,0:35:40.22,0:35:44.48,yin,,0,0,0,,60次每秒或许就是这里的极限了\\N{\\fs12}60 times a second, probably about the maximum you're going to get out of them.\r\nDialogue: 0,0:35:44.48,0:35:48.62,yin,,0,0,0,,说明文档中可能没有专门说\\N{\\fs12}I don't think the documentation specifically says.\r\nDialogue: 0,0:35:48.62,0:35:52.21,yin,,0,0,0,,这里可以有多个处理器block\\N{\\fs12}It is okay to have multiple handler blocks.\r\nDialogue: 0,0:35:52.21,0:35:54.56,yin,,0,0,0,,也就是说 你可以调用startAccelerometerUpdates\\N{\\fs12}In other words, to call start accelerometer updates\r\nDialogue: 0,0:35:54.56,0:35:55.96,yin,,0,0,0,,带block 给它一个block\\N{\\fs12}with block, give it a block,\r\nDialogue: 0,0:35:55.97,0:35:57.39,yin,,0,0,0,,之后再在别处\\N{\\fs12}and then later somewhere else,\r\nDialogue: 0,0:35:57.39,0:35:59.87,yin,,0,0,0,,startAccelerometerUpdates 带block\\N{\\fs12}start accelerator updates with block\r\nDialogue: 0,0:35:59.87,0:36:01.19,yin,,0,0,0,,再给另外一个block\\N{\\fs12}and give it a different block,\r\nDialogue: 0,0:36:01.19,0:36:03.19,yin,,0,0,0,,两个block都会被调用\\N{\\fs12}and both of those blocks will get called.\r\nDialogue: 0,0:36:03.19,0:36:04.88,yin,,0,0,0,,调用频率也相同\\N{\\fs12}They're both going to get called at the same rate,\r\nDialogue: 0,0:36:04.88,0:36:07.26,yin,,0,0,0,,这个更新时间区间\\N{\\fs12}this update interval, but two different--\r\nDialogue: 0,0:36:07.26,0:36:10.67,yin,,0,0,0,,但每个时间区间内 你可以做两件不同的事\\N{\\fs12}you could be doing two different things every time this interval happens.\r\nDialogue: 0,0:36:10.67,0:36:14.28,yin,,0,0,0,,这完全没问题 这里并不只能处理一个block\\N{\\fs12}That's perfectly fine, say it's not like there can only be one block.\r\nDialogue: 0,0:36:14.28,0:36:16.52,yin,,0,0,0,,理解吗\\N{\\fs12}Make sense?\r\nDialogue: 0,0:36:16.52,0:36:18.08,yin,,0,0,0,,好 我有一个demo\\N{\\fs12}Alright, so I have a demo.\r\nDialogue: 0,0:36:18.08,0:36:22.01,yin,,0,0,0,,这个最好是用demo来讲更好理解\\N{\\fs12}This is all definitely best understood with a demo,\r\nDialogue: 0,0:36:22.01,0:36:25.34,yin,,0,0,0,,demo中我还会演示其它一些东西\\N{\\fs12}and this demo lets me show you a couple other things as well,\r\nDialogue: 0,0:36:25.34,0:36:30.62,yin,,0,0,0,,同往常一样 我的demo都是一举多得的\\N{\\fs12}as usual, I try to make these demos count for multiple things here,\r\nDialogue: 0,0:36:30.62,0:36:33.97,yin,,0,0,0,,这是一个新app 叫作Bouncer\\N{\\fs12}so this is going to be a new app we're going to write, it's called Bouncer.\r\nDialogue: 0,0:36:33.97,0:36:38.18,yin,,0,0,0,,Bouncer将有一个小方块\\N{\\fs12}And Bouncer is going to be a little square that I'm going\r\nDialogue: 0,0:36:38.18,0:36:40.49,yin,,0,0,0,,出现在屏幕上\\N{\\fs12}to have appear on my device,\r\nDialogue: 0,0:36:40.49,0:36:43.89,yin,,0,0,0,,最终我们会让重力来决定\\N{\\fs12}and eventually we're going to have gravity\r\nDialogue: 0,0:36:43.89,0:36:48.46,yin,,0,0,0,,方块在屏幕上动画到什么地方去\\N{\\fs12}determine where that square is animated to on screen,\r\nDialogue: 0,0:36:48.46,0:36:50.19,yin,,0,0,0,,然后我们会加一个方块\\N{\\fs12}then we'll put another square on there, and then\r\nDialogue: 0,0:36:50.19,0:36:52.03,yin,,0,0,0,,让两者相互碰撞\\N{\\fs12}we'll bang those things into each other,\r\nDialogue: 0,0:36:52.03,0:36:54.14,yin,,0,0,0,,我们还会计分\\N{\\fs12}and maybe we'll put a little score in there,\r\nDialogue: 0,0:36:54.14,0:36:56.19,yin,,0,0,0,,然后再写个小游戏\\N{\\fs12}and then we've made ourselves a little game.\r\nDialogue: 0,0:36:56.19,0:36:58.71,yin,,0,0,0,,这是一个小游戏\\N{\\fs12}So it's a little, basically\r\nDialogue: 0,0:36:58.71,0:37:01.87,yin,,0,0,0,,游戏的输入是加速计\\N{\\fs12}game where the input to the game is the accelerometer.\r\nDialogue: 0,0:37:01.87,0:37:03.02,yin,,0,0,0,,我将用加速计\\N{\\fs12}So I'm going to use accelerometer,\r\nDialogue: 0,0:37:03.02,0:37:06.14,yin,,0,0,0,,因为这是设备运动中最简单的\\N{\\fs12}because it's the simplest of the device motion things.\r\nDialogue: 0,0:37:06.14,0:37:09.82,yin,,0,0,0,,不过获得信息的方式都是一样的\\N{\\fs12}But they all basically do the same approach of how you get the information back.\r\nDialogue: 0,0:37:09.82,0:37:13.14,yin,,0,0,0,,我们将使用加速计来驱动我们的UI\\N{\\fs12}So we use the accelerometer to drive our UI, just like\r\nDialogue: 0,0:37:13.15,0:37:15.94,yin,,0,0,0,,像是接触 猛击这些\\N{\\fs12}touching and swiping, or whatever,\r\nDialogue: 0,0:37:15.94,0:37:18.38,yin,,0,0,0,,我们将把加速计当作输入\\N{\\fs12}we're going to use the accelerometer as an input.\r\nDialogue: 0,0:37:18.38,0:37:21.09,yin,,0,0,0,,好 这里创建一个新项目\\N{\\fs12}Alright, so let's make a new project here.\r\nDialogue: 0,0:37:21.09,0:37:22.64,yin,,0,0,0,,不是新文件\\N{\\fs12}Whoops! Not a new file.\r\nDialogue: 0,0:37:22.64,0:37:26.01,yin,,0,0,0,,取消 新项目\\N{\\fs12}Cancel. A new project.\r\nDialogue: 0,0:37:27.24,0:37:30.90,yin,,0,0,0,,好 这个项目起名为Bouncer\\N{\\fs12}Okay. And we're going to call this project Bouncer.\r\nDialogue: 0,0:37:30.90,0:37:32.23,yin,,0,0,0,,它将是通用的\\N{\\fs12}And it's going to be universal.\r\nDialogue: 0,0:37:32.23,0:37:35.09,yin,,0,0,0,,这个app中将有一点是之前我从未做过的\\N{\\fs12}I'm also going to do something with this app that I haven't done all quarter,\r\nDialogue: 0,0:37:35.09,0:37:38.66,yin,,0,0,0,,也就是 我不会在故事板中做任何事\\N{\\fs12}which is I'm not going to do anything in the storyboard.\r\nDialogue: 0,0:37:38.66,0:37:40.97,yin,,0,0,0,,这里100%是用代码\\N{\\fs12}We're going to do all of this 100 percent in code,\r\nDialogue: 0,0:37:40.97,0:37:42.66,yin,,0,0,0,,看看这是怎样的\\N{\\fs12}just to see what that looks like.\r\nDialogue: 0,0:37:42.66,0:37:47.45,yin,,0,0,0,,我不打算接触故事板\\N{\\fs12}So I'm not even going to touch my storyboard.\r\nDialogue: 0,0:37:47.45,0:37:51.26,yin,,0,0,0,,实际上 我打算把故事板移到支持文件中\\N{\\fs12}Alright, in fact, I'm going to move my storyboards down to supporting files,\r\nDialogue: 0,0:37:51.26,0:37:53.28,yin,,0,0,0,,因为我不打算用\\N{\\fs12}because I'm not going to use them. It's all going to be\r\nDialogue: 0,0:37:53.28,0:37:57.92,yin,,0,0,0,,整个实现都在这一个文件中\\N{\\fs12}in this one file, the entire implementation we're going to do here.\r\nDialogue: 0,0:37:57.92,0:37:59.97,yin,,0,0,0,,好 首先我们要做什么呢\\N{\\fs12}Alright, so what are we going to do to start?\r\nDialogue: 0,0:37:59.97,0:38:03.71,yin,,0,0,0,,首先将一个红色方块放到屏幕上\\N{\\fs12}Let's start by just putting a little red square on the screen.\r\nDialogue: 0,0:38:03.71,0:38:04.83,yin,,0,0,0,,这很简单\\N{\\fs12}So we'll start simple.\r\nDialogue: 0,0:38:04.83,0:38:08.24,yin,,0,0,0,,这里我写一个属性 非原子\\N{\\fs12}I'm going to have a little property here, non-atomic,\r\nDialogue: 0,0:38:08.24,0:38:11.74,yin,,0,0,0,,强 只是一个小UIView 起名为redBlock\\N{\\fs12}strong, just a little UI view, I'm going to call it red block.\r\nDialogue: 0,0:38:11.74,0:38:16.53,yin,,0,0,0,,这是我将放到屏幕上的一个红色小方块\\N{\\fs12}It's going to be a little red square that I'm going to put on screen.\r\nDialogue: 0,0:38:16.53,0:38:21.06,yin,,0,0,0,,我将在viewDidAppear中将它放到屏幕上\\N{\\fs12}And I'm going to do it, I'm going to put in on screen in ViewDidAppear,\r\nDialogue: 0,0:38:21.06,0:38:24.27,yin,,0,0,0,,一旦这个视图出现在屏幕上\\N{\\fs12}so once this view appears on screen,\r\nDialogue: 0,0:38:24.27,0:38:26.78,yin,,0,0,0,,我马上就会把这个小方块放上去\\N{\\fs12}then I'm going to put this little block out there,\r\nDialogue: 0,0:38:26.78,0:38:29.52,yin,,0,0,0,,做法是通过这个方法 startGame\\N{\\fs12}and I'm going to do that in a method called Start Game,\r\nDialogue: 0,0:38:29.52,0:38:30.78,yin,,0,0,0,,该方法会开始游戏\\N{\\fs12}so it's going to be the start of my game.\r\nDialogue: 0,0:38:30.78,0:38:33.01,yin,,0,0,0,,最终 这里将不只是一个红色方块\\N{\\fs12}I mean, eventually it's going to be more than just a red block there,\r\nDialogue: 0,0:38:33.01,0:38:35.42,yin,,0,0,0,,因此 这里我们说startGame\\N{\\fs12}so we'll say we're starting our game.\r\nDialogue: 0,0:38:35.42,0:38:37.13,yin,,0,0,0,,startGame中怎么做呢\\N{\\fs12}So what do we do in Start Game?\r\nDialogue: 0,0:38:37.13,0:38:40.90,yin,,0,0,0,,我只打算说 self.redBlock = …\\N{\\fs12}I'm just going to say self dot red block equals--\r\nDialogue: 0,0:38:40.90,0:38:44.84,yin,,0,0,0,,我需要创建一个方块 我想把它放到屏幕中央\\N{\\fs12}now I would need to create a block, I want to put it in the center of the screen,\r\nDialogue: 0,0:38:44.84,0:38:50.46,yin,,0,0,0,,因此 在这里 我会创建一个方法 叫addBlock…\\N{\\fs12}so I create a nice little method here, called add block,\r\nDialogue: 0,0:38:50.46,0:38:53.89,yin,,0,0,0,,如这里所示 它的作用很明显\\N{\\fs12}this little guy right here, and all it does, as you can see,\r\nDialogue: 0,0:38:53.89,0:38:56.62,yin,,0,0,0,,也就是initWithFrame和addSubview\\N{\\fs12}is it just does init with frame and add subview.\r\nDialogue: 0,0:38:56.62,0:38:58.89,yin,,0,0,0,,它会计算frame在哪\\N{\\fs12}And all it's doing is calculating where that frame is.\r\nDialogue: 0,0:38:58.89,0:39:03.97,yin,,0,0,0,,它会放到中央 偏移我想要的值 任何UI偏移量\\N{\\fs12}So it's putting in the center offset by anything I want, any UI offset.\r\nDialogue: 0,0:39:03.97,0:39:06.46,yin,,0,0,0,,最开始 我将把方块放到中央\\N{\\fs12}So I'm going to put it initially right in the center.\r\nDialogue: 0,0:39:06.46,0:39:10.23,yin,,0,0,0,,顺便说下 这个和这个在整个demo中不会用到\\N{\\fs12}By the way, we don't need this or this for this entire demo.\r\nDialogue: 0,0:39:10.23,0:39:13.93,yin,,0,0,0,,然后我说self addBlockOffset…\\N{\\fs12}Alright, so I'm going to do self, add, block, offset,\r\nDialogue: 0,0:39:13.93,0:39:17.95,yin,,0,0,0,,然后是UIOffsetMake 0 0\\N{\\fs12}and I'm going to do UI offset make zero zero.\r\nDialogue: 0,0:39:17.95,0:39:19.89,yin,,0,0,0,,这就放到了中央\\N{\\fs12}So it's going to put it right in the center.\r\nDialogue: 0,0:39:19.89,0:39:23.00,yin,,0,0,0,,大家都理解这个的作用了吗\\N{\\fs12}Everyone understand what this does,\r\nDialogue: 0,0:39:23.00,0:39:26.49,yin,,0,0,0,,它将一个UIView放到了屏幕中央\\N{\\fs12}is just putting-- adding UI view to the center of the screen.\r\nDialogue: 0,0:39:26.49,0:39:29.99,yin,,0,0,0,,我的方块是红色的 因此这里用红色\\N{\\fs12}And my block is red, so let's make it red.\r\nDialogue: 0,0:39:29.99,0:39:34.37,yin,,0,0,0,,.backgroundColor = UIColor redColor\\N{\\fs12}Dot background color equals UI color, red color.\r\nDialogue: 0,0:39:34.37,0:39:37.35,yin,,0,0,0,,让我们来运行这个\\N{\\fs12}So let's go ahead and run that.\r\nDialogue: 0,0:39:45.14,0:39:47.41,yin,,0,0,0,,好 很好的开始\\N{\\fs12}Alright, good start.\r\nDialogue: 0,0:39:47.41,0:39:51.67,yin,,0,0,0,,下面 我希望有一些重力\\N{\\fs12}So what we want now is I want some gravity.\r\nDialogue: 0,0:39:51.67,0:39:56.62,yin,,0,0,0,,我希望这个方块不再待在中央 而是移动到别处\\N{\\fs12}I want this block to go somewhere else besides in the middle of the screen.\r\nDialogue: 0,0:39:56.62,0:39:59.89,yin,,0,0,0,,做法你们已经非常熟悉了\\N{\\fs12}So we do that with something you're all very familiar\r\nDialogue: 0,0:39:59.89,0:40:03.13,yin,,0,0,0,,这是作业四的内容 也就是动态动画器\\N{\\fs12}from assignment 4, which is animators, dynamic animator.\r\nDialogue: 0,0:40:03.13,0:40:05.83,yin,,0,0,0,,这里我将添加一个动态动画器\\N{\\fs12}So I'm just going to add a dynamic animator here\r\nDialogue: 0,0:40:05.83,0:40:07.57,yin,,0,0,0,,来加入重力\\N{\\fs12}to add gravity\r\nDialogue: 0,0:40:07.57,0:40:09.94,yin,,0,0,0,,让方块来到边缘时\\N{\\fs12}and to make it so when the block gets to the edge,\r\nDialogue: 0,0:40:09.94,0:40:11.46,yin,,0,0,0,,会反弹\\N{\\fs12}it's going to bounce off.\r\nDialogue: 0,0:40:11.46,0:40:13.54,yin,,0,0,0,,而不是离开屏幕\\N{\\fs12}Instead of just going off the screen.\r\nDialogue: 0,0:40:13.54,0:40:14.95,yin,,0,0,0,,让我们来做这个\\N{\\fs12}So let's do that.\r\nDialogue: 0,0:40:14.95,0:40:17.85,yin,,0,0,0,,你们都知道动画器\\N{\\fs12}Uh, that, I have since you all know about animator,\r\nDialogue: 0,0:40:17.85,0:40:20.33,yin,,0,0,0,,我就不一点点键入了\\N{\\fs12}I'm not going to type all that in, I'm just going\r\nDialogue: 0,0:40:20.33,0:40:24.19,yin,,0,0,0,,直接把它们加到这里\\N{\\fs12}to show it here, this is what I just added.\r\nDialogue: 0,0:40:24.19,0:40:26.18,yin,,0,0,0,,这里\\N{\\fs12}Right here.\r\nDialogue: 0,0:40:26.18,0:40:27.84,yin,,0,0,0,,我有一些属性\\N{\\fs12}Okay, I've got some properties.\r\nDialogue: 0,0:40:27.84,0:40:31.47,yin,,0,0,0,,这里的属性是\\N{\\fs12}The properties I have here are...\r\nDialogue: 0,0:40:31.47,0:40:35.22,yin,,0,0,0,,一个动态动画器 还有重力行为\\N{\\fs12}a dynamic animator, of course, I've got a gravity behavior,\r\nDialogue: 0,0:40:35.22,0:40:37.62,yin,,0,0,0,,这是拉拽红色方块的重力\\N{\\fs12}that's going to be the gravity pulling on my red block.\r\nDialogue: 0,0:40:37.62,0:40:40.34,yin,,0,0,0,,碰撞器 这是外边缘处的情况\\N{\\fs12}Collider, that's just going to be the outer edges,\r\nDialogue: 0,0:40:40.34,0:40:42.64,yin,,0,0,0,,这是现在唯一的碰撞器\\N{\\fs12}that's the only collider I'm going to have for now.\r\nDialogue: 0,0:40:42.64,0:40:44.92,yin,,0,0,0,,然后弹性是一个项目行为\\N{\\fs12}And then elastic is an item behavior.\r\nDialogue: 0,0:40:44.92,0:40:46.85,yin,,0,0,0,,我希望它碰壁弹回\\N{\\fs12}I want it to really bounce off the walls.\r\nDialogue: 0,0:40:46.85,0:40:50.82,yin,,0,0,0,,这里我设置了它的弹性 让它具有完全弹性\\N{\\fs12}So I'm going to set it's elasticity so that it's completely elastic.\r\nDialogue: 0,0:40:50.82,0:40:55.41,yin,,0,0,0,,碰壁都是弹性碰撞\\N{\\fs12}All of it's hitting the walls are elastic collisions.\r\nDialogue: 0,0:40:55.41,0:40:57.60,yin,,0,0,0,,这是动画器\\N{\\fs12}And so here's the animator.\r\nDialogue: 0,0:40:57.60,0:41:02.93,yin,,0,0,0,,惰性实例化 没有特别的东西 这是碰撞器\\N{\\fs12}Lazy instantiation not doing anything special there, here's the collider.\r\nDialogue: 0,0:41:02.93,0:41:06.62,yin,,0,0,0,,其作用是translatesReferenceBoundsIntoBoundary\\N{\\fs12}The only thing that does is translates reference bounds into boundary.\r\nDialogue: 0,0:41:06.62,0:41:09.51,yin,,0,0,0,,你们知道这个\\N{\\fs12}Okay, you know about that.\r\nDialogue: 0,0:41:09.51,0:41:12.17,yin,,0,0,0,,这是重力 不过是默认的重力\\N{\\fs12}Here's gravity, just default gravity.\r\nDialogue: 0,0:41:12.17,0:41:17.18,yin,,0,0,0,,一开始重力会在视图中指向下方\\N{\\fs12}It's going to start out with our gravity pointing down in our view.\r\nDialogue: 0,0:41:17.18,0:41:20.08,yin,,0,0,0,,而无论下是哪个方向 换句话说\\N{\\fs12}Whatever down is in our view, in other words,\r\nDialogue: 0,0:41:20.08,0:41:23.21,yin,,0,0,0,,视图Y方向向下 这就是重力最开始的情况\\N{\\fs12}increasing Y, that's where gravity's going to start out,\r\nDialogue: 0,0:41:23.21,0:41:26.95,yin,,0,0,0,,我们希望用现实世界的重力取代这个重力\\N{\\fs12}we want to replace that gravity with the real gravity of the world,\r\nDialogue: 0,0:41:26.96,0:41:29.49,yin,,0,0,0,,这是我们马上要做的\\N{\\fs12}that's what we're going to be doing in a moment.\r\nDialogue: 0,0:41:29.49,0:41:30.63,yin,,0,0,0,,然后这里是弹性\\N{\\fs12}And then here's elastic.\r\nDialogue: 0,0:41:30.63,0:41:35.56,yin,,0,0,0,,弹性也就是项目行为中的弹性\\N{\\fs12}Elastic is an item behavior which just sets one thing, which is the elasticity.\r\nDialogue: 0,0:41:35.56,0:41:39.04,yin,,0,0,0,,说的是碰撞弹性有多强\\N{\\fs12}This says how elastic the collisions are, and I'm going\r\nDialogue: 0,0:41:39.04,0:41:42.96,yin,,0,0,0,,我设为1.0 也就是完全弹性碰撞\\N{\\fs12}to have it be 1.0, which means fully elastic collision.\r\nDialogue: 0,0:41:42.96,0:41:45.99,yin,,0,0,0,,你甚至可以将这个设为大于1\\N{\\fs12}You can actually make this greater than 1, and it will pick\r\nDialogue: 0,0:41:45.99,0:41:47.72,yin,,0,0,0,,这样碰撞时就会加速\\N{\\fs12}up speed when it hits a collision,\r\nDialogue: 0,0:41:47.72,0:41:51.00,yin,,0,0,0,,你也可以设为小于1 这时就会有阻尼\\N{\\fs12}and you can make it less than 1, and it will dampen, right?\r\nDialogue: 0,0:41:51.00,0:41:53.53,yin,,0,0,0,,最小值是0 这好像是默认值\\N{\\fs12}All the way down to zero, which is the default, I think,\r\nDialogue: 0,0:41:53.53,0:41:55.66,yin,,0,0,0,,也就是方块碰到底部\\N{\\fs12}which is that's a block, hit the bottom\r\nDialogue: 0,0:41:55.66,0:41:57.14,yin,,0,0,0,,就不再弹起\\N{\\fs12}and then just kind of settle real quick.\r\nDialogue: 0,0:41:57.14,0:42:01.26,yin,,0,0,0,,这就是程序中方块的弹性了\\N{\\fs12}That's what we had, I think, the elasticity of our blocks in Drop It, were that.\r\nDialogue: 0,0:42:02.40,0:42:04.93,yin,,0,0,0,,好 我有了动画器和所有这些\\N{\\fs12}Alright, so I have this animator and all these things,\r\nDialogue: 0,0:42:04.93,0:42:09.58,yin,,0,0,0,,下面我要将红色方块添加到这些\\N{\\fs12}so now I just want to make sure that I take my red block and add it to all these,\r\nDialogue: 0,0:42:09.58,0:42:15.83,yin,,0,0,0,,我这里说 我希望红色方块在碰撞器中\\N{\\fs12}so I'm going to say I want the red block to be in the collider,\r\nDialogue: 0,0:42:15.83,0:42:22.09,yin,,0,0,0,,我希望红色方块具有弹性\\N{\\fs12}and I want the red block to be elastic.\r\nDialogue: 0,0:42:22.09,0:42:25.97,yin,,0,0,0,,我希望红色方块受重力影响\\N{\\fs12}And I want the red block to be affected by gravity.\r\nDialogue: 0,0:42:28.73,0:42:32.05,yin,,0,0,0,,我把红色方块加到了这些行为\\N{\\fs12}Okay, so I'm just adding the red block to these behaviors.\r\nDialogue: 0,0:42:32.05,0:42:35.99,yin,,0,0,0,,但愿这些你们都很熟悉 这是作业四的内容\\N{\\fs12}Again, hopefully this is all really familiar to you from assignment 4.\r\nDialogue: 0,0:42:35.99,0:42:39.42,yin,,0,0,0,,看看我们现在有些什么\\N{\\fs12}So let's run to see what we've got now.\r\nDialogue: 0,0:42:39.42,0:42:42.12,yin,,0,0,0,,我们有了重力 碰撞和弹性\\N{\\fs12}So we've got gravity, collision and elastic,\r\nDialogue: 0,0:42:42.12,0:42:45.58,yin,,0,0,0,,于是这个红色方块就会下落弹起\\N{\\fs12}so this red block, boom, it goes down and it bounces.\r\nDialogue: 0,0:42:45.58,0:42:48.22,yin,,0,0,0,,这很棒 我们开了个好头\\N{\\fs12}So this is excellent, we've got a good start here.\r\nDialogue: 0,0:42:48.22,0:42:50.69,yin,,0,0,0,,很不幸的是 这还不是现实世界的重力\\N{\\fs12}Unfortunately, this is not real-world gravity,\r\nDialogue: 0,0:42:50.69,0:42:51.89,yin,,0,0,0,,转动设备\\N{\\fs12}I'm moving this thing around,\r\nDialogue: 0,0:42:51.89,0:42:54.25,yin,,0,0,0,,它还是在这个方向上弹\\N{\\fs12}it's still going straight down and bouncing.\r\nDialogue: 0,0:42:54.25,0:42:59.15,yin,,0,0,0,,因为默认重力是视图中的Y方向向下\\N{\\fs12}That's because the default gravity is down, in other words increasing Y in my view.\r\nDialogue: 0,0:42:59.15,0:43:02.23,yin,,0,0,0,,下面我将使用运动管理器\\N{\\fs12}So what I'm going to do now is use the motion manager\r\nDialogue: 0,0:43:02.23,0:43:05.78,yin,,0,0,0,,将重力从Y方向向下\\N{\\fs12}to set the gravity to instead of being down,\r\nDialogue: 0,0:43:05.78,0:43:09.74,yin,,0,0,0,,设为实际重力 使用加速计\\N{\\fs12}to be wherever the real gravity is, by using the accelerometer.\r\nDialogue: 0,0:43:09.74,0:43:12.97,yin,,0,0,0,,记得吧 加速计测量的总是重力加速度\\N{\\fs12}Okay, remember, the accelerometer is always measuring acceleration due\r\nDialogue: 0,0:43:12.97,0:43:17.11,yin,,0,0,0,,这样我就总能知道实际重力在哪\\N{\\fs12}to gravity so I will always know where real gravity is.\r\nDialogue: 0,0:43:17.11,0:43:19.08,yin,,0,0,0,,让我们来做这个\\N{\\fs12}So let's do that.\r\nDialogue: 0,0:43:19.08,0:43:22.29,yin,,0,0,0,,这也很简单 我们在startGame中来做这个\\N{\\fs12}That's pretty straightforward too, we're going to do that here in Start Game.\r\nDialogue: 0,0:43:22.29,0:43:26.87,yin,,0,0,0,,做Core Motion的任何事情 都需要一个运动管理器\\N{\\fs12}So to do anything with core motion, I need a motion manager.\r\nDialogue: 0,0:43:26.87,0:43:28.53,yin,,0,0,0,,到这里获得一个运动管理器\\N{\\fs12}So let's go get a motion manager here.\r\nDialogue: 0,0:43:28.53,0:43:32.60,yin,,0,0,0,,设置一个属性 非原子 强\\N{\\fs12}I'm going to make a property, non-atomic strong,\r\nDialogue: 0,0:43:32.60,0:43:36.51,yin,,0,0,0,,CMMotionManager 我需要导入\\N{\\fs12}CMMotionManager, okay I need to import.\r\nDialogue: 0,0:43:36.51,0:43:38.65,yin,,0,0,0,,Core Motion\\N{\\fs12}Core motion.\r\nDialogue: 0,0:43:38.65,0:43:40.67,yin,,0,0,0,,哦 不是Core Media\\N{\\fs12}Oops, not core media,\r\nDialogue: 0,0:43:40.67,0:43:42.22,yin,,0,0,0,,Core Motion\\N{\\fs12}core motion.\r\nDialogue: 0,0:43:43.46,0:43:47.22,yin,,0,0,0,,好 现在我就有了一个运动管理器\\N{\\fs12}Alright. And now I have a motion manager,\r\nDialogue: 0,0:43:47.23,0:43:51.28,yin,,0,0,0,,我将惰性实例化这个东西\\N{\\fs12}and I'm going to lazily instantiate this thing.\r\nDialogue: 0,0:43:51.28,0:43:53.82,yin,,0,0,0,,让我们在下面这里来做\\N{\\fs12}So let's do that down here.\r\nDialogue: 0,0:43:53.82,0:43:57.30,yin,,0,0,0,,CMMotionManager\\N{\\fs12}CMMotionManager,\r\nDialogue: 0,0:43:57.30,0:44:00.18,yin,,0,0,0,,if (!_motionManager)\\N{\\fs12}if not motion manager,\r\nDialogue: 0,0:44:00.18,0:44:03.77,yin,,0,0,0,,那么_motionManager =\\N{\\fs12}then motion manager equals\r\nDialogue: 0,0:44:03.77,0:44:07.47,yin,,0,0,0,,CMMotionManager alloc init\\N{\\fs12}CMMotionManager alloc init,\r\nDialogue: 0,0:44:07.47,0:44:11.03,yin,,0,0,0,,然后我这样设置运动管理器\\N{\\fs12}and then I'm going to set the motion manager\r\nDialogue: 0,0:44:11.03,0:44:17.67,yin,,0,0,0,,让它进行加速计更新 频率10次每秒\\N{\\fs12}to do accelerometer updates at 10 per second.\r\nDialogue: 0,0:44:17.67,0:44:18.49,yin,,0,0,0,,应该够了\\N{\\fs12}Should be enough.\r\nDialogue: 0,0:44:18.49,0:44:19.98,yin,,0,0,0,,我是说 这里对于UI\\N{\\fs12}I mean, I'm doing UI here.\r\nDialogue: 0,0:44:19.98,0:44:24.92,yin,,0,0,0,,我觉得10次每秒就足够让红色方块\\N{\\fs12}I think 10 per second is going to give me smooth enough changing of direction,\r\nDialogue: 0,0:44:24.92,0:44:27.94,yin,,0,0,0,,在运动中获得平滑的方向变化了\\N{\\fs12}of my red square as I move around, but you know,\r\nDialogue: 0,0:44:27.94,0:44:31.69,yin,,0,0,0,,不过如果反应不够快 我可以调高一些\\N{\\fs12}I could crank it up a little bit if it doesn't seem responsive enough to my moving,\r\nDialogue: 0,0:44:31.69,0:44:34.13,yin,,0,0,0,,如果反应太快 我也可以调低一些\\N{\\fs12}or I could crank it down if it seems plenty responsive\r\nDialogue: 0,0:44:34.13,0:44:37.40,yin,,0,0,0,,这样就能避免绘制的内容多于需要绘制的内容\\N{\\fs12}and I just don't want to do any more drawing than I have to do.\r\nDialogue: 0,0:44:37.40,0:44:39.93,yin,,0,0,0,,这里先设为这个\\N{\\fs12}So we're going to set it to be that,\r\nDialogue: 0,0:44:39.93,0:44:43.07,yin,,0,0,0,,然后返回我们的运动管理器\\N{\\fs12}and then let's return our motion manager.\r\nDialogue: 0,0:44:43.07,0:44:46.37,yin,,0,0,0,,现在我有了这个运动管理器\\N{\\fs12}Okay, so now we have this motion manager, so now what I'm going\r\nDialogue: 0,0:44:46.37,0:44:49.76,yin,,0,0,0,,然后我要检查\\N{\\fs12}to do is say first of all I'm going to check to see\r\nDialogue: 0,0:44:49.76,0:44:54.72,yin,,0,0,0,,我是否已经在进行加速计更新\\N{\\fs12}if I'm already doing accelerometer updates,\r\nDialogue: 0,0:44:54.72,0:44:58.04,yin,,0,0,0,,这里我说 isAccelerometerActive\\N{\\fs12}so I'm going to say accelerometer active.\r\nDialogue: 0,0:44:59.64,0:45:03.99,yin,,0,0,0,,我只在加速计没有在活动时\\N{\\fs12}And I'm only going to start monitoring this thing\r\nDialogue: 0,0:45:03.99,0:45:07.48,yin,,0,0,0,,才开始监视这个东西\\N{\\fs12}if the accelerometer is not already active.\r\nDialogue: 0,0:45:07.48,0:45:10.16,yin,,0,0,0,,哦 让我删掉这个 谢谢\\N{\\fs12}Whoops, let me...erase...thank you...okay.\r\nDialogue: 0,0:45:10.16,0:45:13.21,yin,,0,0,0,,如果没在活动 那我就会\\N{\\fs12}So if it's not active, then I'm going\r\nDialogue: 0,0:45:13.21,0:45:16.14,yin,,0,0,0,,给它一个block来调用\\N{\\fs12}to basically give it a block to call me,\r\nDialogue: 0,0:45:16.14,0:45:21.52,yin,,0,0,0,,而block的作用是更新重力行为的重力\\N{\\fs12}and all I'm going to do in that block is update my gravity behavior's gravity.\r\nDialogue: 0,0:45:21.52,0:45:24.02,yin,,0,0,0,,让我们来做这个\\N{\\fs12}So let's do that.\r\nDialogue: 0,0:45:24.02,0:45:26.49,yin,,0,0,0,,self.motionManager\\N{\\fs12}Self dot motion manager,\r\nDialogue: 0,0:45:26.49,0:45:30.74,yin,,0,0,0,,startAccelerometerUpdatesToQueue\\N{\\fs12}start accelerometer updates to queue,\r\nDialogue: 0,0:45:30.74,0:45:33.35,yin,,0,0,0,,我将给它一个队列 每秒仅仅10次\\N{\\fs12}so we'll give it a queue, I'm only doing 10 per second,\r\nDialogue: 0,0:45:33.35,0:45:36.67,yin,,0,0,0,,我想主队列处理得来\\N{\\fs12}I think I can easily go main queue on this one.\r\nDialogue: 0,0:45:36.67,0:45:38.82,yin,,0,0,0,,因此这里设为主队列\\N{\\fs12}So I'll go main queue,\r\nDialogue: 0,0:45:40.98,0:45:43.35,yin,,0,0,0,,这里是处理器\\N{\\fs12}and here's the handler.\r\nDialogue: 0,0:45:43.35,0:45:44.81,yin,,0,0,0,,双击得到处理器\\N{\\fs12}Double clicking to get the handler,\r\nDialogue: 0,0:45:44.81,0:45:48.96,yin,,0,0,0,,放到这里来 这样更容易看清\\N{\\fs12}we'll put this right here, in fact, we'll make it even easier\r\nDialogue: 0,0:45:48.96,0:45:52.34,yin,,0,0,0,,把这里移回去 像这样\\N{\\fs12}to see, we'll move this back here like this.\r\nDialogue: 0,0:45:52.34,0:45:53.61,yin,,0,0,0,,好 这是处理器\\N{\\fs12}Alright. So here's our handler.\r\nDialogue: 0,0:45:53.61,0:45:55.95,yin,,0,0,0,,在处理器中我们要做什么呢\\N{\\fs12}And what do we want to do inside this handler?\r\nDialogue: 0,0:45:55.95,0:45:59.66,yin,,0,0,0,,我们要获得加速度的x和y\\N{\\fs12}Well let's get the X and Y of acceleration,\r\nDialogue: 0,0:45:59.66,0:46:04.11,yin,,0,0,0,,让我们获得x 这是accelerometerData\\N{\\fs12}so let's get the X, that's accelerometer data.\r\nDialogue: 0,0:46:04.11,0:46:06.22,yin,,0,0,0,,也就是方块的这个参数\\N{\\fs12}So that's this argument here to our block,\r\nDialogue: 0,0:46:06.22,0:46:08.09,yin,,0,0,0,,.acceleration\\N{\\fs12}dot acceleration,\r\nDialogue: 0,0:46:08.09,0:46:10.96,yin,,0,0,0,,这就是现有的加速度\\N{\\fs12}that's the acceleration that is happening,\r\nDialogue: 0,0:46:10.96,0:46:13.27,yin,,0,0,0,,而x是我要的方向\\N{\\fs12}and X is the direction I want.\r\nDialogue: 0,0:46:13.27,0:46:15.18,yin,,0,0,0,,这是x方向\\N{\\fs12}So here's the X direction, and then I'm going\r\nDialogue: 0,0:46:15.18,0:46:20.38,yin,,0,0,0,,y也一样 y = accelerometerData.acceleration.y\\N{\\fs12}to do the same thing Y equals accelerometer data, acceleration, dot Y.\r\nDialogue: 0,0:46:20.38,0:46:23.94,yin,,0,0,0,,这样我就有了x和y方向上由于重力产生的加速度\\N{\\fs12}So now I have the X and Y acceleration due to gravity.\r\nDialogue: 0,0:46:23.94,0:46:26.70,yin,,0,0,0,,还有设备的运动\\N{\\fs12}And do the device moving.\r\nDialogue: 0,0:46:26.70,0:46:27.34,yin,,0,0,0,,两者都\\N{\\fs12}Both.\r\nDialogue: 0,0:46:27.34,0:46:28.62,yin,,0,0,0,,这是一个组合\\N{\\fs12}So it's a kind of combination.\r\nDialogue: 0,0:46:28.62,0:46:31.84,yin,,0,0,0,,如果我将设备向下倾斜 方块就会往下\\N{\\fs12}So that way, if I tilt my thing down, my blocks are going to go down.\r\nDialogue: 0,0:46:31.84,0:46:34.42,yin,,0,0,0,,如果反过来倾斜 方块也会反过来\\N{\\fs12}If I tilt it back the other way, it's going to go the other way, right?\r\nDialogue: 0,0:46:34.42,0:46:37.70,yin,,0,0,0,,如果我摇动它 它就会朝那个方向加速\\N{\\fs12}If I shake it over, it's going to accelerate a little bit in that direction.\r\nDialogue: 0,0:46:37.70,0:46:40.36,yin,,0,0,0,,这里方块对设备加速有些响应\\N{\\fs12}So it's kind of like that block is going to be responding\r\nDialogue: 0,0:46:40.36,0:46:44.20,yin,,0,0,0,,不过主要是基于重力的加速度\\N{\\fs12}to my acceleration and my device, but mostly acceleration due to gravity.\r\nDialogue: 0,0:46:44.20,0:46:49.71,yin,,0,0,0,,我如何设置这个行为的重力方向呢\\N{\\fs12}So how do I set the direction of the gravity of that behavior?\r\nDialogue: 0,0:46:49.71,0:46:54.89,yin,,0,0,0,,我有self.gravity 这是我的重力行为\\N{\\fs12}Well, I have self dot gravity, that's my gravity behavior.\r\nDialogue: 0,0:46:54.89,0:46:59.15,yin,,0,0,0,,它有gravityDirection 重力方向\\N{\\fs12}It has something called gravity direction, which is exactly what we want.\r\nDialogue: 0,0:46:59.15,0:47:01.44,yin,,0,0,0,,这是一个向量 一个CGVector\\N{\\fs12}It's a vector, a CG vector,\r\nDialogue: 0,0:47:01.45,0:47:05.07,yin,,0,0,0,,它有一个Δx和一个Δy\\N{\\fs12}and it just has a delta X and delta Y vector, right?\r\nDialogue: 0,0:47:05.07,0:47:09.00,yin,,0,0,0,,同数学中的向量一样 我们有这个向量\\N{\\fs12}So like in math, vector, and so we're just going to have the vector,\r\nDialogue: 0,0:47:09.01,0:47:12.32,yin,,0,0,0,,让我们尝试x和y 看会发生什么\\N{\\fs12}let's try doing X and Y, see what happens here.\r\nDialogue: 0,0:47:12.32,0:47:15.38,yin,,0,0,0,,它无法正常工作 不过不妨一试\\N{\\fs12}It's not going to work, but we'll try it.\r\nDialogue: 0,0:47:15.38,0:47:18.24,yin,,0,0,0,,然后是分号\\N{\\fs12}And we can do semicolon.\r\nDialogue: 0,0:47:18.24,0:47:21.97,yin,,0,0,0,,有些人应该已经开始想这为什么不行了\\N{\\fs12}Okay. Now, hopefully in some of your minds you're trying\r\nDialogue: 0,0:47:21.97,0:47:26.08,yin,,0,0,0,,毕竟这看起来似乎应该能行才对\\N{\\fs12}to think why this is not going to work, because it seems like this should just work.\r\nDialogue: 0,0:47:26.08,0:47:28.82,yin,,0,0,0,,我们看看会发生什么\\N{\\fs12}But let's see what happens.\r\nDialogue: 0,0:47:28.82,0:47:31.01,yin,,0,0,0,,有人猜猜为什么不能正常工作吗 请讲\\N{\\fs12}Anyone want to hazard a guess why it's not going to work? Yeah?\r\nDialogue: 0,0:47:35.77,0:47:39.25,yin,,0,0,0,,对 回答是\\N{\\fs12}Yeah, so the answer that was posited is\r\nDialogue: 0,0:47:39.25,0:47:41.82,yin,,0,0,0,,纵轴可以翻转 说得没错\\N{\\fs12}that the vertical axis can be flipped, and that's true.\r\nDialogue: 0,0:47:41.82,0:47:44.52,yin,,0,0,0,,或许更好的说法是\\N{\\fs12}Maybe a better way of saying it is that the acceleration\r\nDialogue: 0,0:47:44.52,0:47:48.30,yin,,0,0,0,,这个设备的加速度总是\\N{\\fs12}of this device is always the acceleration\r\nDialogue: 0,0:47:48.30,0:47:52.93,yin,,0,0,0,,在设备中朝这个方向往下\\N{\\fs12}where it's...down this way in the device,\r\nDialogue: 0,0:47:52.93,0:47:55.62,yin,,0,0,0,,如果我把它横过来\\N{\\fs12}so if I have it turned sideways, okay,\r\nDialogue: 0,0:47:55.62,0:47:57.43,yin,,0,0,0,,注意方块在弹\\N{\\fs12}then look at my thing it's bouncing.\r\nDialogue: 0,0:47:57.43,0:48:01.41,yin,,0,0,0,,把这个拿起来 它却朝这个方向弹\\N{\\fs12}I have this turned up, face-up, and it's bouncing this way.\r\nDialogue: 0,0:48:01.41,0:48:03.22,yin,,0,0,0,,为什么这样弹呢\\N{\\fs12}Why is it bouncing this way?\r\nDialogue: 0,0:48:03.22,0:48:06.98,yin,,0,0,0,,因为它是在这个轴上进行测量\\N{\\fs12}That's because it's measuring this stuff all on this axis.\r\nDialogue: 0,0:48:06.98,0:48:10.84,yin,,0,0,0,,我想让它在这个轴上测量 这里是z\\N{\\fs12}I want it measuring it in this axis, basically, where here's Z,\r\nDialogue: 0,0:48:10.84,0:48:13.51,yin,,0,0,0,,这里是y 这里是x\\N{\\fs12}here's Y, and here's X.\r\nDialogue: 0,0:48:13.51,0:48:17.73,yin,,0,0,0,,因此我需要知道 用户将设备朝向哪个方向\\N{\\fs12}So I basically have to know which way the user has my device turned.\r\nDialogue: 0,0:48:17.73,0:48:21.05,yin,,0,0,0,,这里我把它放成横屏模式\\N{\\fs12}So I have it turned kind of landscape.\r\nDialogue: 0,0:48:21.05,0:48:23.87,yin,,0,0,0,,横屏左 home键在左边\\N{\\fs12}Landscape left, the home button is on the left.\r\nDialogue: 0,0:48:23.87,0:48:27.40,yin,,0,0,0,,我需要翻转x和y\\N{\\fs12}So that's going to-- I'm going to have to flip the X and Y\r\nDialogue: 0,0:48:27.40,0:48:29.59,yin,,0,0,0,,去-y而不是y\\N{\\fs12}and go negative Y instead of Y,\r\nDialogue: 0,0:48:29.59,0:48:31.87,yin,,0,0,0,,如果是这个方向\\N{\\fs12}and if I were doing it this way,\r\nDialogue: 0,0:48:31.87,0:48:34.12,yin,,0,0,0,,这里我锁了\\N{\\fs12}which I have my...locked in here.\r\nDialogue: 0,0:48:34.12,0:48:36.73,yin,,0,0,0,,如果我反过来 它就会翻转\\N{\\fs12}But if I do it the other way around, then it's flipped.\r\nDialogue: 0,0:48:36.73,0:48:40.45,yin,,0,0,0,,这是另一个方向 如果这样向上 它会是另一个方向\\N{\\fs12}It has to be the other way, and if I'm doing it up this way, then it's another way.\r\nDialogue: 0,0:48:40.45,0:48:46.22,yin,,0,0,0,,重力加速度怎样影响我的视图取决于\\N{\\fs12}So basically, which way the acceleration to gravity is affecting my view depends\r\nDialogue: 0,0:48:46.22,0:48:48.80,yin,,0,0,0,,视图的朝向是怎样的\\N{\\fs12}on what the orientation of my view is.\r\nDialogue: 0,0:48:48.80,0:48:51.09,yin,,0,0,0,,我们加些代码来处理这个\\N{\\fs12}So let's put some code in to deal with that.\r\nDialogue: 0,0:48:51.09,0:48:52.81,yin,,0,0,0,,其实很简单\\N{\\fs12}Turns out to be pretty straightforward.\r\nDialogue: 0,0:48:52.81,0:48:54.47,yin,,0,0,0,,我们不能这么头脑简单\\N{\\fs12}So we can't just do this simple one.\r\nDialogue: 0,0:48:54.47,0:48:56.08,yin,,0,0,0,,将这个删掉\\N{\\fs12}So let's take that out.\r\nDialogue: 0,0:48:56.08,0:49:00.03,yin,,0,0,0,,为了节省键入工作量 我这样\\N{\\fs12}And...to save some typing, we'll do it this way.\r\nDialogue: 0,0:49:00.03,0:49:04.57,yin,,0,0,0,,所有视图控制器都有这个属性\\N{\\fs12}So all view controllers have this property called\r\nDialogue: 0,0:49:04.57,0:49:06.37,yin,,0,0,0,,self.interfaceOrientation\\N{\\fs12}self interface orientation that will\r\nDialogue: 0,0:49:06.37,0:49:08.85,yin,,0,0,0,,告诉你是竖屏还是横屏\\N{\\fs12}tell you whether you're portrait, portrait upside-down,\r\nDialogue: 0,0:49:08.85,0:49:10.34,yin,,0,0,0,,是正的还是反的\\N{\\fs12}landscape left or landscape right.\r\nDialogue: 0,0:49:10.34,0:49:15.02,yin,,0,0,0,,这是视图控制器告诉你 你还可以从设备得到\\N{\\fs12}That's telling you, the view controller, you can also get this from the device.\r\nDialogue: 0,0:49:15.02,0:49:18.27,yin,,0,0,0,,还有一个很有趣 你可以从UIApplication得到\\N{\\fs12}And you can also get an interesting one from UI application,\r\nDialogue: 0,0:49:18.28,0:49:22.07,yin,,0,0,0,,或许在这里使用会更好 也就是statusBarOrientation\\N{\\fs12}might even be better to use here, which is status bar orientation.\r\nDialogue: 0,0:49:22.07,0:49:24.06,yin,,0,0,0,,这告诉你状态栏在哪\\N{\\fs12}That tells you where the status bar is.\r\nDialogue: 0,0:49:24.06,0:49:25.96,yin,,0,0,0,,或许这是最正确的东西\\N{\\fs12}And that's really probably the most correct thing,\r\nDialogue: 0,0:49:25.96,0:49:27.84,yin,,0,0,0,,或许也是这里我们应当用的\\N{\\fs12}and probably what we should be using here.\r\nDialogue: 0,0:49:27.84,0:49:29.15,yin,,0,0,0,,因为在用户看来\\N{\\fs12}Because from the user's standpoint,\r\nDialogue: 0,0:49:29.15,0:49:32.37,yin,,0,0,0,,状态栏在哪 哪就应该是屏幕顶部\\N{\\fs12}wherever their status bar is, that's the top of the screen.\r\nDialogue: 0,0:49:32.37,0:49:36.42,yin,,0,0,0,,哪怕是像这样旋转 它处在错误的位置\\N{\\fs12}Even if it's been slow to notice rotation, and it's in the wrong place,\r\nDialogue: 0,0:49:36.42,0:49:37.81,yin,,0,0,0,,对于用户而言\\N{\\fs12}to the user, it's still to them,\r\nDialogue: 0,0:49:37.81,0:49:39.94,yin,,0,0,0,,用户仍然认为这是屏幕顶部\\N{\\fs12}they think that's the top of their screen.\r\nDialogue: 0,0:49:39.94,0:49:43.21,yin,,0,0,0,,不过这里只需要跟踪就行了\\N{\\fs12}But this is mostly going to track that anyway,\r\nDialogue: 0,0:49:43.21,0:49:45.48,yin,,0,0,0,,我们用这个 这个更方便\\N{\\fs12}so we'll use this one, it's convenient.\r\nDialogue: 0,0:49:45.48,0:49:47.47,yin,,0,0,0,,这里 横屏右\\N{\\fs12}And so here, landscape right,\r\nDialogue: 0,0:49:47.47,0:49:51.93,yin,,0,0,0,,可以看到 x和y交换了位置\\N{\\fs12}you can see we are swapping the X and Y. You see?\r\nDialogue: 0,0:49:51.93,0:49:55.14,yin,,0,0,0,,这是x 我用的是y\\N{\\fs12}This is the X, and I'm using the Y. Alright?\r\nDialogue: 0,0:49:55.14,0:49:59.46,yin,,0,0,0,,在横屏中我们都这样做了\\N{\\fs12}And so both of the landscapes we're doing that in,\r\nDialogue: 0,0:49:59.46,0:50:03.12,yin,,0,0,0,,y是负是正则依赖于\\N{\\fs12}and whether Y is negative or positive depends, you know,\r\nDialogue: 0,0:50:03.12,0:50:05.36,yin,,0,0,0,,横屏模式是反过来的 还是正确方向向上\\N{\\fs12}Y increases as we go down, so it just depends\r\nDialogue: 0,0:50:05.36,0:50:08.64,yin,,0,0,0,,横屏模式是反过来的 还是正确方向向上\\N{\\fs12}on whether we're portrait upside down or portrait right side up,\r\nDialogue: 0,0:50:08.64,0:50:10.44,yin,,0,0,0,,竖屏模式也一样\\N{\\fs12}and same thing for landscape.\r\nDialogue: 0,0:50:10.44,0:50:13.49,yin,,0,0,0,,你们可以以后再来研究这个\\N{\\fs12}So you can look at these, stare at these later,\r\nDialogue: 0,0:50:13.49,0:50:16.30,yin,,0,0,0,,确信这是正确的x和y\\N{\\fs12}as in convince yourself these are the right Xs and Ys.\r\nDialogue: 0,0:50:16.32,0:50:19.20,yin,,0,0,0,,这里我们用的是不同的 具体要看情况\\N{\\fs12}But you can just see, that we're using different ones depending.\r\nDialogue: 0,0:50:19.20,0:50:22.39,yin,,0,0,0,,我们看看这个怎么样\\N{\\fs12}So let's see how this works.\r\nDialogue: 0,0:50:22.39,0:50:25.75,yin,,0,0,0,,找到一个很好的朝向\\N{\\fs12}Let's get ourselves into a nice orientation here.\r\nDialogue: 0,0:50:25.75,0:50:27.99,yin,,0,0,0,,这里\\N{\\fs12}Just, here.\r\nDialogue: 0,0:50:27.99,0:50:31.24,yin,,0,0,0,,现在是往下弹 然后我转动设备\\N{\\fs12}Alright, so now it's bouncing around, and if I tilt it, see,\r\nDialogue: 0,0:50:31.24,0:50:33.69,yin,,0,0,0,,它弹到了一侧 再转向另一侧\\N{\\fs12}it's going off to the side, or I tilt it to the other side,\r\nDialogue: 0,0:50:33.69,0:50:36.01,yin,,0,0,0,,或是转向这边 或是往下\\N{\\fs12}or tilt it this way or down.\r\nDialogue: 0,0:50:36.01,0:50:39.88,yin,,0,0,0,,它现在跟着我转动设备在运动\\N{\\fs12}So now it's following me, however I tilt my device,\r\nDialogue: 0,0:50:39.88,0:50:43.40,yin,,0,0,0,,它追随着重力 我还可以用它来\\N{\\fs12}it is following that gravity, and I can kind of use it\r\nDialogue: 0,0:50:43.40,0:50:47.56,yin,,0,0,0,,越来越快地加速 看到了吗\\N{\\fs12}to accelerate faster and faster even, see that?\r\nDialogue: 0,0:50:47.56,0:50:50.23,yin,,0,0,0,,这就是我想要的\\N{\\fs12}So this is exactly what I want.\r\nDialogue: 0,0:50:50.23,0:50:55.13,yin,,0,0,0,,现在我就能够控制红色方块运动到哪\\N{\\fs12}I've got this thing so that I can control where my red block goes,\r\nDialogue: 0,0:50:55.13,0:50:58.10,yin,,0,0,0,,运动取决于我倾斜设备的方式\\N{\\fs12}depending on how I tilt my device.\r\nDialogue: 0,0:50:58.10,0:51:01.70,yin,,0,0,0,,我锁定了我的用户界面朝向\\N{\\fs12}Okay, now I've locked my user interface orientation here.\r\nDialogue: 0,0:51:01.70,0:51:05.14,yin,,0,0,0,,看 如果解锁 它就会有些让人不知所措\\N{\\fs12}Watch, if I unlock it, then it's a little disconcerting\r\nDialogue: 0,0:51:05.14,0:51:07.55,yin,,0,0,0,,我点这里 转向 哦\\N{\\fs12}because okay I'm clicking here, now I turn, and whoop!\r\nDialogue: 0,0:51:07.55,0:51:10.29,yin,,0,0,0,,我的状态栏移动了 但还是能行\\N{\\fs12}My status bar moved, but it's still working.\r\nDialogue: 0,0:51:10.29,0:51:12.15,yin,,0,0,0,,因为每次获得更新时\\N{\\fs12}Because every time I get an update,\r\nDialogue: 0,0:51:12.15,0:51:15.59,yin,,0,0,0,,它还是会重新调整下方在哪\\N{\\fs12}it's still readjusting to where down is.\r\nDialogue: 0,0:51:15.59,0:51:17.77,yin,,0,0,0,,用户可能有些晕头转向\\N{\\fs12}It's a little disconcerting to the user.\r\nDialogue: 0,0:51:17.77,0:51:20.13,yin,,0,0,0,,如果我是用户 我在玩这个游戏\\N{\\fs12}If I were a user and really playing this game,\r\nDialogue: 0,0:51:20.13,0:51:25.87,yin,,0,0,0,,我或许就应该锁定设备的朝向\\N{\\fs12}I would probably, you know, lock my thing into some orientation,\r\nDialogue: 0,0:51:25.87,0:51:28.43,yin,,0,0,0,,开关在这里 像这样\\N{\\fs12}where's that switch, here it is, like this.\r\nDialogue: 0,0:51:28.43,0:51:30.10,yin,,0,0,0,,这样玩起来就更有趣一些\\N{\\fs12}It would just be a little more fun to play this game\r\nDialogue: 0,0:51:30.10,0:51:33.23,yin,,0,0,0,,我的状态栏不会到处转 不过这还是能工作\\N{\\fs12}if it wasn't constantly switching my status bar, but it's still working,\r\nDialogue: 0,0:51:33.23,0:51:35.61,yin,,0,0,0,,只是这样会更好一些\\N{\\fs12}it's just a little...okay, this is better.\r\nDialogue: 0,0:51:35.61,0:51:37.95,yin,,0,0,0,,之前讲的都理解吗 有问题\\N{\\fs12}Make sense what we're doing so far? Question?\r\nDialogue: 0,0:51:41.51,0:51:43.93,yin,,0,0,0,,问题是 编程上能否锁定屏幕旋转\\N{\\fs12}The question is can you programmatically do rotation lock?\r\nDialogue: 0,0:51:43.93,0:51:48.13,yin,,0,0,0,,理论上可以 因为你可以指定说 应用程序只在\\N{\\fs12}Well, you kind of can, because you can specify that you're application only works\r\nDialogue: 0,0:51:48.13,0:51:49.75,yin,,0,0,0,,特定朝向下能够工作\\N{\\fs12}in certain orientations, right?\r\nDialogue: 0,0:51:49.75,0:51:54.17,yin,,0,0,0,,这样实际上就将朝向锁定住了\\N{\\fs12}And so by doing so, then you can basically do orientation lock.\r\nDialogue: 0,0:51:54.17,0:51:57.01,yin,,0,0,0,,我不知道有没有做法可以说\\N{\\fs12}So. I don't know that there's a way to kind of say\r\nDialogue: 0,0:51:57.01,0:51:59.15,yin,,0,0,0,,锁定在当前朝向\\N{\\fs12}\"lock it in the current orientation,\"\r\nDialogue: 0,0:51:59.15,0:52:01.79,yin,,0,0,0,,我不确定 也有可能有\\N{\\fs12}like I'm not sure there's a way to do that, there might be,\r\nDialogue: 0,0:52:01.79,0:52:04.40,yin,,0,0,0,,不过我不知道\\N{\\fs12}but I don't know offhand.\r\nDialogue: 0,0:52:04.40,0:52:07.44,yin,,0,0,0,,这样我们就能让方块弹起 并对我们的行为作出反应\\N{\\fs12}Alright. So now we've got this thing bouncing and responding\r\nDialogue: 0,0:52:07.44,0:52:08.75,yin,,0,0,0,,这很棒\\N{\\fs12}to our thing, that's a good idea.\r\nDialogue: 0,0:52:08.75,0:52:11.36,yin,,0,0,0,,下面我将\\N{\\fs12}One thing I'm going to do also here is I'm going\r\nDialogue: 0,0:52:11.36,0:52:14.88,yin,,0,0,0,,在开始之前将重力方向设为\\N{\\fs12}to set the gravity direction before we start,\r\nDialogue: 0,0:52:14.88,0:52:18.22,yin,,0,0,0,,VectorMake(0,0)\\N{\\fs12}equal to vector makes zero, zero.\r\nDialogue: 0,0:52:18.22,0:52:20.50,yin,,0,0,0,,这是因为在开始之前\\N{\\fs12}That's because I'm going to be starting this thing going off.\r\nDialogue: 0,0:52:20.50,0:52:25.86,yin,,0,0,0,,我不想让第一个有任何的向下加速度\\N{\\fs12}I don't want, before the first one goes off, to have any kind of downward acceleration,\r\nDialogue: 0,0:52:25.87,0:52:28.39,yin,,0,0,0,,我这里设置成为没有重力\\N{\\fs12}so I'm basically going to set it so we have no gravity, and then\r\nDialogue: 0,0:52:28.39,0:52:32.17,yin,,0,0,0,,然后开启加速计 让这个开始运动\\N{\\fs12}I'm going to start this accelerometer to get the, this going.\r\nDialogue: 0,0:52:32.17,0:52:34.01,yin,,0,0,0,,这很好\\N{\\fs12}So that's good.\r\nDialogue: 0,0:52:34.01,0:52:38.76,yin,,0,0,0,,如果再加一个方块就会更酷了\\N{\\fs12}Alright. This would be kind of cool if we added another block.\r\nDialogue: 0,0:52:38.76,0:52:42.78,yin,,0,0,0,,这里让我再来创建一个黑色方块\\N{\\fs12}So let's put another block in here. I'm going to create a black block.\r\nDialogue: 0,0:52:42.78,0:52:46.26,yin,,0,0,0,,到上面这里 设置属性 非原子\\N{\\fs12}So I'm going to go up here, and set property, non-atomic,\r\nDialogue: 0,0:52:46.26,0:52:49.99,yin,,0,0,0,,或许这些应该设为弱\\N{\\fs12}actually might as well make these weak,\r\nDialogue: 0,0:52:49.99,0:52:53.61,yin,,0,0,0,,如果它们离开了视图层级\\N{\\fs12}if they leave the view hierarchy,\r\nDialogue: 0,0:52:53.61,0:52:55.91,yin,,0,0,0,,我们就应该把它们清除掉\\N{\\fs12}then we'll clean them up.\r\nDialogue: 0,0:52:55.91,0:52:57.74,yin,,0,0,0,,黑色方块\\N{\\fs12}Black block.\r\nDialogue: 0,0:52:57.74,0:53:00.58,yin,,0,0,0,,注意 这里的所有行为也都设为了弱\\N{\\fs12}Notice I made these behaviors all weak as well.\r\nDialogue: 0,0:53:00.58,0:53:01.99,yin,,0,0,0,,为什么设为弱呢\\N{\\fs12}Why did I make these weak?\r\nDialogue: 0,0:53:01.99,0:53:04.74,yin,,0,0,0,,因为 如果这个动态动画器没有\\N{\\fs12}Well, because if this dynamic animator isn't holding\r\nDialogue: 0,0:53:04.74,0:53:07.00,yin,,0,0,0,,强引用它们 那我就不想要它们了\\N{\\fs12}on strongly to them, then I don't want them.\r\nDialogue: 0,0:53:07.00,0:53:10.16,yin,,0,0,0,,outlet设为弱也是一样的道理\\N{\\fs12}Same thing when we make an outlet weak, right?\r\nDialogue: 0,0:53:10.16,0:53:12.48,yin,,0,0,0,,如果视图层级不再引用它们\\N{\\fs12}If the view hierarchy isn't holding on to them,\r\nDialogue: 0,0:53:12.48,0:53:14.65,yin,,0,0,0,,这里我没有使用故事板\\N{\\fs12}and since I'm not doing storyboards here,\r\nDialogue: 0,0:53:14.65,0:53:16.72,yin,,0,0,0,,我只是写代码 不过情况还是一样\\N{\\fs12}I'm doing code, I'm still kind of doing the same thing.\r\nDialogue: 0,0:53:16.72,0:53:18.91,yin,,0,0,0,,如果不再处在视图层级中\\N{\\fs12}I don't want my red and black block to be around\r\nDialogue: 0,0:53:18.91,0:53:21.61,yin,,0,0,0,,我显然就不再需要红色和黑色方块\\N{\\fs12}if I take them out of the view hierarchy.\r\nDialogue: 0,0:53:21.61,0:53:23.70,yin,,0,0,0,,下面来创建黑色方块\\N{\\fs12}Alright, so let's make my black block.\r\nDialogue: 0,0:53:23.70,0:53:24.73,yin,,0,0,0,,很类似\\N{\\fs12}Actually it's very similar.\r\nDialogue: 0,0:53:24.73,0:53:28.73,yin,,0,0,0,,我们可以从红色方块那里复制粘贴\\N{\\fs12}Let's copy and paste my red block,\r\nDialogue: 0,0:53:28.73,0:53:34.14,yin,,0,0,0,,黑色方块 我们这样做\\N{\\fs12}black block, and we'll do this, and...\r\nDialogue: 0,0:53:38.95,0:53:39.90,yin,,0,0,0,,很有趣\\N{\\fs12}Well that's interesting.\r\nDialogue: 0,0:53:39.90,0:53:41.66,yin,,0,0,0,,这很奇怪\\N{\\fs12}Okay. That's very strange.\r\nDialogue: 0,0:53:41.66,0:53:45.67,yin,,0,0,0,,好 黑色方块 这里也是黑色方块\\N{\\fs12}Okay, black block, and then here's another black block,\r\nDialogue: 0,0:53:45.67,0:53:48.39,yin,,0,0,0,,黑色方块需要是黑色的\\N{\\fs12}and the black block wants to be black,\r\nDialogue: 0,0:53:48.39,0:53:52.71,yin,,0,0,0,,我们希望黑色方块有碰撞器的作用\\N{\\fs12}and we're going to have the black block do the collider,\r\nDialogue: 0,0:53:52.72,0:53:57.82,yin,,0,0,0,,但它不是弹性的 也不考虑重力这些\\N{\\fs12}but I'm not going to have it be as elastic, nor am I going to have it do the gravity.\r\nDialogue: 0,0:53:57.82,0:54:00.97,yin,,0,0,0,,黑色方块唯一运动的情况\\N{\\fs12}So the black block, the only thing that's going to make the black block move\r\nDialogue: 0,0:54:00.97,0:54:04.64,yin,,0,0,0,,是跟红色方块碰撞时\\N{\\fs12}is if we hit it with the red block. That's the only thing that can impart.\r\nDialogue: 0,0:54:04.64,0:54:07.46,yin,,0,0,0,,或是同边缘碰撞时\\N{\\fs12}Or if it collides with the edge, we'll get a little bit\r\nDialogue: 0,0:54:07.46,0:54:10.61,yin,,0,0,0,,我们会得到一些反应\\N{\\fs12}of reactive thing, but that's basically it.\r\nDialogue: 0,0:54:10.61,0:54:12.00,yin,,0,0,0,,这是黑色\\N{\\fs12}This is black.\r\nDialogue: 0,0:54:12.00,0:54:13.99,yin,,0,0,0,,让我们把黑色方块放到这里\\N{\\fs12}Alright? So let's put that black block on there,\r\nDialogue: 0,0:54:13.99,0:54:16.29,yin,,0,0,0,,两者一开始不能都在中间\\N{\\fs12}and let's not have them both start in the center,\r\nDialogue: 0,0:54:16.29,0:54:19.85,yin,,0,0,0,,这个开始于-100 这个开始于+100\\N{\\fs12}so we'll have that one start at minus 100 and this one start at plus 100.\r\nDialogue: 0,0:54:19.85,0:54:21.94,yin,,0,0,0,,看看是怎样的\\N{\\fs12}So we'll see what this looks like.\r\nDialogue: 0,0:54:21.94,0:54:28.22,yin,,0,0,0,,红色方块之外 加了一个黑色方块\\N{\\fs12}You add a black block to our red block.\r\nDialogue: 0,0:54:28.22,0:54:35.62,yin,,0,0,0,,可以看到 碰撞它 两者都会弹开\\N{\\fs12}Okay. So now if I can hit it, see you can see that they're both bouncing around.\r\nDialogue: 0,0:54:35.62,0:54:38.81,yin,,0,0,0,,红色这个有弹性\\N{\\fs12}The red one has more elasticity,\r\nDialogue: 0,0:54:38.81,0:54:43.25,yin,,0,0,0,,它会比黑色方块弹得更远\\N{\\fs12}so it bounces off quite a bit more powerfully than the black block.\r\nDialogue: 0,0:54:43.25,0:54:45.46,yin,,0,0,0,,不过我还是可以让黑色方块运动\\N{\\fs12}But I can still try and get that black block moving.\r\nDialogue: 0,0:54:45.46,0:54:48.48,yin,,0,0,0,,你可以很快将这做成一个游戏\\N{\\fs12}So now you can imagine turning this into a game pretty quick,\r\nDialogue: 0,0:54:48.48,0:54:53.12,yin,,0,0,0,,游戏的目标是保持黑色方块的运动\\N{\\fs12}which is the object of the game is to keep that black block moving.\r\nDialogue: 0,0:54:53.12,0:54:56.61,yin,,0,0,0,,运动维持得越好 你的得分就会越高\\N{\\fs12}The more you can make that black block move, the more points you get.\r\nDialogue: 0,0:54:56.61,0:55:00.61,yin,,0,0,0,,我们给这个游戏添加一个分数\\N{\\fs12}So let's go add some score. Let's add a score to this game.\r\nDialogue: 0,0:55:00.61,0:55:04.35,yin,,0,0,0,,这部分不能算是学习练习\\N{\\fs12}Now this part is not really that much of a learning exercise,\r\nDialogue: 0,0:55:04.35,0:55:09.82,yin,,0,0,0,,我只打算快速键入 你们可以以后去看\\N{\\fs12}so I'm going to just type that in, real fast, you can go look at this later.\r\nDialogue: 0,0:55:09.82,0:55:12.44,yin,,0,0,0,,涉及到很多属性\\N{\\fs12}It's got a whole bunch of properties involved\r\nDialogue: 0,0:55:12.44,0:55:15.13,yin,,0,0,0,,用来计分 像这样\\N{\\fs12}in keeping score, like that,\r\nDialogue: 0,0:55:15.13,0:55:18.23,yin,,0,0,0,,我们在代码中 只需要更新分数\\N{\\fs12}and all we need to do in our code is update the score.\r\nDialogue: 0,0:55:18.23,0:55:22.27,yin,,0,0,0,,我打算按加速计的频率更新计分\\N{\\fs12}And I'm going to update my score when the accelerometer goes off.\r\nDialogue: 0,0:55:22.27,0:55:25.06,yin,,0,0,0,,也就是10次每秒 这个频率似乎不错\\N{\\fs12}That's 10 times a second, that seems like a good rate to me,\r\nDialogue: 0,0:55:25.06,0:55:26.49,yin,,0,0,0,,我打算这样更新分值\\N{\\fs12}so I'm just going to update my score there.\r\nDialogue: 0,0:55:26.49,0:55:29.15,yin,,0,0,0,,我们来看看这个\\N{\\fs12}So let's look at that.\r\nDialogue: 0,0:55:29.15,0:55:33.35,yin,,0,0,0,,积分只是跟踪黑色方块在哪\\N{\\fs12}All the scorekeeping does is just keeps track of where the black block is,\r\nDialogue: 0,0:55:33.35,0:55:36.00,yin,,0,0,0,,它这样做了多久\\N{\\fs12}how long it's been doing that,\r\nDialogue: 0,0:55:36.00,0:55:38.24,yin,,0,0,0,,然后分数被写到中间\\N{\\fs12}and then it puts the score in the middle there. You can see,\r\nDialogue: 0,0:55:38.25,0:55:44.62,yin,,0,0,0,,这里同时记录了当前分数和目前最高分\\N{\\fs12}and it keeps both the current score and your highest score so far, with this block.\r\nDialogue: 0,0:55:44.62,0:55:48.61,yin,,0,0,0,,如果你让黑色方块停下 不再撞击它\\N{\\fs12}If you let the black block stay there, and you don't hit it,\r\nDialogue: 0,0:55:48.61,0:55:52.27,yin,,0,0,0,,可以看到 分值很快就会降低\\N{\\fs12}you can see that my score is going to start going down pretty soon.\r\nDialogue: 0,0:55:52.27,0:55:54.15,yin,,0,0,0,,看到了吧 正在下降\\N{\\fs12}See, it's going down.\r\nDialogue: 0,0:55:54.15,0:55:58.59,yin,,0,0,0,,再次撞击它 它又会开始运动\\N{\\fs12}But if I start hitting it again, make it move there we go,\r\nDialogue: 0,0:55:58.59,0:56:00.37,yin,,0,0,0,,分数又会上升\\N{\\fs12}it will start going back up again.\r\nDialogue: 0,0:56:00.37,0:56:05.79,yin,,0,0,0,,这样做得越久 分值就越难上升\\N{\\fs12}And the longer I keep doing this, the harder it is to get my score high,\r\nDialogue: 0,0:56:05.79,0:56:08.13,yin,,0,0,0,,现在还好\\N{\\fs12}but it's doing okay.\r\nDialogue: 0,0:56:08.13,0:56:10.90,yin,,0,0,0,,你们可以试试最高能得多少分\\N{\\fs12}So you can try and see what's the highest possible score.\r\nDialogue: 0,0:56:10.90,0:56:13.90,yin,,0,0,0,,我没有很好地完成保持黑色方块移动的任务\\N{\\fs12}Now I haven't done a very good job here of keeping that black block moving,\r\nDialogue: 0,0:56:13.90,0:56:16.27,yin,,0,0,0,,可以想象 分数还可以比这高很多\\N{\\fs12}so you can imagine the scores could be much, much higher.\r\nDialogue: 0,0:56:16.27,0:56:21.30,yin,,0,0,0,,还注意一点很有趣 碰到分数时 方块也会弹开\\N{\\fs12}Notice also for fun, I made it so that the score bounces off.\r\nDialogue: 0,0:56:21.30,0:56:23.14,yin,,0,0,0,,无法穿越分数\\N{\\fs12}So it doesn't go over the scores.\r\nDialogue: 0,0:56:23.14,0:56:25.06,yin,,0,0,0,,这会让游戏更难一些\\N{\\fs12}This will just kind of make it a little harder, actually,\r\nDialogue: 0,0:56:25.06,0:56:27.20,yin,,0,0,0,,你无法直接击中方块\\N{\\fs12}so you can't go straight to that block, you have to\r\nDialogue: 0,0:56:27.20,0:56:29.11,yin,,0,0,0,,你需要绕过分数的障碍\\N{\\fs12}think about the score being in the way.\r\nDialogue: 0,0:56:29.11,0:56:31.08,yin,,0,0,0,,这很酷\\N{\\fs12}So that's kind of cool.\r\nDialogue: 0,0:56:31.08,0:56:33.36,yin,,0,0,0,,我们准备把这发布到App商店\\N{\\fs12}We're almost ready to ship this on the app store.\r\nDialogue: 0,0:56:33.36,0:56:35.22,yin,,0,0,0,,还需要做什么呢\\N{\\fs12}What else are we going to do?\r\nDialogue: 0,0:56:35.22,0:56:40.34,yin,,0,0,0,,我们来想想这类游戏的一个很重要的部分\\N{\\fs12}Let's go ahead and think about an important part of a game like this,\r\nDialogue: 0,0:56:40.35,0:56:42.59,yin,,0,0,0,,也就是暂停\\N{\\fs12}which is pausing.\r\nDialogue: 0,0:56:42.59,0:56:45.04,yin,,0,0,0,,为什么要暂停呢\\N{\\fs12}Why would you ever want to pause this game?\r\nDialogue: 0,0:56:45.04,0:56:46.02,yin,,0,0,0,,原因有很多\\N{\\fs12}A lot of reasons.\r\nDialogue: 0,0:56:46.02,0:56:49.61,yin,,0,0,0,,这个游戏可能处在一系列游戏中 有一个标签栏\\N{\\fs12}What if this game were in a suite of games, where there was a tab bar,\r\nDialogue: 0,0:56:49.61,0:56:50.95,yin,,0,0,0,,你可以在游戏间切换\\N{\\fs12}and you were switching between games.\r\nDialogue: 0,0:56:50.95,0:56:53.33,yin,,0,0,0,,点击其它选项卡切换到别的游戏\\N{\\fs12}When you switch to another game on a different tab,\r\nDialogue: 0,0:56:53.33,0:56:56.80,yin,,0,0,0,,例如Machismo 这个游戏就需要暂停\\N{\\fs12}like machismo or something, you would want this game to pause,\r\nDialogue: 0,0:56:56.80,0:56:59.44,yin,,0,0,0,,以后回到它时 它就应当继续\\N{\\fs12}and then when you went back to it, you would want to continue.\r\nDialogue: 0,0:56:59.44,0:57:01.31,yin,,0,0,0,,我也有可能切换到另外一个程序\\N{\\fs12}Or what if I switch to another app?\r\nDialogue: 0,0:57:01.31,0:57:03.76,yin,,0,0,0,,像这样 切换到另一个程序\\N{\\fs12}I go like this, and go switch to another app\r\nDialogue: 0,0:57:03.76,0:57:07.23,yin,,0,0,0,,做点别的什么 然后回到游戏发现 哦\\N{\\fs12}and doing some other things, you know, and then I come back to my game, it's like, \"Oh!\r\nDialogue: 0,0:57:07.23,0:57:08.40,yin,,0,0,0,,我的分数毁了\\N{\\fs12}My score! Ruined.\"\r\nDialogue: 0,0:57:08.40,0:57:10.75,yin,,0,0,0,,因为方块一直待在那里没动\\N{\\fs12}Because it was sitting there doing nothing for all that time.\r\nDialogue: 0,0:57:10.75,0:57:13.51,yin,,0,0,0,,我希望这里有暂停 回来时再继续\\N{\\fs12}I want it to pause, and then continue when I come back.\r\nDialogue: 0,0:57:13.51,0:57:16.58,yin,,0,0,0,,我也有可能需要点击屏幕时暂停\\N{\\fs12}Or maybe I want to be able to just tap on it and pause,\r\nDialogue: 0,0:57:16.58,0:57:18.33,yin,,0,0,0,,再点击继续\\N{\\fs12}and tap again to continue, right?\r\nDialogue: 0,0:57:18.33,0:57:20.30,yin,,0,0,0,,暂停/继续是很需要的\\N{\\fs12}So pausing/resuming would be really cool.\r\nDialogue: 0,0:57:20.30,0:57:23.08,yin,,0,0,0,,那如何让游戏暂停/继续呢\\N{\\fs12}So how can we make our game pause and resume?\r\nDialogue: 0,0:57:23.08,0:57:27.09,yin,,0,0,0,,我们可以很轻松地将startGame转化为\\N{\\fs12}Well, we can take this start game and turn it pretty easily\r\nDialogue: 0,0:57:27.09,0:57:28.83,yin,,0,0,0,,resumeGame\\N{\\fs12}into resume game,\r\nDialogue: 0,0:57:28.83,0:57:31.84,yin,,0,0,0,,我们只需要检查\\N{\\fs12}and all we need to do to do that is check\r\nDialogue: 0,0:57:31.84,0:57:34.93,yin,,0,0,0,,游戏是否已经开始\\N{\\fs12}to see if the game is already started,\r\nDialogue: 0,0:57:34.93,0:57:37.92,yin,,0,0,0,,如果已经开始… 这里应该是非\\N{\\fs12}because if it's already started, well that's going to be not,\r\nDialogue: 0,0:57:37.92,0:57:40.10,yin,,0,0,0,,if (!…redBlock)\\N{\\fs12}if not red block,\r\nDialogue: 0,0:57:40.10,0:57:44.06,yin,,0,0,0,,如果游戏没开始 我们就需要创建红色和黑色方块\\N{\\fs12}if we haven't start a game, then we need to create the red and black block.\r\nDialogue: 0,0:57:44.06,0:57:47.80,yin,,0,0,0,,否则 我们可以开启这个加速计\\N{\\fs12}But otherwise, we can just fire up this accelerometer,\r\nDialogue: 0,0:57:47.80,0:57:51.56,yin,,0,0,0,,暂停则只需要停止加速计\\N{\\fs12}and what we'll do to pause is we'll just stop the accelerometer.\r\nDialogue: 0,0:57:51.56,0:57:53.63,yin,,0,0,0,,这里我只需要说\\N{\\fs12}So I'm just going to say\r\nDialogue: 0,0:57:53.63,0:57:58.13,yin,,0,0,0,,self.motionManager stopAccelerometerUpdates\\N{\\fs12}self dot motion manager stop accelerometer updates.\r\nDialogue: 0,0:57:58.13,0:58:02.45,yin,,0,0,0,,我这就暂停了 停止了加速计的更新\\N{\\fs12}So I've paused, I've just stopped the accelerometer from updating.\r\nDialogue: 0,0:58:02.45,0:58:03.61,yin,,0,0,0,,这很好\\N{\\fs12}Which is a pretty good thing.\r\nDialogue: 0,0:58:03.61,0:58:08.44,yin,,0,0,0,,然后还要暂停计分 我显然要这样做\\N{\\fs12}I also have pause scoring okay, because I want to do that.\r\nDialogue: 0,0:58:08.44,0:58:14.01,yin,,0,0,0,,不要太在意这个里面都有些什么\\N{\\fs12}Don't look too closely behind the curtain for that one\r\nDialogue: 0,0:58:14.01,0:58:21.15,yin,,0,0,0,,我还希望我的重力方向回到0\\N{\\fs12}and then also I want my gravity direction to be back to being zero.\r\nDialogue: 0,0:58:21.15,0:58:27.75,yin,,0,0,0,,暂停时 我不希望红色方块还因重力运动\\N{\\fs12}I don't want my red thing to be trying to do gravity when it's paused, right?\r\nDialogue: 0,0:58:27.75,0:58:30.03,yin,,0,0,0,,这就是暂停游戏所需要做的\\N{\\fs12}So that's all I really need to do to pause this game.\r\nDialogue: 0,0:58:30.03,0:58:35.88,yin,,0,0,0,,让我们添加一个点击手势用于暂停和继续游戏\\N{\\fs12}So let's put a little tap gesture in that pauses the game, and then continues the game.\r\nDialogue: 0,0:58:35.88,0:58:38.04,yin,,0,0,0,,这个这时可以继续\\N{\\fs12}This will, now can be resume,\r\nDialogue: 0,0:58:38.04,0:58:43.49,yin,,0,0,0,,我要创建一个点击手势 在viewDidLoad中\\N{\\fs12}and so I'm going to do a tap gesture, I'm going to do it in ViewDidLoad.\r\nDialogue: 0,0:58:43.49,0:58:48.09,yin,,0,0,0,,我说过 我不打算在故事板中做任何事\\N{\\fs12}Told you I wasn't going to do anything in the storyboard, and so I'm just going\r\nDialogue: 0,0:58:48.09,0:58:52.11,yin,,0,0,0,,这里我说 self.view addGestureRecognizer\\N{\\fs12}to say self dot view add gesture recognizer,\r\nDialogue: 0,0:58:52.11,0:58:53.93,yin,,0,0,0,,UITapGesture…\\N{\\fs12}UI tap gesture,\r\nDialogue: 0,0:58:53.93,0:58:56.21,yin,,0,0,0,,alloc\\N{\\fs12}alloc\r\nDialogue: 0,0:58:56.21,0:58:59.16,yin,,0,0,0,,initWithTarget:self\\N{\\fs12}init with target self,\r\nDialogue: 0,0:58:59.16,0:59:05.00,yin,,0,0,0,,action是tap 就这些了\\N{\\fs12}action is going to be tap, okay, that's it.\r\nDialogue: 0,0:59:05.00,0:59:08.01,yin,,0,0,0,,这样我就添加了点击手势 然后创建tap\\N{\\fs12}So now I've added this tap gesture, so now let's make tap.\r\nDialogue: 0,0:59:08.01,0:59:10.47,yin,,0,0,0,,tap的作用是这样的\\N{\\fs12}And all tap needs to do is when you say\r\nDialogue: 0,0:59:10.47,0:59:16.42,yin,,0,0,0,,如果暂停了 那就继续\\N{\\fs12}if we're paused, then resume,\r\nDialogue: 0,0:59:16.42,0:59:21.28,yin,,0,0,0,,否则就暂停\\N{\\fs12}otherwise, pause.\r\nDialogue: 0,0:59:21.28,0:59:27.43,yin,,0,0,0,,我们需要isPaused 如何知道有没有暂停呢\\N{\\fs12}So we need an \"is paused,\" how are we going to tell if we're paused or not?\r\nDialogue: 0,0:59:27.43,0:59:32.33,yin,,0,0,0,,很简单 isPaused 我将返回\\N{\\fs12}Real easy, is paused, I'm just going to return\r\nDialogue: 0,0:59:32.33,0:59:38.33,yin,,0,0,0,,如果运动管理器的加速计没有处在活动状态\\N{\\fs12}if the motion manager's accelerometer is not active.\r\nDialogue: 0,0:59:39.10,0:59:42.14,yin,,0,0,0,,如果运动管理器的加速计没有处在活动状态\\N{\\fs12}So if the accelerometer in the motion manager is not active,\r\nDialogue: 0,0:59:42.14,0:59:45.50,yin,,0,0,0,,那么我们就要暂停\\N{\\fs12}then we must be paused.\r\nDialogue: 0,0:59:47.37,0:59:48.46,yin,,0,0,0,,明白吗\\N{\\fs12}See what I did there?\r\nDialogue: 0,0:59:48.46,0:59:51.76,yin,,0,0,0,,我们来试试这个\\N{\\fs12}So let's go try this, see if this works.\r\nDialogue: 0,0:59:52.84,0:59:54.63,yin,,0,0,0,,这个将能行\\N{\\fs12}And this is going to work,\r\nDialogue: 0,0:59:54.63,0:59:59.23,yin,,0,0,0,,不过同我们想要的可能会有出入 我们来看看\\N{\\fs12}but not quite exactly how we might want, as you'll see.\r\nDialogue: 0,0:59:59.23,1:00:02.54,yin,,0,0,0,,首先让这个开始运动\\N{\\fs12}Alright, so let's go get some motion happening here first.\r\nDialogue: 0,1:00:02.54,1:00:05.24,yin,,0,0,0,,这个现在在运动 我点暂停\\N{\\fs12}Alright, so we got this thing, motion, I'm going to hit pause.\r\nDialogue: 0,1:00:05.24,1:00:09.98,yin,,0,0,0,,暂停了 但还在动\\N{\\fs12}Okay, so it paused, okay, but it's still--\r\nDialogue: 0,1:00:09.98,1:00:12.76,yin,,0,0,0,,暂停时加速计不再工作\\N{\\fs12}it paused in that my accelerometer is not working,\r\nDialogue: 0,1:00:12.76,1:00:15.33,yin,,0,0,0,,但红色方块还在运动\\N{\\fs12}but the red block still kind of kept moving,\r\nDialogue: 0,1:00:15.33,1:00:18.86,yin,,0,0,0,,这里我重新开启 重力回来了 暂停\\N{\\fs12}so here I turn it back on, gravity's back, I pause,\r\nDialogue: 0,1:00:18.86,1:00:21.59,yin,,0,0,0,,红色方块还会运动好久\\N{\\fs12}it's like the red block keeps moving a long way.\r\nDialogue: 0,1:00:21.59,1:00:23.31,yin,,0,0,0,,为什么它还在运动呢\\N{\\fs12}Okay, why does that red block keep moving?\r\nDialogue: 0,1:00:23.31,1:00:26.90,yin,,0,0,0,,因为之前有一个力施加在它之上\\N{\\fs12}Well, because it already has a force applied to it,\r\nDialogue: 0,1:00:26.90,1:00:30.02,yin,,0,0,0,,现在它要让这个力的作用自己消失\\N{\\fs12}and it's just letting that force kind of play out.\r\nDialogue: 0,1:00:30.02,1:00:31.95,yin,,0,0,0,,真正的暂停\\N{\\fs12}So what would be really nice when we pause is\r\nDialogue: 0,1:00:31.95,1:00:36.79,yin,,0,0,0,,最好是在这里放些减速沙 让其快速减慢\\N{\\fs12}if we put some quicksand in here, and everything kind of slowed down, right?\r\nDialogue: 0,1:00:36.79,1:00:38.50,yin,,0,0,0,,我不希望一切立刻停止\\N{\\fs12}I don't want everything to stop immediately,\r\nDialogue: 0,1:00:38.50,1:00:41.75,yin,,0,0,0,,不过我希望它们能够很好地减速\\N{\\fs12}but I want things to, you know, nicely slow down.\r\nDialogue: 0,1:00:41.75,1:00:43.92,yin,,0,0,0,,如何添加减速沙呢\\N{\\fs12}So how do we add quicksand?\r\nDialogue: 0,1:00:43.92,1:00:47.75,yin,,0,0,0,,这可以通过另一个动态动画器的做法来做到\\N{\\fs12}Well, I can do that with another dynamic animator thing.\r\nDialogue: 0,1:00:47.75,1:00:49.01,yin,,0,0,0,,放到下面这里\\N{\\fs12}Let's put this down here,\r\nDialogue: 0,1:00:49.01,1:00:52.52,yin,,0,0,0,,这里我将它称作quicksand\\N{\\fs12}I'm going to call it quicksand, in fact, alright?\r\nDialogue: 0,1:00:52.52,1:00:57.98,yin,,0,0,0,,quicksand是这里我要加的另一个行为\\N{\\fs12}And so quicksand is just another behavior that I'm adding right here.\r\nDialogue: 0,1:00:57.98,1:01:00.05,yin,,0,0,0,,quicksand是怎样的呢\\N{\\fs12}And what does this quicksand look like?\r\nDialogue: 0,1:01:00.05,1:01:01.82,yin,,0,0,0,,它是这样的 这就是我加的\\N{\\fs12}It's this, it's what I added.\r\nDialogue: 0,1:01:01.82,1:01:05.62,yin,,0,0,0,,这是一个具有阻力的UIDynamicAnimator\\N{\\fs12}And as a UI dynamic animator that has resistance,\r\nDialogue: 0,1:01:05.62,1:01:10.45,yin,,0,0,0,,阻力是物体上对抗所施力的阻力\\N{\\fs12}so resistance is a item's resistance to forces being applied to it.\r\nDialogue: 0,1:01:10.45,1:01:15.02,yin,,0,0,0,,最开始这是0 因此阻力是0 这是默认值\\N{\\fs12}So I'll start it out at zero, which means no resistance to it. That's the default.\r\nDialogue: 0,1:01:15.02,1:01:18.68,yin,,0,0,0,,它不会阻碍任何的力 包括重力\\N{\\fs12}So it doesn't resist any of the forces, you know, the gravity,\r\nDialogue: 0,1:01:18.68,1:01:21.71,yin,,0,0,0,,这些都不受阻 方块到处弹\\N{\\fs12}it doesn't resist any of that, just things are bouncing around.\r\nDialogue: 0,1:01:21.71,1:01:26.80,yin,,0,0,0,,然后在暂停时 我会让这个阻力瞬间提高到1\\N{\\fs12}And then when we pause, I'm going to crank this resistance up to like at least 1.\r\nDialogue: 0,1:01:26.80,1:01:30.25,yin,,0,0,0,,1也就是完全抵抗所施力 让速度很快下降\\N{\\fs12}1 is it completely resists forces so it will slow down really quickly,\r\nDialogue: 0,1:01:30.25,1:01:31.64,yin,,0,0,0,,这个值还可以大于1\\N{\\fs12}but I can go even more than 1,\r\nDialogue: 0,1:01:31.64,1:01:37.80,yin,,0,0,0,,也就是积极降低所施力 反应会非常积极\\N{\\fs12}which is it actively, you know, reduces its forces on it, its response to forces on it.\r\nDialogue: 0,1:01:37.80,1:01:39.46,yin,,0,0,0,,总之 我们有了quicksand\\N{\\fs12}But we've got this quicksand,\r\nDialogue: 0,1:01:39.46,1:01:47.00,yin,,0,0,0,,我们只需要将两个物体 红色方块\\N{\\fs12}all we need to do is add both the red item, the red block,\r\nDialogue: 0,1:01:47.00,1:01:50.82,yin,,0,0,0,,还有黑色方块 添加到quicksand\\N{\\fs12}and the black block, to the quicksand.\r\nDialogue: 0,1:01:54.15,1:01:56.52,yin,,0,0,0,,我少复制了一次\\N{\\fs12}I missed a copy key quite a bit.\r\nDialogue: 0,1:01:56.52,1:01:58.13,yin,,0,0,0,,好 黑色方块\\N{\\fs12}Okay black block.\r\nDialogue: 0,1:01:58.13,1:02:00.65,yin,,0,0,0,,把它们都放到quicksand中\\N{\\fs12}So we'll put them both in this quicksand,\r\nDialogue: 0,1:02:00.65,1:02:04.02,yin,,0,0,0,,然后我们要在暂停时\\N{\\fs12}and then we're just going to, when we pause,\r\nDialogue: 0,1:02:04.02,1:02:07.90,yin,,0,0,0,,将quicksand的阻力设为\\N{\\fs12}we're going to set the quicksand's resistance\r\nDialogue: 0,1:02:07.90,1:02:10.49,yin,,0,0,0,,10 这是非常高的阻力\\N{\\fs12}to let's say 10, which is pretty high resistance,\r\nDialogue: 0,1:02:10.49,1:02:12.19,yin,,0,0,0,,物体会很快慢下来\\N{\\fs12}they're going to slow down pretty fast with that.\r\nDialogue: 0,1:02:12.19,1:02:14.33,yin,,0,0,0,,如果实在太大 我们还可以调整\\N{\\fs12}We could tweak that, whether we want it to be that much.\r\nDialogue: 0,1:02:14.33,1:02:16.27,yin,,0,0,0,,之后继续游戏时\\N{\\fs12}And then when we resume the game,\r\nDialogue: 0,1:02:16.27,1:02:20.34,yin,,0,0,0,,我们会将quicksand的阻力重新设为0\\N{\\fs12}we're going to set the quicksand's resistance back to zero.\r\nDialogue: 0,1:02:20.34,1:02:23.34,yin,,0,0,0,,让我们来做这个\\N{\\fs12}So let's do that.\r\nDialogue: 0,1:02:23.34,1:02:27.61,yin,,0,0,0,,做这个是为了让你们看到暂停的效果\\N{\\fs12}And I'm mostly doing this so you can see the effect of pausing,\r\nDialogue: 0,1:02:27.61,1:02:31.76,yin,,0,0,0,,因为后面我还会讲到另一种情况下的暂停\\N{\\fs12}because next we're going to show how to do pausing in a different circumstance.\r\nDialogue: 0,1:02:31.76,1:02:35.79,yin,,0,0,0,,这里 让这个开始动 它在到处运动\\N{\\fs12}Okay so here, let's go, get this guy going again, right, he's moving around.\r\nDialogue: 0,1:02:35.79,1:02:38.29,yin,,0,0,0,,点暂停 看它停得有多快\\N{\\fs12}Now, if I pause, let's see how quickly he stopped.\r\nDialogue: 0,1:02:38.29,1:02:41.05,yin,,0,0,0,,还在旋转 但运动已经停止了\\N{\\fs12}He's still spinning, but he has stopped his motion.\r\nDialogue: 0,1:02:41.05,1:02:45.08,yin,,0,0,0,,如果继续 重力就会重新作用于它\\N{\\fs12}And if I continue, now gravity is going to work on him again.\r\nDialogue: 0,1:02:45.08,1:02:49.25,yin,,0,0,0,,像这样快速停止 让你有了作弊的机会\\N{\\fs12}One thing about stopping him so quickly, it allows you to cheat a little bit,\r\nDialogue: 0,1:02:49.25,1:02:51.03,yin,,0,0,0,,操作不好控制时\\N{\\fs12}because if this guy's out of control\r\nDialogue: 0,1:02:51.03,1:02:53.05,yin,,0,0,0,,你可以通过暂停来重新获得控制\\N{\\fs12}and you're trying to get him back in control so you can get\r\nDialogue: 0,1:02:53.05,1:02:56.93,yin,,0,0,0,,停下来以后再重开 你就很容易追上黑色方块了\\N{\\fs12}after the black block, this stops him, right? Too quick.\r\nDialogue: 0,1:02:56.93,1:03:01.94,yin,,0,0,0,,因此 或许10作为阻力值有些太大\\N{\\fs12}So it might be that having 10 be our quicksand is a little too high.\r\nDialogue: 0,1:03:01.94,1:03:03.57,yin,,0,0,0,,或许1就够了\\N{\\fs12}Maybe we only want 1.\r\nDialogue: 0,1:03:03.57,1:03:08.37,yin,,0,0,0,,这时减缓的速度就会更正常 更慢\\N{\\fs12}Which would mean it would slow down kind of at a normal or a much slower rate.\r\nDialogue: 0,1:03:08.37,1:03:10.67,yin,,0,0,0,,你们可以自己调\\N{\\fs12}So you could play with that.\r\nDialogue: 0,1:03:10.67,1:03:14.22,yin,,0,0,0,,什么时候我们想暂停呢\\N{\\fs12}Alright, so when would we want to do pausing.\r\nDialogue: 0,1:03:14.22,1:03:17.68,yin,,0,0,0,,需要暂停的一个很重要的地方就是\\N{\\fs12}Well, one of the real important places to pause is\r\nDialogue: 0,1:03:17.68,1:03:20.74,yin,,0,0,0,,用户点击进入另一个程序\\N{\\fs12}when someone clicks to go to another app.\r\nDialogue: 0,1:03:20.74,1:03:25.42,yin,,0,0,0,,我打算简要回到幻灯片\\N{\\fs12}So I'm going to go back to the slides, really briefly,\r\nDialogue: 0,1:03:25.42,1:03:29.53,yin,,0,0,0,,跟你们讲这个\\N{\\fs12}and show you this,\r\nDialogue: 0,1:03:29.53,1:03:32.98,yin,,0,0,0,,然后 我们再回来\\N{\\fs12}and then we'll go back.\r\nDialogue: 0,1:03:32.98,1:03:37.84,yin,,0,0,0,,你的程序的状态 你的程序的生命周期\\N{\\fs12}So your applications state the life cycle of your application,\r\nDialogue: 0,1:03:37.84,1:03:39.38,yin,,0,0,0,,会通过特定状态\\N{\\fs12}it goes through certain states,\r\nDialogue: 0,1:03:39.38,1:03:42.56,yin,,0,0,0,,其中之一就是 它是活动的应用程序\\N{\\fs12}and one of them is it's the active application.\r\nDialogue: 0,1:03:42.56,1:03:45.48,yin,,0,0,0,,活动应用程序是说你在获取事件\\N{\\fs12}And being the active application means you're getting events,\r\nDialogue: 0,1:03:45.48,1:03:47.71,yin,,0,0,0,,你的视图在获取事件\\N{\\fs12}your views are getting events, right?\r\nDialogue: 0,1:03:47.71,1:03:49.08,yin,,0,0,0,,触摸事件在发生\\N{\\fs12}Touch events are happening to you.\r\nDialogue: 0,1:03:49.08,1:03:52.07,yin,,0,0,0,,你在对世界作出响应\\N{\\fs12}You're basically responding to the world.\r\nDialogue: 0,1:03:52.07,1:03:54.91,yin,,0,0,0,,这些都只发生在你是活动程序的时候\\N{\\fs12}That's only happens when you're the active application.\r\nDialogue: 0,1:03:54.91,1:03:58.33,yin,,0,0,0,,如果你是活动程序 你的方块在弹动\\N{\\fs12}Now, if you're the active application, you're bouncing,\r\nDialogue: 0,1:03:58.33,1:04:01.57,yin,,0,0,0,,游戏正在进行 什么会导致你不再成为活动程序\\N{\\fs12}you're playing your game, what could cause you to stop being active application?\r\nDialogue: 0,1:04:01.57,1:04:05.18,yin,,0,0,0,,显然 只要用户点了home键 并进入另一个程序\\N{\\fs12}Well, obviously someone could click on the home button and go to another app,\r\nDialogue: 0,1:04:05.20,1:04:07.02,yin,,0,0,0,,不过还有可能有其它情况\\N{\\fs12}but there's other things too that could happen.\r\nDialogue: 0,1:04:07.02,1:04:08.83,yin,,0,0,0,,iPhone上可能会有来电\\N{\\fs12}A phone call could come in on your iPhone,\r\nDialogue: 0,1:04:08.83,1:04:14.57,yin,,0,0,0,,这时任何活动程序都需要停止 UI需要处理来电\\N{\\fs12}now you've stopped being the active app, whatever the UI is for handling a phone call.\r\nDialogue: 0,1:04:14.57,1:04:16.48,yin,,0,0,0,,哪怕是通知 这很重要\\N{\\fs12}Even notifications, very important,\r\nDialogue: 0,1:04:16.48,1:04:19.70,yin,,0,0,0,,系统通知也可以出现 让你的程序呈灰色\\N{\\fs12}system notifications can come up and, you know,\r\nDialogue: 0,1:04:19.70,1:04:22.22,yin,,0,0,0,,并在中间弹出一个警告窗口\\N{\\fs12}they gray out your app, they put an alert view in the middle,\r\nDialogue: 0,1:04:22.22,1:04:24.18,yin,,0,0,0,,给你某项通知\\N{\\fs12}and some notification happened,\r\nDialogue: 0,1:04:24.18,1:04:26.78,yin,,0,0,0,,这也会让你的程序停止活动\\N{\\fs12}that could make your app stop being active.\r\nDialogue: 0,1:04:26.78,1:04:29.14,yin,,0,0,0,,知道程序何时停止活动非常重要\\N{\\fs12}So it's important to know when your app stops being active,\r\nDialogue: 0,1:04:29.14,1:04:31.84,yin,,0,0,0,,例如Bouncer 它可以暂停游戏\\N{\\fs12}like Bouncer, so Bouncer can pause the game.\r\nDialogue: 0,1:04:31.84,1:04:35.30,yin,,0,0,0,,我希望将程序的活动性\\N{\\fs12}So I like to think of active, the activeness\r\nDialogue: 0,1:04:35.30,1:04:40.01,yin,,0,0,0,,对应于程序的暂停/继续\\N{\\fs12}of your application being the pause/resume of your application.\r\nDialogue: 0,1:04:40.01,1:04:42.14,yin,,0,0,0,,你可以知道这些状态\\N{\\fs12}So you find out about these,\r\nDialogue: 0,1:04:42.14,1:04:43.89,yin,,0,0,0,,应用程序委托有这些方法\\N{\\fs12}your application delegates have these methods.\r\nDialogue: 0,1:04:43.89,1:04:45.43,yin,,0,0,0,,applicationDidBecomeActive\\N{\\fs12}Application did become active,\r\nDialogue: 0,1:04:45.43,1:04:47.04,yin,,0,0,0,,applicationWillResignActive\\N{\\fs12}application will resign active, right?\r\nDialogue: 0,1:04:47.04,1:04:49.51,yin,,0,0,0,,这是在两种状态间转换\\N{\\fs12}That's going in between the two states,\r\nDialogue: 0,1:04:49.51,1:04:52.01,yin,,0,0,0,,不过这里还有一个广播站\\N{\\fs12}but there's also a radio station for it.\r\nDialogue: 0,1:04:52.01,1:04:54.43,yin,,0,0,0,,理解这个很重要 这里还有广播站\\N{\\fs12}And that's important to understand, there's this radio station too,\r\nDialogue: 0,1:04:54.43,1:04:55.56,yin,,0,0,0,,你可以有视图控制器\\N{\\fs12}and so you can have view controllers\r\nDialogue: 0,1:04:55.56,1:04:56.91,yin,,0,0,0,,像这个Bouncer的\\N{\\fs12}like this Bouncer guy,\r\nDialogue: 0,1:04:56.91,1:04:59.99,yin,,0,0,0,,监听广播站 弄清情况并进行暂停\\N{\\fs12}listen to the radio station and find this out and do the pausing.\r\nDialogue: 0,1:04:59.99,1:05:02.10,yin,,0,0,0,,等下我们就会在demo中这样做\\N{\\fs12}So we're going to do that in the demo in a second.\r\nDialogue: 0,1:05:02.10,1:05:05.05,yin,,0,0,0,,既然讲到了这里 我就来讲下应用状态的其它内容吧\\N{\\fs12}While I'm here, though, let me talk about some other application state things.\r\nDialogue: 0,1:05:05.05,1:05:07.30,yin,,0,0,0,,其中之一是后台/前台\\N{\\fs12}One of them is background/foreground,\r\nDialogue: 0,1:05:07.30,1:05:10.31,yin,,0,0,0,,这同活动/非活动是不同的\\N{\\fs12}which is a different thing than active/not active.\r\nDialogue: 0,1:05:10.31,1:05:14.56,yin,,0,0,0,,活动是说你在前台 而且你在接收事件\\N{\\fs12}Active means you're in the foreground, and you're receiving events.\r\nDialogue: 0,1:05:14.56,1:05:19.48,yin,,0,0,0,,当用户换程序时 你不再活动\\N{\\fs12}When someone clicks to go on some other app, you stop being active,\r\nDialogue: 0,1:05:19.48,1:05:21.21,yin,,0,0,0,,但你还没在后台\\N{\\fs12}but you're not in the background yet.\r\nDialogue: 0,1:05:21.21,1:05:26.10,yin,,0,0,0,,你可以把后台看成是被搁置了起来\\N{\\fs12}You can think of background as kind of being shelved. You're being put on the shelf.\r\nDialogue: 0,1:05:26.10,1:05:28.42,yin,,0,0,0,,搁置起来后 你就不再运行\\N{\\fs12}And when you're put on the shelf, you don't run.\r\nDialogue: 0,1:05:28.42,1:05:31.52,yin,,0,0,0,,在后台运行的情况只有 后台取回\\N{\\fs12}The only time you're ever going to run when you're on the shelf is a background fetch,\r\nDialogue: 0,1:05:31.52,1:05:33.13,yin,,0,0,0,,几周前我们看到过\\N{\\fs12}which we saw a couple weeks ago,\r\nDialogue: 0,1:05:33.13,1:05:35.04,yin,,0,0,0,,或者 你是一种特殊应用\\N{\\fs12}or your a special kind of app,\r\nDialogue: 0,1:05:35.04,1:05:38.08,yin,,0,0,0,,例如VOIP应用 或是位置服务应用\\N{\\fs12}like a VOIP app or a location services app,\r\nDialogue: 0,1:05:38.08,1:05:40.33,yin,,0,0,0,,这时你就可以在后台\\N{\\fs12}where you're getting locations, then you can come off the shelf\r\nDialogue: 0,1:05:40.33,1:05:43.12,yin,,0,0,0,,偶尔运行一下 但你是被搁置的\\N{\\fs12}and run for a little bit occasionally, but you're being shelved.\r\nDialogue: 0,1:05:43.12,1:05:44.86,yin,,0,0,0,,后台就是搁置\\N{\\fs12}So background is shelving.\r\nDialogue: 0,1:05:44.86,1:05:48.89,yin,,0,0,0,,活动是说 你或许还是用户正在使用的应用程序\\N{\\fs12}Active is just, you might still be the app that the user is using,\r\nDialogue: 0,1:05:48.89,1:05:51.98,yin,,0,0,0,,但或许有别的东西暂时打断了这个\\N{\\fs12}but something has happened to interrupt that, maybe temporarily.\r\nDialogue: 0,1:05:51.98,1:05:54.08,yin,,0,0,0,,活动是是否接收事件\\N{\\fs12}So active is whether you're receiving events.\r\nDialogue: 0,1:05:54.08,1:05:55.45,yin,,0,0,0,,它是暂停/继续\\N{\\fs12}It's kind of a pause/resume.\r\nDialogue: 0,1:05:55.45,1:05:56.78,yin,,0,0,0,,后台是搁置\\N{\\fs12}Background is shelved.\r\nDialogue: 0,1:05:56.78,1:05:57.91,yin,,0,0,0,,在被搁置之前\\N{\\fs12}So before you get shelved,\r\nDialogue: 0,1:05:57.91,1:06:00.28,yin,,0,0,0,,你显然希望你的世界打理干净了\\N{\\fs12}you want to definitely make sure your world's cleaned up\r\nDialogue: 0,1:06:00.28,1:06:02.91,yin,,0,0,0,,一切都处在良好状态 因为\\N{\\fs12}and everything is a nice state, because one thing,\r\nDialogue: 0,1:06:02.91,1:06:06.03,yin,,0,0,0,,搁置的东西有可能被清理 你会被丢掉\\N{\\fs12}the shelf can sometimes be cleaned off and you're thrown out.\r\nDialogue: 0,1:06:06.03,1:06:08.52,yin,,0,0,0,,如果内存出现问题这些\\N{\\fs12}If memory became a problem or something\r\nDialogue: 0,1:06:08.52,1:06:11.13,yin,,0,0,0,,你可能完全无法再运行\\N{\\fs12}like that you could just completely never run again.\r\nDialogue: 0,1:06:11.13,1:06:15.03,yin,,0,0,0,,被放入后台时 你需要知道这些\\N{\\fs12}So when you get put in the background, you want to know about that maybe.\r\nDialogue: 0,1:06:15.03,1:06:18.25,yin,,0,0,0,,你还需要在回前台的时候弄清\\N{\\fs12}But you find out when you come back in the foreground, too.\r\nDialogue: 0,1:06:18.25,1:06:20.10,yin,,0,0,0,,这样你就可以撤销\\N{\\fs12}So, you know, then you can undo.\r\nDialogue: 0,1:06:20.10,1:06:24.15,yin,,0,0,0,,通常在前台 你会撤销你在后台做的\\N{\\fs12}Usually in the foreground one, you undo what you did in the background one.\r\nDialogue: 0,1:06:24.15,1:06:27.52,yin,,0,0,0,,还有一些应用程序委托项目也很有趣\\N{\\fs12}There are some other application delegate items of interest\r\nDialogue: 0,1:06:27.52,1:06:29.91,yin,,0,0,0,,你们可以到说明文档中查一下\\N{\\fs12}that you can look up in the documentation.\r\nDialogue: 0,1:06:29.91,1:06:31.89,yin,,0,0,0,,一个是本地通知\\N{\\fs12}One is local notifications.\r\nDialogue: 0,1:06:31.89,1:06:34.78,yin,,0,0,0,,本地通知是进行计划安排\\N{\\fs12}Local notifications are a way for you to schedule\r\nDialogue: 0,1:06:34.78,1:06:38.34,yin,,0,0,0,,让程序中某个东西在特定时间日期发生\\N{\\fs12}something to happen in your app at a certain date and time,\r\nDialogue: 0,1:06:38.34,1:06:40.97,yin,,0,0,0,,这个发生时 如果你的程序没在运行\\N{\\fs12}and when that happens, if your application is not running,\r\nDialogue: 0,1:06:40.97,1:06:43.46,yin,,0,0,0,,程序就可以启动来处理它\\N{\\fs12}you can be launched to handle it.\r\nDialogue: 0,1:06:43.46,1:06:47.45,yin,,0,0,0,,这是一种让程序在特定时间运行的方式\\N{\\fs12}So it's a way to kind of make sure your app runs at a certain time.\r\nDialogue: 0,1:06:47.45,1:06:50.52,yin,,0,0,0,,例如日历程序 它就是这样提醒你特定事件\\N{\\fs12}So like the calendar app, this is how it would make sure\r\nDialogue: 0,1:06:50.52,1:06:54.11,yin,,0,0,0,,例如你要在什么时候去上课 或是别的什么\\N{\\fs12}that you got reminded that you're supposed to go to class or whatever, even\r\nDialogue: 0,1:06:54.11,1:06:57.09,yin,,0,0,0,,有时日历程序甚至没在运行\\N{\\fs12}if the calendar app is not even running.\r\nDialogue: 0,1:06:57.09,1:06:59.32,yin,,0,0,0,,本地通知你们可以看看\\N{\\fs12}So local notification is something to look at.\r\nDialogue: 0,1:06:59.32,1:07:02.31,yin,,0,0,0,,状态恢复 如果你被搁置了\\N{\\fs12}State restoration, if you got put on the shelf,\r\nDialogue: 0,1:07:02.31,1:07:06.04,yin,,0,0,0,,然后被关闭 用户重新运行你\\N{\\fs12}and then you got killed, and the user ran you again,\r\nDialogue: 0,1:07:06.04,1:07:10.23,yin,,0,0,0,,你不希望你的UI以最初UI的形式出现\\N{\\fs12}you don't want your UI to come up like in some base start UI,\r\nDialogue: 0,1:07:10.23,1:07:13.42,yin,,0,0,0,,你希望UI能呈现出搁置时的状态\\N{\\fs12}you still want to come back to where it was when you got put on the shelf.\r\nDialogue: 0,1:07:13.42,1:07:16.84,yin,,0,0,0,,状态恢复能够帮你跟踪之前的UI状态\\N{\\fs12}So state restoration is a formalism where you keep track\r\nDialogue: 0,1:07:16.84,1:07:19.57,yin,,0,0,0,,你被搁置 然后被关闭\\N{\\fs12}of where your UI is, so when you get put on the shelf,\r\nDialogue: 0,1:07:19.57,1:07:23.92,yin,,0,0,0,,之后重启时 你就能回到这种状态\\N{\\fs12}if you get killed and have to come back, you can restore your state to where it was.\r\nDialogue: 0,1:07:23.92,1:07:26.30,yin,,0,0,0,,数据保护很有趣\\N{\\fs12}Data protection is an interesting one.\r\nDialogue: 0,1:07:26.30,1:07:28.39,yin,,0,0,0,,这是一种保护文件的方式\\N{\\fs12}There are ways to protect files that say\r\nDialogue: 0,1:07:28.39,1:07:31.39,yin,,0,0,0,,如果设备被锁 在锁屏条件下\\N{\\fs12}if this device is locked, in other words, at the lock screen,\r\nDialogue: 0,1:07:31.39,1:07:33.21,yin,,0,0,0,,那么你就不能访问这个文件\\N{\\fs12}then you can't access this file.\r\nDialogue: 0,1:07:33.21,1:07:35.12,yin,,0,0,0,,如果没锁 你就能访问\\N{\\fs12}But if it's unlocked, then you can.\r\nDialogue: 0,1:07:35.12,1:07:37.01,yin,,0,0,0,,这是一种特殊的保护\\N{\\fs12}So it's kind of a special kind of protection.\r\nDialogue: 0,1:07:37.01,1:07:41.57,yin,,0,0,0,,你可以了解到何时有锁 何时没锁\\N{\\fs12}You can find out about changes in that, i.e., when the thing is locked and unlocked,\r\nDialogue: 0,1:07:41.57,1:07:46.64,yin,,0,0,0,,也有方法能够让你知道当前有没有锁\\N{\\fs12}and also there's method in there for finding out currently is it locked or not.\r\nDialogue: 0,1:07:46.64,1:07:48.20,yin,,0,0,0,,然后还有Open URL\\N{\\fs12}Then there's open URL.\r\nDialogue: 0,1:07:48.20,1:07:50.56,yin,,0,0,0,,Open URL很酷 你可以到Xcode\\N{\\fs12}Open URL is kind of a cool thing, you can go into X code\r\nDialogue: 0,1:07:50.56,1:07:54.57,yin,,0,0,0,,在项目设置中找到info选项卡\\N{\\fs12}if you go to the info tab there in project settings.\r\nDialogue: 0,1:07:54.57,1:07:59.10,yin,,0,0,0,,在这里定义一个URL 不是http:什么什么\\N{\\fs12}You can define a URL, like not http colon something\r\nDialogue: 0,1:07:59.10,1:08:01.72,yin,,0,0,0,,而是Photomania:什么什么这些\\N{\\fs12}but like PhotoMania colon something, for example,\r\nDialogue: 0,1:08:01.72,1:08:03.27,yin,,0,0,0,,假设Photomania想要做这个\\N{\\fs12}if PhotoMania wanted to do it.\r\nDialogue: 0,1:08:03.27,1:08:04.39,yin,,0,0,0,,如果其他人\\N{\\fs12}And then if other people\r\nDialogue: 0,1:08:04.39,1:08:05.99,yin,,0,0,0,,在其它程序中说\\N{\\fs12}in other apps say\r\nDialogue: 0,1:08:05.99,1:08:08.81,yin,,0,0,0,,open URL Photomania://\\N{\\fs12}open URL PhotoMania colon slash slash,\r\nDialogue: 0,1:08:08.81,1:08:11.05,yin,,0,0,0,,什么什么什么 问号 这个 那个\\N{\\fs12}something something something, question mark, this, that,\r\nDialogue: 0,1:08:11.05,1:08:15.19,yin,,0,0,0,,这样的完整URL\\N{\\fs12}all the full URL things you can do in the world of URLs,\r\nDialogue: 0,1:08:15.19,1:08:18.88,yin,,0,0,0,,那么Photomania就会被启动 处理那个URL\\N{\\fs12}then PhotoMania would get launched to go handle that URL.\r\nDialogue: 0,1:08:18.88,1:08:23.67,yin,,0,0,0,,这里会有应用程序委托方法被调用 处理这个URL\\N{\\fs12}And there will be application delegate method called, handle this URL.\r\nDialogue: 0,1:08:23.67,1:08:26.49,yin,,0,0,0,,这是应用程序委托中值得看看的另外一个东西\\N{\\fs12}So that's another thing to look at in application delegate.\r\nDialogue: 0,1:08:27.39,1:08:31.38,yin,,0,0,0,,好 这方面就这些了\\N{\\fs12}Okay. So. That's the end, that's all I wanted to cover on that.\r\nDialogue: 0,1:08:31.38,1:08:33.36,yin,,0,0,0,,下面回到Bouncer\\N{\\fs12}But now, let's go back to Bouncer,\r\nDialogue: 0,1:08:33.36,1:08:35.08,yin,,0,0,0,,演示这个的使用\\N{\\fs12}and show using this.\r\nDialogue: 0,1:08:35.08,1:08:40.04,yin,,0,0,0,,我打算在停止活动时暂停\\N{\\fs12}I'm going to pause when I get, stop being active, and I'm going\r\nDialogue: 0,1:08:40.04,1:08:43.43,yin,,0,0,0,,重新活动时 我将继续\\N{\\fs12}to un-pause when I go back to being active.\r\nDialogue: 0,1:08:43.43,1:08:45.53,yin,,0,0,0,,做法很简单\\N{\\fs12}And the way I'm going to do that, very simple,\r\nDialogue: 0,1:08:45.53,1:08:47.87,yin,,0,0,0,,NSNotificationCenter\\N{\\fs12}NS notification center,\r\nDialogue: 0,1:08:47.87,1:08:49.53,yin,,0,0,0,,defaultCenter\\N{\\fs12}default center,\r\nDialogue: 0,1:08:49.53,1:08:51.68,yin,,0,0,0,,addObserverForName\\N{\\fs12}add observer for name,\r\nDialogue: 0,1:08:51.75,1:08:59.69,yin,,0,0,0,,我要的是UIApplicationWillResignActive\\N{\\fs12}and the one I want is UIApplicationWillResignActive.\r\nDialogue: 0,1:09:00.08,1:09:05.44,yin,,0,0,0,,这会在应用程序退出活动时发生\\N{\\fs12}So that happens when I'm going to resign being the active application.\r\nDialogue: 0,1:09:05.44,1:09:10.98,yin,,0,0,0,,object:Nil 我不在乎这来自于谁\\N{\\fs12}And object nil, I don't really care who-- whoops! Who this comes from.\r\nDialogue: 0,1:09:10.98,1:09:14.71,yin,,0,0,0,,反正它会来自某个应用程序对象\\N{\\fs12}It's going to come from the application, whatever, application object.\r\nDialogue: 0,1:09:14.71,1:09:18.46,yin,,0,0,0,,queue 可以在我调用这个的队列上\\N{\\fs12}Queue, fine to do it on this queue that I'm calling this from.\r\nDialogue: 0,1:09:18.46,1:09:20.68,yin,,0,0,0,,然后这里是我要使用的block\\N{\\fs12}And then, here's the block I want to do,\r\nDialogue: 0,1:09:20.68,1:09:24.56,yin,,0,0,0,,在我的程序中这很简单 self pauseGame\\N{\\fs12}in my app, really simple, self, pause, game.\r\nDialogue: 0,1:09:24.56,1:09:28.22,yin,,0,0,0,,我将让程序不再活动 这就需要暂停\\N{\\fs12}I'm going to resign being the active application, so I'm going to pause.\r\nDialogue: 0,1:09:28.22,1:09:33.67,yin,,0,0,0,,回到这里来做相同的事情\\N{\\fs12}And similarly, can do the same thing when I come back,\r\nDialogue: 0,1:09:33.67,1:09:37.80,yin,,0,0,0,,不过这里是UIApplicationDidBecomeActive\\N{\\fs12}but here it's UIApplicationDidBecomeActive,\r\nDialogue: 0,1:09:37.81,1:09:41.86,yin,,0,0,0,,而这里我想要继续\\N{\\fs12}and here I want to resume.\r\nDialogue: 0,1:09:41.86,1:09:44.81,yin,,0,0,0,,看看这能否正常工作\\N{\\fs12}So let's see if this works.\r\nDialogue: 0,1:09:52.22,1:09:54.47,yin,,0,0,0,,好 开始游戏\\N{\\fs12}Alright, so let's get this doing something\r\nDialogue: 0,1:09:54.47,1:09:58.81,yin,,0,0,0,,我们来得点分数 有了\\N{\\fs12}so we can see some points being scored, there we go.\r\nDialogue: 0,1:09:58.81,1:10:03.11,yin,,0,0,0,,现在我们得到了一些分数 80 90 100 110\\N{\\fs12}Okay so we've got some points, we're about 80, 90, 100, 110,\r\nDialogue: 0,1:10:03.11,1:10:08.84,yin,,0,0,0,,暂停后 我还是会在110多分 看 再次暂停\\N{\\fs12}okay so if I pause, I'll still be at 110-ish, see, pause again.\r\nDialogue: 0,1:10:08.84,1:10:11.67,yin,,0,0,0,,分数还是原来的分数 之后会快速降低\\N{\\fs12}Okay, my score is saying the same score, down now pretty fast\r\nDialogue: 0,1:10:11.67,1:10:15.83,yin,,0,0,0,,因为我没有撞击黑色方块 再让它运动起来\\N{\\fs12}because I'm not hitting that black block, let's get him going again.\r\nDialogue: 0,1:10:15.83,1:10:18.49,yin,,0,0,0,,分数重新加起 下面再去另一个app\\N{\\fs12}Get the score back up, okay now I'm going to go to another app.\r\nDialogue: 0,1:10:18.49,1:10:21.56,yin,,0,0,0,,105 113 我们去另一个app\\N{\\fs12}105, 113, so let's go to another app.\r\nDialogue: 0,1:10:21.56,1:10:26.43,yin,,0,0,0,,我可以进设置 我的app现在应该暂停了\\N{\\fs12}Okay, maybe settings or something like that, and my app right now is paused, I hope.\r\nDialogue: 0,1:10:26.43,1:10:29.47,yin,,0,0,0,,回来看看Bouncer是不是和原来一样\\N{\\fs12}So let's go back and hopefully Bouncer will be\r\nDialogue: 0,1:10:29.47,1:10:32.84,yin,,0,0,0,,差不多 还是100左右\\N{\\fs12}about where it was, and it is, it was at about 100.\r\nDialogue: 0,1:10:32.84,1:10:37.56,yin,,0,0,0,,实际上 我们可以回头看看\\N{\\fs12}Now, in fact, if we go away and come back, if you first look,\r\nDialogue: 0,1:10:37.56,1:10:41.93,yin,,0,0,0,,回来时它显示了一下暂停 因为这里确实暂停了\\N{\\fs12}you'll see it shows paused for a second because it was paused.\r\nDialogue: 0,1:10:41.93,1:10:47.65,yin,,0,0,0,,你们还可以看到 这里是71 70 69 68 67\\N{\\fs12}Also, though, you'll notice that see this is 71, 70, 69, 68, 67.\r\nDialogue: 0,1:10:47.65,1:10:52.66,yin,,0,0,0,,等我回来时 它不是66 而是更少一些 这里是65\\N{\\fs12}But now when I come back it's not going to be at 66, it's farther along, see 65.\r\nDialogue: 0,1:10:52.66,1:10:53.23,yin,,0,0,0,,为什么呢\\N{\\fs12}Why is that?\r\nDialogue: 0,1:10:53.23,1:10:56.25,yin,,0,0,0,,这是因为它还运行了几秒\\N{\\fs12}Well that is because it does get to run for a few seconds.\r\nDialogue: 0,1:10:56.25,1:10:58.72,yin,,0,0,0,,我点到别的app时\\N{\\fs12}When I click to go to another app,\r\nDialogue: 0,1:10:58.72,1:11:00.90,yin,,0,0,0,,这个app还会保持活动几秒钟\\N{\\fs12}I stay the active app for a few seconds,\r\nDialogue: 0,1:11:00.90,1:11:04.02,yin,,0,0,0,,运行一下后才不是活动app\\N{\\fs12}and it gets to run a little bit, and now I'm not the active app,\r\nDialogue: 0,1:11:04.02,1:11:06.73,yin,,0,0,0,,我暂停 然后回来\\N{\\fs12}so I pause, and then we come back.\r\nDialogue: 0,1:11:06.73,1:11:10.51,yin,,0,0,0,,这里有点时间差 我只是想让你们知道一下\\N{\\fs12}So there is a short amount of time there, just so you know there's that window.\r\nDialogue: 0,1:11:10.51,1:11:14.71,yin,,0,0,0,,我们想要暂停和继续的最后一个地方是这里\\N{\\fs12}The last place that we want to pause and resume is here.\r\nDialogue: 0,1:11:14.71,1:11:16.47,yin,,0,0,0,,这是viewDidAppear\\N{\\fs12}Here's viewDidAppear,\r\nDialogue: 0,1:11:16.47,1:11:18.79,yin,,0,0,0,,这里已经是继续了 之前是开始\\N{\\fs12}we're already resuming here because we used to be starting\r\nDialogue: 0,1:11:18.79,1:11:20.25,yin,,0,0,0,,现在我们改为了继续\\N{\\fs12}and then we changed it to resume.\r\nDialogue: 0,1:11:20.25,1:11:37.55,yin,,0,0,0,,显然 在viewWillDisappear中 我们希望暂停游戏\\N{\\fs12}Obviously in view will disappear, we want to self pause game.\r\nDialogue: 0,1:11:37.55,1:11:40.37,yin,,0,0,0,,这是我们点到标签栏中\\N{\\fs12}That's again if we're in the tab bar,\r\nDialogue: 0,1:11:40.37,1:11:44.00,yin,,0,0,0,,点另一个选项卡时的情况 我们希望暂停 然后回来\\N{\\fs12}click on another tab, we want to pause and come back.\r\nDialogue: 0,1:11:45.54,1:11:48.11,yin,,0,0,0,,好 我还没有讲动作表单\\N{\\fs12}Okay, so I didn't get to do action sheet.\r\nDialogue: 0,1:11:48.11,1:11:52.30,yin,,0,0,0,,我会发布动作表单的代码\\N{\\fs12}I will post the code for the action sheet thing.\r\nDialogue: 0,1:11:52.30,1:11:53.89,yin,,0,0,0,,对于动作表单\\N{\\fs12}All I was going to do in the action sheet\r\nDialogue: 0,1:11:53.89,1:11:56.55,yin,,0,0,0,,我只是在Photomania中添加了一个按钮\\N{\\fs12}is just add another button in PhotoMania\r\nDialogue: 0,1:11:56.55,1:11:58.92,yin,,0,0,0,,来进行照片选择 叫作照片滤镜\\N{\\fs12}to do the little photo choosing, called filter photo,\r\nDialogue: 0,1:11:58.92,1:12:00.37,yin,,0,0,0,,它会给你一个动作表单\\N{\\fs12}and it was going to put up an action sheet,\r\nDialogue: 0,1:12:00.37,1:12:04.85,yin,,0,0,0,,你可以选一个滤镜 例如黑色\\N{\\fs12}and you could pick a photo like, or a filter, like I had noir,\r\nDialogue: 0,1:12:04.85,1:12:06.67,yin,,0,0,0,,铬黄 模糊\\N{\\fs12}and chrome, and blur,\r\nDialogue: 0,1:12:06.67,1:12:09.07,yin,,0,0,0,,你选一个 然后应用滤镜\\N{\\fs12}you pick one of those, and it would apply the filter to it,\r\nDialogue: 0,1:12:09.07,1:12:10.58,yin,,0,0,0,,这就是动作表单的作用\\N{\\fs12}and that's all we were doing on the action sheet.\r\nDialogue: 0,1:12:10.58,1:12:12.07,yin,,0,0,0,,它会告诉你如何弹出动作表单\\N{\\fs12}But it shows you how to put up an action sheet,\r\nDialogue: 0,1:12:12.07,1:12:14.85,yin,,0,0,0,,加载一些东西 然后对它作出反应\\N{\\fs12}load it up with some things, and respond to it.\r\nDialogue: 0,1:12:14.85,1:12:19.44,yin,,0,0,0,,我今天会发布代码 你们会看到具体怎么做\\N{\\fs12}So I'll just post that code today and you'll get to see that.\r\nDialogue: 0,1:12:19.44,1:12:20.77,yin,,0,0,0,,好 就这些了\\N{\\fs12}Okay, that is it.\r\nDialogue: 0,1:12:20.77,1:12:25.27,yin,,0,0,0,,下周是感恩节 我们一周半以后再见\\N{\\fs12}Uh, Thanksgiving next week so I will not see you for a week and a half.\r\nDialogue: 0,1:12:25.27,1:12:27.88,yin,,0,0,0,,期末项目请不要耽搁\\N{\\fs12}Don't procrastinate on your final projects everybody.\r\nDialogue: 0,1:12:27.88,1:12:31.31,yin,,0,0,0,,请正常推进 有问题的可以来问我\\N{\\fs12}Get them going and if you have any questions I'll be here.\r\nDialogue: 0,1:12:31.31,1:12:32.64,yin,,0,0,0,,谢谢\\N{\\fs12}Thank you.\r\nDialogue: 0,1:12:33.83,1:12:37.36,yin,,0,0,0,,更多内容 请访问我校官网stanford.edu\\N{\\fs12}> For more, please visit us at stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/18. Localization, Adding UI to Settings.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.2.0\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage]\r\nLast Style Storage: Default\r\nActive Line: 7\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.33,0:00:07.78,yin,,0,0,0,,斯坦福大学\\N{\\fs12}> Stanford University.\r\nDialogue: 0,0:00:07.78,0:00:15.86,yin,,0,0,0,,欢迎来到CS193P课程 2013-14秋季第18讲\\N{\\fs12}> Okay. Well, welcome to lecture number 18 of CS193P, fall 2013/14.\r\nDialogue: 0,0:00:15.86,0:00:18.42,yin,,0,0,0,,在我讲今天要讲的内容之前\\N{\\fs12}Before I talk about what I'm going to talk about today,\r\nDialogue: 0,0:00:18.42,0:00:20.12,yin,,0,0,0,,首先谈谈后面有些什么\\N{\\fs12}let's talk a little bit about what's coming\r\nDialogue: 0,0:00:20.12,0:00:22.74,yin,,0,0,0,,因为我们这学期已经接近尾声了\\N{\\fs12}up because we're right at the end of the quarter here.\r\nDialogue: 0,0:00:22.74,0:00:25.38,yin,,0,0,0,,周三的下一讲\\N{\\fs12}So on Wednesday -- next lecture --\r\nDialogue: 0,0:00:25.38,0:00:28.58,yin,,0,0,0,,将是备选期末陈述日\\N{\\fs12}we are going to have this alternate final presentation day.\r\nDialogue: 0,0:00:28.58,0:00:32.29,yin,,0,0,0,,你们有些人已经说了要进行陈述\\N{\\fs12}And a few of you have already said that you wanted to do that.\r\nDialogue: 0,0:00:32.29,0:00:36.76,yin,,0,0,0,,如果你想在周三进行陈述\\N{\\fs12}And really, the only thing you need to do to sign up to do that if you want to use\r\nDialogue: 0,0:00:36.76,0:00:41.44,yin,,0,0,0,,而不是在常规的期末陈述时间\\N{\\fs12}this Wednesday as opposed to the following Thursday normal final presentation\r\nDialogue: 0,0:00:41.44,0:00:43.13,yin,,0,0,0,,来进行陈述\\N{\\fs12}time to do your presentation,\r\nDialogue: 0,0:00:43.13,0:00:48.36,yin,,0,0,0,,你只需要在明天中午12点前提交Keynote幻灯片\\N{\\fs12}is to submit the Keynote slides, okay, by tomorrow at noon.\r\nDialogue: 0,0:00:48.36,0:00:48.99,yin,,0,0,0,,这很重要\\N{\\fs12}That's very important.\r\nDialogue: 0,0:00:48.99,0:00:50.79,yin,,0,0,0,,如果明天中午12点我们没看到你的幻灯片\\N{\\fs12}If I don't see your slides by tomorrow at noon,\r\nDialogue: 0,0:00:50.79,0:00:53.40,yin,,0,0,0,,那么你就不能在周三进行陈述\\N{\\fs12}then you're basically not going to be presenting on Wednesday.\r\nDialogue: 0,0:00:53.42,0:00:58.13,yin,,0,0,0,,那你就只能在周四进行陈述了\\N{\\fs12}And then you'll be forced to present next Thursday.\r\nDialogue: 0,0:00:58.13,0:01:01.36,yin,,0,0,0,,关于Keynote幻灯片我只想说一点\\N{\\fs12}So the only thing I'll say about your Keynote slides,\r\nDialogue: 0,0:01:01.36,0:01:06.83,yin,,0,0,0,,记得做成宽屏格式 1280乘以720\\N{\\fs12}make sure that they're widescreen format, okay, 1280 by 720.\r\nDialogue: 0,0:01:06.83,0:01:10.21,yin,,0,0,0,,如果你是用PPT或别的什么来做幻灯片\\N{\\fs12}If you are submitting PowerPoint or something else, you know,\r\nDialogue: 0,0:01:10.21,0:01:13.02,yin,,0,0,0,,提交后就得看运气了 因为我会将其转为Keynote\\N{\\fs12}you're taking your chances because I'm going to convert them to Keynote.\r\nDialogue: 0,0:01:13.02,0:01:17.59,yin,,0,0,0,,如果字体这些转换正确 那你运气就蛮好\\N{\\fs12}So if they have fonts and stuff, convert them -- you're in good shape; if not, you know,\r\nDialogue: 0,0:01:17.59,0:01:21.28,yin,,0,0,0,,否则 你的幻灯片可能会看起来很糟糕\\N{\\fs12}you're slides might look a little wonky.\r\nDialogue: 0,0:01:21.28,0:01:23.05,yin,,0,0,0,,你们只需要正常提交\\N{\\fs12}You just submit them normally, right?\r\nDialogue: 0,0:01:23.05,0:01:25.91,yin,,0,0,0,,只需要按照常规课堂提交脚本来\\N{\\fs12}Just do the normal class submit script.\r\nDialogue: 0,0:01:25.91,0:01:28.01,yin,,0,0,0,,作为期末项目提交\\N{\\fs12}You submit it as your final project.\r\nDialogue: 0,0:01:28.01,0:01:31.62,yin,,0,0,0,,当然 你还可以重新提交 直到截止时间\\N{\\fs12}And of course, you can submit again, all the way up until the deadline.\r\nDialogue: 0,0:01:31.63,0:01:36.79,yin,,0,0,0,,周三在学生进行完期末陈述后…\\N{\\fs12}And the other thing we're going to do on Wednesday after we have a few people, you know,\r\nDialogue: 0,0:01:36.79,0:01:39.71,yin,,0,0,0,,顺便说下 我建议大家都来\\N{\\fs12}do their final presentations -- which by the way, I, you know,\r\nDialogue: 0,0:01:39.71,0:01:42.61,yin,,0,0,0,,并为这些人担当听众\\N{\\fs12}really encourage all of you to come and be an audience\r\nDialogue: 0,0:01:42.61,0:01:47.40,yin,,0,0,0,,这样你们就能够听到别人的期末陈述是怎么做的\\N{\\fs12}for those people just because you'll get to see some final\r\nDialogue: 0,0:01:47.40,0:01:49.18,yin,,0,0,0,,这对你有额外的好处\\N{\\fs12}presentations; you'll get a little bit of bonus.\r\nDialogue: 0,0:01:49.18,0:01:52.93,yin,,0,0,0,,我会简单讲到期末陈述\\N{\\fs12}I'll talk a little bit about the final presentations.\r\nDialogue: 0,0:01:52.93,0:01:55.23,yin,,0,0,0,,如果我看到什么 我会说 请务必注意\\N{\\fs12}If I see something, I'm like, \"Oh, let's make sure\r\nDialogue: 0,0:01:55.23,0:01:58.31,yin,,0,0,0,,这个在下周四不要发生\\N{\\fs12}that this doesn't happen next Thursday or whatever.\"\r\nDialogue: 0,0:01:58.31,0:02:02.70,yin,,0,0,0,,而且在这完成后 如果你计划做一个现场演示\\N{\\fs12}Also, after that's done, if you're planning to do a live demo,\r\nDialogue: 0,0:02:02.70,0:02:05.43,yin,,0,0,0,,周三将是很好的机会 因为我会设置所有这些\\N{\\fs12}Wednesday will be a great time because I'll have this whole setup here.\r\nDialogue: 0,0:02:05.43,0:02:07.31,yin,,0,0,0,,你可以连接你的设备\\N{\\fs12}And you can try and hook up your device,\r\nDialogue: 0,0:02:07.31,0:02:10.18,yin,,0,0,0,,使用我用的这些无线设备\\N{\\fs12}and using this wireless thing that I use,\r\nDialogue: 0,0:02:10.18,0:02:15.74,yin,,0,0,0,,这个 这让我能够设置起来\\N{\\fs12}and this thing right here -- which let me set that up --\r\nDialogue: 0,0:02:15.74,0:02:18.76,yin,,0,0,0,,以此展示你的demo 确保它能工作\\N{\\fs12}to show your demo and make sure that it's working,\r\nDialogue: 0,0:02:18.76,0:02:21.06,yin,,0,0,0,,确保你的设备能行 等等\\N{\\fs12}make sure your device works, all that stuff\r\nDialogue: 0,0:02:21.06,0:02:22.66,yin,,0,0,0,,这样就能有很好很流畅的demo\\N{\\fs12}so that you can have a nice, smooth demo.\r\nDialogue: 0,0:02:22.66,0:02:24.90,yin,,0,0,0,,我们会在周三做所有这些\\N{\\fs12}So we'll be doing all that on Wednesday.\r\nDialogue: 0,0:02:24.90,0:02:28.85,yin,,0,0,0,,周三我不会讲特定主题\\N{\\fs12}Otherwise I'm not going to present a particular topic.\r\nDialogue: 0,0:02:28.85,0:02:32.62,yin,,0,0,0,,这些事情 我鼓励你们去做\\N{\\fs12}So it's one of those things where, again, I encourage you\r\nDialogue: 0,0:02:32.62,0:02:36.32,yin,,0,0,0,,我希望你们来听别人的期末陈述\\N{\\fs12}to come be an audience for the people who are doing alternate presentation,\r\nDialogue: 0,0:02:36.32,0:02:37.89,yin,,0,0,0,,不过这不是强制的\\N{\\fs12}but it's not a mandatory.\r\nDialogue: 0,0:02:37.89,0:02:41.64,yin,,0,0,0,,当然 最后的所有这些课都不是强制的\\N{\\fs12}I mean, all these lectures at the end here are not mandatory per se.\r\nDialogue: 0,0:02:41.64,0:02:44.08,yin,,0,0,0,,以上就是周三的情况了\\N{\\fs12}But that's what's going on, on Wednesday.\r\nDialogue: 0,0:02:44.08,0:02:46.86,yin,,0,0,0,,这方面有问题吗\\N{\\fs12}Any questions about that?\r\nDialogue: 0,0:02:46.86,0:02:47.34,yin,,0,0,0,,好\\N{\\fs12}All right.\r\nDialogue: 0,0:02:47.34,0:02:49.66,yin,,0,0,0,,然后周五没有辅导课\\N{\\fs12}And then Friday, no section on Friday.\r\nDialogue: 0,0:02:49.66,0:02:53.15,yin,,0,0,0,,周五好像是官方期末考试开始的日子\\N{\\fs12}I think it might even be officially start of final exam period on Friday.\r\nDialogue: 0,0:02:53.15,0:02:55.84,yin,,0,0,0,,我不确定 不过我们没有辅导课\\N{\\fs12}I'm not one hundred percent sure. But in any case, no section.\r\nDialogue: 0,0:02:55.84,0:03:00.68,yin,,0,0,0,,项目截止时间改成了周日晚上12点\\N{\\fs12}We've moved your project deadline, as you know, to Sunday night at midnight.\r\nDialogue: 0,0:03:00.68,0:03:04.57,yin,,0,0,0,,提交期末项目时 请一同提交幻灯片\\N{\\fs12}And when you submit your final project, submit your slides.\r\nDialogue: 0,0:03:04.57,0:03:07.23,yin,,0,0,0,,明天中午12点如果无法上交\\N{\\fs12}Assuming you're not submitting them by noon tomorrow,\r\nDialogue: 0,0:03:07.23,0:03:09.38,yin,,0,0,0,,周日晚上请务必提交\\N{\\fs12}make sure you submit them by Sunday night.\r\nDialogue: 0,0:03:09.38,0:03:12.05,yin,,0,0,0,,提交的东西都要放到顶层目录\\N{\\fs12}And just put them right at the top level of whatever you submit.\r\nDialogue: 0,0:03:12.05,0:03:14.45,yin,,0,0,0,,无论顶层目录在哪 反正就放到那里\\N{\\fs12}Just whatever the top level directory is, just put them there --\r\nDialogue: 0,0:03:14.45,0:03:15.94,yin,,0,0,0,,Keynote幻灯片这些\\N{\\fs12}Keynote slides.\r\nDialogue: 0,0:03:15.96,0:03:19.85,yin,,0,0,0,,期末陈述是下周四\\N{\\fs12}The final presentations are a week from Thursday,\r\nDialogue: 0,0:03:19.85,0:03:24.22,yin,,0,0,0,,也就是分配给这门课的期末考时间 12:15到3:15\\N{\\fs12}so the normally scheduled final exam period for this class, 12:15 to 3:15.\r\nDialogue: 0,0:03:24.22,0:03:25.46,yin,,0,0,0,,陈述是必需的\\N{\\fs12}The presentation is required.\r\nDialogue: 0,0:03:25.46,0:03:26.63,yin,,0,0,0,,有人问 是否可选\\N{\\fs12}Some people say, \"Is it optional?\"\r\nDialogue: 0,0:03:26.63,0:03:27.95,yin,,0,0,0,,不 这是必需的\\N{\\fs12}No, it's required.\r\nDialogue: 0,0:03:27.95,0:03:31.13,yin,,0,0,0,,这学期的陈述有2分半钟 这已经很长了\\N{\\fs12}You get two and a half minutes this quarter, which is a long time.\r\nDialogue: 0,0:03:31.13,0:03:33.54,yin,,0,0,0,,一般我们都只有2分钟\\N{\\fs12}Usually we only give two minutes.\r\nDialogue: 0,0:03:33.54,0:03:37.27,yin,,0,0,0,,看起来很长 但上去讲你可能就会觉得不够用了\\N{\\fs12}And seems like a long time; when you get up there it will seem short.\r\nDialogue: 0,0:03:37.27,0:03:39.84,yin,,0,0,0,,重复一次 宽屏纵横比\\N{\\fs12}And again, widescreen aspect ratio.\r\nDialogue: 0,0:03:39.84,0:03:41.65,yin,,0,0,0,,顺序是随机的\\N{\\fs12}And the order is going to be random.\r\nDialogue: 0,0:03:41.65,0:03:44.10,yin,,0,0,0,,不要在当天跟我说\\N{\\fs12}You're not going to find out until the day you get it,\r\nDialogue: 0,0:03:44.10,0:03:46.92,yin,,0,0,0,,也不要发信息跟我说 我要赶飞机\\N{\\fs12}so don't even send me something that I says, \"Oh, I got a flight\r\nDialogue: 0,0:03:46.92,0:03:48.68,yin,,0,0,0,,请让我先讲\\N{\\fs12}to catch, so let me go first.\"\r\nDialogue: 0,0:03:48.68,0:03:51.84,yin,,0,0,0,,如果你要赶飞机 那就周三来讲\\N{\\fs12}If you got a flight to catch, then go on Wednesday.\r\nDialogue: 0,0:03:51.84,0:03:55.17,yin,,0,0,0,,因为出于公平考虑\\N{\\fs12}Go the day after tomorrow because for fairness,\r\nDialogue: 0,0:03:55.17,0:03:58.54,yin,,0,0,0,,我们打算按事先公布的随机顺序来\\N{\\fs12}I'm going to put it in a random order that will be revealed at the beginning.\r\nDialogue: 0,0:03:58.54,0:04:02.45,yin,,0,0,0,,这方面有问题吗\\N{\\fs12}Any questions about that?\r\nDialogue: 0,0:04:02.45,0:04:09.23,yin,,0,0,0,,关于期末项目提交程序和周日晚的截止时间 有问题吗\\N{\\fs12}Any questions about the final project submission process or due date Sunday night?\r\nDialogue: 0,0:04:09.23,0:04:10.83,yin,,0,0,0,,好 非常棒\\N{\\fs12}Okay. Excellent.\r\nDialogue: 0,0:04:10.83,0:04:14.04,yin,,0,0,0,,今天的两大主题 一是本地化\\N{\\fs12}So today's two topics, localization --\r\nDialogue: 0,0:04:14.04,0:04:16.92,yin,,0,0,0,,其实是国际化\\N{\\fs12}really, it's internationalization that I'm going to be talking about --\r\nDialogue: 0,0:04:16.92,0:04:19.19,yin,,0,0,0,,二是设置\\N{\\fs12}and then settings, which is a UI.\r\nDialogue: 0,0:04:19.19,0:04:22.99,yin,,0,0,0,,你可以将UI加到设置应用\\N{\\fs12}You can add UI to the settings application\r\nDialogue: 0,0:04:22.99,0:04:25.42,yin,,0,0,0,,来控制你的程序的特定设置选项\\N{\\fs12}to control certain settings about your application.\r\nDialogue: 0,0:04:25.42,0:04:26.87,yin,,0,0,0,,然后我要演示两个demo\\N{\\fs12}And the two demos I'm going to do,\r\nDialogue: 0,0:04:26.87,0:04:29.27,yin,,0,0,0,,我要国际化Photomania\\N{\\fs12}I'm going to internationalize PhotoMania,\r\nDialogue: 0,0:04:29.27,0:04:31.68,yin,,0,0,0,,我还会对Bouncer添加设置\\N{\\fs12}and I'm going to add a setting to Bouncer.\r\nDialogue: 0,0:04:31.68,0:04:34.42,yin,,0,0,0,,这两个我都会用demo来演示\\N{\\fs12}That way we'll get both of these things demoed.\r\nDialogue: 0,0:04:34.42,0:04:36.24,yin,,0,0,0,,好 让我们来讲国际化\\N{\\fs12}All right. So let's talk about internationalization.\r\nDialogue: 0,0:04:36.24,0:04:38.65,yin,,0,0,0,,国际化实际上有两步\\N{\\fs12}There's really two steps to internationalization:\r\nDialogue: 0,0:04:38.65,0:04:40.87,yin,,0,0,0,,一个是我们说的国际化\\N{\\fs12}There's something we called \"internationalization\" --\r\nDialogue: 0,0:04:40.87,0:04:43.03,yin,,0,0,0,,有时也简称为i18n\\N{\\fs12}sometimes abbreviated I-18-N\r\nDialogue: 0,0:04:43.03,0:04:46.08,yin,,0,0,0,,因为其中有18个字母 i18n 国际化\\N{\\fs12}because there's 18 letters in there; I-18-N, internationalization --\r\nDialogue: 0,0:04:46.08,0:04:48.00,yin,,0,0,0,,二是本地化\\N{\\fs12}and then there's localization.\r\nDialogue: 0,0:04:48.00,0:04:53.45,yin,,0,0,0,,国际化是让app能够本地化的过程\\N{\\fs12}\"Internationalization\" is the process of making your app possible to be localized.\r\nDialogue: 0,0:04:53.45,0:04:58.89,yin,,0,0,0,,让app能够以多种语言提供\\N{\\fs12}Making it so that your app can be shipped in multiple different languages.\r\nDialogue: 0,0:04:58.89,0:05:02.50,yin,,0,0,0,,本地化则是实际翻译的过程\\N{\\fs12}\"Localization\" is the process of actually translating that --\r\nDialogue: 0,0:05:02.50,0:05:04.46,yin,,0,0,0,,将应用程序翻译为另一种语言\\N{\\fs12}your application -- to another language.\r\nDialogue: 0,0:05:04.46,0:05:05.83,yin,,0,0,0,,这是一个两步的过程\\N{\\fs12}So it's really a two-step process.\r\nDialogue: 0,0:05:05.83,0:05:08.60,yin,,0,0,0,,国际化 这是你作为开发者要做的\\N{\\fs12}Internationalization, that's something you do as the developer.\r\nDialogue: 0,0:05:08.60,0:05:11.58,yin,,0,0,0,,本地化 这通常需要雇人来做\\N{\\fs12}Localization, usually hire someone to go do that.\r\nDialogue: 0,0:05:11.58,0:05:14.49,yin,,0,0,0,,我不建议你用谷歌翻译本地化app\\N{\\fs12}I don't recommend using Google Translate to localize your app.\r\nDialogue: 0,0:05:14.49,0:05:15.94,yin,,0,0,0,,结果会非常奇怪\\N{\\fs12}You get some very strange results.\r\nDialogue: 0,0:05:15.94,0:05:17.97,yin,,0,0,0,,你需要非常职业的本地化翻译\\N{\\fs12}You want a professional localizer\r\nDialogue: 0,0:05:17.97,0:05:22.46,yin,,0,0,0,,他们需要理解本地语言的惯用语\\N{\\fs12}who understands the idioms of the local language.\r\nDialogue: 0,0:05:22.47,0:05:25.85,yin,,0,0,0,,有两点需要本地化\\N{\\fs12}There's really two things that need to be localized:\r\nDialogue: 0,0:05:25.85,0:05:28.09,yin,,0,0,0,,一是故事板\\N{\\fs12}One is your storyboard and\r\nDialogue: 0,0:05:28.09,0:05:30.46,yin,,0,0,0,,二是应用中的所有字符串字面量\\N{\\fs12}one is kind of all the literal strings in your application.\r\nDialogue: 0,0:05:30.46,0:05:32.52,yin,,0,0,0,,我们先来讲故事板\\N{\\fs12}So let's talk about the storyboards first.\r\nDialogue: 0,0:05:32.52,0:05:35.71,yin,,0,0,0,,在iOS7中本地化故事板\\N{\\fs12}The way we localize storyboards in iOS 7\r\nDialogue: 0,0:05:35.71,0:05:40.36,yin,,0,0,0,,我们只需要改变故事板中出现的字符串\\N{\\fs12}is we only change the strings that appear in the storyboard,\r\nDialogue: 0,0:05:40.36,0:05:45.43,yin,,0,0,0,,然后我们再让自动布局来匹配字符串的变宽和变窄\\N{\\fs12}and we let Auto Layout resize things to fit wider and shorter strings.\r\nDialogue: 0,0:05:45.43,0:05:48.93,yin,,0,0,0,,这是自动布局很方便的一点\\N{\\fs12}That's a great side benefit of having Auto Layout,\r\nDialogue: 0,0:05:48.93,0:05:52.91,yin,,0,0,0,,这样本地化就只关系到故事板的字符串了\\N{\\fs12}is that localization now is just about the strings when it comes to the storyboard.\r\nDialogue: 0,0:05:52.91,0:05:53.93,yin,,0,0,0,,不过首先\\N{\\fs12}But the first thing we need\r\nDialogue: 0,0:05:53.93,0:05:57.84,yin,,0,0,0,,在进行任何本地化之前\\N{\\fs12}to do before we do any localization is to go\r\nDialogue: 0,0:05:57.84,0:06:02.20,yin,,0,0,0,,我们都需要到项目设置 设置所有语言\\N{\\fs12}to our project settings and set the list of all the languages\r\nDialogue: 0,0:06:02.20,0:06:04.96,yin,,0,0,0,,所有我们要支持本地化的都要选\\N{\\fs12}that we are going to support localization for.\r\nDialogue: 0,0:06:04.96,0:06:07.51,yin,,0,0,0,,每次发布新版本程序时\\N{\\fs12}So you know, as you release new versions\r\nDialogue: 0,0:06:07.51,0:06:09.20,yin,,0,0,0,,你都应该多支持几种语言\\N{\\fs12}of your app, you'll support a few more languages.\r\nDialogue: 0,0:06:09.20,0:06:12.68,yin,,0,0,0,,你可以到这个项目设定中 添加更多语言\\N{\\fs12}You'll go back to this project settings and add more languages.\r\nDialogue: 0,0:06:12.68,0:06:14.83,yin,,0,0,0,,关于这个有一点比较巧妙\\N{\\fs12}One thing that's a little tricky about this is\r\nDialogue: 0,0:06:14.83,0:06:16.50,yin,,0,0,0,,你们原来到项目设置\\N{\\fs12}you're used to going to your project settings,\r\nDialogue: 0,0:06:16.50,0:06:19.58,yin,,0,0,0,,也就是导航器左上角那部分\\N{\\fs12}which is that upper left-hand top part of the navigator.\r\nDialogue: 0,0:06:19.58,0:06:22.34,yin,,0,0,0,,一般设置的都是\\N{\\fs12}But actually, what we've been setting the settings of\r\nDialogue: 0,0:06:22.34,0:06:25.66,yin,,0,0,0,,目标 也就是要创建的app\\N{\\fs12}there is the target, the app that you're building.\r\nDialogue: 0,0:06:25.66,0:06:28.71,yin,,0,0,0,,这里 你要设置的是项目本身\\N{\\fs12}Here you want to actually set the settings of the project itself.\r\nDialogue: 0,0:06:28.71,0:06:33.35,yin,,0,0,0,,可以看到蓝色对话框所指的 这里说Photomania\\N{\\fs12}So you can see where that little bubble points to right there that says PhotoMania.\r\nDialogue: 0,0:06:33.35,0:06:35.64,yin,,0,0,0,,这实际是一个弹窗 你可以点它\\N{\\fs12}That's a little popup actually; you're going to click that\r\nDialogue: 0,0:06:35.64,0:06:37.65,yin,,0,0,0,,切换到项目的编辑\\N{\\fs12}and switch up to editing the project.\r\nDialogue: 0,0:06:37.65,0:06:40.10,yin,,0,0,0,,这样做时 整个项目并没有太多设置\\N{\\fs12}And when you do, there's not a whole lot of settings for the whole project.\r\nDialogue: 0,0:06:40.10,0:06:42.50,yin,,0,0,0,,所有都在这里\\N{\\fs12}You're seeing them all right here.\r\nDialogue: 0,0:06:42.50,0:06:44.14,yin,,0,0,0,,你只需要到底部\\N{\\fs12}And you're just going to go down to the bottom there.\r\nDialogue: 0,0:06:44.14,0:06:45.15,yin,,0,0,0,,它说本地化\\N{\\fs12}It says localizations.\r\nDialogue: 0,0:06:45.15,0:06:47.62,yin,,0,0,0,,这不过是一系列语言\\N{\\fs12}It's just a list of languages.\r\nDialogue: 0,0:06:47.62,0:06:49.75,yin,,0,0,0,,这些是预支持的语言\\N{\\fs12}These are pre-supported languages\r\nDialogue: 0,0:06:49.75,0:06:52.06,yin,,0,0,0,,因为这些语言需要匹配\\N{\\fs12}because these languages need to match up with the languages\r\nDialogue: 0,0:06:52.06,0:06:55.25,yin,,0,0,0,,iOS操作系统所支持的语言\\N{\\fs12}that the operating system, iOS, supports\r\nDialogue: 0,0:06:55.25,0:06:57.79,yin,,0,0,0,,当用户到设置或是其它程序\\N{\\fs12}so that when people go to settings and other apps,\r\nDialogue: 0,0:06:57.79,0:07:00.01,yin,,0,0,0,,语言也都会是这些\\N{\\fs12}that's in whatever language as well.\r\nDialogue: 0,0:07:00.01,0:07:02.96,yin,,0,0,0,,点击左下角的+按钮\\N{\\fs12}So when you hit that little plus button down in the lower left-hand corner,\r\nDialogue: 0,0:07:02.96,0:07:04.95,yin,,0,0,0,,一系列语言会弹出\\N{\\fs12}it's going to be a popup with a list of languages.\r\nDialogue: 0,0:07:04.95,0:07:08.45,yin,,0,0,0,,你不需要键入阿拉伯语或是法语\\N{\\fs12}You're not going to just type in the word Arabic or French;\r\nDialogue: 0,0:07:08.45,0:07:11.42,yin,,0,0,0,,你可以从iOS支持的语言中来选\\N{\\fs12}it's going to be something you're going to pick from a list\r\nDialogue: 0,0:07:11.42,0:07:13.84,yin,,0,0,0,,你可以从iOS支持的语言中来选\\N{\\fs12}of supported languages for iOS.\r\nDialogue: 0,0:07:13.84,0:07:15.41,yin,,0,0,0,,还可以看到\\N{\\fs12}And you can also see\r\nDialogue: 0,0:07:15.41,0:07:18.04,yin,,0,0,0,,这里有个语言称作base(基础)\\N{\\fs12}that there's a language there called base, right?\r\nDialogue: 0,0:07:18.04,0:07:21.77,yin,,0,0,0,,还有一个开关说 使用base国际化\\N{\\fs12}And there's a switch that says use base internationalization.\r\nDialogue: 0,0:07:21.77,0:07:23.94,yin,,0,0,0,,base国际化的概念是说\\N{\\fs12}The concept of base internationalization is\r\nDialogue: 0,0:07:23.94,0:07:26.59,yin,,0,0,0,,这里会有一个本地化\\N{\\fs12}that there's going to be a localization.\r\nDialogue: 0,0:07:26.59,0:07:31.16,yin,,0,0,0,,这不是任何语言的本地化 而是base本地化\\N{\\fs12}It's not a localization that is in anybody's language; it's just the base localization.\r\nDialogue: 0,0:07:31.16,0:07:33.37,yin,,0,0,0,,这就像是所有的默认值\\N{\\fs12}And that's going to be kind of like all the defaults:\r\nDialogue: 0,0:07:33.37,0:07:35.98,yin,,0,0,0,,默认故事板字符串\\N{\\fs12}The default storyboard strings,\r\nDialogue: 0,0:07:35.98,0:07:40.32,yin,,0,0,0,,app中的默认字符串 会来自于base本地化\\N{\\fs12}default strings throughout your app are going to come out of the base localization.\r\nDialogue: 0,0:07:40.32,0:07:41.90,yin,,0,0,0,,然后其它这些本地化\\N{\\fs12}And then all these other localizations,\r\nDialogue: 0,0:07:41.90,0:07:46.05,yin,,0,0,0,,甚至英语 然后还有法语 德语这些\\N{\\fs12}like English even, but French, and German, and whatever,\r\nDialogue: 0,0:07:46.05,0:07:48.78,yin,,0,0,0,,这些会修改这些字符串\\N{\\fs12}those are going to modify those strings.\r\nDialogue: 0,0:07:48.78,0:07:51.04,yin,,0,0,0,,如果你忘了本地化一个字符串\\N{\\fs12}And so if you forget to localize a string,\r\nDialogue: 0,0:07:51.04,0:07:55.10,yin,,0,0,0,,base本地化就会接手\\N{\\fs12}the base localization will shine through.\r\nDialogue: 0,0:07:55.10,0:07:59.51,yin,,0,0,0,,等下我们会看到故事板中这是怎样的情况\\N{\\fs12}And so we'll see what that looks like when it comes to storyboards in a second here.\r\nDialogue: 0,0:07:59.51,0:08:03.30,yin,,0,0,0,,故事板是这样的\\N{\\fs12}So the storyboards look like this.\r\nDialogue: 0,0:08:03.30,0:08:05.13,yin,,0,0,0,,你选择一个故事板\\N{\\fs12}You select a storyboard.\r\nDialogue: 0,0:08:05.13,0:08:09.91,yin,,0,0,0,,如果你做了我上一张幻灯片中所示的事情\\N{\\fs12}And when you do the thing I showed you on the previous slide,\r\nDialogue: 0,0:08:09.91,0:08:12.91,yin,,0,0,0,,那么你的故事板在文件浏览器中就会像这样\\N{\\fs12}then your storyboards are going to look like this in the file navigator.\r\nDialogue: 0,0:08:12.91,0:08:15.30,yin,,0,0,0,,看到这里有主iPhone故事板了吗\\N{\\fs12}You see how there's main, iPhone, storyboard?\r\nDialogue: 0,0:08:15.30,0:08:18.94,yin,,0,0,0,,这里你有一个小三角可以点\\N{\\fs12}And now it has a little triangle that you can click\r\nDialogue: 0,0:08:18.94,0:08:23.28,yin,,0,0,0,,它下面还是显示有主iPhone故事板 base\\N{\\fs12}and it now is showing underneath it main, iPhone, storyboard again -- base.\r\nDialogue: 0,0:08:23.28,0:08:25.55,yin,,0,0,0,,这是base故事板\\N{\\fs12}So that's your base storyboard.\r\nDialogue: 0,0:08:25.55,0:08:28.94,yin,,0,0,0,,然后对于法语 它说主iPhone 点字符串\\N{\\fs12}And then for French, it says main, iPhone, dot strings.\r\nDialogue: 0,0:08:28.94,0:08:33.75,yin,,0,0,0,,这里只是故事板中的字符串被提取了\\N{\\fs12}So that's just the strings only for the storyboards that have been extracted.\r\nDialogue: 0,0:08:33.75,0:08:37.15,yin,,0,0,0,,做了前面那件事 这个就会被提取出来\\N{\\fs12}When we did that previous thing, it extracted those out there.\r\nDialogue: 0,0:08:37.15,0:08:40.20,yin,,0,0,0,,点故事板 到文件检查器\\N{\\fs12}And when you click on the storyboard and if you go to the file inspector,\r\nDialogue: 0,0:08:40.20,0:08:42.39,yin,,0,0,0,,你就能看到这个显示在那里\\N{\\fs12}you can see this little thing showing there\r\nDialogue: 0,0:08:42.39,0:08:44.94,yin,,0,0,0,,有base 这是总有的\\N{\\fs12}where there's base -- there will always be base --\r\nDialogue: 0,0:08:44.94,0:08:48.43,yin,,0,0,0,,然后是你想翻译成的任意多种语言\\N{\\fs12}and then however many languages you want to translate to.\r\nDialogue: 0,0:08:48.43,0:08:50.78,yin,,0,0,0,,注意到这里 英语甚至没有勾选\\N{\\fs12}Now, here notice that English is not even checked;\r\nDialogue: 0,0:08:50.78,0:08:55.09,yin,,0,0,0,,这是因为我将假定我的base是英语\\N{\\fs12}that's because I'm going to assume that my base is English.\r\nDialogue: 0,0:08:55.09,0:08:57.38,yin,,0,0,0,,你并不需要总是这样假定\\N{\\fs12}Now, you don't always want to assume that.\r\nDialogue: 0,0:08:57.38,0:08:59.23,yin,,0,0,0,,你甚至大多数时候都可以假定\\N{\\fs12}And you could even mostly assume that\r\nDialogue: 0,0:08:59.23,0:09:01.06,yin,,0,0,0,,还是有一个英语点字符串文件\\N{\\fs12}but still have an English dot strings file\r\nDialogue: 0,0:09:01.06,0:09:03.49,yin,,0,0,0,,在需要的时候改变一些东西\\N{\\fs12}that changed a couple of things if you wanted.\r\nDialogue: 0,0:09:03.49,0:09:07.00,yin,,0,0,0,,或者你可以让这整个东西\\N{\\fs12}Or you could have the whole thing be, you know,\r\nDialogue: 0,0:09:07.00,0:09:09.69,yin,,0,0,0,,用英文字符串文件明言出来\\N{\\fs12}explicitly in a strings file for English.\r\nDialogue: 0,0:09:09.69,0:09:12.02,yin,,0,0,0,,但这里我没有勾选英文\\N{\\fs12}But here I have not even checked English.\r\nDialogue: 0,0:09:12.02,0:09:14.18,yin,,0,0,0,,base故事板中的东西\\N{\\fs12}So whatever's in my base storyboard, that's what's going\r\nDialogue: 0,0:09:14.18,0:09:15.82,yin,,0,0,0,,就是语言为英文时的情况\\N{\\fs12}to ship when I'm in the language English.\r\nDialogue: 0,0:09:15.82,0:09:18.52,yin,,0,0,0,,不过法语中 我有一个可本地化的字符串文件\\N{\\fs12}But in French I have a localizable without strings file,\r\nDialogue: 0,0:09:18.52,0:09:19.84,yin,,0,0,0,,马上我就会展示\\N{\\fs12}which I'll show you in a second,\r\nDialogue: 0,0:09:19.84,0:09:23.08,yin,,0,0,0,,这会改变故事板中的所有字符串\\N{\\fs12}which is going to change all the strings in my storyboard.\r\nDialogue: 0,0:09:23.08,0:09:29.42,yin,,0,0,0,,法语语言字符串是怎样的呢\\N{\\fs12}So what does that look like? The French language strings?\r\nDialogue: 0,0:09:29.42,0:09:31.83,yin,,0,0,0,,这部分内容将推迟一些\\N{\\fs12}I'm going to postpone showing what that looks\r\nDialogue: 0,0:09:31.83,0:09:34.89,yin,,0,0,0,,我们将先笼统地讨论字符串\\N{\\fs12}like until we talk about strings in general.\r\nDialogue: 0,0:09:34.89,0:09:37.60,yin,,0,0,0,,我们来看字符串字面量\\N{\\fs12}And so let's talk about literal strings.\r\nDialogue: 0,0:09:37.60,0:09:40.08,yin,,0,0,0,,故事板的那些将是\\N{\\fs12}So the storyboard strings are going to be\r\nDialogue: 0,0:09:40.08,0:09:42.81,yin,,0,0,0,,我在刚才那张幻灯片中讲的\\N{\\fs12}in this thing I showed you in the last slide.\r\nDialogue: 0,0:09:42.81,0:09:45.76,yin,,0,0,0,,不过app中还有一些字符串不在故事板中\\N{\\fs12}But there's other strings inside your app that aren't in the storyboard,\r\nDialogue: 0,0:09:45.76,0:09:48.61,yin,,0,0,0,,例如警告消息中的字符串 警告按钮\\N{\\fs12}like things that come up in alert messages, the alert buttons.\r\nDialogue: 0,0:09:48.61,0:09:52.53,yin,,0,0,0,,所有这些都不在故事板中 但也需要本地化\\N{\\fs12}All those things are not in your storyboard, but they need be localized as well.\r\nDialogue: 0,0:09:52.53,0:09:55.50,yin,,0,0,0,,我们让这些字符串得到本地化的方式\\N{\\fs12}And the way we get those strings to be localizable\r\nDialogue: 0,0:09:55.51,0:10:00.05,yin,,0,0,0,,是使用这些以NSLocalizedString开头的宏\\N{\\fs12}is using these macros here that start with NS localized string.\r\nDialogue: 0,0:10:00.05,0:10:01.91,yin,,0,0,0,,这里有NSLocalizedStringWithDefaultValue\\N{\\fs12}So there's NS localized string with default value;\r\nDialogue: 0,0:10:01.91,0:10:03.73,yin,,0,0,0,,有NSLocalizedStringFromTable\\N{\\fs12}there's NS localized string from table;\r\nDialogue: 0,0:10:03.74,0:10:05.61,yin,,0,0,0,,有NSLocalizedString\\N{\\fs12}there's NS localized string.\r\nDialogue: 0,0:10:05.61,0:10:07.94,yin,,0,0,0,,这些宏的参数都略有不同\\N{\\fs12}And each of these macros takes a little bit different arguments.\r\nDialogue: 0,0:10:07.94,0:10:11.20,yin,,0,0,0,,它们的主要作用是给你一个键\\N{\\fs12}But the main thing they're doing is you're giving a key that's\r\nDialogue: 0,0:10:11.20,0:10:14.47,yin,,0,0,0,,到字符串去查找 会返回一个值\\N{\\fs12}going to be looked up in a strings file and it's going to return a value.\r\nDialogue: 0,0:10:14.47,0:10:16.16,yin,,0,0,0,,版本有多种是因为\\N{\\fs12}The different variants just determine:\r\nDialogue: 0,0:10:16.16,0:10:19.25,yin,,0,0,0,,不能找到字符串时的默认值会不同\\N{\\fs12}What's the default value if I can't find the thing in the string,\r\nDialogue: 0,0:10:19.25,0:10:22.16,yin,,0,0,0,,在哪些点字符串文件中找也会不同\\N{\\fs12}and which dot strings file am I going to look in?\r\nDialogue: 0,0:10:22.16,0:10:25.40,yin,,0,0,0,,对于故事板 总是只关联有一个字符串文件\\N{\\fs12}Okay, for our storyboard there's always one string file associated.\r\nDialogue: 0,0:10:25.40,0:10:29.81,yin,,0,0,0,,但对于代码中的字符串字面量\\N{\\fs12}But when we have literal strings inside of our code, we can\r\nDialogue: 0,0:10:29.81,0:10:33.92,yin,,0,0,0,,我们可以把翻译拆分到不同的文件中\\N{\\fs12}split up all the translations into different files if we want.\r\nDialogue: 0,0:10:33.92,0:10:35.04,yin,,0,0,0,,demo中我会这样做\\N{\\fs12}In the demo I'll do that.\r\nDialogue: 0,0:10:35.04,0:10:36.85,yin,,0,0,0,,我会把它们放到一个单独的小文件中\\N{\\fs12}I'll put them in a little separate file\r\nDialogue: 0,0:10:36.85,0:10:38.48,yin,,0,0,0,,只针对一个视图控制器\\N{\\fs12}just for one view controller.\r\nDialogue: 0,0:10:38.48,0:10:42.38,yin,,0,0,0,,例如 如果你有字符串字面量 hello\\N{\\fs12}So for example, if you had the literal string hello,\r\nDialogue: 0,0:10:42.38,0:10:44.71,yin,,0,0,0,,@号 引号 hello在app中\\N{\\fs12}at sign, quote, hello in your app\r\nDialogue: 0,0:10:44.72,0:10:47.17,yin,,0,0,0,,而这会出现在UI中 那么\\N{\\fs12}and that is going to appear in the UI, then you would change\r\nDialogue: 0,0:10:47.17,0:10:49.41,yin,,0,0,0,,你就要把它变为NSLocalizedString\\N{\\fs12}that to NS localized string\r\nDialogue: 0,0:10:49.41,0:10:51.37,yin,,0,0,0,,@ hello 逗号\\N{\\fs12}at hello comma.\r\nDialogue: 0,0:10:51.37,0:10:56.46,yin,,0,0,0,,之后 最后一个参数是给本地化者的注释\\N{\\fs12}And then, the last argument there is a comment to the localizers.\r\nDialogue: 0,0:10:56.46,0:11:01.18,yin,,0,0,0,,你可以假定本地化者说你的语言 你的base语言\\N{\\fs12}So you can assume the localizers speak your language, whatever your base language is,\r\nDialogue: 0,0:11:01.18,0:11:02.80,yin,,0,0,0,,你给他们一个注释\\N{\\fs12}and you're giving them a comment.\r\nDialogue: 0,0:11:02.80,0:11:04.74,yin,,0,0,0,,告诉他们这个hello是什么\\N{\\fs12}You're telling them what is this hello?\r\nDialogue: 0,0:11:04.74,0:11:06.65,yin,,0,0,0,,它在什么环境中出现\\N{\\fs12}Where does it appear? What's its environment?\r\nDialogue: 0,0:11:06.65,0:11:09.15,yin,,0,0,0,,这里我说 它是应用开始时的寒暄\\N{\\fs12}So here I'm saying it's a greeting at the start of the application.\r\nDialogue: 0,0:11:09.15,0:11:13.12,yin,,0,0,0,,那么讲法语的人就会把这翻译成bonjour\\N{\\fs12}So the person would know in French to make that be bonjour or whatever.\r\nDialogue: 0,0:11:13.12,0:11:16.95,yin,,0,0,0,,这就是将所有字符串字面量\\N{\\fs12}Right? So that's how you change all your literal strings\r\nDialogue: 0,0:11:16.95,0:11:20.20,yin,,0,0,0,,转化为NSLocalizedString的方式\\N{\\fs12}to these NS localized string, one of these variants.\r\nDialogue: 0,0:11:20.20,0:11:23.32,yin,,0,0,0,,这些NSLocalizedString是做什么的呢\\N{\\fs12}Now what are these things actually doing, these NS localized string?\r\nDialogue: 0,0:11:23.32,0:11:26.41,yin,,0,0,0,,它们会在NSBundle中调用一个方法\\N{\\fs12}They're actually calling a method in NS bundle.\r\nDialogue: 0,0:11:26.41,0:11:28.99,yin,,0,0,0,,NSBundle是一个类\\N{\\fs12}NS bundle is a class\r\nDialogue: 0,0:11:28.99,0:11:32.47,yin,,0,0,0,,它会将你app里的一切收集起来\\N{\\fs12}that kind of collects everything about your app,\r\nDialogue: 0,0:11:32.47,0:11:36.01,yin,,0,0,0,,到一个API中 用于访问其资源\\N{\\fs12}okay, into an API for accessing the resources of it.\r\nDialogue: 0,0:11:36.01,0:11:38.26,yin,,0,0,0,,我们可以用它来访问字符串文件\\N{\\fs12}And we can use it to access strings files,\r\nDialogue: 0,0:11:38.26,0:11:40.21,yin,,0,0,0,,做法是使用Bundle中的这个方法\\N{\\fs12}and we do that with this method in bundle\r\nDialogue: 0,0:11:40.21,0:11:43.40,yin,,0,0,0,,也就是localizedStringForKey value table\\N{\\fs12}called localized string for key value table, right?\r\nDialogue: 0,0:11:43.40,0:11:47.15,yin,,0,0,0,,顾名思义 key是用于在字符串文件中查找的键\\N{\\fs12}Exactly what you would think: Key is what we're looking up in the strings files;\r\nDialogue: 0,0:11:47.16,0:11:49.05,yin,,0,0,0,,value是这里的默认值\\N{\\fs12}value is the default value there;\r\nDialogue: 0,0:11:49.05,0:11:51.13,yin,,0,0,0,,table是在哪个表格中查询\\N{\\fs12}and table is which table to look in.\r\nDialogue: 0,0:11:51.13,0:11:54.72,yin,,0,0,0,,顺便说下 Bundle还可以被用于查找资源的URL\\N{\\fs12}The bundle can also be used, by the way, to find URLs\r\nDialogue: 0,0:11:54.72,0:11:57.27,yin,,0,0,0,,资源诸如图像等等\\N{\\fs12}to resources like images, things like that.\r\nDialogue: 0,0:11:57.27,0:11:59.98,yin,,0,0,0,,如果你拖动一张jpeg图像\\N{\\fs12}If you drag an image -- a JPEG image --\r\nDialogue: 0,0:11:59.98,0:12:02.42,yin,,0,0,0,,到导航器的顶层\\N{\\fs12}right into the top level of your navigator,\r\nDialogue: 0,0:12:02.42,0:12:04.80,yin,,0,0,0,,那你就可以使用NSBundle mainBundle\\N{\\fs12}then you can use NS bundle main bundle.\r\nDialogue: 0,0:12:04.80,0:12:07.60,yin,,0,0,0,,这里有URLForResource\\N{\\fs12}There's something called URL for resource,\r\nDialogue: 0,0:12:07.60,0:12:09.44,yin,,0,0,0,,你给它jpeg文件的名称\\N{\\fs12}and you give it the name of that JPEG file.\r\nDialogue: 0,0:12:09.44,0:12:10.96,yin,,0,0,0,,它会告诉你相应的URL\\N{\\fs12}It will give you a URL to it.\r\nDialogue: 0,0:12:10.96,0:12:13.13,yin,,0,0,0,,有时 你需要某张图像的完整URL\\N{\\fs12}Sometimes you need a full URL to some image.\r\nDialogue: 0,0:12:13.13,0:12:15.72,yin,,0,0,0,,如果你不使用图像名 你会使用完整URL\\N{\\fs12}Or if you're not using image named, you need some full URL.\r\nDialogue: 0,0:12:15.72,0:12:21.66,yin,,0,0,0,,NSBundle就是这样一个类 需要你有所理解\\N{\\fs12}So NS bundle is a class for you to kind of understand a little bit as well.\r\nDialogue: 0,0:12:21.66,0:12:25.44,yin,,0,0,0,,有时 我们会调用这个localizedStringForKey\\N{\\fs12}But we don't usually -- well, sometimes we'll call this localized string for key,\r\nDialogue: 0,0:12:25.44,0:12:27.17,yin,,0,0,0,,demo中我也会这样做\\N{\\fs12}and I'll do it in the demo as well. But\r\nDialogue: 0,0:12:27.17,0:12:29.92,yin,,0,0,0,,可以用这些宏时 我们就应当使用\\N{\\fs12}when we can use the macros, we should.\r\nDialogue: 0,0:12:29.92,0:12:33.52,yin,,0,0,0,,不过NSLocalizedString中的宏有很大的局限性\\N{\\fs12}But there's a significant limitation on those macros, the NS localized string:\r\nDialogue: 0,0:12:33.53,0:12:36.83,yin,,0,0,0,,所有的字符串都必须是字符串字面量\\N{\\fs12}All the arguments have to be literal strings,\r\nDialogue: 0,0:12:36.83,0:12:39.77,yin,,0,0,0,,包括评论 键 值\\N{\\fs12}including the comment; the key; the value;\r\nDialogue: 0,0:12:39.77,0:12:42.86,yin,,0,0,0,,表名 等等 这里不能是变量\\N{\\fs12}the table name; etc. They can't be variables.\r\nDialogue: 0,0:12:42.86,0:12:44.17,yin,,0,0,0,,必然是字符串字面量\\N{\\fs12}They have to be literal strings.\r\nDialogue: 0,0:12:44.17,0:12:45.89,yin,,0,0,0,,@号引号什么 @号引号什么\\N{\\fs12}At sign quote something, at sign quote something\r\nDialogue: 0,0:12:45.89,0:12:48.36,yin,,0,0,0,,LocalizedString的每个参数都是如此\\N{\\fs12}for every argument of those localized strings.\r\nDialogue: 0,0:12:48.36,0:12:50.42,yin,,0,0,0,,我们来谈谈为什么是这样\\N{\\fs12}And then let's talk about why that is.\r\nDialogue: 0,0:12:50.42,0:12:54.60,yin,,0,0,0,,答案是有一个命令行实用程序叫作\\N{\\fs12}The answer for that is there's a command line utility called\r\nDialogue: 0,0:12:54.60,0:12:55.85,yin,,0,0,0,,genstrings\\N{\\fs12}genstrings --\r\nDialogue: 0,0:12:55.85,0:12:57.38,yin,,0,0,0,,生成字符串的简写\\N{\\fs12}short for generate strings --\r\nDialogue: 0,0:12:57.38,0:13:00.13,yin,,0,0,0,,它会找遍整个.m文件\\N{\\fs12}which will look through a dot M file\r\nDialogue: 0,0:13:00.13,0:13:03.02,yin,,0,0,0,,找所有LocalizedString宏\\N{\\fs12}for all those NS localized string macros\r\nDialogue: 0,0:13:03.02,0:13:06.61,yin,,0,0,0,,并将它们提取到一个字符串文件\\N{\\fs12}and extract them all out into a strings file for you.\r\nDialogue: 0,0:13:06.61,0:13:10.34,yin,,0,0,0,,这就是你得到base字符串文件的方式\\N{\\fs12}And that's how you get the base string file\r\nDialogue: 0,0:13:10.34,0:13:12.88,yin,,0,0,0,,然后你再本地化到其它语言\\N{\\fs12}that you will then localize to other languages.\r\nDialogue: 0,0:13:12.88,0:13:15.16,yin,,0,0,0,,我们也会在demo中演示这个\\N{\\fs12}And we'll show this in the demo as well.\r\nDialogue: 0,0:13:15.16,0:13:18.18,yin,,0,0,0,,例如 我们有NSLocalizedString @号 hello\\N{\\fs12}And so, for example, we had that NS localized string at sign hello,\r\nDialogue: 0,0:13:18.18,0:13:19.68,yin,,0,0,0,,应用开始时的寒暄\\N{\\fs12}greeting at start of application.\r\nDialogue: 0,0:13:19.68,0:13:23.73,yin,,0,0,0,,这会在字符串文件中转化为下面那两行\\N{\\fs12}That would get turned into the following two lines there in a strings file:\r\nDialogue: 0,0:13:23.74,0:13:26.16,yin,,0,0,0,,注释 应用开始时的寒暄\\N{\\fs12}Comment, greeting is started by application,\r\nDialogue: 0,0:13:26.16,0:13:28.05,yin,,0,0,0,,然后 hello等于hello\\N{\\fs12}and then hello equals hello.\r\nDialogue: 0,0:13:28.05,0:13:30.26,yin,,0,0,0,,法国人看到这个\\N{\\fs12}And the French person would come along\r\nDialogue: 0,0:13:30.26,0:13:33.47,yin,,0,0,0,,可以将其改成hello等于bonjour\\N{\\fs12}and they would change hello equals bonjour.\r\nDialogue: 0,0:13:33.47,0:13:35.87,yin,,0,0,0,,执行genstrings\\N{\\fs12}Now, when you do genstrings\r\nDialogue: 0,0:13:35.87,0:13:37.89,yin,,0,0,0,,会生成得到.strings文件\\N{\\fs12}and you get dot strings files generated --\r\nDialogue: 0,0:13:37.89,0:13:39.64,yin,,0,0,0,,你会得到多个这样的文件\\N{\\fs12}and you might get multiple of them because remember,\r\nDialogue: 0,0:13:39.64,0:13:41.54,yin,,0,0,0,,因为NSLocalizedString的一个方法就是\\N{\\fs12}one of the NS localized strings is\r\nDialogue: 0,0:13:41.54,0:13:43.42,yin,,0,0,0,,NSLocalizedStringFromTable\\N{\\fs12}NS localized string from table,\r\nDialogue: 0,0:13:43.42,0:13:44.65,yin,,0,0,0,,你需要指定表名\\N{\\fs12}so you might specify table name.\r\nDialogue: 0,0:13:44.65,0:13:47.63,yin,,0,0,0,,这会为你生成多个.strings文件\\N{\\fs12}And so it might be making multiple dot strings files for you.\r\nDialogue: 0,0:13:47.63,0:13:49.71,yin,,0,0,0,,你只需要将这些.strings文件\\N{\\fs12}You just take those dot strings files,\r\nDialogue: 0,0:13:49.71,0:13:53.89,yin,,0,0,0,,拖入到应用程序 到Xcode项目中\\N{\\fs12}drag them into your application, into your Xcode project,\r\nDialogue: 0,0:13:53.89,0:13:56.55,yin,,0,0,0,,然后打开文件检查器检查它们\\N{\\fs12}and then inspect them with a file inspector.\r\nDialogue: 0,0:13:56.55,0:13:58.29,yin,,0,0,0,,这时你可以看到这个按钮\\N{\\fs12}And when you do, you're going to see this button,\r\nDialogue: 0,0:13:58.29,0:14:00.67,yin,,0,0,0,,上面那个按钮 它说本地化\\N{\\fs12}the top button there that says localize.\r\nDialogue: 0,0:14:00.67,0:14:04.53,yin,,0,0,0,,点这个 你会得到一系列语言的列表\\N{\\fs12}And when you click that, then you'll get a list of the languages.\r\nDialogue: 0,0:14:04.53,0:14:07.24,yin,,0,0,0,,你可以勾选任意多种语言\\N{\\fs12}And you can click however many of the languages you want\r\nDialogue: 0,0:14:07.24,0:14:10.22,yin,,0,0,0,,来支持这个字符串文件的本地化\\N{\\fs12}to support localizing this string file for.\r\nDialogue: 0,0:14:10.22,0:14:12.19,yin,,0,0,0,,然后在文件浏览器中\\N{\\fs12}And then in your file navigator\r\nDialogue: 0,0:14:12.19,0:14:14.50,yin,,0,0,0,,你会看到每种语言都有一个.strings文件\\N{\\fs12}you'll see a dot strings file for every language.\r\nDialogue: 0,0:14:14.50,0:14:15.34,yin,,0,0,0,,点开它\\N{\\fs12}You can click on it.\r\nDialogue: 0,0:14:15.34,0:14:17.97,yin,,0,0,0,,通常你会看到\\N{\\fs12}And then you -- usually what you'll do is you'll click on it\r\nDialogue: 0,0:14:17.97,0:14:19.76,yin,,0,0,0,,hello等于hello\\N{\\fs12}and you'll see hello equal hello.\r\nDialogue: 0,0:14:19.76,0:14:22.78,yin,,0,0,0,,然后你把所有.strings文件\\N{\\fs12}You'll take that entire file or all the strings files,\r\nDialogue: 0,0:14:22.78,0:14:24.81,yin,,0,0,0,,交给本地化者\\N{\\fs12}ship them off to a localizer --\r\nDialogue: 0,0:14:24.81,0:14:27.81,yin,,0,0,0,,或许还连同app的demo一起\\N{\\fs12}maybe with a demo of your app or something like that --\r\nDialogue: 0,0:14:27.81,0:14:30.02,yin,,0,0,0,,他们会翻译所有这些字符串并发送回来\\N{\\fs12}they'll translate all the strings and send them back.\r\nDialogue: 0,0:14:30.02,0:14:35.13,yin,,0,0,0,,你把这些放入到Xcode项目中 就可以交付了\\N{\\fs12}And then you just plop them into your Xcode project and ship it.\r\nDialogue: 0,0:14:36.89,0:14:41.40,yin,,0,0,0,,这些Bundle的排列方式是这样的\\N{\\fs12}So the way that these bundles are arranged is inside a\r\nDialogue: 0,0:14:41.40,0:14:44.03,yin,,0,0,0,,你的应用程序是主Bundle\\N{\\fs12}bundle -- and your application is the main bundle,\r\nDialogue: 0,0:14:44.03,0:14:45.91,yin,,0,0,0,,这会在应用程序的顶层\\N{\\fs12}so that's the top level of your application --\r\nDialogue: 0,0:14:45.91,0:14:48.98,yin,,0,0,0,,其中是这些lproj目录\\N{\\fs12}inside are these lproj directories.\r\nDialogue: 0,0:14:48.98,0:14:51.06,yin,,0,0,0,,lproj目录的名称\\N{\\fs12}And the name of the lproj directory is\r\nDialogue: 0,0:14:51.06,0:14:54.22,yin,,0,0,0,,会是两个字母的语言表示\\N{\\fs12}like a little two-letter symbol for the language.\r\nDialogue: 0,0:14:54.22,0:14:56.81,yin,,0,0,0,,例如en.lproj 这是英语\\N{\\fs12}So there's EN dot lproj; that's English.\r\nDialogue: 0,0:14:56.81,0:15:00.14,yin,,0,0,0,,fr.lproj 这是法语\\N{\\fs12}There's FR dot lproj; that's French.\r\nDialogue: 0,0:15:00.14,0:15:05.92,yin,,0,0,0,,lproj中是所有的字符串文件 用于语言本地化\\N{\\fs12}And inside the lproj is all the strings files for localizing to that language.\r\nDialogue: 0,0:15:05.92,0:15:08.04,yin,,0,0,0,,就这么简单\\N{\\fs12}It's as simple as that.\r\nDialogue: 0,0:15:08.04,0:15:13.07,yin,,0,0,0,,如果你支持25种语言 你就会有25个.lproj文件\\N{\\fs12}So you might have, you know, 25 dot lprojs if you support 25 languages.\r\nDialogue: 0,0:15:13.07,0:15:17.34,yin,,0,0,0,,每个里面 都会有要编辑的字符串文件副本\\N{\\fs12}In all them there will be a copy of the strings files that are edited.\r\nDialogue: 0,0:15:17.34,0:15:20.71,yin,,0,0,0,,你们还可以离线去查更多NSBundle方面的信息\\N{\\fs12}You can look more about NS bundle offline,\r\nDialogue: 0,0:15:20.71,0:15:23.69,yin,,0,0,0,,不过字符串文件不仅仅能够关联到\\N{\\fs12}but there are ways to also associate strings files not just\r\nDialogue: 0,0:15:23.69,0:15:25.00,yin,,0,0,0,,app的主Bundle\\N{\\fs12}with your main bundle of your app,\r\nDialogue: 0,0:15:25.00,0:15:28.03,yin,,0,0,0,,它还可以关联到框架这些\\N{\\fs12}but if you had a framework or something else, you could associate it with frameworks\r\nDialogue: 0,0:15:28.03,0:15:30.57,yin,,0,0,0,,因为Bundle除了mainBundle\\N{\\fs12}because bundle, in addition to main bundle,\r\nDialogue: 0,0:15:30.57,0:15:32.62,yin,,0,0,0,,还有这个bundleForClass方法\\N{\\fs12}it has this bundle for class method.\r\nDialogue: 0,0:15:32.62,0:15:34.52,yin,,0,0,0,,它知道这个类来自哪里\\N{\\fs12}And so it knows where that class came from,\r\nDialogue: 0,0:15:34.52,0:15:36.79,yin,,0,0,0,,是框架还是主Bundle\\N{\\fs12}whether it was a framework or your main bundle.\r\nDialogue: 0,0:15:36.79,0:15:39.11,yin,,0,0,0,,它会给你Bundle 然后你会得到一个路径\\N{\\fs12}And it will give you the bundle, and then you can get a path\r\nDialogue: 0,0:15:39.11,0:15:45.15,yin,,0,0,0,,对应资源 或是使用localizedStringForKey value table\\N{\\fs12}for a resource or do localized string for key value table.\r\nDialogue: 0,0:15:45.15,0:15:47.80,yin,,0,0,0,,好 关于本地化调试简单讲两点\\N{\\fs12}Okay. Couple of things about debugging localization.\r\nDialogue: 0,0:15:47.80,0:15:50.30,yin,,0,0,0,,有一个很好的用户默认你可以设置\\N{\\fs12}There's a really nice user default that you can set,\r\nDialogue: 0,0:15:50.30,0:15:52.81,yin,,0,0,0,,NSShowNonLocalizedStrings\\N{\\fs12}NS show non-localized strings.\r\nDialogue: 0,0:15:52.81,0:15:56.50,yin,,0,0,0,,这些NSLocalizedString…\\N{\\fs12}And every time one of those NS localized string --\r\nDialogue: 0,0:15:56.50,0:15:58.57,yin,,0,0,0,,我说方法 其实是宏\\N{\\fs12}I say methods, but really they're macros --\r\nDialogue: 0,0:15:58.57,0:16:02.10,yin,,0,0,0,,只要这些宏不能在字符串文件中找到条目\\N{\\fs12}any time one of those does not find an entry in a string file,\r\nDialogue: 0,0:16:02.10,0:16:03.73,yin,,0,0,0,,你就会得到一个log\\N{\\fs12}you'll get a little log.\r\nDialogue: 0,0:16:03.73,0:16:07.17,yin,,0,0,0,,这时你就知道本地化遗漏了一条\\N{\\fs12}So then you'll know that your localizer missed one.\r\nDialogue: 0,0:16:07.17,0:16:09.27,yin,,0,0,0,,知道这个很重要\\N{\\fs12}Okay. So that's important to know.\r\nDialogue: 0,0:16:09.27,0:16:12.37,yin,,0,0,0,,当你在就本地化进行质量评价时\\N{\\fs12}So that way when you're doing your QA of your localizations\r\nDialogue: 0,0:16:12.37,0:16:15.01,yin,,0,0,0,,你要保证这些能够正常工作\\N{\\fs12}to make sure that they're really working as good.\r\nDialogue: 0,0:16:15.01,0:16:16.96,yin,,0,0,0,,我看到过有人抱怨\\N{\\fs12}I've seen some people complain\r\nDialogue: 0,0:16:16.96,0:16:20.22,yin,,0,0,0,,有时他们添加一些.strings文件到本地化\\N{\\fs12}that sometimes they'll add some strings to a localization\r\nDialogue: 0,0:16:20.22,0:16:23.48,yin,,0,0,0,,测试时会报错说新变化不存在\\N{\\fs12}and test it and it's like, \"Oh, it's not getting the new changes.\"\r\nDialogue: 0,0:16:23.48,0:16:26.15,yin,,0,0,0,,我还没在iOS7中碰到过这种情况\\N{\\fs12}I haven't seen that in iOS 7,\r\nDialogue: 0,0:16:26.16,0:16:28.03,yin,,0,0,0,,如果你碰到了 尝试清除项目\\N{\\fs12}but if you do, building clean\r\nDialogue: 0,0:16:28.03,0:16:30.15,yin,,0,0,0,,重新安装似乎能够解决这个问题\\N{\\fs12}and reinstalling seems to solve that problem.\r\nDialogue: 0,0:16:30.15,0:16:33.82,yin,,0,0,0,,我不知道这种情况什么时候会发生\\N{\\fs12}I don't know exactly the circumstances that supposedly happens under,\r\nDialogue: 0,0:16:33.82,0:16:36.40,yin,,0,0,0,,不过清除项目总是值得尝试\\N{\\fs12}but it can't hurt to build clean.\r\nDialogue: 0,0:16:36.40,0:16:38.61,yin,,0,0,0,,以上是字符串\\N{\\fs12}Okay. So that's strings.\r\nDialogue: 0,0:16:38.61,0:16:41.49,yin,,0,0,0,,所有这些我都会在demo中演示\\N{\\fs12}And we'll see all this happening in the demo.\r\nDialogue: 0,0:16:41.49,0:16:45.90,yin,,0,0,0,,很不幸的是 本地化还不仅仅是字符串这么简单\\N{\\fs12}There's more to localization, though, than just strings unfortunately.\r\nDialogue: 0,0:16:45.90,0:16:48.29,yin,,0,0,0,,这里还有locale(语言区域)的概念\\N{\\fs12}There's also the concept of a locale.\r\nDialogue: 0,0:16:48.29,0:16:51.14,yin,,0,0,0,,用户不仅可能使用不同语言\\N{\\fs12}So your user not only might speak a different language,\r\nDialogue: 0,0:16:51.14,0:16:55.38,yin,,0,0,0,,还有可能有不同的locale\\N{\\fs12}they might live in any number of different locales.\r\nDialogue: 0,0:16:55.38,0:16:57.89,yin,,0,0,0,,英语是个很好的例子\\N{\\fs12}An easy one to think about is English.\r\nDialogue: 0,0:16:57.89,0:16:59.74,yin,,0,0,0,,美国人说英语\\N{\\fs12}In America we speak English.\r\nDialogue: 0,0:16:59.74,0:17:02.07,yin,,0,0,0,,英国人也说英语\\N{\\fs12}In Great Britain they speak English.\r\nDialogue: 0,0:17:02.07,0:17:07.41,yin,,0,0,0,,但当地惯用语 货币表示都不一样\\N{\\fs12}But there are local idioms and the way that we express currency,\r\nDialogue: 0,0:17:07.41,0:17:10.29,yin,,0,0,0,,还有大数字表示\\N{\\fs12}the way we even just express numbers -- big numbers --\r\nDialogue: 0,0:17:10.29,0:17:13.08,yin,,0,0,0,,例如逗号和句号被交换了\\N{\\fs12}the commas and the periods are swapped, for example.\r\nDialogue: 0,0:17:13.08,0:17:14.46,yin,,0,0,0,,一切都略有不同\\N{\\fs12}Things just are all slightly different.\r\nDialogue: 0,0:17:14.46,0:17:17.94,yin,,0,0,0,,虽然两个国家的语言都是英语\\N{\\fs12}So even though language in both of those countries would be English,\r\nDialogue: 0,0:17:17.94,0:17:19.22,yin,,0,0,0,,但locale不同\\N{\\fs12}the locales would be different.\r\nDialogue: 0,0:17:19.22,0:17:21.64,yin,,0,0,0,,这里对于locale 有另外一个系统\\N{\\fs12}So there's a whole other system here for locales.\r\nDialogue: 0,0:17:21.64,0:17:23.10,yin,,0,0,0,,用户用设置app\\N{\\fs12}And users set their language\r\nDialogue: 0,0:17:23.10,0:17:25.29,yin,,0,0,0,,设定语言和locale\\N{\\fs12}and their locale using the settings app.\r\nDialogue: 0,0:17:25.29,0:17:27.87,yin,,0,0,0,,你的应用则会作出适应\\N{\\fs12}And your application it's just supposed to adapt.\r\nDialogue: 0,0:17:27.87,0:17:33.17,yin,,0,0,0,,这需要通过一些将locale作为参数的方法\\N{\\fs12}And you adapt by using some of these methods that take a locale as an argument\r\nDialogue: 0,0:17:33.17,0:17:34.98,yin,,0,0,0,,或是使用locale的方法\\N{\\fs12}or that use a locale under the covers.\r\nDialogue: 0,0:17:34.98,0:17:38.41,yin,,0,0,0,,你可以用这些方法知道当前locale是什么\\N{\\fs12}You can find out what current locale is with these methods,\r\nDialogue: 0,0:17:38.41,0:17:41.48,yin,,0,0,0,,还有这个很棒的autoupdatingCurrentLocale\\N{\\fs12}and you can also have this nice autoupdating current locale,\r\nDialogue: 0,0:17:41.48,0:17:43.30,yin,,0,0,0,,如果用户更改了locale\\N{\\fs12}which if the user changes their locale,\r\nDialogue: 0,0:17:43.30,0:17:45.83,yin,,0,0,0,,它会自动替你进行更新\\N{\\fs12}it will just automatically update underneath the covers;\r\nDialogue: 0,0:17:45.83,0:17:49.07,yin,,0,0,0,,只是你可能需要监听这个广播站\\N{\\fs12}although, you probably want to listen to this radio station,\r\nDialogue: 0,0:17:49.07,0:17:53.30,yin,,0,0,0,,因为发生变化时 你可能需要重新绘制UI\\N{\\fs12}too, because if it changes, you might have to redraw your UI. Right? If they change?\r\nDialogue: 0,0:17:53.30,0:17:56.07,yin,,0,0,0,,用户一般不会在程序运行时\\N{\\fs12}But it's pretty unusual for the user to change their locale\r\nDialogue: 0,0:17:56.07,0:17:59.20,yin,,0,0,0,,更改locale或语言 不过这可能发生\\N{\\fs12}or their language while they're in the middle of running your app, but it could happen.\r\nDialogue: 0,0:17:59.20,0:18:02.45,yin,,0,0,0,,你需要防患于未然\\N{\\fs12}Okay. You should be prepared for that to happen.\r\nDialogue: 0,0:18:02.45,0:18:04.72,yin,,0,0,0,,locale中有些什么不同呢\\N{\\fs12}So what are some of the things that are different in a locale?\r\nDialogue: 0,0:18:04.72,0:18:06.44,yin,,0,0,0,,这里涉及到数字\\N{\\fs12}Well, there's numbers.\r\nDialogue: 0,0:18:06.44,0:18:08.88,yin,,0,0,0,,数字格式方面这里有很多东西\\N{\\fs12}Now, there's a lot going on with formatting numbers.\r\nDialogue: 0,0:18:08.88,0:18:10.25,yin,,0,0,0,,你可能会以为很简单\\N{\\fs12}It seems like it's really simple,\r\nDialogue: 0,0:18:10.25,0:18:12.25,yin,,0,0,0,,但这里有很多要考虑的东西\\N{\\fs12}but there's actually a lot to think about here.\r\nDialogue: 0,0:18:12.25,0:18:14.86,yin,,0,0,0,,我打算讲两个很简单的例子\\N{\\fs12}But I'm going to look at two pretty simple cases.\r\nDialogue: 0,0:18:14.86,0:18:18.25,yin,,0,0,0,,一个是显示数字 另一个是读取数字\\N{\\fs12}One is displaying numbers and one is reading numbers.\r\nDialogue: 0,0:18:18.25,0:18:22.70,yin,,0,0,0,,对于在屏幕上显示数字 你可能希望\\N{\\fs12}So for displaying number on screen you're probably want\r\nDialogue: 0,0:18:22.70,0:18:25.21,yin,,0,0,0,,使用stringWithFormat %g\\N{\\fs12}to do string with format percent G.\r\nDialogue: 0,0:18:25.21,0:18:28.65,yin,,0,0,0,,%g是说通用浮点数\\N{\\fs12}\"Percent G\" just means generic floating point number.\r\nDialogue: 0,0:18:28.65,0:18:30.61,yin,,0,0,0,,但这里不要这样\\N{\\fs12}But you don't want to do that.\r\nDialogue: 0,0:18:30.61,0:18:34.01,yin,,0,0,0,,你需要使用NSNumberFormatter中的这个方法\\N{\\fs12}What you want to do is use this method in NS number formatter\r\nDialogue: 0,0:18:34.01,0:18:36.88,yin,,0,0,0,,名为localizedStringFromNumber numberStyle\\N{\\fs12}called localized string from number, number style.\r\nDialogue: 0,0:18:36.88,0:18:40.21,yin,,0,0,0,,数字样式有很多 例如小数 还有拼出\\N{\\fs12}Okay. And there's different number styles like decimal and spell out.\r\nDialogue: 0,0:18:40.21,0:18:43.89,yin,,0,0,0,,拼出是说 例如4 我们要拼成four\\N{\\fs12}We'll even spell it out. Like, if you put a four in there, it will say four, f-o-u-r.\r\nDialogue: 0,0:18:43.89,0:18:45.03,yin,,0,0,0,,这是拼出\\N{\\fs12}Okay, spell it out.\r\nDialogue: 0,0:18:45.03,0:18:47.36,yin,,0,0,0,,这里有不同的格式\\N{\\fs12}So there's different formats for doing that.\r\nDialogue: 0,0:18:47.38,0:18:50.15,yin,,0,0,0,,这会返回一个可以放到UI中的字符串\\N{\\fs12}And that will give you back a string that you can put in the UI\r\nDialogue: 0,0:18:50.15,0:18:54.10,yin,,0,0,0,,显示数字的方式将适用于你所处的locale\\N{\\fs12}that will display the number in a way that's appropriate for the locale you're in.\r\nDialogue: 0,0:18:54.10,0:18:57.08,yin,,0,0,0,,对于大数字 例如1000\\N{\\fs12}And especially, again, a large number like a thousand\r\nDialogue: 0,0:18:57.08,0:19:01.21,yin,,0,0,0,,美国会写成1,000.00\\N{\\fs12}in the US might be one comma zero zero zero point zero zero;\r\nDialogue: 0,0:19:01.21,0:19:05.41,yin,,0,0,0,,而英国会写成1.000,00\\N{\\fs12}whereas in Great Britain it would be one period zero zero zero comma zero zero.\r\nDialogue: 0,0:19:05.41,0:19:07.62,yin,,0,0,0,,这样做就能弄对那些\\N{\\fs12}Okay. And so this would get that right.\r\nDialogue: 0,0:19:07.62,0:19:10.12,yin,,0,0,0,,然后有解析数字 读取数字\\N{\\fs12}Then there's parsing numbers, reading them.\r\nDialogue: 0,0:19:10.12,0:19:14.79,yin,,0,0,0,,这里你可能想说int value\\N{\\fs12}You really probably want here to just say int value\r\nDialogue: 0,0:19:14.79,0:19:16.84,yin,,0,0,0,,或是字符串的float value\\N{\\fs12}or float value of a string,\r\nDialogue: 0,0:19:16.84,0:19:21.57,yin,,0,0,0,,这会将浮点数或是整型数解释为输入\\N{\\fs12}which will parse it and try it interpret a float or an int as the input.\r\nDialogue: 0,0:19:21.57,0:19:23.09,yin,,0,0,0,,但这并不是正确的做法\\N{\\fs12}But that's not really the right way to do it.\r\nDialogue: 0,0:19:23.09,0:19:24.84,yin,,0,0,0,,你应该使用NumberFormatter\\N{\\fs12}You should use the number formatter here.\r\nDialogue: 0,0:19:24.84,0:19:26.29,yin,,0,0,0,,你创建一个formatter\\N{\\fs12}So you just create a formatter,\r\nDialogue: 0,0:19:26.29,0:19:28.62,yin,,0,0,0,,设置你要读取数字的样式\\N{\\fs12}set the style of number that you're trying to read in --\r\nDialogue: 0,0:19:28.62,0:19:30.37,yin,,0,0,0,,同上面一样\\N{\\fs12}same thing as we saw above there --\r\nDialogue: 0,0:19:30.37,0:19:32.94,yin,,0,0,0,,然后你将得到解析后的数字 作为NSNumber\\N{\\fs12}and then you're going to get the parsed number as in NS number\r\nDialogue: 0,0:19:32.94,0:19:35.17,yin,,0,0,0,,通过调用numberFromString\\N{\\fs12}by calling number from string.\r\nDialogue: 0,0:19:35.17,0:19:37.23,yin,,0,0,0,,这会去看那个字符串\\N{\\fs12}And that's going to look in that string,\r\nDialogue: 0,0:19:37.23,0:19:41.68,yin,,0,0,0,,然后把它解析为货币或是小数\\N{\\fs12}parse it like a currency or just a decimal number.\r\nDialogue: 0,0:19:41.68,0:19:45.51,yin,,0,0,0,,如果用户键入1.000,00\\N{\\fs12}And so if the person types in one period zero zero zero comma zero zero,\r\nDialogue: 0,0:19:45.51,0:19:48.91,yin,,0,0,0,,而他处在英国locale 你就会得到1000\\N{\\fs12}you'll get a thousand if they're in the Great Britain locale.\r\nDialogue: 0,0:19:48.91,0:19:49.93,yin,,0,0,0,,理解吗\\N{\\fs12}Make sense?\r\nDialogue: 0,0:19:49.93,0:19:51.52,yin,,0,0,0,,而在美国 你就无法得到\\N{\\fs12}Whereas in the US you wouldn't get that.\r\nDialogue: 0,0:19:51.52,0:19:55.57,yin,,0,0,0,,1.000可能让你得到1 甚至nil\\N{\\fs12}One period zero zero zero probably will give you one or might even give you nil\r\nDialogue: 0,0:19:55.57,0:19:58.78,yin,,0,0,0,,因为这甚至不是合法的数字\\N{\\fs12}because that's not really even a number.\r\nDialogue: 0,0:20:00.03,0:20:04.35,yin,,0,0,0,,日期 这个也很复杂 你需要小心\\N{\\fs12}Dates -- another complicated one you have to be careful of.\r\nDialogue: 0,0:20:04.35,0:20:07.01,yin,,0,0,0,,关于日期 我只想说\\N{\\fs12}All I'm going to say about dates is\r\nDialogue: 0,0:20:07.01,0:20:10.27,yin,,0,0,0,,记住我们所使用的公历\\N{\\fs12}familiarize yourself with the concept that our calendar,\r\nDialogue: 0,0:20:10.27,0:20:13.52,yin,,0,0,0,,并不是世界上唯一的历法\\N{\\fs12}the Gregorian calendar, is not the only calendar in the world.\r\nDialogue: 0,0:20:13.52,0:20:15.67,yin,,0,0,0,,历法还有别的\\N{\\fs12}There are other calendars out there.\r\nDialogue: 0,0:20:15.67,0:20:19.62,yin,,0,0,0,,iOS中有处理所有这些的机制\\N{\\fs12}And there's mechanism in iOS for dealing with all of them,\r\nDialogue: 0,0:20:19.62,0:20:22.75,yin,,0,0,0,,不过你需要知道怎么做 我显然没时间一一讲到\\N{\\fs12}but you have to know how to do it. I can't cover it all in one lecture --\r\nDialogue: 0,0:20:22.75,0:20:26.20,yin,,0,0,0,,我就算用一堂课讲 也不见得讲得完\\N{\\fs12}even if I had a whole lecture devoted to it probably.\r\nDialogue: 0,0:20:26.20,0:20:29.03,yin,,0,0,0,,不过你们可以看看NSCalendar这些类\\N{\\fs12}But you want to look at classes like NS calendar,\r\nDialogue: 0,0:20:29.03,0:20:31.44,yin,,0,0,0,,看看其说明文档 去熟悉一下\\N{\\fs12}search through the documentation. Kind of familiarize yourself.\r\nDialogue: 0,0:20:31.44,0:20:34.73,yin,,0,0,0,,如果你要让应用程序具有多语言\\N{\\fs12}If you're really going to do a multi-language,\r\nDialogue: 0,0:20:34.73,0:20:37.51,yin,,0,0,0,,多locale 而日期是你UI的一部分\\N{\\fs12}multi-locale application, and dates are part of your UI,\r\nDialogue: 0,0:20:37.51,0:20:40.43,yin,,0,0,0,,你就需要理解这里是怎么回事\\N{\\fs12}you really want to understand what you're doing there.\r\nDialogue: 0,0:20:40.43,0:20:44.26,yin,,0,0,0,,对于简单日期的格式化 这里有一个很棒的方法\\N{\\fs12}For formatting simple dates there's this nice method,\r\nDialogue: 0,0:20:44.26,0:20:47.38,yin,,0,0,0,,localizedStringFromDate 带有dateStyle\\N{\\fs12}localize string from date with the date style.\r\nDialogue: 0,0:20:47.38,0:20:52.76,yin,,0,0,0,,使用这个 你就能完成很多事情\\N{\\fs12}You can get away with a lot by just using this one.\r\nDialogue: 0,0:20:52.76,0:20:55.45,yin,,0,0,0,,不过如果你要对日期做更复杂的事\\N{\\fs12}But if you're doing anything more complicated with dates\r\nDialogue: 0,0:20:55.45,0:20:57.40,yin,,0,0,0,,例如你写的是日历app\\N{\\fs12}like you're writing the calendar app or something,\r\nDialogue: 0,0:20:57.40,0:21:00.09,yin,,0,0,0,,那么你显然就需要更好地理解日期\\N{\\fs12}then you obviously want to really understand dates better.\r\nDialogue: 0,0:21:00.09,0:21:04.80,yin,,0,0,0,,字符串 这里很有趣 如果你在字符串中搜索\\N{\\fs12}Strings, an interesting thing: If you're searching in a string,\r\nDialogue: 0,0:21:04.80,0:21:07.43,yin,,0,0,0,,特别是区分大小写的搜索\\N{\\fs12}okay, especially if you're searching case insensitively\r\nDialogue: 0,0:21:07.43,0:21:09.32,yin,,0,0,0,,想找到字符串中的一个单词\\N{\\fs12}to try and find a word in a string,\r\nDialogue: 0,0:21:09.32,0:21:11.95,yin,,0,0,0,,不要使用一般的rangeOfString方法\\N{\\fs12}you don't want to use the range of string method;\r\nDialogue: 0,0:21:11.95,0:21:13.94,yin,,0,0,0,,你要用这个rangeOfString方法\\N{\\fs12}you want to use this range of string method --\r\nDialogue: 0,0:21:13.94,0:21:16.48,yin,,0,0,0,,rangeOfString range locale\\N{\\fs12}range of string options range locale --\r\nDialogue: 0,0:21:16.48,0:21:18.36,yin,,0,0,0,,传递给它当前locale\\N{\\fs12}and pass the current locale.\r\nDialogue: 0,0:21:18.36,0:21:23.19,yin,,0,0,0,,区分大小写和变音符号的情况尤是如此\\N{\\fs12}And this is especially true with case insensitivity and when diacritics are involved\r\nDialogue: 0,0:21:23.21,0:21:26.77,yin,,0,0,0,,因为不同语言对变音符号的处理是不同的\\N{\\fs12}because different languages treat the diacritics differently.\r\nDialogue: 0,0:21:26.77,0:21:30.34,yin,,0,0,0,,不同语言对区分大小写的处理也是不同的\\N{\\fs12}And case sensitivity is different in different languages.\r\nDialogue: 0,0:21:30.34,0:21:33.30,yin,,0,0,0,,这里你显然需要使用这个方法\\N{\\fs12}So you would definitely want to use this method for that.\r\nDialogue: 0,0:21:33.30,0:21:35.10,yin,,0,0,0,,UIImage很有趣\\N{\\fs12}UI image is kind of an interesting one.\r\nDialogue: 0,0:21:35.10,0:21:38.62,yin,,0,0,0,,想想你在写一个app 例如一个驾车app\\N{\\fs12}What if you were writing an app, some kind of driving app\r\nDialogue: 0,0:21:38.62,0:21:41.42,yin,,0,0,0,,你有一个停止标志\\N{\\fs12}or something like that and you have a stop sign?\r\nDialogue: 0,0:21:41.42,0:21:44.76,yin,,0,0,0,,停止标志在几乎所有locale都是相同的\\N{\\fs12}The stop sign is pretty much the same in almost all locales.\r\nDialogue: 0,0:21:44.76,0:21:45.76,yin,,0,0,0,,这就很好了\\N{\\fs12}So you're good to go.\r\nDialogue: 0,0:21:45.76,0:21:49.74,yin,,0,0,0,,但其它标志 例如让路标志 可能会非常不同\\N{\\fs12}But other signs, like yield signs and things like that, can be quite different\r\nDialogue: 0,0:21:49.74,0:21:53.26,yin,,0,0,0,,在其locale 用户可能会不认识你的让路标志\\N{\\fs12}and your user wouldn't even recognize a yield sign in their locale.\r\nDialogue: 0,0:21:53.26,0:21:57.88,yin,,0,0,0,,你需要用不同的图像 让图像也能本地化\\N{\\fs12}You might want to have a different image and have the image be localizable.\r\nDialogue: 0,0:21:57.88,0:21:59.77,yin,,0,0,0,,做起来很简单\\N{\\fs12}Really easy to do.\r\nDialogue: 0,0:21:59.77,0:22:05.29,yin,,0,0,0,,对于每个locale 你只需要将图像放到其lproj中…\\N{\\fs12}You just put the image for each locale, you know, in its lproj --\r\nDialogue: 0,0:22:05.29,0:22:08.32,yin,,0,0,0,,抱歉 对于语言 放到lproj中\\N{\\fs12}sorry -- for the languages in its lproj\r\nDialogue: 0,0:22:08.32,0:22:10.18,yin,,0,0,0,,然后你将它提出\\N{\\fs12}and then you pull it out.\r\nDialogue: 0,0:22:10.18,0:22:14.00,yin,,0,0,0,,不过哪怕这里 如果语言还有不同的locale\\N{\\fs12}But even there, if you have a language that might have different locales\r\nDialogue: 0,0:22:14.00,0:22:17.53,yin,,0,0,0,,不同的标志会有相同的语言在它上面\\N{\\fs12}that have a different sign with the same language on it,\r\nDialogue: 0,0:22:17.53,0:22:21.19,yin,,0,0,0,,有趣的是 停止在很多语言中都是一样的\\N{\\fs12}amazingly stop is \"stop\" in most languages,\r\nDialogue: 0,0:22:21.19,0:22:23.57,yin,,0,0,0,,哪怕stop不是法语中的单词\\N{\\fs12}even though \"stop\" is obviously not a word in French.\r\nDialogue: 0,0:22:23.57,0:22:25.98,yin,,0,0,0,,你去法国 你看到停止标志说stop\\N{\\fs12}If you go to France, you'll see stop signs that say \"stop,\"\r\nDialogue: 0,0:22:25.98,0:22:27.29,yin,,0,0,0,,这有些奇怪\\N{\\fs12}which is kind of strange.\r\nDialogue: 0,0:22:27.29,0:22:29.89,yin,,0,0,0,,不过可能 不同locale的情况会有不同\\N{\\fs12}But there might be locales where things are different,\r\nDialogue: 0,0:22:29.89,0:22:33.82,yin,,0,0,0,,这样就需要在UIImage imageNamed上做些额外工作\\N{\\fs12}so you might have to do a little extra work on top of UI image image named.\r\nDialogue: 0,0:22:33.82,0:22:37.09,yin,,0,0,0,,你可能需要说 如果我在这个locale 它就应该是这样\\N{\\fs12}You might have to say, \"Oh, if I'm in this locale, then it looks like this.\"\r\nDialogue: 0,0:22:37.09,0:22:42.52,yin,,0,0,0,,这只发生在应用中会有路标这样的图像时\\N{\\fs12}Now, again, that's only if you're doing an application that has imagery like road signs\r\nDialogue: 0,0:22:42.52,0:22:44.76,yin,,0,0,0,,这些东西非常具有locale特异性\\N{\\fs12}or whatever that's very locale-specific.\r\nDialogue: 0,0:22:44.76,0:22:47.72,yin,,0,0,0,,这方面本地化者可能也会帮助你\\N{\\fs12}That's something a localizer will hopefully help you.\r\nDialogue: 0,0:22:48.34,0:22:50.27,yin,,0,0,0,,你放上一个让路标志\\N{\\fs12}You'll put a yield sign up, and they'll say, \"Oh,\r\nDialogue: 0,0:22:50.27,0:22:54.76,yin,,0,0,0,,他们可能会说 瑞典的路标不一样\\N{\\fs12}wait a second in\" -- you know, I don't know -- \"Sweden that looks different.\"\r\nDialogue: 0,0:22:54.76,0:22:57.13,yin,,0,0,0,,或是 阿富汗是这样的\\N{\\fs12}Or, you know, \"In Afghanistan it's this.\"\r\nDialogue: 0,0:22:57.13,0:23:00.39,yin,,0,0,0,,本地化者可能会帮助你\\N{\\fs12}And so your localizers will hopefully help you.\r\nDialogue: 0,0:23:00.39,0:23:01.97,yin,,0,0,0,,不过UIImage imageNamed\\N{\\fs12}But UI image, image named\r\nDialogue: 0,0:23:01.97,0:23:04.80,yin,,0,0,0,,会在lproj中为你找\\N{\\fs12}will look in the lprojs for you.\r\nDialogue: 0,0:23:04.80,0:23:08.01,yin,,0,0,0,,这上面可能还需要locale\\N{\\fs12}You might still have to locale on top of that.\r\nDialogue: 0,0:23:08.01,0:23:10.02,yin,,0,0,0,,这里我们要做的demo是\\N{\\fs12}So the demo we're going to do here is\r\nDialogue: 0,0:23:10.02,0:23:12.26,yin,,0,0,0,,国际化Photomania\\N{\\fs12}internationalizing PhotoMania.\r\nDialogue: 0,0:23:12.26,0:23:20.91,yin,,0,0,0,,我将打开上周那堂课我们最后得到的Photomania\\N{\\fs12}So I'm going to start with the PhotoMania that we had at our last lecture, last week.\r\nDialogue: 0,0:23:20.91,0:23:22.58,yin,,0,0,0,,这是Photomania\\N{\\fs12}So here's PhotoMania.\r\nDialogue: 0,0:23:22.58,0:23:26.55,yin,,0,0,0,,看Photomania这里的UI\\N{\\fs12}And PhotoMania is UI here.\r\nDialogue: 0,0:23:26.55,0:23:29.12,yin,,0,0,0,,很美妙 它其实很容易本地化\\N{\\fs12}It's amazing, it's actually pretty easy to localize\r\nDialogue: 0,0:23:29.12,0:23:34.02,yin,,0,0,0,,因为Photomania显示的主要是内容\\N{\\fs12}because PhotoMania, primarily what it displays is its content.\r\nDialogue: 0,0:23:34.02,0:23:38.03,yin,,0,0,0,,看看所有这些UI你会发现\\N{\\fs12}Right? If you look at almost all of this UI,\r\nDialogue: 0,0:23:38.03,0:23:41.46,yin,,0,0,0,,它不过是显示从Flickr取回的数据\\N{\\fs12}it's just only displaying what's coming back from Flickr.\r\nDialogue: 0,0:23:41.46,0:23:43.86,yin,,0,0,0,,其中很少再有别的文字了\\N{\\fs12}It hardly has any other text in it.\r\nDialogue: 0,0:23:43.86,0:23:46.21,yin,,0,0,0,,这是很好的UI设计\\N{\\fs12}That's actually very good UI design.\r\nDialogue: 0,0:23:46.21,0:23:48.96,yin,,0,0,0,,一般而言 你希望UI中尽量高百分比的\\N{\\fs12}Generally, you want as high a percentage of the UI\r\nDialogue: 0,0:23:48.96,0:23:50.58,yin,,0,0,0,,都是你要显示的\\N{\\fs12}to be what you're displaying --\r\nDialogue: 0,0:23:50.58,0:23:52.20,yin,,0,0,0,,如果你是照片观赏app\\N{\\fs12}so if you're photo viewing app,\r\nDialogue: 0,0:23:52.20,0:23:57.38,yin,,0,0,0,,你希望到处都是照片 只在边上有少量控制元件\\N{\\fs12}you would want photo everywhere and just a little bit of controls around the edges.\r\nDialogue: 0,0:23:57.38,0:23:59.09,yin,,0,0,0,,不过还是有些地方\\N{\\fs12}But there is a couple of places.\r\nDialogue: 0,0:23:59.09,0:24:03.48,yin,,0,0,0,,你可以看到这个 这里有不少字符串\\N{\\fs12}You can see this guy right here has quite a few strings in it right there.\r\nDialogue: 0,0:24:03.48,0:24:06.67,yin,,0,0,0,,此外还有各种字符串出现在\\N{\\fs12}And there's some miscellaneous strings that we load up as part\r\nDialogue: 0,0:24:06.67,0:24:11.34,yin,,0,0,0,,这些原型单元格中 这是需要可本地化的\\N{\\fs12}of these prototype cells that might need to be localizable.\r\nDialogue: 0,0:24:11.34,0:24:17.93,yin,,0,0,0,,我们先从添加具有其它这些语言的能力开始\\N{\\fs12}But let's start, like I said, with adding the ability to have these other languages.\r\nDialogue: 0,0:24:17.93,0:24:24.99,yin,,0,0,0,,做法是点这里来编辑我们的项目\\N{\\fs12}And we do that by clicking here to edit our project.\r\nDialogue: 0,0:24:24.99,0:24:28.45,yin,,0,0,0,,重申一次 我们要编辑的不是目标 而是这个\\N{\\fs12}But again, we don't want to be editing the target; we want to edit this.\r\nDialogue: 0,0:24:28.45,0:24:29.96,yin,,0,0,0,,这是这里\\N{\\fs12}So this is something right here.\r\nDialogue: 0,0:24:29.96,0:24:31.27,yin,,0,0,0,,不要忘记这一步\\N{\\fs12}Don't forget this step right here.\r\nDialogue: 0,0:24:31.27,0:24:33.11,yin,,0,0,0,,我们要的是项目\\N{\\fs12}We want the project.\r\nDialogue: 0,0:24:33.13,0:24:35.39,yin,,0,0,0,,这样做之后 你会看到本地化\\N{\\fs12}And when we do that, now you'll see there's localization.\r\nDialogue: 0,0:24:35.39,0:24:37.28,yin,,0,0,0,,下面这里是本地化\\N{\\fs12}Here's the localizations down here.\r\nDialogue: 0,0:24:37.28,0:24:40.03,yin,,0,0,0,,我们要使用base本地化\\N{\\fs12}And we are going to use base localization,\r\nDialogue: 0,0:24:40.03,0:24:43.23,yin,,0,0,0,,这意味着故事板将是我们的base\\N{\\fs12}which means our storyboard is going to be our base\r\nDialogue: 0,0:24:43.23,0:24:45.08,yin,,0,0,0,,之后我们会修改这些字符串\\N{\\fs12}and we're going to modify the strings after that.\r\nDialogue: 0,0:24:45.08,0:24:47.61,yin,,0,0,0,,我要添加法语\\N{\\fs12}So I'm going to add French.\r\nDialogue: 0,0:24:47.61,0:24:48.80,yin,,0,0,0,,让我们添加法语\\N{\\fs12}So let's add French.\r\nDialogue: 0,0:24:48.80,0:24:49.87,yin,,0,0,0,,它问我\\N{\\fs12}It's asking me,\r\nDialogue: 0,0:24:49.87,0:24:54.02,yin,,0,0,0,,已有的东西里面 你要为哪些创建.strings文件\\N{\\fs12}\"What existing stuff do you want to make strings files for?\"\r\nDialogue: 0,0:24:54.02,0:24:56.66,yin,,0,0,0,,我要所有这些 故事板的所有这些\\N{\\fs12}And I'm just going to say all of it, all my storyboards\r\nDialogue: 0,0:24:56.66,0:24:59.25,yin,,0,0,0,,不要太担心InfoPlist.strings\\N{\\fs12}and don't worry too much about info P list dot strings.\r\nDialogue: 0,0:24:59.25,0:25:00.78,yin,,0,0,0,,这里只有少许需要本地化\\N{\\fs12}There's a little bit in there to localize,\r\nDialogue: 0,0:25:00.78,0:25:02.76,yin,,0,0,0,,例如app名可以本地化\\N{\\fs12}like your app name can actually be localized.\r\nDialogue: 0,0:25:02.76,0:25:05.48,yin,,0,0,0,,不过主要是在故事板中\\N{\\fs12}But most of your stuff is in your storyboard.\r\nDialogue: 0,0:25:05.48,0:25:07.45,yin,,0,0,0,,这里两个故事板都选上\\N{\\fs12}So we'll have both storyboards.\r\nDialogue: 0,0:25:07.45,0:25:10.39,yin,,0,0,0,,这样做时 它会添加法语\\N{\\fs12}And when we do that, it just adds French here.\r\nDialogue: 0,0:25:10.39,0:25:12.58,yin,,0,0,0,,我们可以看看这个\\N{\\fs12}And if we look up here, look at this.\r\nDialogue: 0,0:25:12.58,0:25:16.31,yin,,0,0,0,,这里有个小三角 点它\\N{\\fs12}Now this has a little triangle that, if we click it,\r\nDialogue: 0,0:25:16.31,0:25:19.55,yin,,0,0,0,,我们就能看到这里有base故事板\\N{\\fs12}we get to see that there's the base storyboard\r\nDialogue: 0,0:25:19.55,0:25:22.63,yin,,0,0,0,,然后是法语的.strings文件\\N{\\fs12}and now there's string files for French.\r\nDialogue: 0,0:25:22.63,0:25:25.14,yin,,0,0,0,,.strings文件就是这样的\\N{\\fs12}So here's what a strings file looks like.\r\nDialogue: 0,0:25:25.14,0:25:30.08,yin,,0,0,0,,它有给本地化者的注释 然后是一个键 然后是一个值\\N{\\fs12}It's got a comment to the localizer, and then a key, and then a value.\r\nDialogue: 0,0:25:30.08,0:25:32.80,yin,,0,0,0,,这里的这些键\\N{\\fs12}Now, these keys right here,\r\nDialogue: 0,0:25:32.80,0:25:35.38,yin,,0,0,0,,我们怎么知道什么匹配什么\\N{\\fs12}how do we know what matches up with what?\r\nDialogue: 0,0:25:35.38,0:25:38.26,yin,,0,0,0,,多数时候 我们可以看值 例如done\\N{\\fs12}Well, most of the time we can look at the value like done.\r\nDialogue: 0,0:25:38.26,0:25:41.36,yin,,0,0,0,,我们知道done是这个完成按钮 很容易\\N{\\fs12}Well, we know that done is this done button -- easy.\r\nDialogue: 0,0:25:41.36,0:25:43.18,yin,,0,0,0,,但看title\\N{\\fs12}But look at title.\r\nDialogue: 0,0:25:43.18,0:25:45.93,yin,,0,0,0,,这里有三个title\\N{\\fs12}See, there's two, three titles.\r\nDialogue: 0,0:25:45.93,0:25:48.72,yin,,0,0,0,,这里有一个 这里有两个\\N{\\fs12}There's a title right here and there's two title right here.\r\nDialogue: 0,0:25:48.72,0:25:51.41,yin,,0,0,0,,哪个标题是哪个呢\\N{\\fs12}It's like which title is which?\r\nDialogue: 0,0:25:51.41,0:25:52.70,yin,,0,0,0,,这是哪个\\N{\\fs12}Which is this?\r\nDialogue: 0,0:25:52.70,0:25:57.28,yin,,0,0,0,,这个title又是哪个\\N{\\fs12}And which is this title right here, for example?\r\nDialogue: 0,0:25:57.28,0:26:00.13,yin,,0,0,0,,你可以点这些title来看\\N{\\fs12}And you can find that out by clicking on any of the titles.\r\nDialogue: 0,0:26:00.13,0:26:01.14,yin,,0,0,0,,例如点这个\\N{\\fs12}Like, let's click on this one\r\nDialogue: 0,0:26:01.14,0:26:03.47,yin,,0,0,0,,这个我们显然需要本地化\\N{\\fs12}because we do definitely want to localize this one.\r\nDialogue: 0,0:26:03.47,0:26:08.38,yin,,0,0,0,,到检查器中 到身份检查器 这是其身份的一部分\\N{\\fs12}Go over to the inspector, go to the identity inspector -- it's part of its identity --\r\nDialogue: 0,0:26:08.38,0:26:12.67,yin,,0,0,0,,可以看到所有对象在故事板中都有对象ID\\N{\\fs12}and you can see that all objects have an object ID in a storyboard.\r\nDialogue: 0,0:26:12.67,0:26:13.64,yin,,0,0,0,,看到了吗\\N{\\fs12}You see that?\r\nDialogue: 0,0:26:13.64,0:26:16.69,yin,,0,0,0,,这个是65e-yS-HIT\\N{\\fs12}So this one's 65EYS hit.\r\nDialogue: 0,0:26:16.69,0:26:18.76,yin,,0,0,0,,也就是这个\\N{\\fs12}So that is this one.\r\nDialogue: 0,0:26:18.76,0:26:22.88,yin,,0,0,0,,这个就对应于之前的那个title了\\N{\\fs12}So this one is the title that is the title of that.\r\nDialogue: 0,0:26:22.88,0:26:27.41,yin,,0,0,0,,另外这两个title 我们甚至不需要本地化它们\\N{\\fs12}Now, these other two titles, we don't even need to localize them\r\nDialogue: 0,0:26:27.41,0:26:33.09,yin,,0,0,0,,因为它们在这些原型中\\N{\\fs12}because they are in these prototypes here.\r\nDialogue: 0,0:26:33.09,0:26:35.93,yin,,0,0,0,,这两个原型 它们不会出现在UI上\\N{\\fs12}These two prototypes, so they never appear on the UI, right,\r\nDialogue: 0,0:26:35.93,0:26:37.47,yin,,0,0,0,,这些title和subtitle\\N{\\fs12}these titles and subtitles. We always\r\nDialogue: 0,0:26:37.48,0:26:42.21,yin,,0,0,0,,因为我们总会用表格视图中的数据来填充它们\\N{\\fs12}drive them with whatever our data source is for our table view.\r\nDialogue: 0,0:26:42.21,0:26:44.07,yin,,0,0,0,,不过这个我们需要本地化\\N{\\fs12}But this one we do need to localize,\r\nDialogue: 0,0:26:44.07,0:26:47.01,yin,,0,0,0,,然后这个subtitle也是 它是qcj\\N{\\fs12}and then also this little subtitle one here, too, which is QCJ.\r\nDialogue: 0,0:26:47.01,0:26:49.93,yin,,0,0,0,,它也需要本地化\\N{\\fs12}This one also needs to be localized.\r\nDialogue: 0,0:26:49.93,0:26:51.70,yin,,0,0,0,,怎样本地化呢\\N{\\fs12}So what does it look like to localize these?\r\nDialogue: 0,0:26:51.70,0:26:53.93,yin,,0,0,0,,假设我是一个本地化者 在本地化它\\N{\\fs12}Let's say I'm a localizer and I'm localizing it.\r\nDialogue: 0,0:26:53.93,0:26:57.04,yin,,0,0,0,,很不幸 我没有掌握本地化它所需的法语\\N{\\fs12}Unfortunately, I don't quite know enough French to localize this.\r\nDialogue: 0,0:26:57.04,0:27:00.75,yin,,0,0,0,,我要给你们展示一个很酷的本地化方式\\N{\\fs12}So I'm going to show you a kind of cool way to localize --\r\nDialogue: 0,0:27:00.75,0:27:03.90,yin,,0,0,0,,这对于测试很有帮助 也就是放一个句点\\N{\\fs12}which is good for testing -- which is just to put a period\r\nDialogue: 0,0:27:03.90,0:27:06.39,yin,,0,0,0,,在每个字母之间 像这样\\N{\\fs12}between every letter like that.\r\nDialogue: 0,0:27:07.00,0:27:11.29,yin,,0,0,0,,作为开发者像这样进行本地化会很方便\\N{\\fs12}So do a localization like this as a developer because it's easy for you to do.\r\nDialogue: 0,0:27:11.29,0:27:12.96,yin,,0,0,0,,你不需要懂那门语言\\N{\\fs12}You don't have to know the language.\r\nDialogue: 0,0:27:12.96,0:27:15.83,yin,,0,0,0,,而且很酷的是 这会让一切都变宽\\N{\\fs12}And what's cool about this is it makes everything wide.\r\nDialogue: 0,0:27:15.83,0:27:18.45,yin,,0,0,0,,这会挑战你的UI\\N{\\fs12}So it's going to really challenge your UI\r\nDialogue: 0,0:27:18.45,0:27:21.27,yin,,0,0,0,,让其在字符串变更时能够匹配宽度\\N{\\fs12}to make things fit when you change these strings, right?\r\nDialogue: 0,0:27:21.29,0:27:26.18,yin,,0,0,0,,这甚至能够对德语奏效 要知道德语单词都很长\\N{\\fs12}It might even work for German if you do this because German tends to be very long words.\r\nDialogue: 0,0:27:26.18,0:27:29.21,yin,,0,0,0,,而且 你可以很快地这样做\\N{\\fs12}And it's also, again, really -- you can do it really quickly.\r\nDialogue: 0,0:27:29.21,0:27:34.49,yin,,0,0,0,,让我们这样来本地化这整个文件\\N{\\fs12}Let's go ahead and localize this entire file by doing this.\r\nDialogue: 0,0:27:36.62,0:27:38.94,yin,,0,0,0,,关于这个还有一点好处也就是\\N{\\fs12}And another good thing about this is\r\nDialogue: 0,0:27:38.94,0:27:41.11,yin,,0,0,0,,UI中这个出现的任何位置\\N{\\fs12}everywhere in the UI that this appears,\r\nDialogue: 0,0:27:41.11,0:27:43.79,yin,,0,0,0,,马上都会非常明显\\N{\\fs12}it's going to be really obvious immediately.\r\nDialogue: 0,0:27:43.79,0:27:45.63,yin,,0,0,0,,糟糕 我忘了这个\\N{\\fs12}Oops. I forgot that one, right?\r\nDialogue: 0,0:27:45.63,0:27:51.15,yin,,0,0,0,,因为句点在UI中很容易看到\\N{\\fs12}Because this period's very, very easy to see in the UI.\r\nDialogue: 0,0:27:51.15,0:27:53.42,yin,,0,0,0,,这两个title和这个subtitle我们不需要管\\N{\\fs12}So we don't need to do these two titles or this subtitle.\r\nDialogue: 0,0:27:53.42,0:27:57.16,yin,,0,0,0,,这个也不需要管 因为这是占位符\\N{\\fs12}We don't need to do this because that's just a placeholder.\r\nDialogue: 0,0:27:57.16,0:27:59.33,yin,,0,0,0,,不过下面这个subtitle要处理\\N{\\fs12}We want this subtitle down here, though,\r\nDialogue: 0,0:27:59.33,0:28:02.19,yin,,0,0,0,,因为这是另一个subtitle\\N{\\fs12}because that's the other subtitle.\r\nDialogue: 0,0:28:02.19,0:28:04.29,yin,,0,0,0,,这个也一样\\N{\\fs12}We want this one, too.\r\nDialogue: 0,0:28:05.66,0:28:09.41,yin,,0,0,0,,然后是这个URL\\N{\\fs12}And so the little URL guy here.\r\nDialogue: 0,0:28:09.41,0:28:11.06,yin,,0,0,0,,还有cancel\\N{\\fs12}And cancel.\r\nDialogue: 0,0:28:12.07,0:28:15.16,yin,,0,0,0,,这样就本地化了所有\\N{\\fs12}So we've localized this entire thing,\r\nDialogue: 0,0:28:15.16,0:28:18.17,yin,,0,0,0,,需要本地化为法语的东西\\N{\\fs12}everything that needs to be localized to French.\r\nDialogue: 0,0:28:18.17,0:28:22.56,yin,,0,0,0,,将文件发送给本地化者时 这些也可以删掉\\N{\\fs12}When you send this off to the localizer you might even take these things out of here.\r\nDialogue: 0,0:28:22.56,0:28:27.12,yin,,0,0,0,,这样对于哪些该翻译 本地化者就不会感到困扰了\\N{\\fs12}So the localizer on this one, too. The localizer doesn't even get confused,\r\nDialogue: 0,0:28:27.12,0:28:28.51,yin,,0,0,0,,这样对于哪些该翻译 本地化者就不会感到困扰了\\N{\\fs12}you know, like, what's going on.\r\nDialogue: 0,0:28:28.51,0:28:30.86,yin,,0,0,0,,不过有些参数需要留着\\N{\\fs12}However, there's some arguments to leave them in\r\nDialogue: 0,0:28:30.86,0:28:34.69,yin,,0,0,0,,因为你要使用NSShowNonLocalizedStrings\\N{\\fs12}because you're going to put that little NS show non-localized strings --\r\nDialogue: 0,0:28:34.69,0:28:36.28,yin,,0,0,0,,用户默认 我讲过的\\N{\\fs12}the user default I talked about --\r\nDialogue: 0,0:28:36.28,0:28:38.91,yin,,0,0,0,,你可能会对所有这些抱怨很多\\N{\\fs12}on, and then you're going to complaint about all these ones.\r\nDialogue: 0,0:28:38.91,0:28:42.90,yin,,0,0,0,,这里有大概6个 如果你要这样做的话\\N{\\fs12}So its kinda, 6 in one hand, half dozen in the other, if you want to do that.\r\nDialogue: 0,0:28:42.90,0:28:44.50,yin,,0,0,0,,好 现在我们本地化了这个\\N{\\fs12}All right. So now we've localized this.\r\nDialogue: 0,0:28:44.50,0:28:49.17,yin,,0,0,0,,结果会是怎样呢 我们运行着试试\\N{\\fs12}What does it look like? So let's run this and see.\r\nDialogue: 0,0:28:49.17,0:28:54.45,yin,,0,0,0,,好 运行这个UI时 它都是英文\\N{\\fs12}All right. So when we run this UI, it all looks like it's in English, right?\r\nDialogue: 0,0:28:54.45,0:28:59.03,yin,,0,0,0,,点击这里的添加照片按钮\\N{\\fs12}And in fact, if we go over to our little add photo guy right\r\nDialogue: 0,0:28:59.03,0:29:02.14,yin,,0,0,0,,这些都是英语 一切正常\\N{\\fs12}here, this all looks to be English and everything looks fine.\r\nDialogue: 0,0:29:02.14,0:29:04.78,yin,,0,0,0,,没有任何东西变化了 因为我们没调成法语\\N{\\fs12}Nothing has changed because we're not running in French.\r\nDialogue: 0,0:29:04.78,0:29:05.68,yin,,0,0,0,,这里还是英语\\N{\\fs12}We're still running in English.\r\nDialogue: 0,0:29:05.68,0:29:08.23,yin,,0,0,0,,显示的都还是base故事板\\N{\\fs12}So the base storyboard is still showing through.\r\nDialogue: 0,0:29:08.23,0:29:08.86,yin,,0,0,0,,这很好\\N{\\fs12}Okay, that's good.\r\nDialogue: 0,0:29:08.86,0:29:09.89,yin,,0,0,0,,检查很必要\\N{\\fs12}That's a good thing to check,\r\nDialogue: 0,0:29:09.89,0:29:14.36,yin,,0,0,0,,确保没有在本地化过程中破坏什么东西\\N{\\fs12}to make sure you haven't broken anything by adding a localization.\r\nDialogue: 0,0:29:14.36,0:29:18.22,yin,,0,0,0,,下面我们将语言换成法语\\N{\\fs12}But now let's go and change the language to be French.\r\nDialogue: 0,0:29:18.22,0:29:22.21,yin,,0,0,0,,这可以在模拟器中进行 也可以在设备上进行\\N{\\fs12}So you do that, you can do it in the simulator and you can do it on your device.\r\nDialogue: 0,0:29:22.21,0:29:28.52,yin,,0,0,0,,到通用 国际 语言 我们选法语\\N{\\fs12}And you just go here to general, international, language -- we'll change it to French.\r\nDialogue: 0,0:29:28.52,0:29:30.75,yin,,0,0,0,,现在语言变更了\\N{\\fs12}Okay. It's changing the language.\r\nDialogue: 0,0:29:30.75,0:29:33.02,yin,,0,0,0,,你的应用如果现在在运行\\N{\\fs12}Your application, if it was running right now,\r\nDialogue: 0,0:29:33.02,0:29:35.92,yin,,0,0,0,,会得到我们谈到过的通知说\\N{\\fs12}would get that notification that we talked about that says,\r\nDialogue: 0,0:29:35.92,0:29:37.72,yin,,0,0,0,,哦 这个变了\\N{\\fs12}\"Oh, this has changed.\"\r\nDialogue: 0,0:29:37.72,0:29:39.96,yin,,0,0,0,,你可以重新绘制你的UI\\N{\\fs12}So you could redraw your UI.\r\nDialogue: 0,0:29:39.96,0:29:46.78,yin,,0,0,0,,我们回到这里来运行 看看会得到什么\\N{\\fs12}But let's go back and run here and see what we get.\r\nDialogue: 0,0:29:46.78,0:29:48.30,yin,,0,0,0,,这是拍照者\\N{\\fs12}So here's photographer.\r\nDialogue: 0,0:29:48.30,0:29:51.68,yin,,0,0,0,,但愿这里能够填入正确的数据\\N{\\fs12}Hopefully this is going to fill in with its normal data.\r\nDialogue: 0,0:29:51.68,0:29:52.80,yin,,0,0,0,,没问题\\N{\\fs12}Yes, it does.\r\nDialogue: 0,0:29:52.80,0:29:55.83,yin,,0,0,0,,再到这里 看这个\\N{\\fs12}Let's go over here and look here.\r\nDialogue: 0,0:29:55.83,0:30:01.30,yin,,0,0,0,,可以看到这里加的点都显示了出来\\N{\\fs12}And you can see that it has done our little dot language here.\r\nDialogue: 0,0:30:01.30,0:30:04.05,yin,,0,0,0,,我们切换到了法语 这里都加了点\\N{\\fs12}We switched it to French and it's done our little dot language,\r\nDialogue: 0,0:30:04.05,0:30:06.78,yin,,0,0,0,,但我们什么都读不到 因为宽度超了\\N{\\fs12}but we can't really read everything because nothing fits, right?\r\nDialogue: 0,0:30:06.78,0:30:08.21,yin,,0,0,0,,副标题和标题都超了\\N{\\fs12}Subtitle doesn't fit, title.\r\nDialogue: 0,0:30:08.21,0:30:12.04,yin,,0,0,0,,宽度无法匹配 这就是加点的一个好处\\N{\\fs12}So this is good that it doesn't fit, and this is part of the advantage of doing the dots.\r\nDialogue: 0,0:30:12.04,0:30:13.80,yin,,0,0,0,,还注意到这个\\N{\\fs12}Also notice this.\r\nDialogue: 0,0:30:13.80,0:30:19.31,yin,,0,0,0,,这还是英语 这不好 让我们修正这些\\N{\\fs12}This is all still in English. So that's no good. So let's fix these things.\r\nDialogue: 0,0:30:19.31,0:30:21.93,yin,,0,0,0,,宽度不匹配很好解决\\N{\\fs12}The things not fitting is quite easy to fix.\r\nDialogue: 0,0:30:21.93,0:30:24.19,yin,,0,0,0,,我们只需要到这里的故事板\\N{\\fs12}We're just going to go to the storyboard right here,\r\nDialogue: 0,0:30:24.19,0:30:29.95,yin,,0,0,0,,重置为使用自动布局\\N{\\fs12}and I'm going to reset to use Auto Layout.\r\nDialogue: 0,0:30:29.95,0:30:32.51,yin,,0,0,0,,把所有这些拖入时\\N{\\fs12}Okay. Now when I dragged all these things in,\r\nDialogue: 0,0:30:32.51,0:30:34.86,yin,,0,0,0,,我相信我使用了蓝线\\N{\\fs12}I believe I used the blue lines.\r\nDialogue: 0,0:30:34.86,0:30:37.63,yin,,0,0,0,,在重置为建议约束条件时\\N{\\fs12}So when I reset to suggested constraints,\r\nDialogue: 0,0:30:37.63,0:30:40.90,yin,,0,0,0,,建议约束条件应该就能工作\\N{\\fs12}I think I'm going to get suggested constraints that work.\r\nDialogue: 0,0:30:40.90,0:30:43.85,yin,,0,0,0,,让我们来看看\\N{\\fs12}So let's go ahead and take a look.\r\nDialogue: 0,0:30:43.85,0:30:47.15,yin,,0,0,0,,现在就可以看到 这些宽度都匹配好了\\N{\\fs12}Enter enough and you can see now all these things fit.\r\nDialogue: 0,0:30:47.15,0:30:51.23,yin,,0,0,0,,看到了吗 cancel done title都好了\\N{\\fs12}See that? Cancel fits, done, title.\r\nDialogue: 0,0:30:51.23,0:30:54.14,yin,,0,0,0,,自动布局把一切都办得很好\\N{\\fs12}So we did a good job with our Auto Layout.\r\nDialogue: 0,0:30:54.14,0:30:57.39,yin,,0,0,0,,自动布局是本地化的一个基本组成部分\\N{\\fs12}So Auto Layout is a fundamental part of localization.\r\nDialogue: 0,0:30:57.39,0:30:58.89,yin,,0,0,0,,很基本\\N{\\fs12}Fundamental.\r\nDialogue: 0,0:30:58.89,0:31:02.75,yin,,0,0,0,,如果自动布局没有设对 本地化就无从谈起\\N{\\fs12}If you don't have your Auto Layout right, you cannot do localization\r\nDialogue: 0,0:31:02.75,0:31:03.96,yin,,0,0,0,,因为字符串变化时\\N{\\fs12}because when you change the strings,\r\nDialogue: 0,0:31:03.96,0:31:07.33,yin,,0,0,0,,到处都会被切断 都是... 所有这些糟糕的东西\\N{\\fs12}everything will be cut off, and dot dot dot, and all this bad stuff.\r\nDialogue: 0,0:31:07.33,0:31:09.24,yin,,0,0,0,,那这里的英语呢\\N{\\fs12}But what about this English right here?\r\nDialogue: 0,0:31:09.24,0:31:11.41,yin,,0,0,0,,这个我们也需要改成法语\\N{\\fs12}We got to fix this, we got to get rid of this.\r\nDialogue: 0,0:31:11.41,0:31:13.92,yin,,0,0,0,,这些都不在故事板中\\N{\\fs12}And these are actually not in my storyboard.\r\nDialogue: 0,0:31:13.92,0:31:16.17,yin,,0,0,0,,这些字符串 例如OK 还有Add Photo\\N{\\fs12}These strings, like \"Okay,\" and \"Add photo,\"\r\nDialogue: 0,0:31:16.17,0:31:18.13,yin,,0,0,0,,还有Sorry, this device cannot add a photo\\N{\\fs12}and \"Sorry, this device cannot add a photo,\"\r\nDialogue: 0,0:31:18.13,0:31:21.01,yin,,0,0,0,,这些都是代码中的字符串字面量\\N{\\fs12}those are all literal strings in my code.\r\nDialogue: 0,0:31:21.01,0:31:23.42,yin,,0,0,0,,让我们来本地化它们\\N{\\fs12}So let's go localize those.\r\nDialogue: 0,0:31:23.42,0:31:26.40,yin,,0,0,0,,这些都是我们上周加的代码\\N{\\fs12}And those are all in the thing we added last week.\r\nDialogue: 0,0:31:26.40,0:31:31.24,yin,,0,0,0,,但愿你们记得这些 也就是AddPhotoViewController\\N{\\fs12}So hopefully you remember some of this code, which is add photo view controller.\r\nDialogue: 0,0:31:31.24,0:31:33.36,yin,,0,0,0,,这是AddPhotoViewController\\N{\\fs12}So here's add photo view controller.\r\nDialogue: 0,0:31:33.36,0:31:37.26,yin,,0,0,0,,这里在我实现的任何东西中\\N{\\fs12}So one thing I like to do in anything that I implement\r\nDialogue: 0,0:31:37.26,0:31:40.08,yin,,0,0,0,,我都可以搜索@号引号\\N{\\fs12}is search for at sign quote.\r\nDialogue: 0,0:31:40.08,0:31:42.97,yin,,0,0,0,,因为@号引号就意味着字符串字面量\\N{\\fs12}Because at sign quote is going to be literal strings.\r\nDialogue: 0,0:31:42.97,0:31:45.72,yin,,0,0,0,,并非所有字符串字面量都需要本地化\\N{\\fs12}Now, not all literal strings need to be localized.\r\nDialogue: 0,0:31:45.72,0:31:50.53,yin,,0,0,0,,但这个 这个 这个和这个需要本地化\\N{\\fs12}But like, this one does, and this one, and this one, and this one.\r\nDialogue: 0,0:31:50.53,0:31:53.68,yin,,0,0,0,,这个不需要 这是segue标识符\\N{\\fs12}This one not; this is a segue identifier.\r\nDialogue: 0,0:31:53.68,0:31:56.47,yin,,0,0,0,,不会出现在UI中 不需要本地化\\N{\\fs12}Never appears in the UI. Does not need to be localized.\r\nDialogue: 0,0:31:56.47,0:32:00.95,yin,,0,0,0,,这个也不需要 这是数据库中实体的名称\\N{\\fs12}This one also not; this is the name of an entity in the database --\r\nDialogue: 0,0:32:00.95,0:32:03.18,yin,,0,0,0,,至少这里我们不会放到UI中\\N{\\fs12}or at least in this case we don't put this in the UI,\r\nDialogue: 0,0:32:03.18,0:32:05.06,yin,,0,0,0,,虽然在UI的其它地方可能需要本地化\\N{\\fs12}although we do somewhere else in the UI.\r\nDialogue: 0,0:32:05.06,0:32:06.81,yin,,0,0,0,,对未来做什么可能会有一个预览\\N{\\fs12}A little preview of what we're going to do later.\r\nDialogue: 0,0:32:06.81,0:32:10.85,yin,,0,0,0,,当然 所有这些都需要本地化\\N{\\fs12}And then, of course, all of these need to be localized, right?\r\nDialogue: 0,0:32:10.85,0:32:11.92,yin,,0,0,0,,这个也需要\\N{\\fs12}This one also.\r\nDialogue: 0,0:32:11.92,0:32:13.79,yin,,0,0,0,,这些东西都是警告用的\\N{\\fs12}All these things do is alerts.\r\nDialogue: 0,0:32:13.79,0:32:15.55,yin,,0,0,0,,这个不需要 这是缩略图\\N{\\fs12}This one not; this is thumbnail.\r\nDialogue: 0,0:32:15.55,0:32:17.06,yin,,0,0,0,,这是文件扩展名\\N{\\fs12}This is just a little file extension\r\nDialogue: 0,0:32:17.06,0:32:20.12,yin,,0,0,0,,用于缩略图URL 不会出现在UI中\\N{\\fs12}for our thumbnail URL -- never appears in the UI.\r\nDialogue: 0,0:32:20.12,0:32:21.76,yin,,0,0,0,,这个也不会出现在UI中\\N{\\fs12}Here's another one that never appears the UI.\r\nDialogue: 0,0:32:21.76,0:32:25.25,yin,,0,0,0,,这就是我们创建独特文档URL的方式\\N{\\fs12}This is how we're making a unique document URL.\r\nDialogue: 0,0:32:25.25,0:32:28.85,yin,,0,0,0,,这里我们不需要使用NumberFormatter这些\\N{\\fs12}So here we don't need to use a number formatter and all that business.\r\nDialogue: 0,0:32:28.85,0:32:31.79,yin,,0,0,0,,然后这里滤镜中还有一些\\N{\\fs12}And then here's some more of the filter stuff.\r\nDialogue: 0,0:32:31.79,0:32:35.84,yin,,0,0,0,,注意到滤镜中 这个需要本地化 这个则不需要\\N{\\fs12}Notice in the filter stuff this does not need to be localized, but this does.\r\nDialogue: 0,0:32:35.84,0:32:39.85,yin,,0,0,0,,这个会出现在动作表单 这个只用于幕后的代码\\N{\\fs12}This appears in the action sheet; this is just used in the code behind the scenes.\r\nDialogue: 0,0:32:39.85,0:32:43.78,yin,,0,0,0,,因此我们只需要本地化chrome blur noir和fade\\N{\\fs12}So we only have to do these chrome, blur, noir, and fade.\r\nDialogue: 0,0:32:44.91,0:32:46.90,yin,,0,0,0,,以上就是需要本地化的东西\\N{\\fs12}So that's the stuff that needs to be localized.\r\nDialogue: 0,0:32:46.90,0:32:47.97,yin,,0,0,0,,如何本地化呢\\N{\\fs12}So how are we going to localize that?\r\nDialogue: 0,0:32:47.97,0:32:49.30,yin,,0,0,0,,让我们选一个\\N{\\fs12}Let's pick one of these.\r\nDialogue: 0,0:32:49.30,0:32:52.78,yin,,0,0,0,,选这个如何\\N{\\fs12}How about let's pick this one right here:\r\nDialogue: 0,0:32:52.78,0:32:54.40,yin,,0,0,0,,Sorry, this device cannot add a photo.\\N{\\fs12}\"Sorry, this device cannot add a photo.\"\r\nDialogue: 0,0:32:54.40,0:32:56.59,yin,,0,0,0,,因为我们知道这个立马就会出现\\N{\\fs12}Because we know that's going to come up right away.\r\nDialogue: 0,0:32:56.59,0:32:59.10,yin,,0,0,0,,如何本地化这个呢\\N{\\fs12}So how would we localize this?\r\nDialogue: 0,0:32:59.10,0:33:02.15,yin,,0,0,0,,这部分涉及到编程艺术\\N{\\fs12}Some of this is art of programming;\r\nDialogue: 0,0:33:02.15,0:33:06.41,yin,,0,0,0,,部分涉及到怎样才能有效工作\\N{\\fs12}some of it is kind of what's a way that's really going to work effectively?\r\nDialogue: 0,0:33:06.41,0:33:10.33,yin,,0,0,0,,我认为这里最佳的做法之一是\\N{\\fs12}But I think one of the best ways to do this is to get rid\r\nDialogue: 0,0:33:10.33,0:33:14.72,yin,,0,0,0,,将字符串字面量用#号定义取代\\N{\\fs12}of this literal string and replace it with something you pound sign define.\r\nDialogue: 0,0:33:14.72,0:33:21.95,yin,,0,0,0,,这个我打算称作ALERT_CANT_ADD_PHOTO\\N{\\fs12}So I'm going to call this one \"Alert can't add photo.\"\r\nDialogue: 0,0:33:23.80,0:33:27.66,yin,,0,0,0,,这里我还要加些注释 把这个粘贴回来\\N{\\fs12}And I'm actually going to put a little comment here and paste that thing back\r\nDialogue: 0,0:33:27.66,0:33:31.43,yin,,0,0,0,,这样我就记得我原来想用英语说什么了\\N{\\fs12}so I can remember what I originally intended to say in English.\r\nDialogue: 0,0:33:31.43,0:33:33.68,yin,,0,0,0,,然后我要添加一个#号定义\\N{\\fs12}And then I'm going to add a pound sign define\r\nDialogue: 0,0:33:33.68,0:33:36.02,yin,,0,0,0,,用于这个警告 ALERT_CANT_ADD_PHOTO\\N{\\fs12}for this alert, can't add photo\r\nDialogue: 0,0:33:36.02,0:33:38.51,yin,,0,0,0,,这是一个NSLocalizedString\\N{\\fs12}that's an NS localized string --\r\nDialogue: 0,0:33:38.51,0:33:40.06,yin,,0,0,0,,那个宏 NSLocalizedString\\N{\\fs12}that macro NS localized string.\r\nDialogue: 0,0:33:40.06,0:33:41.46,yin,,0,0,0,,实际上是NSLocalizedStringFromTable\\N{\\fs12}In fact, NS localized string from table.\r\nDialogue: 0,0:33:41.46,0:33:45.52,yin,,0,0,0,,我打算把这些放到我的警告部分\\N{\\fs12}So I'm going to put those up here in my alert section here.\r\nDialogue: 0,0:33:45.52,0:33:51.20,yin,,0,0,0,,这里我#define ALERT_CANT_ADD_PHOTO\\N{\\fs12}So I'm just going to pound sign define can't add photo\r\nDialogue: 0,0:33:51.20,0:33:55.22,yin,,0,0,0,,为NSLocalizedStringFromTable\\N{\\fs12}to be NS localized string from table.\r\nDialogue: 0,0:33:55.22,0:33:56.86,yin,,0,0,0,,我需要给它一个字符串\\N{\\fs12}So I have to give it the string.\r\nDialogue: 0,0:33:56.86,0:34:02.48,yin,,0,0,0,,这里你可以放英语版的文字\\N{\\fs12}And here, one thing you could say here is you could put the English version here.\r\nDialogue: 0,0:34:02.48,0:34:05.24,yin,,0,0,0,,放英语版的好处在于\\N{\\fs12}And a nice thing about putting the English version here is\r\nDialogue: 0,0:34:05.24,0:34:09.06,yin,,0,0,0,,在不本地化时 你至少会得到英语\\N{\\fs12}that if you don't localize it, you'll get English at least.\r\nDialogue: 0,0:34:09.06,0:34:12.38,yin,,0,0,0,,但我不喜欢这个策略\\N{\\fs12}But I actually don't believe in that strategy\r\nDialogue: 0,0:34:12.38,0:34:16.48,yin,,0,0,0,,因为如果我是法国人 我得到英语 那就会很糟\\N{\\fs12}because if I'm French and I get English, it looks bad.\r\nDialogue: 0,0:34:16.48,0:34:18.16,yin,,0,0,0,,这让我的app看起来很糟\\N{\\fs12}It makes my app look bad.\r\nDialogue: 0,0:34:18.16,0:34:21.25,yin,,0,0,0,,更好的做法是使用某种内部定义\\N{\\fs12}It's almost better to get some kind of internal thing\r\nDialogue: 0,0:34:21.25,0:34:25.93,yin,,0,0,0,,例如说 这个app坏掉了 它会立刻在测试中被找到\\N{\\fs12}that's like, \"Oh, this app is broken.\" It will be found in testing right away.\r\nDialogue: 0,0:34:25.93,0:34:29.64,yin,,0,0,0,,如果你在app中丢一些英语出来\\N{\\fs12}There's many places that you would ship your app\r\nDialogue: 0,0:34:29.64,0:34:32.97,yin,,0,0,0,,很多时候 用户都会感到被冒犯\\N{\\fs12}to get offended if you throw English in there.\r\nDialogue: 0,0:34:32.97,0:34:35.06,yin,,0,0,0,,他们会说 呃 英语 好吧\\N{\\fs12}They're kind of like, \"Oh yeah, English. Great.\"\r\nDialogue: 0,0:34:35.06,0:34:35.90,yin,,0,0,0,,懂我说的吗\\N{\\fs12}You know what I mean?\r\nDialogue: 0,0:34:35.90,0:34:37.42,yin,,0,0,0,,因此 最好别这样做\\N{\\fs12}So it's almost better not to do it.\r\nDialogue: 0,0:34:37.42,0:34:39.92,yin,,0,0,0,,这里还有一个问题 也就是\\N{\\fs12}Also, there's another problem here, which is that what\r\nDialogue: 0,0:34:39.92,0:34:43.79,yin,,0,0,0,,如果这里只是简单的单词例如alert或yes会怎样\\N{\\fs12}if this word is a simple word like \"alert\" or \"yes\"?\r\nDialogue: 0,0:34:43.79,0:34:48.48,yin,,0,0,0,,这个键只能到表格中去一次\\N{\\fs12}Well, there can only be this key into this table once.\r\nDialogue: 0,0:34:48.48,0:34:52.20,yin,,0,0,0,,如果yes可能在别的语言中对应两个不同的词\\N{\\fs12}And so if that yes might want to be two different words in a different language,\r\nDialogue: 0,0:34:52.20,0:34:54.22,yin,,0,0,0,,那就没办法区分它们了\\N{\\fs12}there's no way to distinguish them.\r\nDialogue: 0,0:34:54.22,0:34:56.51,yin,,0,0,0,,yes是键\\N{\\fs12}You would just yes would be the key,\r\nDialogue: 0,0:34:56.51,0:34:59.91,yin,,0,0,0,,你只能将yes转为oui或别的什么\\N{\\fs12}and you can only convert yes to \"oui\" or whatever,\r\nDialogue: 0,0:34:59.91,0:35:01.72,yin,,0,0,0,,但你做不了别的\\N{\\fs12}but you can't do anything else.\r\nDialogue: 0,0:35:01.72,0:35:07.44,yin,,0,0,0,,因此这里 我打算将这个内部定义放到这里\\N{\\fs12}So what I do is I actually put this -- this internal define -- into here.\r\nDialogue: 0,0:35:07.44,0:35:08.57,yin,,0,0,0,,这是键\\N{\\fs12}So that's the key.\r\nDialogue: 0,0:35:08.57,0:35:12.92,yin,,0,0,0,,这意味着 我必须提供英语.strings文件\\N{\\fs12}What that means is I have to provide an English dot strings\r\nDialogue: 0,0:35:12.92,0:35:17.33,yin,,0,0,0,,否则这就会出现在UI 因为这是默认值\\N{\\fs12}because otherwise this is going to appear in the UI because that's the default.\r\nDialogue: 0,0:35:17.33,0:35:21.04,yin,,0,0,0,,我必须这样做\\N{\\fs12}So I'm going to have to do that.\r\nDialogue: 0,0:35:21.04,0:35:25.10,yin,,0,0,0,,我还要为本地化者提供注释\\N{\\fs12}I also am going to give the comment for the localizer here,\r\nDialogue: 0,0:35:25.10,0:35:27.03,yin,,0,0,0,,我这里说 这是\\N{\\fs12}I'm just going to say, \"This is\r\nDialogue: 0,0:35:27.03,0:35:36.81,yin,,0,0,0,,用户想添加照片 但存在不可恢复问题时\\N{\\fs12}message given to user if the user tries to add a photo\r\nDialogue: 0,0:35:36.81,0:35:41.75,yin,,0,0,0,,给用户的警告消息\\N{\\fs12}but there is an unrecoverable problem.\"\r\nDialogue: 0,0:35:41.75,0:35:43.61,yin,,0,0,0,,这就是它的作用\\N{\\fs12}Okay. Because that's when this is shown.\r\nDialogue: 0,0:35:43.61,0:35:47.91,yin,,0,0,0,,当canAddPhoto返回NO时 就会无法添加照片\\N{\\fs12}This can't add photo happens right here with when can add photo returns no.\r\nDialogue: 0,0:35:47.91,0:35:51.84,yin,,0,0,0,,例如 无法获得地理位置信息\\N{\\fs12}So this is something like, \"I can't get where your location is\r\nDialogue: 0,0:35:51.84,0:35:53.90,yin,,0,0,0,,但这是因为受限\\N{\\fs12}on Earth, but it's because you're restricted.\r\nDialogue: 0,0:35:53.90,0:35:55.46,yin,,0,0,0,,这时你什么都做不了\\N{\\fs12}So there's nothing you can do about it\"\r\nDialogue: 0,0:35:55.46,0:35:59.05,yin,,0,0,0,,或是 设备上没有摄像头 这时你什么都做不了\\N{\\fs12}or \"There's no camera on this device, so there's nothing you can do about it.\"\r\nDialogue: 0,0:35:59.65,0:36:01.93,yin,,0,0,0,,哦 按钮错了\\N{\\fs12}Oops, wrong button there.\r\nDialogue: 0,0:36:01.93,0:36:04.39,yin,,0,0,0,,这是不可恢复的错误\\N{\\fs12}So it's an unrecoverable error.\r\nDialogue: 0,0:36:04.39,0:36:06.99,yin,,0,0,0,,我这里想解释给本地化者\\N{\\fs12}So I'm trying to explain to the localizer here\r\nDialogue: 0,0:36:06.99,0:36:09.26,yin,,0,0,0,,这段消息是关于什么的\\N{\\fs12}what this message is about.\r\nDialogue: 0,0:36:09.26,0:36:11.26,yin,,0,0,0,,我还要把它放到一张表中\\N{\\fs12}And I'm also going to put it in a table.\r\nDialogue: 0,0:36:11.26,0:36:14.28,yin,,0,0,0,,我使用LocalizedStringFromTable\\N{\\fs12}I'm using localized string from table, and I'm going\r\nDialogue: 0,0:36:14.28,0:36:18.24,yin,,0,0,0,,表格我将称之为AddPhotoViewController表格\\N{\\fs12}to call the table the \"add photo view controller table.\"\r\nDialogue: 0,0:36:18.24,0:36:21.51,yin,,0,0,0,,这意味着当我运行genstrings时\\N{\\fs12}So that means that when I run that genstrings thing,\r\nDialogue: 0,0:36:21.51,0:36:23.27,yin,,0,0,0,,它会生成一个.strings文件称作\\N{\\fs12}it's going to generate a strings file called\r\nDialogue: 0,0:36:23.27,0:36:25.43,yin,,0,0,0,,AddPhotoViewController.strings\\N{\\fs12}add photo view controller dot strings.\r\nDialogue: 0,0:36:25.43,0:36:27.03,yin,,0,0,0,,这就是放这个的地方\\N{\\fs12}And that's where it's going to put this.\r\nDialogue: 0,0:36:27.03,0:36:31.56,yin,,0,0,0,,我将这个视图控制器中的所有这些字符串收集到\\N{\\fs12}So I'm kind of collecting all the strings for this particular view controller\r\nDialogue: 0,0:36:31.56,0:36:32.61,yin,,0,0,0,,一个.strings文件中\\N{\\fs12}into one strings file.\r\nDialogue: 0,0:36:32.61,0:36:35.30,yin,,0,0,0,,我可以更细致地分一下\\N{\\fs12}I could separate it even more fine grained,\r\nDialogue: 0,0:36:35.30,0:36:39.12,yin,,0,0,0,,我也可以将app中的所有字符串放到一个大的里面\\N{\\fs12}or I could put all the strings in my whole app into one big one. That's possible too.\r\nDialogue: 0,0:36:39.12,0:36:40.06,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,0:36:46.28,0:36:47.51,yin,,0,0,0,,问题是\\N{\\fs12}Yeah. So the question is:\r\nDialogue: 0,0:36:47.52,0:36:51.98,yin,,0,0,0,,让本地化者看到英语字符串是否会有好处\\N{\\fs12}Would it be beneficial to let the localizer see the English string?\r\nDialogue: 0,0:36:51.98,0:36:52.70,yin,,0,0,0,,当然有\\N{\\fs12}Absolutely.\r\nDialogue: 0,0:36:52.70,0:36:55.39,yin,,0,0,0,,当你把法语.strings文件\\N{\\fs12}And when you send this French dot string --\r\nDialogue: 0,0:36:55.39,0:36:57.72,yin,,0,0,0,,发送给法语本地化者时\\N{\\fs12}French version of the strings -- off to the French localizer,\r\nDialogue: 0,0:36:57.72,0:37:00.41,yin,,0,0,0,,英语那个你也要发送 这样他们就可以知道\\N{\\fs12}you'll want to send the English one, too, so they can see, \"Oh,\r\nDialogue: 0,0:37:00.41,0:37:01.57,yin,,0,0,0,,这在英语中是什么\\N{\\fs12}I see what this is in English.\"\r\nDialogue: 0,0:37:01.57,0:37:04.04,yin,,0,0,0,,实际上 在我们进行本地化时\\N{\\fs12}And in fact, when we do our localization we're going\r\nDialogue: 0,0:37:04.04,0:37:05.92,yin,,0,0,0,,我们会从英语开始 然后再到法语\\N{\\fs12}to start with the English one and we'll go to French.\r\nDialogue: 0,0:37:05.92,0:37:08.31,yin,,0,0,0,,这是这个\\N{\\fs12}So there's that one.\r\nDialogue: 0,0:37:08.31,0:37:11.97,yin,,0,0,0,,我本地化了这一个字符串\\N{\\fs12}Now, so I've localized that one string right there.\r\nDialogue: 0,0:37:11.97,0:37:13.60,yin,,0,0,0,,但这里还有很多字符串\\N{\\fs12}But I got a lot of other strings in here.\r\nDialogue: 0,0:37:13.60,0:37:17.32,yin,,0,0,0,,为了让这个更快一些 我准备了一些代码\\N{\\fs12}So to make this go a little faster I have a snippet here\r\nDialogue: 0,0:37:17.32,0:37:21.94,yin,,0,0,0,,作用是完成剩余的#号定义 我称其为strings… 对\\N{\\fs12}that does the rest of the pound sign defines, which I've called strings yes.\r\nDialogue: 0,0:37:21.94,0:37:22.79,yin,,0,0,0,,就是这些了\\N{\\fs12}So here it is.\r\nDialogue: 0,0:37:22.79,0:37:27.10,yin,,0,0,0,,这些就是其它那些的#号定义\\N{\\fs12}So these are all just pound sign defines for all the other things --\r\nDialogue: 0,0:37:27.10,0:37:29.29,yin,,0,0,0,,这个已经有了 删掉\\N{\\fs12}actually, I guess I already did that one so we'll do that.\r\nDialogue: 0,0:37:29.29,0:37:33.49,yin,,0,0,0,,可以看到 这些都有相同的格式\\N{\\fs12}So you can see that they all are the same format, right?\r\nDialogue: 0,0:37:33.49,0:37:36.97,yin,,0,0,0,,我用了相同的东西 使用AddPhotoViewController\\N{\\fs12}I'm using the same thing there, using add photo view controller.\r\nDialogue: 0,0:37:36.97,0:37:39.84,yin,,0,0,0,,实际上我的参数顺序有些不同 那是错的\\N{\\fs12}Actually, I had the arguments in a different order there so that was wrong.\r\nDialogue: 0,0:37:39.84,0:37:42.81,yin,,0,0,0,,首先是表格 最后是注释\\N{\\fs12}So table comes first; comment is last.\r\nDialogue: 0,0:37:42.81,0:37:44.51,yin,,0,0,0,,把所有这些放到这里\\N{\\fs12}So I put all these in here.\r\nDialogue: 0,0:37:44.51,0:37:47.95,yin,,0,0,0,,然后我需要在代码中 使用这些东西\\N{\\fs12}And then I just need to go through with my code and use these things everywhere.\r\nDialogue: 0,0:37:47.95,0:37:51.23,yin,,0,0,0,,例如这个 Add Photo是\\N{\\fs12}So like this one, add photo, is\r\nDialogue: 0,0:37:51.23,0:37:56.96,yin,,0,0,0,,ALERT_TITLE_ADD_PHOTO\\N{\\fs12}alert; title; title; add photo.\r\nDialogue: 0,0:37:56.96,0:38:02.80,yin,,0,0,0,,而下面这个是ALERT_DISMISS_BUTTON\\N{\\fs12}And this one down here is alert; dismiss button;\r\nDialogue: 0,0:38:02.80,0:38:04.71,yin,,0,0,0,,这里也一样\\N{\\fs12}same thing here,\r\nDialogue: 0,0:38:04.71,0:38:09.22,yin,,0,0,0,,这里 这里 还有这里\\N{\\fs12}and here, and here, and here.\r\nDialogue: 0,0:38:09.22,0:38:12.45,yin,,0,0,0,,我只需要对所有字符串都这样做\\N{\\fs12}So I just need to do that for all my strings.\r\nDialogue: 0,0:38:12.45,0:38:17.61,yin,,0,0,0,,出于时间考虑 这个方法我就一次性拼出来\\N{\\fs12}Again, for speed here I'm just going to do it for this method all in one spell.\r\nDialogue: 0,0:38:17.61,0:38:20.16,yin,,0,0,0,,所有字符串都弄好了\\N{\\fs12}So you can see all the strings in there.\r\nDialogue: 0,0:38:20.16,0:38:23.47,yin,,0,0,0,,这些都变了 像这样\\N{\\fs12}Now they're all changed, okay, to be like this.\r\nDialogue: 0,0:38:23.47,0:38:25.85,yin,,0,0,0,,下面滤镜也是一样\\N{\\fs12}Same thing down here with filtering.\r\nDialogue: 0,0:38:25.85,0:38:28.53,yin,,0,0,0,,滤镜中有很多\\N{\\fs12}So we've got a lot of things here in filter --\r\nDialogue: 0,0:38:28.53,0:38:32.43,yin,,0,0,0,,动作表单的标题 取消按钮 所有这些滤镜\\N{\\fs12}title of action sheet, cancel button -- all these filters.\r\nDialogue: 0,0:38:32.43,0:38:35.81,yin,,0,0,0,,把这些也替换掉\\N{\\fs12}So I'm going to replace that as well.\r\nDialogue: 0,0:38:35.81,0:38:37.86,yin,,0,0,0,,filter…localized\\N{\\fs12}Filter localized.\r\nDialogue: 0,0:38:37.86,0:38:39.19,yin,,0,0,0,,好了\\N{\\fs12}There we go.\r\nDialogue: 0,0:38:39.19,0:38:41.08,yin,,0,0,0,,这里也一样\\N{\\fs12}So same thing there.\r\nDialogue: 0,0:38:41.08,0:38:43.37,yin,,0,0,0,,我做了一样的事\\N{\\fs12}I'm doing the same strategy.\r\nDialogue: 0,0:38:44.86,0:38:47.26,yin,,0,0,0,,大家都理解我用NSLocalizedString做了什么吗\\N{\\fs12}So everyone understand what we're doing with this NS localized string?\r\nDialogue: 0,0:38:47.26,0:38:48.93,yin,,0,0,0,,这方面有问题吗\\N{\\fs12}Any questions about that?\r\nDialogue: 0,0:38:48.93,0:38:52.26,yin,,0,0,0,,现在 我们本地化了我们的app\\N{\\fs12}So now we've localized our app here, but now we need\r\nDialogue: 0,0:38:52.26,0:38:55.51,yin,,0,0,0,,我们还需要创建.strings文件 然后本地化它\\N{\\fs12}to create this strings file and then localize it.\r\nDialogue: 0,0:38:55.51,0:38:57.16,yin,,0,0,0,,如何创建.strings文件呢\\N{\\fs12}So how do we create the string file?\r\nDialogue: 0,0:38:57.16,0:38:59.42,yin,,0,0,0,,当然是使用genstrings\\N{\\fs12}That we do with this genstrings thing.\r\nDialogue: 0,0:38:59.42,0:39:01.53,yin,,0,0,0,,到Terminal\\N{\\fs12}So let's go get terminal.\r\nDialogue: 0,0:39:01.53,0:39:03.74,yin,,0,0,0,,这里运行Terminal\\N{\\fs12}So I'm going to run terminal here.\r\nDialogue: 0,0:39:03.74,0:39:07.19,yin,,0,0,0,,我想这门课上就这一次我会让你们这样做\\N{\\fs12}This is one of the only time I think in this class that I've asked you to do that.\r\nDialogue: 0,0:39:07.19,0:39:10.61,yin,,0,0,0,,这里我处在主目录中\\N{\\fs12}But here I am in my home directory here.\r\nDialogue: 0,0:39:10.61,0:39:11.38,yin,,0,0,0,,键入ls\\N{\\fs12}I can do LS.\r\nDialogue: 0,0:39:11.38,0:39:12.08,yin,,0,0,0,,我在这里\\N{\\fs12}Here I am.\r\nDialogue: 0,0:39:12.08,0:39:14.73,yin,,0,0,0,,cd到Developer目录\\N{\\fs12}So I'm going to CD to developer.\r\nDialogue: 0,0:39:14.73,0:39:15.68,yin,,0,0,0,,这是Developer\\N{\\fs12}Okay, here's my developer.\r\nDialogue: 0,0:39:15.68,0:39:17.46,yin,,0,0,0,,再cd到Photomania\\N{\\fs12}I'm going to CD to PhotoMania.\r\nDialogue: 0,0:39:17.47,0:39:19.73,yin,,0,0,0,,这样我就到了Photomania的顶层\\N{\\fs12}Now I'm in the top level of PhotoMania.\r\nDialogue: 0,0:39:19.75,0:39:22.39,yin,,0,0,0,,cd到这个里面去\\N{\\fs12}I'm going to CD inside that.\r\nDialogue: 0,0:39:22.39,0:39:24.50,yin,,0,0,0,,这是我的所有代码\\N{\\fs12}Here's all my code.\r\nDialogue: 0,0:39:24.50,0:39:26.55,yin,,0,0,0,,看到了我的.m文件吗\\N{\\fs12}See all my dot M files?\r\nDialogue: 0,0:39:26.55,0:39:30.01,yin,,0,0,0,,这里还可以看到故事板的lproj文件\\N{\\fs12}And here you can even see my lprojs for my storyboard there.\r\nDialogue: 0,0:39:30.01,0:39:32.62,yin,,0,0,0,,要生成.strings文件\\N{\\fs12}So the way I'm going to generate the strings file here is I'm\r\nDialogue: 0,0:39:32.62,0:39:35.14,yin,,0,0,0,,我只需要说genstrings *.m\\N{\\fs12}going to say genstrings star dot M.\r\nDialogue: 0,0:39:35.15,0:39:37.61,yin,,0,0,0,,这会遍历我的所有.m文件\\N{\\fs12}And that's going to look at all my dot M files, look\r\nDialogue: 0,0:39:37.61,0:39:41.12,yin,,0,0,0,,看所有NSLocalizedString的宏\\N{\\fs12}at all those NS localizer string macros,\r\nDialogue: 0,0:39:41.12,0:39:43.77,yin,,0,0,0,,并为所有这些生成.strings文件\\N{\\fs12}and it's going to generate strings files for all of them.\r\nDialogue: 0,0:39:43.77,0:39:45.61,yin,,0,0,0,,我们这样做了 来看看\\N{\\fs12}So we did it. Let's take a look.\r\nDialogue: 0,0:39:45.61,0:39:46.90,yin,,0,0,0,,找.strings文件\\N{\\fs12}Start out strings,\r\nDialogue: 0,0:39:46.90,0:39:49.22,yin,,0,0,0,,果然有了AddPhotoViewController\\N{\\fs12}and sure enough there's add photo view controller\r\nDialogue: 0,0:39:49.22,0:39:51.78,yin,,0,0,0,,这就是所有表格所用的\\N{\\fs12}because we used that for all the tables here.\r\nDialogue: 0,0:39:51.78,0:39:55.96,yin,,0,0,0,,如果我们使用别的名称 或是不用FromTable\\N{\\fs12}If we didn't -- say, if we used a different name here or we didn't do from table,\r\nDialogue: 0,0:39:55.96,0:39:58.29,yin,,0,0,0,,那它就会生成别的.strings文件\\N{\\fs12}then it would have generated other strings files.\r\nDialogue: 0,0:39:58.29,0:40:01.27,yin,,0,0,0,,但这里我们就生成了这个\\N{\\fs12}But this is the only one we did.\r\nDialogue: 0,0:40:01.27,0:40:04.41,yin,,0,0,0,,好 让我们拖动那个\\N{\\fs12}All right. So now let's just drag that thing.\r\nDialogue: 0,0:40:04.41,0:40:05.73,yin,,0,0,0,,先找到它\\N{\\fs12}Let's go find it.\r\nDialogue: 0,0:40:05.73,0:40:06.89,yin,,0,0,0,,在这里\\N{\\fs12}Here it is.\r\nDialogue: 0,0:40:06.89,0:40:08.14,yin,,0,0,0,,这是.strings文件\\N{\\fs12}This is the strings file.\r\nDialogue: 0,0:40:08.14,0:40:10.13,yin,,0,0,0,,AddPhotoViewController.strings\\N{\\fs12}Add photo view controller strings.\r\nDialogue: 0,0:40:10.13,0:40:13.54,yin,,0,0,0,,我要把它拖到项目中 这里\\N{\\fs12}I'm just going to drag this into my project here.\r\nDialogue: 0,0:40:13.54,0:40:14.48,yin,,0,0,0,,放到这里\\N{\\fs12}Put it right here.\r\nDialogue: 0,0:40:14.48,0:40:17.16,yin,,0,0,0,,.strings文件一般都放在view下\\N{\\fs12}Usually we put our strings file all under view.\r\nDialogue: 0,0:40:17.16,0:40:19.82,yin,,0,0,0,,我们会像这样安放故事板\\N{\\fs12}If we kind of arrange our storyboards into a place,\r\nDialogue: 0,0:40:19.82,0:40:22.58,yin,,0,0,0,,.strings文件也放到这里\\N{\\fs12}we'll put the strings file there as well because it is part\r\nDialogue: 0,0:40:22.58,0:40:25.56,yin,,0,0,0,,因为这是关于视图的本地化\\N{\\fs12}of our view, really, the localization of our view.\r\nDialogue: 0,0:40:25.56,0:40:28.29,yin,,0,0,0,,现在我们有了AddPhotoViewController.strings\\N{\\fs12}And so now we have this add photo view controller strings.\r\nDialogue: 0,0:40:28.29,0:40:32.35,yin,,0,0,0,,显然 它有所有这些这个等于那个\\N{\\fs12}And sure enough, see, it's got all these things -- this equals that.\r\nDialogue: 0,0:40:32.35,0:40:34.50,yin,,0,0,0,,好理解吧\\N{\\fs12}Make sense?\r\nDialogue: 0,0:40:34.50,0:40:37.68,yin,,0,0,0,,下面我们需要让这个.strings文件可本地化\\N{\\fs12}Now we need to make this strings file localizable.\r\nDialogue: 0,0:40:37.68,0:40:40.73,yin,,0,0,0,,我们到文件检查器这里\\N{\\fs12}We go over here to the file inspector.\r\nDialogue: 0,0:40:40.73,0:40:43.21,yin,,0,0,0,,这个是文件检查器\\N{\\fs12}This one right here is file inspector.\r\nDialogue: 0,0:40:43.21,0:40:45.46,yin,,0,0,0,,我选了.strings文件\\N{\\fs12}And I got the strings file selected.\r\nDialogue: 0,0:40:45.46,0:40:47.52,yin,,0,0,0,,我要点本地化\\N{\\fs12}I'm going to hit localize.\r\nDialogue: 0,0:40:47.52,0:40:51.85,yin,,0,0,0,,它问 这是什么语言\\N{\\fs12}It's going to say \"What language is this?\"\r\nDialogue: 0,0:40:51.85,0:40:53.39,yin,,0,0,0,,这是我们的base\\N{\\fs12}And that's going to be our base,\r\nDialogue: 0,0:40:53.39,0:40:56.26,yin,,0,0,0,,然后再根据这个来创建英语和法语文件\\N{\\fs12}and then we're going to have English and French created off of that.\r\nDialogue: 0,0:40:56.26,0:40:57.44,yin,,0,0,0,,这里就选base\\N{\\fs12}So I'm going to leave that be base.\r\nDialogue: 0,0:40:57.44,0:40:58.93,yin,,0,0,0,,点本地化\\N{\\fs12}So I'll hit localize.\r\nDialogue: 0,0:40:58.93,0:41:02.01,yin,,0,0,0,,这时我选.strings文件\\N{\\fs12}Now when I select the strings file,\r\nDialogue: 0,0:41:02.01,0:41:04.21,yin,,0,0,0,,它显示的不是本地化按钮\\N{\\fs12}instead of having a localize button, it shows me a list\r\nDialogue: 0,0:41:04.21,0:41:07.26,yin,,0,0,0,,而是我在项目设置中设置的各种本地化\\N{\\fs12}of all the localizations that I had set up in my project settings.\r\nDialogue: 0,0:41:07.26,0:41:10.85,yin,,0,0,0,,我要添加一个英语本地化和一个法语本地化\\N{\\fs12}So I'm going to add an English localization and a French localization.\r\nDialogue: 0,0:41:10.85,0:41:13.59,yin,,0,0,0,,这样做时 这里我会得到一个小三角\\N{\\fs12}And when I do that, I get a little triangle over here.\r\nDialogue: 0,0:41:13.59,0:41:15.51,yin,,0,0,0,,可以看到 这是我的base\\N{\\fs12}And you can see here's my base.\r\nDialogue: 0,0:41:15.51,0:41:20.24,yin,,0,0,0,,然后我有了英语和法语 最开始这只是base的拷贝\\N{\\fs12}And now I have English and French, which it has copied the base to start.\r\nDialogue: 0,0:41:20.24,0:41:24.04,yin,,0,0,0,,下面我将把这本地化为英语 让我们来这样做\\N{\\fs12}Now I would localize this to English. So let's localize this to English.\r\nDialogue: 0,0:41:24.04,0:41:27.43,yin,,0,0,0,,我有一段代码 大概在这里\\N{\\fs12}I have a little snippet for that, too, somewhere here.\r\nDialogue: 0,0:41:27.43,0:41:30.31,yin,,0,0,0,,Photomania 国际化\\N{\\fs12}PhotoMania, internationalization.\r\nDialogue: 0,0:41:30.31,0:41:32.80,yin,,0,0,0,,这个是英语\\N{\\fs12}This one's English. Here it is.\r\nDialogue: 0,0:41:32.80,0:41:36.00,yin,,0,0,0,,全选 复制 粘贴\\N{\\fs12}Select all, copy, paste.\r\nDialogue: 0,0:41:36.00,0:41:41.33,yin,,0,0,0,,这就得到了所有这些东西的英语版\\N{\\fs12}So I've just made English -- the English versions of all of these things.\r\nDialogue: 0,0:41:41.33,0:41:43.46,yin,,0,0,0,,大家都理解我刚做了什么吗\\N{\\fs12}Everyone understand what I did there?\r\nDialogue: 0,0:41:44.59,0:41:46.32,yin,,0,0,0,,法语也是一样的\\N{\\fs12}And then French, same thing.\r\nDialogue: 0,0:41:46.32,0:41:49.47,yin,,0,0,0,,我可以将点插入到所有这些中间\\N{\\fs12}I could take all these and put dots in here,\r\nDialogue: 0,0:41:49.47,0:41:52.02,yin,,0,0,0,,不过这些我都离线完成了 以便节省时间\\N{\\fs12}but I did that offline to save us some time.\r\nDialogue: 0,0:41:52.02,0:41:53.56,yin,,0,0,0,,这是这个\\N{\\fs12}That's this.\r\nDialogue: 0,0:41:53.56,0:41:56.99,yin,,0,0,0,,复制 粘贴\\N{\\fs12}Copy, paste.\r\nDialogue: 0,0:41:56.99,0:42:01.83,yin,,0,0,0,,我把这个本地化为了法语 用点表示的\\N{\\fs12}So I've localized this to French dot French.\r\nDialogue: 0,0:42:01.83,0:42:07.12,yin,,0,0,0,,现在我们有了这个的本地化 下面来运行\\N{\\fs12}So now we have localization for that. And so now when we run --\r\nDialogue: 0,0:42:11.91,0:42:12.75,yin,,0,0,0,,好\\N{\\fs12}okay.\r\nDialogue: 0,0:42:12.75,0:42:17.73,yin,,0,0,0,,运行时我们发现 还是有些东西需要本地化\\N{\\fs12}So when we run, now we still have some stuff left to localize here.\r\nDialogue: 0,0:42:17.73,0:42:20.47,yin,,0,0,0,,这些东西还是英语\\N{\\fs12}Right? You can see that these things are still in English.\r\nDialogue: 0,0:42:20.47,0:42:24.63,yin,,0,0,0,,但到这里 看看这个\\N{\\fs12}But if we go over to here, look at this.\r\nDialogue: 0,0:42:24.63,0:42:27.12,yin,,0,0,0,,这个上次我们已经看过了\\N{\\fs12}[Inaudible] we already saw that from last time.\r\nDialogue: 0,0:42:27.12,0:42:31.78,yin,,0,0,0,,我可能忘记提了 地图部分也都本地化了\\N{\\fs12}I forgot to mention that maybe. But the maps part of it is all localized.\r\nDialogue: 0,0:42:31.78,0:42:33.91,yin,,0,0,0,,到这里 所有这些也有加了点\\N{\\fs12}And when we go over here, we have all these dots.\r\nDialogue: 0,0:42:33.91,0:42:36.78,yin,,0,0,0,,这些字符串也都本地化了\\N{\\fs12}And now we have these strings also localized.\r\nDialogue: 0,0:42:36.78,0:42:38.67,yin,,0,0,0,,这里的Add Photo\\N{\\fs12}The add photo here.\r\nDialogue: 0,0:42:40.41,0:42:42.02,yin,,0,0,0,,我们可以都检查一下\\N{\\fs12}And if we went through and checked them all,\r\nDialogue: 0,0:42:42.02,0:42:43.57,yin,,0,0,0,,其它那些也都有点\\N{\\fs12}all the other ones would all have the dots, too.\r\nDialogue: 0,0:42:43.57,0:42:46.91,yin,,0,0,0,,我们在本地化方面取得了不错的进展\\N{\\fs12}So we're making good progress here in terms of our localization.\r\nDialogue: 0,0:42:46.91,0:42:50.63,yin,,0,0,0,,不过还有一些东西没有本地化\\N{\\fs12}Couple of things, though, not localized here.\r\nDialogue: 0,0:42:50.63,0:42:53.57,yin,,0,0,0,,一是My Photos\\N{\\fs12}One, my photos, right?\r\nDialogue: 0,0:42:53.57,0:42:57.55,yin,,0,0,0,,法语中是什么 mes photos还是什么\\N{\\fs12}In French that would be I don't know, mes photos or something.\r\nDialogue: 0,0:42:57.55,0:42:59.17,yin,,0,0,0,,我不清楚\\N{\\fs12}I don't know.\r\nDialogue: 0,0:42:59.17,0:43:01.95,yin,,0,0,0,,这里应该是M.y P.h.…\\N{\\fs12}Actually, it would be M dot Y, P dot H dot -- okay.\r\nDialogue: 0,0:43:01.95,0:43:03.08,yin,,0,0,0,,这个也需要本地化\\N{\\fs12}So we would need to localize that.\r\nDialogue: 0,0:43:03.08,0:43:04.24,yin,,0,0,0,,这在哪里呢\\N{\\fs12}Where is that?\r\nDialogue: 0,0:43:04.24,0:43:08.26,yin,,0,0,0,,这在Photographers的这里…\\N{\\fs12}That is here in photographers.\r\nDialogue: 0,0:43:08.26,0:43:12.44,yin,,0,0,0,,不对 应该是在Core Data中\\N{\\fs12}Actually, no, that's in -- sorry -- that's in core data.\r\nDialogue: 0,0:43:12.44,0:43:13.86,yin,,0,0,0,,Photographer+Create\\N{\\fs12}Photographer create.\r\nDialogue: 0,0:43:13.86,0:43:15.85,yin,,0,0,0,,这只是一个字符串字面量\\N{\\fs12}Right? So that's just a literal string.\r\nDialogue: 0,0:43:15.85,0:43:19.64,yin,,0,0,0,,我们可以将这个用NSLocalizedString本地化\\N{\\fs12}So we would probably localize this with NS localized string.\r\nDialogue: 0,0:43:19.64,0:43:21.91,yin,,0,0,0,,我不打算做 因为你们已经知道怎么做了\\N{\\fs12}Not going to do it because I've already showed you how to do that.\r\nDialogue: 0,0:43:21.91,0:43:24.09,yin,,0,0,0,,还有什么没本地化\\N{\\fs12}What else do we have that's not localized?\r\nDialogue: 0,0:43:24.09,0:43:27.70,yin,,0,0,0,,这一行也没有\\N{\\fs12}This little line right here, zero photos.\r\nDialogue: 0,0:43:27.70,0:43:30.39,yin,,0,0,0,,或许在法语中这碰巧是正确的\\N{\\fs12}That's actually probably correct in real French.\r\nDialogue: 0,0:43:30.39,0:43:33.78,yin,,0,0,0,,法语中这个应该也是photos\\N{\\fs12}I think photo is French; in French it's photo as well.\r\nDialogue: 0,0:43:33.78,0:43:35.66,yin,,0,0,0,,但我们要确保这个可本地化\\N{\\fs12}But we want to make sure that was localizable.\r\nDialogue: 0,0:43:35.66,0:43:37.51,yin,,0,0,0,,这就是我们要用点的另外一个理由\\N{\\fs12}That's another reason we should do the dot thing\r\nDialogue: 0,0:43:37.51,0:43:40.03,yin,,0,0,0,,很显然 这里没有点\\N{\\fs12}because it would be obvious that there's no dot here;\r\nDialogue: 0,0:43:40.03,0:43:41.85,yin,,0,0,0,,如果你只是检查法语翻译 你可能会说\\N{\\fs12}whereas if you're just checking it with French, you'd be like,\r\nDialogue: 0,0:43:41.85,0:43:44.44,yin,,0,0,0,,哦 对 这个本地化了 其实则没有\\N{\\fs12}\"Oh yeah, that's localized,\" but in fact, it's not.\r\nDialogue: 0,0:43:44.44,0:43:45.69,yin,,0,0,0,,这在哪呢\\N{\\fs12}So where is that?\r\nDialogue: 0,0:43:45.69,0:43:50.10,yin,,0,0,0,,在下面这里 这个应该在Photographers里\\N{\\fs12}That's down here in -- that's the one that's in photographers.\r\nDialogue: 0,0:43:50.10,0:43:55.23,yin,,0,0,0,,它是一个用于表格视图的stringWithFormat\\N{\\fs12}You can see it's just a string with format thing here for table view.\r\nDialogue: 0,0:43:55.23,0:43:59.44,yin,,0,0,0,,我们希望在这里使用另一个NSLocalizedString\\N{\\fs12}So we would want to do another NS localized string here, right?\r\nDialogue: 0,0:43:59.44,0:44:02.95,yin,,0,0,0,,然后还有一个是用英语写的\\N{\\fs12}And then there's one other thing that's in English:\r\nDialogue: 0,0:44:02.95,0:44:05.28,yin,,0,0,0,,这个词Photographer\\N{\\fs12}This word \"photographer\" right here.\r\nDialogue: 0,0:44:05.28,0:44:08.76,yin,,0,0,0,,你可能会惊讶 这是哪来的\\N{\\fs12}Now, you might be surprised; where does this come from?\r\nDialogue: 0,0:44:08.76,0:44:13.27,yin,,0,0,0,,这其实是Core Data表格视图控制器提供的\\N{\\fs12}This is actually being provided by core data table view controller.\r\nDialogue: 0,0:44:13.27,0:44:17.43,yin,,0,0,0,,几周前我给你们的那个类\\N{\\fs12}That class that we gave you many weeks ago.\r\nDialogue: 0,0:44:17.43,0:44:20.51,yin,,0,0,0,,在这里 Core Data表格视图控制器\\N{\\fs12}And what happens here is core data table view controller,\r\nDialogue: 0,0:44:20.51,0:44:24.00,yin,,0,0,0,,在你设置了取回结果控制器后会检查\\N{\\fs12}when you set a fetch results controller, it checks to see\r\nDialogue: 0,0:44:24.00,0:44:25.81,yin,,0,0,0,,表格视图有没标题\\N{\\fs12}if your table view has a title.\r\nDialogue: 0,0:44:25.81,0:44:28.84,yin,,0,0,0,,如果没有标题 它就会将标题\\N{\\fs12}And if it doesn't have a title, then it sets the title\r\nDialogue: 0,0:44:28.84,0:44:33.77,yin,,0,0,0,,设为实体名 Photographer或Photo\\N{\\fs12}to be the entity name -- photographer or photo.\r\nDialogue: 0,0:44:33.77,0:44:37.04,yin,,0,0,0,,这个的本地化很有趣\\N{\\fs12}Now, this is an interesting one to localize\r\nDialogue: 0,0:44:37.04,0:44:40.23,yin,,0,0,0,,因为这里我不能使用NSLocalizedString\\N{\\fs12}because I can't use NS localized string here.\r\nDialogue: 0,0:44:40.23,0:44:41.55,yin,,0,0,0,,都理解为什么吗\\N{\\fs12}Everyone understand why?\r\nDialogue: 0,0:44:41.55,0:44:43.55,yin,,0,0,0,,因为NSLocalizedString的所有参数\\N{\\fs12}Because NS localized string, all the arguments have\r\nDialogue: 0,0:44:43.55,0:44:46.37,yin,,0,0,0,,都需要是字面量 @号引号某某\\N{\\fs12}to be literals -- at sign, quote, something.\r\nDialogue: 0,0:44:46.37,0:44:48.00,yin,,0,0,0,,那这个如何本地化呢\\N{\\fs12}So how am I going to localize this?\r\nDialogue: 0,0:44:48.00,0:44:51.22,yin,,0,0,0,,我们可以沿NSLocalizedString往下一层\\N{\\fs12}Well, we can go one level below the NS localized string to\r\nDialogue: 0,0:44:51.23,0:44:52.44,yin,,0,0,0,,到NSBundle\\N{\\fs12}the bundle thing.\r\nDialogue: 0,0:44:52.44,0:44:54.96,yin,,0,0,0,,我会将这个字符串从这里拿出\\N{\\fs12}So let's take this string. I'm going to take it out of there.\r\nDialogue: 0,0:44:54.96,0:44:57.96,yin,,0,0,0,,我这里说 NSBundle mainBundle\\N{\\fs12}I'm going to go NS bundle, main bundle,\r\nDialogue: 0,0:44:57.96,0:45:00.32,yin,,0,0,0,,localizeStringForKey\\N{\\fs12}localize string for key.\r\nDialogue: 0,0:45:00.32,0:45:03.04,yin,,0,0,0,,这个可以是变量\\N{\\fs12}This can be a variable.\r\nDialogue: 0,0:45:03.04,0:45:05.15,yin,,0,0,0,,这里设为实体名\\N{\\fs12}So I'm going to make it be that entity name.\r\nDialogue: 0,0:45:05.15,0:45:09.05,yin,,0,0,0,,value 这是找不到字符串时的默认值\\N{\\fs12}The value, this is the default value if it can't find that string.\r\nDialogue: 0,0:45:09.05,0:45:11.33,yin,,0,0,0,,这个我设为实体名\\N{\\fs12}So I'll make that be the entity name.\r\nDialogue: 0,0:45:11.33,0:45:14.01,yin,,0,0,0,,然后table 这是查找的字符串表格\\N{\\fs12}And then table, this is the strings table to look in.\r\nDialogue: 0,0:45:14.01,0:45:15.79,yin,,0,0,0,,这里我称其为Entities\\N{\\fs12}I'm going to call it entities.\r\nDialogue: 0,0:45:15.79,0:45:19.91,yin,,0,0,0,,这是我要创建的一个新strings表格\\N{\\fs12}So this is a new strings table that I'm going to have to invent.\r\nDialogue: 0,0:45:19.91,0:45:21.52,yin,,0,0,0,,如何创建这个strings表格呢\\N{\\fs12}So how do I invent this strings table?\r\nDialogue: 0,0:45:21.52,0:45:24.57,yin,,0,0,0,,我不能使用genstrings 因为genstrings只能\\N{\\fs12}I can't use that genstrings thing because all genstrings does is look\r\nDialogue: 0,0:45:24.57,0:45:27.15,yin,,0,0,0,,针对NSLocalizedString 那些宏\\N{\\fs12}at NS localized string, those macros.\r\nDialogue: 0,0:45:27.15,0:45:30.03,yin,,0,0,0,,如何为这个生成.strings文件\\N{\\fs12}How am I going to make a strings file for this?\r\nDialogue: 0,0:45:30.03,0:45:33.94,yin,,0,0,0,,我要使用新文件\\N{\\fs12}Well, I'm going to use new file.\r\nDialogue: 0,0:45:33.94,0:45:37.23,yin,,0,0,0,,新文件 然后到下面这里的资源\\N{\\fs12}So when you do new file, if you go down here to resource --\r\nDialogue: 0,0:45:37.23,0:45:40.51,yin,,0,0,0,,看到资源了吗 这里有strings文件\\N{\\fs12}you see resource right here -- you'll see that there is strings file.\r\nDialogue: 0,0:45:40.51,0:45:43.16,yin,,0,0,0,,我要创建一个新strings文件\\N{\\fs12}So I'm going to create a new file, call it strings file.\r\nDialogue: 0,0:45:43.16,0:45:45.84,yin,,0,0,0,,名为我刚才说的Entities\\N{\\fs12}I'm going to call it entities; that's what I said I called it.\r\nDialogue: 0,0:45:45.84,0:45:48.74,yin,,0,0,0,,把它和视图那些放一起\\N{\\fs12}I'm going to put it where I keep my view stuff.\r\nDialogue: 0,0:45:48.74,0:45:50.70,yin,,0,0,0,,点创建\\N{\\fs12}And I hit create.\r\nDialogue: 0,0:45:50.70,0:45:53.31,yin,,0,0,0,,创建在了这里 Entities.strings\\N{\\fs12}It makes it, it right here. Entities dot string.\r\nDialogue: 0,0:45:53.31,0:45:55.14,yin,,0,0,0,,我要让它可本地化\\N{\\fs12}I'm going to make it localizable,\r\nDialogue: 0,0:45:55.14,0:45:57.81,yin,,0,0,0,,同其它.strings文件一样\\N{\\fs12}the same way as I did the other strings file.\r\nDialogue: 0,0:45:57.81,0:46:00.33,yin,,0,0,0,,这是我们的base 什么都没有\\N{\\fs12}That will be our base, which is nothing.\r\nDialogue: 0,0:46:00.33,0:46:02.17,yin,,0,0,0,,然后我可以说\\N{\\fs12}And then I can say,\r\nDialogue: 0,0:46:02.17,0:46:04.86,yin,,0,0,0,,我不需要英语本地化\\N{\\fs12}\"Well, I don't need an English localization because\r\nDialogue: 0,0:46:04.86,0:46:08.79,yin,,0,0,0,,因为数据库中实体的名称都是英语的\\N{\\fs12}the names of the entities in the database are in English.\"\r\nDialogue: 0,0:46:08.79,0:46:09.70,yin,,0,0,0,,所以不需要\\N{\\fs12}So I don't need one.\r\nDialogue: 0,0:46:09.70,0:46:11.43,yin,,0,0,0,,但法语需要\\N{\\fs12}But French I do.\r\nDialogue: 0,0:46:11.43,0:46:13.13,yin,,0,0,0,,这里我要进行法语本地化\\N{\\fs12}So I'm going to make a French one.\r\nDialogue: 0,0:46:13.13,0:46:15.78,yin,,0,0,0,,到这里看法语 就是这个\\N{\\fs12}Now if you go over here and look at French, here it is.\r\nDialogue: 0,0:46:15.78,0:46:21.28,yin,,0,0,0,,然后我可以说Photographer等于Photographer\\N{\\fs12}And now I can just say photographer equals photographer.\r\nDialogue: 0,0:46:21.28,0:46:23.28,yin,,0,0,0,,这里加上点\\N{\\fs12}And we'll put our dots in here.\r\nDialogue: 0,0:46:23.28,0:46:25.73,yin,,0,0,0,,点点点点\\N{\\fs12}Dot, dot, dot, dot.\r\nDialogue: 0,0:46:25.73,0:46:26.50,yin,,0,0,0,,错了\\N{\\fs12}Whoops.\r\nDialogue: 0,0:46:29.09,0:46:30.13,yin,,0,0,0,,点\\N{\\fs12}Dot.\r\nDialogue: 0,0:46:31.23,0:46:34.62,yin,,0,0,0,,好 这就翻译成了法语\\N{\\fs12}Okay. So we've translated that to French.\r\nDialogue: 0,0:46:34.62,0:46:39.15,yin,,0,0,0,,然后我们可以运行看看\\N{\\fs12}And now when we run,\r\nDialogue: 0,0:46:39.15,0:46:42.34,yin,,0,0,0,,上面的Photographer也本地化了\\N{\\fs12}we'll see that we get photographer along the top here.\r\nDialogue: 0,0:46:42.34,0:46:45.88,yin,,0,0,0,,这就是需要通过调用Bundle那些来本地化的例子\\N{\\fs12}So that's an example of where you need to localize by actually calling the bundle thing,\r\nDialogue: 0,0:46:45.88,0:46:47.81,yin,,0,0,0,,这里不能使用NSLocalizedString\\N{\\fs12}as opposed to NS localized string.\r\nDialogue: 0,0:46:47.81,0:46:49.33,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,0:47:01.75,0:47:02.43,yin,,0,0,0,,问得很好\\N{\\fs12}Yeah. Great question.\r\nDialogue: 0,0:47:02.43,0:47:06.12,yin,,0,0,0,,问题是 使用这些NSLocalizedString时\\N{\\fs12}So the question is: When I did these NS localized strings here\r\nDialogue: 0,0:47:06.12,0:47:08.79,yin,,0,0,0,,它们都被放在PhotoViewController.m中\\N{\\fs12}I put them in my dot M -- photo view controller dot M --\r\nDialogue: 0,0:47:08.79,0:47:10.60,yin,,0,0,0,,看到了吗 都在这里面\\N{\\fs12}see how I put them all right in here?\r\nDialogue: 0,0:47:10.60,0:47:13.64,yin,,0,0,0,,我能否把这些放到.h文件中\\N{\\fs12}Could I put these in a dot H somewhere\r\nDialogue: 0,0:47:13.64,0:47:16.73,yin,,0,0,0,,然后导入它们 在两者之间共享\\N{\\fs12}and then import them and share them between two?\r\nDialogue: 0,0:47:16.73,0:47:18.30,yin,,0,0,0,,答案是完全可以\\N{\\fs12}The answer is absolutely you can do that.\r\nDialogue: 0,0:47:18.30,0:47:21.62,yin,,0,0,0,,genstrings中使用.h文件是完全合法的\\N{\\fs12}When you do genstrings, it's legal to put a dot H file there.\r\nDialogue: 0,0:47:21.62,0:47:24.72,yin,,0,0,0,,实际上genstrings可以用于任何文件\\N{\\fs12}In fact, genstrings will look in any file you want, right?\r\nDialogue: 0,0:47:24.72,0:47:27.41,yin,,0,0,0,,没错 你可以那样做\\N{\\fs12}So yes, you can do that.\r\nDialogue: 0,0:47:27.41,0:47:28.76,yin,,0,0,0,,好\\N{\\fs12}All right.\r\nDialogue: 0,0:47:28.76,0:47:30.82,yin,,0,0,0,,以上就是本地化了\\N{\\fs12}So that's it for localization.\r\nDialogue: 0,0:47:30.82,0:47:33.26,yin,,0,0,0,,我只是粗浅地讲了下本地化\\N{\\fs12}I'm just kind of skimming the surface as far as of localization,\r\nDialogue: 0,0:47:33.26,0:47:34.82,yin,,0,0,0,,不过我认为它很重要\\N{\\fs12}but I think this is a really important one\r\nDialogue: 0,0:47:34.82,0:47:37.72,yin,,0,0,0,,对于在App商店出售的商品 这是必要的\\N{\\fs12}to know if you're going to ship a product on the app store\r\nDialogue: 0,0:47:37.72,0:47:41.60,yin,,0,0,0,,本地化能够让你的产品打开市场\\N{\\fs12}because you can really open up your market by having it localized.\r\nDialogue: 0,0:47:41.60,0:47:45.13,yin,,0,0,0,,本地化这些strings文件的代价并不大\\N{\\fs12}It's not that expensive to have these strings files localized.\r\nDialogue: 0,0:47:45.13,0:47:49.51,yin,,0,0,0,,更大的代价其实是在质量保证上\\N{\\fs12}Really, more of your cost is sometimes just QA-ing it.\r\nDialogue: 0,0:47:49.51,0:47:51.94,yin,,0,0,0,,你需要为法国用户提供法语\\N{\\fs12}You got to put something that's in French in front\r\nDialogue: 0,0:47:51.94,0:47:56.32,yin,,0,0,0,,确保使用了正确的惯用语 确保法国人能够理解\\N{\\fs12}of French users and make sure that it uses the right idioms and that it's understandable.\r\nDialogue: 0,0:47:56.32,0:47:59.39,yin,,0,0,0,,如果你找到了一家好的本地化公司\\N{\\fs12}And, you know, if you get a good localization company doing the\r\nDialogue: 0,0:47:59.39,0:48:03.25,yin,,0,0,0,,他们还会为你进行质量保证\\N{\\fs12}localization for you, they'll do the QA as well and make sure that, you know,\r\nDialogue: 0,0:48:03.25,0:48:05.68,yin,,0,0,0,,确保经受过用户测试\\N{\\fs12}it's actually user-tested as well.\r\nDialogue: 0,0:48:06.95,0:48:08.38,yin,,0,0,0,,好\\N{\\fs12}All right.\r\nDialogue: 0,0:48:08.38,0:48:10.13,yin,,0,0,0,,回到幻灯片\\N{\\fs12}Back to the slides.\r\nDialogue: 0,0:48:14.31,0:48:19.34,yin,,0,0,0,,好 我们要讲的最后一点是设置\\N{\\fs12}Okay. The last thing we're going to talk about here is settings.\r\nDialogue: 0,0:48:19.34,0:48:22.67,yin,,0,0,0,,设置让你能够添加你的应用程序的\\N{\\fs12}So settings allows you to add user interface\r\nDialogue: 0,0:48:22.67,0:48:25.53,yin,,0,0,0,,用户界面到通用设置app中\\N{\\fs12}for your application into the general settings app.\r\nDialogue: 0,0:48:25.53,0:48:29.84,yin,,0,0,0,,看到下方的屏幕截图了吗 这是通用设置app\\N{\\fs12}So you can see the screen capture at the bottom there, that's the general settings app.\r\nDialogue: 0,0:48:29.84,0:48:32.82,yin,,0,0,0,,在第一页滚动到最底部\\N{\\fs12}And if you scroll down towards the bottom of very first page\r\nDialogue: 0,0:48:32.82,0:48:35.57,yin,,0,0,0,,你可以看到其它这些app 例如地图\\N{\\fs12}of settings, you can see all these other apps, like Maps\r\nDialogue: 0,0:48:35.57,0:48:37.24,yin,,0,0,0,,Safari 甚至第三方app\\N{\\fs12}and Safari and even third-party apps --\r\nDialogue: 0,0:48:37.24,0:48:38.90,yin,,0,0,0,,Twitter Facebook Flickr等等\\N{\\fs12}Twitter, Facebook, Flickr, whatever.\r\nDialogue: 0,0:48:38.90,0:48:40.96,yin,,0,0,0,,我不确定这些是不是第三方app\\N{\\fs12}Actually, I'm not sure those are third-party apps; they're\r\nDialogue: 0,0:48:40.97,0:48:44.19,yin,,0,0,0,,或许是iOS7本身集成的\\N{\\fs12}probably iOS 7's integration to those things.\r\nDialogue: 0,0:48:44.19,0:48:47.59,yin,,0,0,0,,总之 你的app也能出现在列表底部\\N{\\fs12}But your apps could appear at the bottom of this list.\r\nDialogue: 0,0:48:47.59,0:48:53.85,yin,,0,0,0,,点其中一个app 它就会转到下一个视图\\N{\\fs12}And when you click on one of those apps, it goes to the next view here.\r\nDialogue: 0,0:48:53.85,0:48:56.67,yin,,0,0,0,,这里我展示了两个 一个是地图的 一个是Safari的\\N{\\fs12}And I've shown two different ones, one for Maps and one for Safari.\r\nDialogue: 0,0:48:56.67,0:48:58.58,yin,,0,0,0,,可以看到这里有一些UI\\N{\\fs12}And you can see that there are some UI in there.\r\nDialogue: 0,0:48:58.58,0:49:00.21,yin,,0,0,0,,这里有一些开关\\N{\\fs12}We got some switches,\r\nDialogue: 0,0:49:00.21,0:49:04.25,yin,,0,0,0,,我们可以从一些预定义的列表中进行选择\\N{\\fs12}we can choose from a predefined list of things\r\nDialogue: 0,0:49:04.25,0:49:05.80,yin,,0,0,0,,例如这里说搜索引擎谷歌\\N{\\fs12}like where it says search engine Google.\r\nDialogue: 0,0:49:05.80,0:49:07.63,yin,,0,0,0,,你可以点它 得到一个列表\\N{\\fs12}You can click on that and have a list of things.\r\nDialogue: 0,0:49:07.63,0:49:10.53,yin,,0,0,0,,这里还可以有滑动条\\N{\\fs12}You can also have sliders in here.\r\nDialogue: 0,0:49:10.53,0:49:12.28,yin,,0,0,0,,你还可以进行分组等等\\N{\\fs12}You can group things, etc.\r\nDialogue: 0,0:49:12.28,0:49:14.86,yin,,0,0,0,,你可以对你的app创建这个UI\\N{\\fs12}So this UI you can build for your app\r\nDialogue: 0,0:49:14.86,0:49:16.67,yin,,0,0,0,,并让设置app做到这个\\N{\\fs12}and have the settings app do this.\r\nDialogue: 0,0:49:16.67,0:49:23.45,yin,,0,0,0,,这个UI实际是建立在NSUserDefaults上的一层UI\\N{\\fs12}This UI is basically a UI on top of NS user defaults.\r\nDialogue: 0,0:49:23.45,0:49:28.55,yin,,0,0,0,,UI中的所有这些 都是在设置NSUserDefaults\\N{\\fs12}So these things -- all these things in the UI -- are setting NS user defaults.\r\nDialogue: 0,0:49:28.55,0:49:29.47,yin,,0,0,0,,这就是它们的作用\\N{\\fs12}That's all they're doing.\r\nDialogue: 0,0:49:29.47,0:49:32.67,yin,,0,0,0,,这也是同你的app进行通信的方式\\N{\\fs12}And that's how it's communicating with your app.\r\nDialogue: 0,0:49:32.67,0:49:34.02,yin,,0,0,0,,就这么简单\\N{\\fs12}So it's as simple as that.\r\nDialogue: 0,0:49:34.02,0:49:36.55,yin,,0,0,0,,这里能放入的UI并不多\\N{\\fs12}There's really not a lot of UI you can put in here.\r\nDialogue: 0,0:49:36.55,0:49:38.45,yin,,0,0,0,,我不打算一一讲解\\N{\\fs12}I'm not going to talk about all the things you can do.\r\nDialogue: 0,0:49:38.45,0:49:40.56,yin,,0,0,0,,你们可以自己去看说明文档\\N{\\fs12}You can look in the documentation for that.\r\nDialogue: 0,0:49:40.56,0:49:44.34,yin,,0,0,0,,不过我说了 滑动条 开关 文本框\\N{\\fs12}But like I said, sliders, switches, text fields,\r\nDialogue: 0,0:49:44.34,0:49:48.58,yin,,0,0,0,,可键入文本框 还有选择列表 主要是这些\\N{\\fs12}typeable text fields, and also selecting from lists are the main things.\r\nDialogue: 0,0:49:48.58,0:49:52.48,yin,,0,0,0,,要加入这些东西 做法是在你的app中\\N{\\fs12}The way you add this to your app is in your app, okay,\r\nDialogue: 0,0:49:52.48,0:49:56.12,yin,,0,0,0,,你到Xcode中添加新文件\\N{\\fs12}you go into Xcode and you say new file.\r\nDialogue: 0,0:49:56.12,0:49:59.07,yin,,0,0,0,,然后在资源下 选择Settings Bundle\\N{\\fs12}And then under resources you pick settings bundle.\r\nDialogue: 0,0:49:59.07,0:50:01.94,yin,,0,0,0,,这和刚才我们添加strings文件是相同的位置\\N{\\fs12}This is the same place we went to add a strings file a moment ago.\r\nDialogue: 0,0:50:01.94,0:50:03.47,yin,,0,0,0,,现在我们选Settings Bundle\\N{\\fs12}Now we're going to do settings bundle.\r\nDialogue: 0,0:50:03.47,0:50:05.15,yin,,0,0,0,,选Settings Bundle后\\N{\\fs12}And when you do settings bundle\r\nDialogue: 0,0:50:05.15,0:50:06.75,yin,,0,0,0,,你会得到这个Settings Bundle\\N{\\fs12}you'll get this little settings bundle.\r\nDialogue: 0,0:50:06.75,0:50:08.35,yin,,0,0,0,,添加到文件浏览器\\N{\\fs12}Add it to your file navigation there.\r\nDialogue: 0,0:50:08.35,0:50:09.88,yin,,0,0,0,,你可以看到它\\N{\\fs12}You can see it.\r\nDialogue: 0,0:50:09.88,0:50:14.43,yin,,0,0,0,,它会给你一个默认的样例Bundle\\N{\\fs12}And it's going to give you a default kind of an example bundle,\r\nDialogue: 0,0:50:14.44,0:50:15.29,yin,,0,0,0,,这很棒\\N{\\fs12}which is really nice\r\nDialogue: 0,0:50:15.29,0:50:20.50,yin,,0,0,0,,能够帮你开个好头 了解能用这个做什么\\N{\\fs12}because it's a good starting point to get started, and what can I do with this thing?\r\nDialogue: 0,0:50:20.50,0:50:24.10,yin,,0,0,0,,所有这些UI 不是在故事板中创建\\N{\\fs12}All that UI that you're going to build, you don't build it in a storyboard, you don't\r\nDialogue: 0,0:50:24.10,0:50:26.94,yin,,0,0,0,,也不是用图形界面来创建\\N{\\fs12}build it, you know, with graphical interface;\r\nDialogue: 0,0:50:26.94,0:50:29.65,yin,,0,0,0,,而是用属性列表来创建\\N{\\fs12}you build it using a property list.\r\nDialogue: 0,0:50:29.65,0:50:33.02,yin,,0,0,0,,这个属性列表有定义良好的键和值\\N{\\fs12}And this property list has well-defined keys and values.\r\nDialogue: 0,0:50:33.02,0:50:34.95,yin,,0,0,0,,这些键和值决定了\\N{\\fs12}And these keys and values determine whether you're doing a\r\nDialogue: 0,0:50:34.95,0:50:38.50,yin,,0,0,0,,你用的是文本框 还是滑动条 还是分组这些\\N{\\fs12}text field, or a slider, or grouping things, or whatever.\r\nDialogue: 0,0:50:38.50,0:50:41.30,yin,,0,0,0,,这里你可以看到\\N{\\fs12}So you can kind of see up here some\r\nDialogue: 0,0:50:41.30,0:50:45.04,yin,,0,0,0,,用于创建这个UI的属性列表\\N{\\fs12}of the property list things you can set to build this UI.\r\nDialogue: 0,0:50:45.04,0:50:47.36,yin,,0,0,0,,例如 屏幕上\\N{\\fs12}For example, what you see on screen,\r\nDialogue: 0,0:50:47.36,0:50:50.65,yin,,0,0,0,,我会跟你们展示 它在设置app中是怎样的\\N{\\fs12}I'm going to show you what that looks like in the settings app.\r\nDialogue: 0,0:50:50.65,0:50:52.99,yin,,0,0,0,,这里有Group 这是项目0\\N{\\fs12}So you see you got a group is item zero.\r\nDialogue: 0,0:50:52.99,0:50:54.48,yin,,0,0,0,,这个会分组\\N{\\fs12}So this thing is going to be grouped.\r\nDialogue: 0,0:50:54.48,0:50:57.19,yin,,0,0,0,,组名是Group 它在顶部会说Group\\N{\\fs12}The name of the group is \"group,\" so it's going to say group at the top.\r\nDialogue: 0,0:50:57.19,0:51:01.09,yin,,0,0,0,,然后我们有一个文本框 一个拨动开关和一个滑动条\\N{\\fs12}And then we got a text field, a toggle switch, and a slider.\r\nDialogue: 0,0:51:01.09,0:51:03.15,yin,,0,0,0,,看到项目1 2 3了吗\\N{\\fs12}You see items one, two, and three?\r\nDialogue: 0,0:51:03.15,0:51:09.56,yin,,0,0,0,,文本框在这里 使用字母键盘\\N{\\fs12}The text field there, you know, using the alphabetic keyboard,\r\nDialogue: 0,0:51:09.56,0:51:12.79,yin,,0,0,0,,不进行自动更正\\N{\\fs12}it doesn't do auto correction,\r\nDialogue: 0,0:51:12.79,0:51:18.00,yin,,0,0,0,,等等 拨动开关 其标题是Enabled\\N{\\fs12}etc. The toggle switch, its title is enabled.\r\nDialogue: 0,0:51:18.00,0:51:21.95,yin,,0,0,0,,它会说Enabled 然后这里有个拨动开关\\N{\\fs12}So it's going to say enabled, and then there's going to be a toggle switch there.\r\nDialogue: 0,0:51:21.95,0:51:25.17,yin,,0,0,0,,滑动条从0到1\\N{\\fs12}The slider looks like it goes from a zero to one.\r\nDialogue: 0,0:51:25.17,0:51:26.57,yin,,0,0,0,,所有这三个\\N{\\fs12}And for all three of them,\r\nDialogue: 0,0:51:26.57,0:51:29.01,yin,,0,0,0,,注意到都有name_preference\\N{\\fs12}do you see how it says name underbar preference,\r\nDialogue: 0,0:51:29.01,0:51:33.21,yin,,0,0,0,,enabled_preference和slider_preference\\N{\\fs12}enabled underbar preference, slider underbar preference in each of those 3 things?\r\nDialogue: 0,0:51:33.21,0:51:37.22,yin,,0,0,0,,这就是它所设置的NS用户默认\\N{\\fs12}That's the NS user default that it's setting.\r\nDialogue: 0,0:51:37.22,0:51:41.44,yin,,0,0,0,,我不是很喜欢这些名称 不过这就是它所设置的\\N{\\fs12}I don't really like those names very much, but that's what it's setting.\r\nDialogue: 0,0:51:41.44,0:51:44.45,yin,,0,0,0,,这个会是怎样的呢\\N{\\fs12}So what is this going to look like? What would this particular thing look like?\r\nDialogue: 0,0:51:44.45,0:51:47.10,yin,,0,0,0,,它会是这样的\\N{\\fs12}Well, it would look like this.\r\nDialogue: 0,0:51:47.10,0:51:50.83,yin,,0,0,0,,Group Name Enabled带有一个开关 然后滑动条\\N{\\fs12}Group, name, enabled with a switch, and then the slider.\r\nDialogue: 0,0:51:52.51,0:51:56.31,yin,,0,0,0,,本地化 我们再来谈谈本地化设置\\N{\\fs12}So localization. Let's talk about localization settings.\r\nDialogue: 0,0:51:56.31,0:51:58.18,yin,,0,0,0,,设置需要本地化\\N{\\fs12}You've got to have localization for setting,\r\nDialogue: 0,0:51:58.18,0:52:01.31,yin,,0,0,0,,否则法国人就不知道如何进行设置\\N{\\fs12}otherwise when a person's French they're not going to understand how to do your settings.\r\nDialogue: 0,0:52:01.31,0:52:04.06,yin,,0,0,0,,做法是使用strings文件\\N{\\fs12}And it's done using strings files.\r\nDialogue: 0,0:52:04.06,0:52:06.03,yin,,0,0,0,,在Settings Bundle中\\N{\\fs12}And if you look inside the settings bundle,\r\nDialogue: 0,0:52:06.03,0:52:08.51,yin,,0,0,0,,你可以看到其中有en.lproj\\N{\\fs12}you'll see it comes with an EN dot lproj;\r\nDialogue: 0,0:52:08.51,0:52:10.95,yin,,0,0,0,,我想这里有点偏向于英文\\N{\\fs12}little bit of English bias there, I think.\r\nDialogue: 0,0:52:10.95,0:52:12.81,yin,,0,0,0,,在en.lproj中…\\N{\\fs12}And in that EN dot lproj --\r\nDialogue: 0,0:52:12.81,0:52:15.13,yin,,0,0,0,,实际上可能没有英文偏向性\\N{\\fs12}actually, might not even be English bias.\r\nDialogue: 0,0:52:15.13,0:52:18.49,yin,,0,0,0,,有可能如果你是法国人 在你开发这个时\\N{\\fs12}It's possible that if you're developing this and you're French,\r\nDialogue: 0,0:52:18.49,0:52:20.96,yin,,0,0,0,,它会创建fr.lproj\\N{\\fs12}it might create an FR dot lproj for you.\r\nDialogue: 0,0:52:20.96,0:52:22.48,yin,,0,0,0,,我不知道 我没试过\\N{\\fs12}I'm not sure, I've never tried that.\r\nDialogue: 0,0:52:22.48,0:52:24.98,yin,,0,0,0,,然后 在这个strings文件中的\\N{\\fs12}And then inside this strings file\r\nDialogue: 0,0:52:24.98,0:52:28.86,yin,,0,0,0,,是你所创建的UI中会显示出的所有字符串\\N{\\fs12}is every string that would appear in this UI that you're building\r\nDialogue: 0,0:52:28.86,0:52:32.13,yin,,0,0,0,,等于 它应该等于的东西\\N{\\fs12}with equals whatever it's supposed to be.\r\nDialogue: 0,0:52:32.13,0:52:37.44,yin,,0,0,0,,无论两张幻灯片前的base plist中是什么\\N{\\fs12}So whatever's in that base P list we saw two slides ago,\r\nDialogue: 0,0:52:37.44,0:52:40.70,yin,,0,0,0,,UI中出现的一切 你都可以说 它等于别的什么\\N{\\fs12}anything that would appear in the UI you can just say it equals something else.\r\nDialogue: 0,0:52:40.70,0:52:43.07,yin,,0,0,0,,然后这里可以有任意多个.lproj文件\\N{\\fs12}And then you can have as many dot lprojs as you want here --\r\nDialogue: 0,0:52:43.07,0:52:45.11,yin,,0,0,0,,法语.lproj等等\\N{\\fs12}French dot lproj, whatever.\r\nDialogue: 0,0:52:45.11,0:52:50.10,yin,,0,0,0,,糟糕的是 没有办法到文件检查器然后点本地化\\N{\\fs12}The bad thing is there's no way to go to the file inspector and hit localize.\r\nDialogue: 0,0:52:50.10,0:52:51.92,yin,,0,0,0,,Xcode中不能\\N{\\fs12}For some reason they have not gotten\r\nDialogue: 0,0:52:51.92,0:52:56.17,yin,,0,0,0,,让Settings Bundle可本地化\\N{\\fs12}around to having the settings bundle be localizable in Xcode.\r\nDialogue: 0,0:52:56.17,0:53:00.48,yin,,0,0,0,,机制是有 但没有检查器UI来这样做\\N{\\fs12}It's got the mechanism there, but there's no inspector UI to do it.\r\nDialogue: 0,0:53:00.48,0:53:02.77,yin,,0,0,0,,那如何本地化这个呢\\N{\\fs12}So how do you localize this thing?\r\nDialogue: 0,0:53:02.77,0:53:05.50,yin,,0,0,0,,如何创建fr.lproj\\N{\\fs12}How do I create an FR dot lproj?\r\nDialogue: 0,0:53:05.50,0:53:11.09,yin,,0,0,0,,答案是 你要到finder中找到这个Settings Bundle\\N{\\fs12}And the answer is you're going to go to finder and find this settings bundle.\r\nDialogue: 0,0:53:11.09,0:53:12.53,yin,,0,0,0,,这可以从Xcode中做到\\N{\\fs12}You can actually do that from Xcode.\r\nDialogue: 0,0:53:12.53,0:53:14.14,yin,,0,0,0,,demo中我会演示\\N{\\fs12}I'll show you how to do that in the demo.\r\nDialogue: 0,0:53:14.14,0:53:16.36,yin,,0,0,0,,然后右键点击Settings Bundle\\N{\\fs12}Then you're going to right-click on the settings bundle\r\nDialogue: 0,0:53:16.36,0:53:18.37,yin,,0,0,0,,选显示包内容\\N{\\fs12}and say show package contents.\r\nDialogue: 0,0:53:18.37,0:53:21.13,yin,,0,0,0,,这会为你显示Settings Bundle中的内容\\N{\\fs12}And that's going to show you what's inside that settings bundle,\r\nDialogue: 0,0:53:21.13,0:53:22.78,yin,,0,0,0,,它会是这样的\\N{\\fs12}which is going to look like this.\r\nDialogue: 0,0:53:22.78,0:53:25.18,yin,,0,0,0,,你会看到其中的en.lproj\\N{\\fs12}And you're going to see the EN dot lproj there.\r\nDialogue: 0,0:53:25.18,0:53:29.28,yin,,0,0,0,,然后你需要手动创建fr.lproj\\N{\\fs12}And now you're going to manually create an FR dot lproj.\r\nDialogue: 0,0:53:29.28,0:53:32.29,yin,,0,0,0,,这里的支持很好\\N{\\fs12}Really nice support for it here.\r\nDialogue: 0,0:53:32.29,0:53:35.91,yin,,0,0,0,,通常我会直接复制粘贴en.lproj\\N{\\fs12}And usually I do this by taking the EN dot lproj and just copying and pasting it\r\nDialogue: 0,0:53:35.92,0:53:36.86,yin,,0,0,0,,然后重命名\\N{\\fs12}and then renaming it\r\nDialogue: 0,0:53:36.86,0:53:40.84,yin,,0,0,0,,从en.lproj到fr.lproj\\N{\\fs12}from EN dot lproj copy to FR dot lproj.\r\nDialogue: 0,0:53:40.84,0:53:43.64,yin,,0,0,0,,然后其中的Root.strings\\N{\\fs12}And then the root dot strings that's inside there,\r\nDialogue: 0,0:53:43.64,0:53:46.70,yin,,0,0,0,,是我要发送给本地化者的\\N{\\fs12}that's what I would send off to my localizer.\r\nDialogue: 0,0:53:46.70,0:53:50.11,yin,,0,0,0,,它会对法语做等于那些\\N{\\fs12}And that would do the equals thing for French.\r\nDialogue: 0,0:53:50.11,0:53:53.30,yin,,0,0,0,,我们来看看Bouncer中的这个是怎样的\\N{\\fs12}So let's see what this looks like in Bouncer.\r\nDialogue: 0,0:53:53.30,0:53:57.46,yin,,0,0,0,,因为Bouncer有些很好的设置我们可以设\\N{\\fs12}Because Bouncer has some nice settings that we could set.\r\nDialogue: 0,0:53:57.46,0:53:59.95,yin,,0,0,0,,我要让弹球的弹性在设置中可设\\N{\\fs12}And what I'm going to do is make it so the elasticity --\r\nDialogue: 0,0:53:59.95,0:54:04.58,yin,,0,0,0,,我要让弹球的弹性在设置中可设\\N{\\fs12}you know, the bounciness of the bouncing ball -- is settable in settings.\r\nDialogue: 0,0:54:04.58,0:54:07.23,yin,,0,0,0,,当前 弹性是1\\N{\\fs12}So right now we have the elasticity set at one,\r\nDialogue: 0,0:54:07.23,0:54:11.99,yin,,0,0,0,,这是弹球能够持续往下落的最大弹性\\N{\\fs12}which is kind of the maximum elasticity that it can have and still settle down.\r\nDialogue: 0,0:54:11.99,0:54:14.68,yin,,0,0,0,,如果大于1 它就会越来越快\\N{\\fs12}If we had more than one, it would start getting faster\r\nDialogue: 0,0:54:14.68,0:54:16.36,yin,,0,0,0,,在壁间越来越快地弹动\\N{\\fs12}and faster as it bounced off the walls.\r\nDialogue: 0,0:54:16.36,0:54:20.80,yin,,0,0,0,,这就不会有平等的弹性回弹了\\N{\\fs12}It would be more than an equally elastic rebound.\r\nDialogue: 0,0:54:20.80,0:54:24.39,yin,,0,0,0,,我们这里让弹性值在0到1之间可设置\\N{\\fs12}So we're going to make it so we can set that elasticity anywhere from zero to one.\r\nDialogue: 0,0:54:24.39,0:54:28.49,yin,,0,0,0,,0表示撞击后就不再弹起\\N{\\fs12}Zero would mean just kind of hits and dampens immediately.\r\nDialogue: 0,0:54:28.49,0:54:29.36,yin,,0,0,0,,好\\N{\\fs12}All right.\r\nDialogue: 0,0:54:29.36,0:54:32.48,yin,,0,0,0,,我们来到Bouncer\\N{\\fs12}So let's go get Bouncer.\r\nDialogue: 0,0:54:32.48,0:54:34.94,yin,,0,0,0,,Bouncer 这里是Bouncer\\N{\\fs12}Bouncer. Here's Bouncer.\r\nDialogue: 0,0:54:36.93,0:54:40.62,yin,,0,0,0,,好 Bouncer在上次发布后就没再更改过了\\N{\\fs12}Okay. Bouncer has not changed since last it was posted.\r\nDialogue: 0,0:54:40.62,0:54:44.74,yin,,0,0,0,,弹性在这里 这个弹性动态的行为\\N{\\fs12}The elasticity is here, this elastic, dynamic behavior.\r\nDialogue: 0,0:54:44.74,0:54:49.22,yin,,0,0,0,,可以看到 它被设为1 这是当前默认值\\N{\\fs12}And you can see that we set it to one, okay, by default right now.\r\nDialogue: 0,0:54:49.22,0:54:54.29,yin,,0,0,0,,我们希望能够从设置app中设置这个弹性值\\N{\\fs12}So we want to be able to set this elasticity from the settings app.\r\nDialogue: 0,0:54:54.29,0:54:57.15,yin,,0,0,0,,首先创建它的UI\\N{\\fs12}So let's build the UI for it first, and then we'll have\r\nDialogue: 0,0:54:57.15,0:55:01.64,yin,,0,0,0,,然后变更代码 来使用UI将会设定的NS用户默认\\N{\\fs12}to change our code to use the NS user default that our UI's going to set.\r\nDialogue: 0,0:55:01.64,0:55:04.78,yin,,0,0,0,,创建UI我们只需要点新文件\\N{\\fs12}So to do the UI we just do new file,\r\nDialogue: 0,0:55:04.78,0:55:09.01,yin,,0,0,0,,来到iOS的资源部分 选Settings Bundle\\N{\\fs12}go to the resource section of iOS, settings bundle.\r\nDialogue: 0,0:55:09.01,0:55:11.62,yin,,0,0,0,,strings文件相同的地方 Settings Bundle\\N{\\fs12}Same place we did strings file right here, settings bundle.\r\nDialogue: 0,0:55:11.62,0:55:13.41,yin,,0,0,0,,创建Settings Bundle\\N{\\fs12}Create the settings bundle.\r\nDialogue: 0,0:55:13.41,0:55:15.82,yin,,0,0,0,,Bundle名叫什么都行\\N{\\fs12}You can call the bundle whatever you want. Doesn't really matter.\r\nDialogue: 0,0:55:15.82,0:55:18.04,yin,,0,0,0,,我就叫它Settings\\N{\\fs12}I'm going to call it settings.\r\nDialogue: 0,0:55:18.04,0:55:19.23,yin,,0,0,0,,这里\\N{\\fs12}Here it is.\r\nDialogue: 0,0:55:19.23,0:55:20.72,yin,,0,0,0,,这是Settings Bundle\\N{\\fs12}Here's the settings bundle.\r\nDialogue: 0,0:55:20.72,0:55:25.00,yin,,0,0,0,,这个Root.plist就是Bundle的内容了\\N{\\fs12}And this root dot P list is what the bundle is,\r\nDialogue: 0,0:55:25.00,0:55:27.01,yin,,0,0,0,,其中有四个项目\\N{\\fs12}and you can see it has four items here.\r\nDialogue: 0,0:55:27.01,0:55:31.63,yin,,0,0,0,,还是分组 文本框 拨动开关 滑动条\\N{\\fs12}Again, group, text field, toggle switch, slider.\r\nDialogue: 0,0:55:33.07,0:55:36.92,yin,,0,0,0,,每次创建Settings Bundle都会得到这些\\N{\\fs12}So you get this -- every time you create a settings bundle you get this one.\r\nDialogue: 0,0:55:36.92,0:55:39.66,yin,,0,0,0,,我来看看这是怎样的\\N{\\fs12}Let's go ahead and see what this looks like.\r\nDialogue: 0,0:55:39.66,0:55:42.51,yin,,0,0,0,,在这里来做\\N{\\fs12}Let's do this over here.\r\nDialogue: 0,0:55:50.67,0:55:55.22,yin,,0,0,0,,这是我们的Bouncer 它具有完全弹性\\N{\\fs12}So here's our Bouncer, and you can see it's got full elasticity\r\nDialogue: 0,0:55:55.22,0:55:57.47,yin,,0,0,0,,弹得很好\\N{\\fs12}-- bounces pretty good, right?\r\nDialogue: 0,0:55:57.47,0:56:00.77,yin,,0,0,0,,我们来到设置app\\N{\\fs12}And if we go over to the settings app right here,\r\nDialogue: 0,0:56:00.77,0:56:03.95,yin,,0,0,0,,滚动到底部 你会看到其它app之外\\N{\\fs12}if we scroll down to the bottom, you'll see that in addition\r\nDialogue: 0,0:56:03.95,0:56:05.76,yin,,0,0,0,,这里还有Bouncer\\N{\\fs12}to these other apps, there's Bouncer.\r\nDialogue: 0,0:56:05.76,0:56:08.32,yin,,0,0,0,,如果Bouncer的图标好点就更好了\\N{\\fs12}If Bouncer had a nice icon, the icon would look better.\r\nDialogue: 0,0:56:08.32,0:56:10.72,yin,,0,0,0,,点Bouncer 这就是UI\\N{\\fs12}But if we click on Bouncer, here's the UI.\r\nDialogue: 0,0:56:10.72,0:56:14.45,yin,,0,0,0,,这里有个可以滑动的滑动条\\N{\\fs12}So we got this slider right here that we can move around\r\nDialogue: 0,0:56:14.45,0:56:15.93,yin,,0,0,0,,还有开关可以关掉\\N{\\fs12}and we've got the switch to turn off.\r\nDialogue: 0,0:56:15.93,0:56:18.39,yin,,0,0,0,,但这些都没同Bouncer关联起来\\N{\\fs12}But none of this is connected to Bouncer in any way;\r\nDialogue: 0,0:56:18.39,0:56:22.14,yin,,0,0,0,,这只是创建到设置app的默认东西\\N{\\fs12}this is just the default stuff we got from creating the settings app.\r\nDialogue: 0,0:56:22.14,0:56:24.72,yin,,0,0,0,,我这里要留下滑动条\\N{\\fs12}So what I'm going to do is I'm going to keep the slider,\r\nDialogue: 0,0:56:24.72,0:56:28.94,yin,,0,0,0,,并让它从0到1 弹性从0到1\\N{\\fs12}and I'm going to have the slider go from zero to one -- elasticity zero to one.\r\nDialogue: 0,0:56:28.94,0:56:31.15,yin,,0,0,0,,Enabled开关我打算删掉\\N{\\fs12}I'm going to get rid of this enabled switch right here.\r\nDialogue: 0,0:56:31.15,0:56:34.31,yin,,0,0,0,,Name文本框我也打算删掉\\N{\\fs12}I'm going to get rid of this name text field right here.\r\nDialogue: 0,0:56:34.31,0:56:36.72,yin,,0,0,0,,Group我打算保留 但是不再称其为Group\\N{\\fs12}And I'm going to keep the group, but instead of calling it\r\nDialogue: 0,0:56:36.72,0:56:38.33,yin,,0,0,0,,而是称其为弹性\\N{\\fs12}\"group,\" I'm going to call it \"elasticity.\"\r\nDialogue: 0,0:56:38.33,0:56:40.38,yin,,0,0,0,,这个UI非常简单\\N{\\fs12}So I'm going to have this really simple UI here\r\nDialogue: 0,0:56:40.38,0:56:42.84,yin,,0,0,0,,只是设置弹性的滑动条\\N{\\fs12}that says elasticity and then has a slider.\r\nDialogue: 0,0:56:43.72,0:56:45.08,yin,,0,0,0,,让我们到这里\\N{\\fs12}So let's go here.\r\nDialogue: 0,0:56:45.08,0:56:47.97,yin,,0,0,0,,删掉文本框\\N{\\fs12}Let's get rid of this text field.\r\nDialogue: 0,0:56:47.97,0:56:50.87,yin,,0,0,0,,删掉拨动开关\\N{\\fs12}Let's get rid of this toggle switch.\r\nDialogue: 0,0:56:50.87,0:56:53.00,yin,,0,0,0,,保留Group和滑动条\\N{\\fs12}And so I'm keeping the group and the slider.\r\nDialogue: 0,0:56:53.00,0:56:58.02,yin,,0,0,0,,将Group改为Elasticity\\N{\\fs12}I'm going to rename the group from group to be \"elasticity.\"\r\nDialogue: 0,0:56:58.02,0:57:01.73,yin,,0,0,0,,然后在滚动条中 我们看看这些\\N{\\fs12}And then in my slider let's look at some of these things here.\r\nDialogue: 0,0:57:01.73,0:57:03.54,yin,,0,0,0,,最大值是1\\N{\\fs12}Okay, the maximum value is one.\r\nDialogue: 0,0:57:03.54,0:57:04.42,yin,,0,0,0,,这很好\\N{\\fs12}That's good.\r\nDialogue: 0,0:57:04.42,0:57:06.09,yin,,0,0,0,,我希望最大弹性为1\\N{\\fs12}That's maximum elasticity I want.\r\nDialogue: 0,0:57:06.09,0:57:06.91,yin,,0,0,0,,最小值0\\N{\\fs12}Minimum zero.\r\nDialogue: 0,0:57:06.91,0:57:08.59,yin,,0,0,0,,这很好 不需要改\\N{\\fs12}So that's good. I don't need to change that,\r\nDialogue: 0,0:57:08.59,0:57:10.83,yin,,0,0,0,,不过这些显然是可更改的\\N{\\fs12}but you can obviously change these things.\r\nDialogue: 0,0:57:10.83,0:57:15.87,yin,,0,0,0,,默认值是0.5 不 我希望默认值是1\\N{\\fs12}The default value of .5 -- no, I really want my default value to be one\r\nDialogue: 0,0:57:15.87,0:57:20.28,yin,,0,0,0,,1才是我希望的默认值 我希望它从这里开始\\N{\\fs12}because that's what my default value was before, and I want it to start there.\r\nDialogue: 0,0:57:20.28,0:57:22.65,yin,,0,0,0,,然后这个slider_preference很重要\\N{\\fs12}And then this is very important, slider preference.\r\nDialogue: 0,0:57:22.65,0:57:26.72,yin,,0,0,0,,这是将这个通信回来的NS用户默认\\N{\\fs12}This is going to be the NS user default that communicates this back.\r\nDialogue: 0,0:57:26.72,0:57:31.56,yin,,0,0,0,,我打算把这称作Settings_Elasticity\\N{\\fs12}And I'm going to call this settings underbar elasticity.\r\nDialogue: 0,0:57:31.56,0:57:34.54,yin,,0,0,0,,我在为NS用户默认取名时\\N{\\fs12}When I do the names of NS user defaults,\r\nDialogue: 0,0:57:34.54,0:57:38.49,yin,,0,0,0,,喜欢使用大范畴的名称 例如类名\\N{\\fs12}I like to name scope them, like, with the name of the class\r\nDialogue: 0,0:57:38.49,0:57:42.05,yin,,0,0,0,,然后下划线 然后项目名\\N{\\fs12}and then an underbar and then all the items in there.\r\nDialogue: 0,0:57:42.05,0:57:46.66,yin,,0,0,0,,这样就能避免重名的问题\\N{\\fs12}So you kind of give it a little bit of protection against the same name thing.\r\nDialogue: 0,0:57:46.66,0:57:48.41,yin,,0,0,0,,这里是设置\\N{\\fs12}Here, since this is set in settings,\r\nDialogue: 0,0:57:48.41,0:57:50.70,yin,,0,0,0,,大范畴于是就是Settings\\N{\\fs12}I'm going to scope it to be settings.\r\nDialogue: 0,0:57:50.70,0:57:53.84,yin,,0,0,0,,怎么做最好 你们可以有自己的见解\\N{\\fs12}We could argue there are better ways to do that.\r\nDialogue: 0,0:57:53.84,0:57:55.20,yin,,0,0,0,,不过这种方式很简单\\N{\\fs12}But it's a simple way to do it.\r\nDialogue: 0,0:57:55.20,0:57:58.51,yin,,0,0,0,,这是代码中我们要用的NS用户默认的名称\\N{\\fs12}So this is going to be the name of the NS user default we want in our code.\r\nDialogue: 0,0:57:58.51,0:58:00.56,yin,,0,0,0,,下面回到我们的代码\\N{\\fs12}So now let's go back to our code and use\r\nDialogue: 0,0:58:00.56,0:58:03.37,yin,,0,0,0,,使用这个NS用户默认 而不是1.0\\N{\\fs12}that NS user default instead of 1.0 here.\r\nDialogue: 0,0:58:03.37,0:58:05.09,yin,,0,0,0,,这里我将删掉这个1.0\\N{\\fs12}So I'm going to get rid of this 1.0.\r\nDialogue: 0,0:58:05.09,0:58:07.08,yin,,0,0,0,,实际上 我要添加一个方法来做这个\\N{\\fs12}And in fact, I'm going to add a method to do this\r\nDialogue: 0,0:58:07.08,0:58:09.18,yin,,0,0,0,,叫resetElasticity\\N{\\fs12}called reset elasticity.\r\nDialogue: 0,0:58:09.18,0:58:13.26,yin,,0,0,0,,让我们写出这个方法\\N{\\fs12}And let's write that method.\r\nDialogue: 0,0:58:14.45,0:58:15.82,yin,,0,0,0,,void\\N{\\fs12}Void.\r\nDialogue: 0,0:58:15.82,0:58:18.31,yin,,0,0,0,,resetElasticity\\N{\\fs12}Reset elasticity.\r\nDialogue: 0,0:58:18.31,0:58:22.08,yin,,0,0,0,,这里我将立刻获取用户默认\\N{\\fs12}And here I'm going to get the user default right off the bat\r\nDialogue: 0,0:58:23.55,0:58:25.16,yin,,0,0,0,,NSUserDefaults\\N{\\fs12}-- NS user defaults.\r\nDialogue: 0,0:58:25.16,0:58:26.19,yin,,0,0,0,,你们知道怎么做这个\\N{\\fs12}You know how to do this.\r\nDialogue: 0,0:58:26.19,0:58:29.07,yin,,0,0,0,,standardUserDefaults\\N{\\fs12}Defaults. Standard user defaults,\r\nDialogue: 0,0:58:29.07,0:58:30.90,yin,,0,0,0,,valueForKey\\N{\\fs12}value for key.\r\nDialogue: 0,0:58:30.90,0:58:34.18,yin,,0,0,0,,键是Settings_Elasticity\\N{\\fs12}And the key is settings, elasticity.\r\nDialogue: 0,0:58:34.18,0:58:37.02,yin,,0,0,0,,或许我们需要进行#define\\N{\\fs12}Again, probably want to pound sign define there, whatever, yes.\r\nDialogue: 0,0:58:37.02,0:58:39.06,yin,,0,0,0,,不过对于demo 我们直接到这里\\N{\\fs12}But for demo we'll go here.\r\nDialogue: 0,0:58:39.06,0:58:41.01,yin,,0,0,0,,我要说 如果它已设置\\N{\\fs12}I'm going to say if it's set --\r\nDialogue: 0,0:58:41.01,0:58:42.89,yin,,0,0,0,,因为它有可能没被设置\\N{\\fs12}because it might be that that's never been set;\r\nDialogue: 0,0:58:42.89,0:58:48.13,yin,,0,0,0,,有可能用户没有去设置app进行设置\\N{\\fs12}no one's ever gone to the settings app and set this so it might just not even be set.\r\nDialogue: 0,0:58:48.13,0:58:51.99,yin,,0,0,0,,如果它已设置 那我就会做一件事 如果没设\\N{\\fs12}So if it's set, then I'll do one thing; if it's not set,\r\nDialogue: 0,0:58:51.99,0:58:54.38,yin,,0,0,0,,如果没人到设置里面去过 那么\\N{\\fs12}if no one's ever gone into settings, then I'm going\r\nDialogue: 0,0:58:54.38,0:58:59.43,yin,,0,0,0,,我就会将弹性设为1.0 和原来一样\\N{\\fs12}to set my elasticity to be 1.0, which is what it was before.\r\nDialogue: 0,0:58:59.43,0:59:01.81,yin,,0,0,0,,但如果有人设置过 那么\\N{\\fs12}But if someone has gone to the settings app, then I'm going\r\nDialogue: 0,0:59:01.81,0:59:08.64,yin,,0,0,0,,我就会将弹性设为这个elasticity的floatValue\\N{\\fs12}to set my elasticity to be this elasticity's float value.\r\nDialogue: 0,0:59:10.15,0:59:12.06,yin,,0,0,0,,就这么简单\\N{\\fs12}Simple as that.\r\nDialogue: 0,0:59:12.06,0:59:17.45,yin,,0,0,0,,这对于运行程序之前设置弹性没有问题\\N{\\fs12}Now, this works great the first time we ask for the elasticity.\r\nDialogue: 0,0:59:17.45,0:59:21.29,yin,,0,0,0,,但如果有人在程序运行时进入设置\\N{\\fs12}But what if someone goes over to settings while my app is running\r\nDialogue: 0,0:59:21.29,0:59:23.22,yin,,0,0,0,,更改弹性该怎么办呢\\N{\\fs12}and changes the elasticity?\r\nDialogue: 0,0:59:23.22,0:59:27.56,yin,,0,0,0,,我们需要知道这个 做法是通过一个广播站\\N{\\fs12}We need to find out about that, and we do that with a radio station.\r\nDialogue: 0,0:59:27.56,0:59:30.08,yin,,0,0,0,,我们会监听又一个广播站\\N{\\fs12}So we're going to listen to another radio station.\r\nDialogue: 0,0:59:30.08,0:59:33.01,yin,,0,0,0,,这个app中已经监听了两个广播站\\N{\\fs12}We're already listening to two radio stations in this app --\r\nDialogue: 0,0:59:33.01,0:59:35.14,yin,,0,0,0,,Resign和BecomeActive\\N{\\fs12}the resign and become active.\r\nDialogue: 0,0:59:35.16,0:59:38.24,yin,,0,0,0,,这里我又要添加一个广播站监听器\\N{\\fs12}So I'm just going to add another radio station listener here.\r\nDialogue: 0,0:59:38.24,0:59:40.93,yin,,0,0,0,,NotificationCenter defaultCenter\\N{\\fs12}Notification center, default center.\r\nDialogue: 0,0:59:40.93,0:59:44.65,yin,,0,0,0,,然后… 星球大战跑出来了\\N{\\fs12}And then a little Star Wars there.\r\nDialogue: 0,0:59:44.65,0:59:47.75,yin,,0,0,0,,然后我们将addObserverForName\\N{\\fs12}And then we're going to add observer for name.\r\nDialogue: 0,0:59:47.75,0:59:51.39,yin,,0,0,0,,这个我们要观测的广播站\\N{\\fs12}And this thing we're going to -- radio station we're going to observe --\r\nDialogue: 0,0:59:51.39,0:59:55.31,yin,,0,0,0,,叫作NSUserDefaultsDidChangeNotification\\N{\\fs12}is called NS user defaults did change notification,\r\nDialogue: 0,0:59:55.31,0:59:58.39,yin,,0,0,0,,顾名思义 用户默认确实更改通知\\N{\\fs12}exactly what you would think it would be called.\r\nDialogue: 0,0:59:58.39,1:00:03.91,yin,,0,0,0,,我们不关心谁告诉我们它变更了\\N{\\fs12}And we don't care who is going to tell us that it changed.\r\nDialogue: 0,1:00:03.91,1:00:06.52,yin,,0,0,0,,我们可以在这个队列上来做 这没问题\\N{\\fs12}And we can do it on this queue. It's fine.\r\nDialogue: 0,1:00:06.52,1:00:08.71,yin,,0,0,0,,当它变化时 我们要做什么\\N{\\fs12}And what are we going to do when it changes?\r\nDialogue: 0,1:00:08.71,1:00:14.05,yin,,0,0,0,,当然 我们只需要重置弹性\\N{\\fs12}Well, of course, we are just going to reset the elasticity.\r\nDialogue: 0,1:00:14.05,1:00:17.66,yin,,0,0,0,,这就是单独放到一个方法中的原因\\N{\\fs12}And that's why I put that in a separate method.\r\nDialogue: 0,1:00:20.97,1:00:24.22,yin,,0,0,0,,它会调用这个 它会读取那个用户默认\\N{\\fs12}So it's going to call this, it's going to read that user default,\r\nDialogue: 0,1:00:24.22,1:00:25.45,yin,,0,0,0,,更新弹性\\N{\\fs12}update the elasticity.\r\nDialogue: 0,1:00:25.45,1:00:28.19,yin,,0,0,0,,根据动态动画器我们知道\\N{\\fs12}As we know with the dynamic animator,\r\nDialogue: 0,1:00:28.19,1:00:33.86,yin,,0,0,0,,弹性值变化后 弹性马上就会受到影响\\N{\\fs12}as soon as you change that elasticity, it's going\r\nDialogue: 0,1:00:33.86,1:00:37.35,yin,,0,0,0,,弹性值变化后 弹性马上就会受到影响\\N{\\fs12}to immediately start affecting the elasticity.\r\nDialogue: 0,1:00:37.35,1:00:40.61,yin,,0,0,0,,我们试试这个\\N{\\fs12}So let's go ahead and try this.\r\nDialogue: 0,1:00:40.61,1:00:42.77,yin,,0,0,0,,看看能否正常工作\\N{\\fs12}See if this works.\r\nDialogue: 0,1:00:51.48,1:00:56.26,yin,,0,0,0,,问题是 滑动条的粒度是多大\\N{\\fs12}Yeah. So the question is: What's the granularity of the slider as we move along?\r\nDialogue: 0,1:00:56.26,1:00:57.86,yin,,0,0,0,,这要看情况\\N{\\fs12}And it depends.\r\nDialogue: 0,1:00:57.86,1:01:02.26,yin,,0,0,0,,如果是浮点数 你就可以进行任意细的划分\\N{\\fs12}If it's a float, then however wide the slider is, you know,\r\nDialogue: 0,1:01:02.26,1:01:04.42,yin,,0,0,0,,如果是浮点数 你就可以进行任意细的划分\\N{\\fs12}however many points that can be divided into,\r\nDialogue: 0,1:01:04.42,1:01:06.48,yin,,0,0,0,,这就是浮点数的粒度\\N{\\fs12}that's how much granularity you're going to get on the float.\r\nDialogue: 0,1:01:06.48,1:01:09.56,yin,,0,0,0,,如果这里是整数\\N{\\fs12}If it's an integer -- you know, if you're making integer --\r\nDialogue: 0,1:01:09.56,1:01:11.96,yin,,0,0,0,,那你就会被四舍五入到最近的整数\\N{\\fs12}then you're going to be rounding off to the nearest integer,\r\nDialogue: 0,1:01:11.96,1:01:14.04,yin,,0,0,0,,这就是从NSUserDefaults得到的情况\\N{\\fs12}right, as you get it from NS user defaults.\r\nDialogue: 0,1:01:14.04,1:01:17.29,yin,,0,0,0,,粒度一般会取决于可用的宽度\\N{\\fs12}But basically granularity depends on the width available.\r\nDialogue: 0,1:01:17.29,1:01:19.24,yin,,0,0,0,,这对于不同设备是不同的\\N{\\fs12}So it's actually going to vary per device.\r\nDialogue: 0,1:01:19.24,1:01:22.40,yin,,0,0,0,,在宽设备上 你能得到更高的粒度\\N{\\fs12}Right? On a wide device you can get a higher granularity.\r\nDialogue: 0,1:01:22.40,1:01:26.36,yin,,0,0,0,,好 这里弹性是默认值\\N{\\fs12}All right. So here we are; elasticity is default.\r\nDialogue: 0,1:01:29.76,1:01:32.27,yin,,0,0,0,,这个好难控制\\N{\\fs12}This guy's hard to control.\r\nDialogue: 0,1:01:32.27,1:01:34.89,yin,,0,0,0,,这里是正常弹性\\N{\\fs12}Okay. So we had normal elasticity going on here.\r\nDialogue: 0,1:01:34.89,1:01:38.31,yin,,0,0,0,,下面我要到设置app中\\N{\\fs12}So now I'm going to go out to the settings app.\r\nDialogue: 0,1:01:38.31,1:01:39.91,yin,,0,0,0,,找到Bouncer\\N{\\fs12}I'm going to go down to Bouncer.\r\nDialogue: 0,1:01:39.91,1:01:41.89,yin,,0,0,0,,这是Bouncer的弹性\\N{\\fs12}Here's Bouncer's elasticity.\r\nDialogue: 0,1:01:41.89,1:01:43.10,yin,,0,0,0,,它位于1\\N{\\fs12}It's at one.\r\nDialogue: 0,1:01:43.10,1:01:47.33,yin,,0,0,0,,我要把它调到最小的0\\N{\\fs12}I'm going to crank it all the way down to zero.\r\nDialogue: 0,1:01:47.33,1:01:49.69,yin,,0,0,0,,这很低 不过没关系\\N{\\fs12}Which is really low, it doesn't matter.\r\nDialogue: 0,1:01:49.69,1:01:53.16,yin,,0,0,0,,再回到Bouncer\\N{\\fs12}And let's go back to Bouncer.\r\nDialogue: 0,1:01:53.16,1:01:57.94,yin,,0,0,0,,然后方块落下时 它就不弹了\\N{\\fs12}And now when this thing bounces, doesn't bounce.\r\nDialogue: 0,1:01:57.94,1:01:59.48,yin,,0,0,0,,低弹性\\N{\\fs12}Low elasticity.\r\nDialogue: 0,1:02:04.27,1:02:05.01,yin,,0,0,0,,理解了吗\\N{\\fs12}Make sense?\r\nDialogue: 0,1:02:05.03,1:02:07.88,yin,,0,0,0,,然后我们可以回来\\N{\\fs12}And then we can go back again.\r\nDialogue: 0,1:02:07.88,1:02:10.48,yin,,0,0,0,,将弹性重新调高\\N{\\fs12}Change the elasticity back to being high.\r\nDialogue: 0,1:02:11.45,1:02:13.88,yin,,0,0,0,,回到这里 到Bouncer\\N{\\fs12}Back here to Bouncer.\r\nDialogue: 0,1:02:13.88,1:02:17.37,yin,,0,0,0,,这样就又能弹起了\\N{\\fs12}And now back to bouncing.\r\nDialogue: 0,1:02:19.23,1:02:22.00,yin,,0,0,0,,理解这里我们做的了吧\\N{\\fs12}Make sense what we did there?\r\nDialogue: 0,1:02:22.00,1:02:25.09,yin,,0,0,0,,关于这个我还要讲最后一点 也就是本地化\\N{\\fs12}Now, one last thing I want to show you about this is localization.\r\nDialogue: 0,1:02:25.09,1:02:30.30,yin,,0,0,0,,这里在设置里面显示的是elasticity\\N{\\fs12}So here we have settings elasticity.\r\nDialogue: 0,1:02:30.30,1:02:32.66,yin,,0,0,0,,这没错 因为现在是英语\\N{\\fs12}Well, that's correct because we're in English.\r\nDialogue: 0,1:02:32.66,1:02:35.07,yin,,0,0,0,,如果在这里更改语言呢\\N{\\fs12}But what happens if we go and change the language here?\r\nDialogue: 0,1:02:35.07,1:02:42.63,yin,,0,0,0,,让我们换成法语\\N{\\fs12}So let's go change to French --\r\nDialogue: 0,1:02:42.63,1:02:48.73,yin,,0,0,0,,国际 语言 法语\\N{\\fs12}international, language, French.\r\nDialogue: 0,1:02:48.73,1:02:49.58,yin,,0,0,0,,好\\N{\\fs12}All right.\r\nDialogue: 0,1:02:49.58,1:02:54.62,yin,,0,0,0,,回到设置 到下面找到Bouncer\\N{\\fs12}So now when we go back to settings and we go down to look at Bouncer.\r\nDialogue: 0,1:02:54.62,1:02:58.53,yin,,0,0,0,,虽然现在是法语 但这里它说的还是elasticity\\N{\\fs12}So we go back here and it still says elasticity even though I'm in French right now.\r\nDialogue: 0,1:02:58.53,1:03:02.50,yin,,0,0,0,,其它这些都是法语 这很棒\\N{\\fs12}So this is all in French. So we got this all in French -- nice, excellent,\r\nDialogue: 0,1:03:02.50,1:03:05.18,yin,,0,0,0,,只有Bouncer是英语\\N{\\fs12}all in French, except for Bouncer is English.\r\nDialogue: 0,1:03:05.18,1:03:08.37,yin,,0,0,0,,这个人会立刻删掉Bouncer\\N{\\fs12}So this person is immediately deleting Bouncer,\r\nDialogue: 0,1:03:08.37,1:03:11.80,yin,,0,0,0,,这个法国人因为看到英语不爽会立刻删掉Bouncer\\N{\\fs12}this French person deleting Bouncer because of the English bias.\r\nDialogue: 0,1:03:11.80,1:03:13.42,yin,,0,0,0,,如何修正这个呢\\N{\\fs12}So how do we fix that?\r\nDialogue: 0,1:03:13.42,1:03:14.34,yin,,0,0,0,,到下面这里\\N{\\fs12}Well, we go down here.\r\nDialogue: 0,1:03:14.34,1:03:17.77,yin,,0,0,0,,我们要修改这个Root.strings\\N{\\fs12}We want to change this root dot strings right here\r\nDialogue: 0,1:03:17.78,1:03:23.42,yin,,0,0,0,,写上Elasticity等于Elasticity\\N{\\fs12}to say elasticity equals elasticity.\r\nDialogue: 0,1:03:23.42,1:03:25.67,yin,,0,0,0,,这是英语中的单词\\N{\\fs12}So this is what we would want in English.\r\nDialogue: 0,1:03:25.67,1:03:29.01,yin,,0,0,0,,在法语中 我们希望这个是法语单词 或是加点的单词\\N{\\fs12}And in French we'd want this to be the French word, or the dots, or whatever.\r\nDialogue: 0,1:03:29.01,1:03:30.89,yin,,0,0,0,,如何做到呢\\N{\\fs12}So how are we going to do this?\r\nDialogue: 0,1:03:30.89,1:03:34.98,yin,,0,0,0,,这里我们需要到文件系统中手动操作\\N{\\fs12}And this is where we have to go out to the file system and do this manually.\r\nDialogue: 0,1:03:34.98,1:03:38.82,yin,,0,0,0,,做法是选择Settings Bundle\\N{\\fs12}So the way you can go out to the file system is you select the settings bundle,\r\nDialogue: 0,1:03:38.82,1:03:40.34,yin,,0,0,0,,右键点它\\N{\\fs12}right-click on it,\r\nDialogue: 0,1:03:40.34,1:03:43.77,yin,,0,0,0,,可以看到第一行就是在finder中显示\\N{\\fs12}and you can see the very first thing here is show in finder.\r\nDialogue: 0,1:03:43.77,1:03:44.59,yin,,0,0,0,,点选它\\N{\\fs12}So I'll show in finder.\r\nDialogue: 0,1:03:44.59,1:03:47.62,yin,,0,0,0,,就在这里 但它没有小三角\\N{\\fs12}Here it is, but it doesn't have a little triangle.\r\nDialogue: 0,1:03:47.62,1:03:49.51,yin,,0,0,0,,因为它是一个包\\N{\\fs12}That's because it's a package.\r\nDialogue: 0,1:03:49.51,1:03:53.48,yin,,0,0,0,,不过我可以右键点击 选显示包内容\\N{\\fs12}But I can right-click and say show package contents.\r\nDialogue: 0,1:03:53.48,1:03:55.46,yin,,0,0,0,,这时就会显示出其中的内容\\N{\\fs12}Now it will show me what's inside of it.\r\nDialogue: 0,1:03:55.46,1:03:57.02,yin,,0,0,0,,这是en.lproj\\N{\\fs12}Here's my EN dot lproj.\r\nDialogue: 0,1:03:57.02,1:03:59.36,yin,,0,0,0,,我只需要复制粘贴\\N{\\fs12}I'm just going to copy it and paste it.\r\nDialogue: 0,1:03:59.36,1:04:01.88,yin,,0,0,0,,这就有了en.lproj 2\\N{\\fs12}So now I have EN dot lproj two.\r\nDialogue: 0,1:04:01.88,1:04:07.33,yin,,0,0,0,,将它重命名为fr.lproj\\N{\\fs12}So I'm going to rename this to be FR dot lproj.\r\nDialogue: 0,1:04:07.33,1:04:11.00,yin,,0,0,0,,finder处理app的方式中有一点很有趣\\N{\\fs12}What's really kind of interesting about the way the finder works with apps\r\nDialogue: 0,1:04:11.00,1:04:14.91,yin,,0,0,0,,也就是 这些都会在你输入时同时出现在Xcode中\\N{\\fs12}is this will all be appearing in Xcode at the same time that you're typing it.\r\nDialogue: 0,1:04:14.91,1:04:17.23,yin,,0,0,0,,这里你不需要做任何特别的事情\\N{\\fs12}So you don't have to do anything special there.\r\nDialogue: 0,1:04:17.23,1:04:19.58,yin,,0,0,0,,创建目录 重命名\\N{\\fs12}As you create these directories and rename them,\r\nDialogue: 0,1:04:19.58,1:04:21.85,yin,,0,0,0,,Xcode都能很好地跟踪\\N{\\fs12}Xcode keeps track of it.\r\nDialogue: 0,1:04:21.85,1:04:25.25,yin,,0,0,0,,这是法语的Root.strings 这个则是英语的\\N{\\fs12}So here's the root dot strings for French and here's the one for English.\r\nDialogue: 0,1:04:25.25,1:04:28.98,yin,,0,0,0,,在法语的那个中 我们把这个转为加点的\\N{\\fs12}So in the French one let's change this to our dot.\r\nDialogue: 0,1:04:39.92,1:04:43.99,yin,,0,0,0,,我把这里都加上了点\\N{\\fs12}So we change this to the dots. And now let's -- yeah.\r\nDialogue: 0,1:04:43.99,1:04:47.99,yin,,0,0,0,,下面让我们来运行这个\\N{\\fs12}So now let's run this.\r\nDialogue: 0,1:04:47.99,1:04:52.54,yin,,0,0,0,,重新安装Bouncer 包括它的Settings Bundle\\N{\\fs12}Reinstall this Bouncer, including its settings bundle.\r\nDialogue: 0,1:04:52.54,1:04:54.39,yin,,0,0,0,,好 这里我们有了Bouncer\\N{\\fs12}All right. So here we have Bouncer.\r\nDialogue: 0,1:04:54.39,1:04:59.14,yin,,0,0,0,,到设置中 看Bouncer设置\\N{\\fs12}Let's go over to settings, look at Bouncer settings,\r\nDialogue: 0,1:04:59.14,1:05:02.61,yin,,0,0,0,,现在我们有了带有点的elasticity\\N{\\fs12}and now we have elasticity with the dots.\r\nDialogue: 0,1:05:04.35,1:05:06.77,yin,,0,0,0,,好 这方面有任何疑问吗\\N{\\fs12}All right. Questions about any of that?\r\nDialogue: 0,1:05:06.77,1:05:07.31,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,1:05:14.60,1:05:15.65,yin,,0,0,0,,问得棒极了\\N{\\fs12}What a great question.\r\nDialogue: 0,1:05:15.65,1:05:18.98,yin,,0,0,0,,问题是 我的app里有一些设置选项\\N{\\fs12}Okay. So the question is: If I have settings in my app\r\nDialogue: 0,1:05:18.98,1:05:22.12,yin,,0,0,0,,用户经常需要进行改变\\N{\\fs12}and the user frequently wants to change them,\r\nDialogue: 0,1:05:22.12,1:05:24.44,yin,,0,0,0,,例如弹性这些\\N{\\fs12}like let's say elasticity is something that,\r\nDialogue: 0,1:05:24.44,1:05:27.37,yin,,0,0,0,,用户可能每次游戏都希望有不同的弹性\\N{\\fs12}you know, every game you want to play with a different elasticity\r\nDialogue: 0,1:05:27.37,1:05:30.51,yin,,0,0,0,,用户希望非常频繁地去设置它\\N{\\fs12}or something like that because, you know, it's not something\r\nDialogue: 0,1:05:30.51,1:05:33.62,yin,,0,0,0,,而不是设置了就不动了\\N{\\fs12}that you just kind of set to taste and then you just leave it,\r\nDialogue: 0,1:05:33.62,1:05:36.38,yin,,0,0,0,,这时你就不应该使用设置app\\N{\\fs12}then you would not want to use the settings app.\r\nDialogue: 0,1:05:36.38,1:05:40.31,yin,,0,0,0,,用户经常要设的东西\\N{\\fs12}Settings that the user wants to set on a regular basis,\r\nDialogue: 0,1:05:40.31,1:05:44.04,yin,,0,0,0,,应该属于app的一部分\\N{\\fs12}that are a normal part the operation, those want to be in your app.\r\nDialogue: 0,1:05:44.04,1:05:49.33,yin,,0,0,0,,我们希望有一种方式能在Bouncer中设置弹性\\N{\\fs12}So we would want to have some way here in Bouncer to be able to set the elasticity\r\nDialogue: 0,1:05:49.33,1:05:52.53,yin,,0,0,0,,可能是某个手势 我们没有使用捏手势\\N{\\fs12}maybe a gesture, maybe, you know, we're not using pinching.\r\nDialogue: 0,1:05:52.53,1:05:54.21,yin,,0,0,0,,或许捏手势不错\\N{\\fs12}Maybe pinching could do it or something.\r\nDialogue: 0,1:05:54.21,1:05:57.26,yin,,0,0,0,,我是说 频繁改变的东西 你可以放到这里\\N{\\fs12}I mean, if it's something you want to change a lot, you want it here.\r\nDialogue: 0,1:05:57.26,1:05:59.23,yin,,0,0,0,,你也可以在顶部放个标题栏\\N{\\fs12}Or you have a title bar across the top\r\nDialogue: 0,1:05:59.23,1:06:01.38,yin,,0,0,0,,用一个栏按钮来处理这个\\N{\\fs12}and have a bar button for it or something.\r\nDialogue: 0,1:06:01.38,1:06:05.69,yin,,0,0,0,,设置app里面应该是些设置了以后就不用再管的东西\\N{\\fs12}Really, the settings app is set it and forget it kind of settings.\r\nDialogue: 0,1:06:05.69,1:06:09.61,yin,,0,0,0,,这些设置用户一旦设定为自己喜欢的样子\\N{\\fs12}Right? Settings that are just maybe something a user tunes\r\nDialogue: 0,1:06:09.61,1:06:11.83,yin,,0,0,0,,就不会再变了\\N{\\fs12}that they like and then it's set.\r\nDialogue: 0,1:06:11.83,1:06:16.79,yin,,0,0,0,,这里不应该是需要不断变更的东西\\N{\\fs12}It's not going to be things that you're going to set constantly.\r\nDialogue: 0,1:06:16.79,1:06:17.34,yin,,0,0,0,,有问题\\N{\\fs12}Question?\r\nDialogue: 0,1:06:24.96,1:06:28.59,yin,,0,0,0,,问题是 如果我有办法在app中设置弹性\\N{\\fs12}Yeah, so the question is: If I did have a way to set elasticity in my app,\r\nDialogue: 0,1:06:28.59,1:06:31.77,yin,,0,0,0,,我是否就肯定不应该再在设置app中设置了\\N{\\fs12}should I definitely not set them in my settings?\r\nDialogue: 0,1:06:31.77,1:06:33.64,yin,,0,0,0,,并不一定\\N{\\fs12}I would say not necessarily.\r\nDialogue: 0,1:06:33.64,1:06:35.85,yin,,0,0,0,,例如 想想如下情形\\N{\\fs12}Like, for example, you might want to --\r\nDialogue: 0,1:06:35.85,1:06:38.55,yin,,0,0,0,,假设弹性你每次游戏都想变更\\N{\\fs12}let's say elasticity is something you change with every game.\r\nDialogue: 0,1:06:38.55,1:06:41.41,yin,,0,0,0,,你点新游戏 然后它就会问你 你想要多大的弹性\\N{\\fs12}Like, you say new game and it says, \"What elasticity do you want?\"\r\nDialogue: 0,1:06:41.41,1:06:42.53,yin,,0,0,0,,这时你仍然\\N{\\fs12}It's possible you might want\r\nDialogue: 0,1:06:42.53,1:06:45.79,yin,,0,0,0,,可以在设置app中去设置默认弹性\\N{\\fs12}to have setting apps set the default elasticity, right,\r\nDialogue: 0,1:06:45.79,1:06:49.72,yin,,0,0,0,,这时程序问多大弹性时 会从这个默认值开始\\N{\\fs12}so that when it asks you about the elasticity, it starts with that default.\r\nDialogue: 0,1:06:49.72,1:06:51.57,yin,,0,0,0,,你可能会需要这样做\\N{\\fs12}So it's possible you might want to have that.\r\nDialogue: 0,1:06:51.57,1:06:53.83,yin,,0,0,0,,不过一般而言 不要把用户搞糊涂了\\N{\\fs12}But generally you don't want the user confused about,\r\nDialogue: 0,1:06:53.83,1:06:57.06,yin,,0,0,0,,让他们不知道是在这里设置 还是在那里设置\\N{\\fs12}\"Where am I setting this? Am I setting it in settings, or am I setting it here?\"\r\nDialogue: 0,1:06:57.06,1:07:01.19,yin,,0,0,0,,这时 在设置app中 你可能需要写默认弹性\\N{\\fs12}So even in that case in settings you'd probably want to call it default elasticity,\r\nDialogue: 0,1:07:01.19,1:07:04.82,yin,,0,0,0,,而这里 你需要写成弹性\\N{\\fs12}and then here you would call it elasticity or something like that.\r\nDialogue: 0,1:07:04.82,1:07:06.62,yin,,0,0,0,,问题都很不错\\N{\\fs12}So good questions.\r\nDialogue: 0,1:07:06.62,1:07:10.72,yin,,0,0,0,,关于设置还有问题吗\\N{\\fs12}Any other questions about settings?\r\nDialogue: 0,1:07:10.72,1:07:13.43,yin,,0,0,0,,好 本地化和设置\\N{\\fs12}Okay. So both localization and settings, you know,\r\nDialogue: 0,1:07:13.43,1:07:17.69,yin,,0,0,0,,这些方面你们显然都能做很多事情\\N{\\fs12}there's obviously a lot you can do here.\r\nDialogue: 0,1:07:17.69,1:07:20.53,yin,,0,0,0,,我这里只是粗浅地讲了一下\\N{\\fs12}And so I'm just kind of trying to skim the surface enough\r\nDialogue: 0,1:07:20.53,1:07:23.39,yin,,0,0,0,,让你们知道怎么开始\\N{\\fs12}so that you understand where to get started, okay,\r\nDialogue: 0,1:07:23.39,1:07:25.83,yin,,0,0,0,,涉及到 如何在设置中创建不同的UI\\N{\\fs12}in terms of \"How do I make different UI in settings,\r\nDialogue: 0,1:07:25.83,1:07:30.69,yin,,0,0,0,,以及如何让app可国际化\\N{\\fs12}and what do I do to make my app international-izable?\"\r\nDialogue: 0,1:07:30.69,1:07:33.22,yin,,0,0,0,,好 差不多就这些了\\N{\\fs12}Okay. So that's pretty much it.\r\nDialogue: 0,1:07:33.22,1:07:35.63,yin,,0,0,0,,这是后面内容的提醒\\N{\\fs12}Here is just a reminder of what's coming up.\r\nDialogue: 0,1:07:35.63,1:07:37.29,yin,,0,0,0,,我们一开始就讲过\\N{\\fs12}We talked about this at the beginning.\r\nDialogue: 0,1:07:37.31,1:07:40.81,yin,,0,0,0,,关于期末项目或任何内容有问题的人\\N{\\fs12}If you have any questions about your final projects or about anything else,\r\nDialogue: 0,1:07:40.82,1:07:44.14,yin,,0,0,0,,都可以来提 我们周三再见\\N{\\fs12}I will be here. And I will see you on Wednesday.\r\nDialogue: 0,1:07:44.88,1:07:48.77,yin,,0,0,0,,更多内容 请访问我校官网stanford.edu\\N{\\fs12}> For more, please visit us at Stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/2. Xcode 5.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.1.2\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\nLast Style Storage: Default\r\nAegisub Scroll Position: 0\r\nAegisub Active Line: 9\r\nAegisub Video Zoom Percent: 1.000000\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.25,0:00:11.50,yin,,0,0,0,, 斯坦福大学 \\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:11.50,0:00:20.86,yin,,0,0,0,, 欢迎来到 2013/2014 学年秋 CS193P 课程的第二课 \\N{\\fs12}Well, welcome to lecture number two of CS 193P for fall of 2013/2014 academic year.\r\nDialogue: 0,0:00:20.86,0:00:24.99,yin,,0,0,0,, 今天最开始我们将有一些幻灯片 \\N{\\fs12}And today we’re going to have some slides at the beginning,\r\nDialogue: 0,0:00:24.99,0:00:28.95,yin,,0,0,0,, 一点讲课 然后我将有一个很大的 demo\\N{\\fs12}little more talking, and then I’m going to have quite a big demo that’s going to try\r\nDialogue: 0,0:00:28.95,0:00:31.22,yin,,0,0,0,, 我希望用它来综合前两讲 \\N{\\fs12}and hopefully synthesize all the things I’ve been talking\r\nDialogue: 0,0:00:31.22,0:00:33.57,yin,,0,0,0,, 我讲过的这些内容 \\N{\\fs12}about on the slides for the first two lectures,\r\nDialogue: 0,0:00:33.59,0:00:36.85,yin,,0,0,0,, 也就是 我们将开始创建我们的纸牌游戏 \\N{\\fs12}which is that we’re going to start building our card game.\r\nDialogue: 0,0:00:36.85,0:00:38.64,yin,,0,0,0,, 这个纸牌匹配游戏 \\N{\\fs12}Okay. This card matching game\r\nDialogue: 0,0:00:38.64,0:00:43.70,yin,,0,0,0,, 将是我们头两周的基础材料 用以学习 Objective-C\\N{\\fs12}is going to be our substrate for the first two weeks of learning some Objective-C,\r\nDialogue: 0,0:00:43.70,0:00:47.87,yin,,0,0,0,, 学习 Xcode 学习 iOS 如何衔接起 \\N{\\fs12}learning about Xcode, learning about how iOS hooks\r\nDialogue: 0,0:00:47.87,0:00:52.54,yin,,0,0,0,, 控制器 视图以及模型 来建立 UI\\N{\\fs12}up the controller, and the view, and the model to make a UI.\r\nDialogue: 0,0:00:52.54,0:00:58.95,yin,,0,0,0,, 记得上次 我讲了这整个 Card 类 \\N{\\fs12}So if you remember from last time, we did this card thing that — we did the entire card.\r\nDialogue: 0,0:00:58.95,0:01:00.24,yin,,0,0,0,, 这个类很简单 \\N{\\fs12}It was a very simple class.\r\nDialogue: 0,0:01:00.24,0:01:04.11,yin,,0,0,0,, 它有三个属性和一个方法 \\N{\\fs12}Got a couple of properties — three properties there — and one method.\r\nDialogue: 0,0:01:04.11,0:01:05.73,yin,,0,0,0,, 就这么简单 \\N{\\fs12}And that’s pretty much it.\r\nDialogue: 0,0:01:05.73,0:01:09.84,yin,,0,0,0,, 今天我们将继续考虑另一个类 也就是 Deck\\N{\\fs12}And so today we’re going to go on and do another class, which is a deck.\r\nDialogue: 0,0:01:09.84,0:01:11.36,yin,,0,0,0,, 表示牌堆 \\N{\\fs12}The deck of cards.\r\nDialogue: 0,0:01:11.36,0:01:14.90,yin,,0,0,0,, 记住 Card 和 Deck 是通用的 \\N{\\fs12}And remember, that card and deck are generic;\r\nDialogue: 0,0:01:14.90,0:01:17.30,yin,,0,0,0,, 它们并非专门针对扑克牌 \\N{\\fs12}they’re not specific to playing cards, right?\r\nDialogue: 0,0:01:17.30,0:01:20.19,yin,,0,0,0,, 扑克牌是 PlayingCard 诸如梅花 A 红心 K 这些 \\N{\\fs12}A playing card, like the ace of clubs or the king of hearts –\r\nDialogue: 0,0:01:20.19,0:01:22.79,yin,,0,0,0,, 扑克牌是 PlayingCard 诸如梅花 A 红心 K 这些 \\N{\\fs12}something that has all that in it — that’s a playing card thing.\r\nDialogue: 0,0:01:22.79,0:01:24.38,yin,,0,0,0,, 这里是笼统的纸牌和牌堆 \\N{\\fs12}These are general cards and decks.\r\nDialogue: 0,0:01:24.38,0:01:26.66,yin,,0,0,0,, 可以是一副抽认卡 \\N{\\fs12}So this could be a deck of flash cards,\r\nDialogue: 0,0:01:26.66,0:01:30.56,yin,,0,0,0,, 一副外语单词卡等等 \\N{\\fs12}a deck of foreign language words you’re trying to learn or whatever.\r\nDialogue: 0,0:01:30.56,0:01:33.90,yin,,0,0,0,, 所以 我们希望这些 Deck 和 Card 类具有通用性 \\N{\\fs12}So we’re trying to keep these deck and card classes somewhat generic.\r\nDialogue: 0,0:01:33.90,0:01:34.84,yin,,0,0,0,, 这是 Deck\\N{\\fs12}So here’s deck.\r\nDialogue: 0,0:01:34.84,0:01:37.68,yin,,0,0,0,, 其基础结构你们应该熟悉 \\N{\\fs12}It should look familiar in terms of its basic structure, right?\r\nDialogue: 0,0:01:37.68,0:01:40.79,yin,,0,0,0,, 这里导入我们的父类框架 \\N{\\fs12}We’re importing our superclasses framework there,\r\nDialogue: 0,0:01:40.79,0:01:45.44,yin,,0,0,0,, 然后在实现中导入我们的头文件 \\N{\\fs12}and then obviously importing our own header file in our implementation.\r\nDialogue: 0,0:01:45.44,0:01:50.31,yin,,0,0,0,,Deck 的接口将有这样两个基础方法 \\N{\\fs12}And the interface for deck is going to have these two kind of fundamental methods:\r\nDialogue: 0,0:01:50.31,0:01:52.15,yin,,0,0,0,, 一是将纸牌加到牌堆中 \\N{\\fs12}One adds a card to the deck\r\nDialogue: 0,0:01:52.15,0:01:55.59,yin,,0,0,0,, 一是随机从牌堆中抽取一张牌 \\N{\\fs12}and one draws a random card out of the deck.\r\nDialogue: 0,0:01:55.59,0:02:00.82,yin,,0,0,0,, 添加纸牌到牌堆中的方法对你们而言有些新 \\N{\\fs12}And the add a card to the deck is a little bit new to you\r\nDialogue: 0,0:02:00.82,0:02:03.15,yin,,0,0,0,, 因为你们会看到它有两个参数 \\N{\\fs12}because you can see it has two arguments.\r\nDialogue: 0,0:02:03.15,0:02:05.88,yin,,0,0,0,, 这是你们第一次看到有两个参数的方法 \\N{\\fs12}This is the first method you’ve seen that has two arguments.\r\nDialogue: 0,0:02:05.88,0:02:08.62,yin,,0,0,0,, 之前你们看到的方法要么是没有参数 \\N{\\fs12}So far you’ve only seen methods with no arguments or a method\r\nDialogue: 0,0:02:08.62,0:02:10.71,yin,,0,0,0,, 要么只有一个参数 如 match\\N{\\fs12}with one argument like that — match –\r\nDialogue: 0,0:02:10.72,0:02:13.91,yin,,0,0,0,,match 只有一个参数 或 setter 也只有一个参数 \\N{\\fs12}match had one argument or the setters, they also have one argument.\r\nDialogue: 0,0:02:13.91,0:02:17.79,yin,,0,0,0,, 注意 Objective-C 中当你有多个参数时 \\N{\\fs12}So notice that when you have multiple arguments\r\nDialogue: 0,0:02:17.79,0:02:22.23,yin,,0,0,0,, 它们会穿插在方法名中间 \\N{\\fs12}in objective C, they’re kind of interspersed with the names of the methods.\r\nDialogue: 0,0:02:22.23,0:02:28.20,yin,,0,0,0,, 这个方法的名称是 addCard 冒号 atTop 冒号 \\N{\\fs12}So the name of this method, this long method is add card colon at top colon.\r\nDialogue: 0,0:02:28.20,0:02:29.95,yin,,0,0,0,, 这是该方法的名称 \\N{\\fs12}That’s the name of this method.\r\nDialogue: 0,0:02:29.95,0:02:33.32,yin,,0,0,0,,atTop 这部分其实也是方法名的一部分 \\N{\\fs12}So the at top part is actually part of the name of this method.\r\nDialogue: 0,0:02:33.32,0:02:35.56,yin,,0,0,0,, 而参数 像这里要加的纸牌 card\\N{\\fs12}And the arguments, like the card that you’re going to add\r\nDialogue: 0,0:02:35.56,0:02:38.19,yin,,0,0,0,, 和表示在牌堆上方还是下方的布尔值 atTop\\N{\\fs12}and at top — which is a Boolean whether to add it at the top\r\nDialogue: 0,0:02:38.19,0:02:40.34,yin,,0,0,0,, 和表示在牌堆上方还是下方的布尔值 atTop\\N{\\fs12}of the deck or at the bottom of the deck –\r\nDialogue: 0,0:02:40.34,0:02:43.58,yin,,0,0,0,, 这些参数穿插在方法名中间 \\N{\\fs12}those arguments are interspersed.\r\nDialogue: 0,0:02:43.58,0:02:47.68,yin,,0,0,0,, 等下你们会看到 这种方法如何调用 \\N{\\fs12}And we’ll see how you call such a method in a moment here.\r\nDialogue: 0,0:02:47.68,0:02:50.80,yin,,0,0,0,, 然后随机抽取一张牌的方法 \\N{\\fs12}And then draw a random card is like a, you know,\r\nDialogue: 0,0:02:50.80,0:02:55.14,yin,,0,0,0,, 没有参数 会返回一个值 这方面同 getter 类似 \\N{\\fs12}similar to a getter in that it returns a value and it has no arguments.\r\nDialogue: 0,0:02:55.14,0:02:58.70,yin,,0,0,0,, 但这不是 getter 因为我们没有将它作为一个属性 \\N{\\fs12}But this is not a getter because we didn’t make this a property.\r\nDialogue: 0,0:02:58.70,0:03:00.65,yin,,0,0,0,, 很重要的一点是 \\N{\\fs12}And it’s kind of important\r\nDialogue: 0,0:03:00.65,0:03:02.62,yin,,0,0,0,, 你可以把它弄成一个属性 \\N{\\fs12}to understand you could have made this a property\r\nDialogue: 0,0:03:02.62,0:03:04.97,yin,,0,0,0,, 例如只读属性这些 \\N{\\fs12}like a read-only property or something that reads it,\r\nDialogue: 0,0:03:04.97,0:03:08.52,yin,,0,0,0,, 但随机抽取一张牌做了一些事情 \\N{\\fs12}but since draw a random card kind of does something,\r\nDialogue: 0,0:03:08.52,0:03:12.32,yin,,0,0,0,, 它有一个算法 一个机制 \\N{\\fs12}it has kind of an algorithm to it — a mechanism –\r\nDialogue: 0,0:03:12.32,0:03:13.91,yin,,0,0,0,, 通常不要把它弄成属性 \\N{\\fs12}you usually wouldn’t make that a property.\r\nDialogue: 0,0:03:13.91,0:03:16.54,yin,,0,0,0,, 让 getter 做这个可以说是滥用 \\N{\\fs12}It’s kind of an abuse of a getter to do that.\r\nDialogue: 0,0:03:16.54,0:03:18.81,yin,,0,0,0,,getter 的作用只是设置和获取一个值 \\N{\\fs12}A getter is really just setting and getting a value.\r\nDialogue: 0,0:03:18.81,0:03:22.20,yin,,0,0,0,, 它可能有副作用 设置可能更新 UI\\N{\\fs12}It might have side effects, like setting it might update the UI\r\nDialogue: 0,0:03:22.21,0:03:26.16,yin,,0,0,0,, 或者获取可能确保先初始化了 诸如此类 \\N{\\fs12}or getting it might make sure it’s initialized first — those kind of things.\r\nDialogue: 0,0:03:26.16,0:03:28.02,yin,,0,0,0,, 做一些事的方法 \\N{\\fs12}You’re not going to — something that does something\r\nDialogue: 0,0:03:28.02,0:03:31.87,yin,,0,0,0,, 例如抽取一张牌不要弄成属性 \\N{\\fs12}like drawing a card is not going to be a property.\r\nDialogue: 0,0:03:31.87,0:03:36.95,yin,,0,0,0,, 如果你想要 atTop 这样的参数可选 \\N{\\fs12}Now, if you want to have, like, that at top argument be optional,\r\nDialogue: 0,0:03:36.95,0:03:39.77,yin,,0,0,0,,Objective-C 中的唯一做法是 \\N{\\fs12}okay, the only way to do that in Objective-C –\r\nDialogue: 0,0:03:39.77,0:03:42.42,yin,,0,0,0,, 显然我们这里需要一个头文件 \\N{\\fs12}obviously we need our header file there –\r\nDialogue: 0,0:03:42.42,0:03:44.01,yin,,0,0,0,,Objective-C 中唯一的做法是 \\N{\\fs12}the only way to do that in Objective-C is\r\nDialogue: 0,0:03:44.01,0:03:48.86,yin,,0,0,0,, 声明新方法 addCard: 不带 atTop\\N{\\fs12}to declare a new method, add card colon with no at top on it.\r\nDialogue: 0,0:03:48.86,0:03:51.49,yin,,0,0,0,, 这是一个完全不同的方法 \\N{\\fs12}So this is a totally different method, totally unrelated\r\nDialogue: 0,0:03:51.49,0:03:54.71,yin,,0,0,0,, 只不过在实现中 我们需要调用另一个方法 \\N{\\fs12}to the other method except for that in its implementation\r\nDialogue: 0,0:03:54.71,0:03:57.84,yin,,0,0,0,, 只不过在实现中 我们需要调用另一个方法 \\N{\\fs12}of this other method we’re just going to call the other one.\r\nDialogue: 0,0:03:57.84,0:04:00.03,yin,,0,0,0,, 所以 addCard 中 我们会说 self addCard\\N{\\fs12}So in add card we’re going to say self add card\r\nDialogue: 0,0:04:00.03,0:04:00.89,yin,,0,0,0,,atTop:\\N{\\fs12}at top colon,\r\nDialogue: 0,0:04:00.89,0:04:03.97,yin,,0,0,0,, 后面跟默认情况 这里也就是 NO\\N{\\fs12}whatever we want the default to be, which I’m going to say is no.\r\nDialogue: 0,0:04:03.97,0:04:07.42,yin,,0,0,0,, 这里只是要你们理解 在某些语言中 \\N{\\fs12}So just understand that, you know, in some languages,\r\nDialogue: 0,0:04:07.42,0:04:10.61,yin,,0,0,0,, 某些参数可以是可选的 \\N{\\fs12}like, some arguments can be optional or you can kind\r\nDialogue: 0,0:04:10.61,0:04:16.17,yin,,0,0,0,, 或者重载 让相同方法具有不同参数 \\N{\\fs12}of overload things to have the same method name have different arguments.\r\nDialogue: 0,0:04:16.17,0:04:19.69,yin,,0,0,0,, 不像 Objective-C 中 每种方法完全不同 \\N{\\fs12}No. In Objective-C every method is completely distinct\r\nDialogue: 0,0:04:19.69,0:04:21.15,yin,,0,0,0,, 有不同的名称 \\N{\\fs12}and has a distinct name.\r\nDialogue: 0,0:04:21.15,0:04:23.86,yin,,0,0,0,, 多出来的参数会像这样穿插 \\N{\\fs12}And extra arguments are interspersed like that.\r\nDialogue: 0,0:04:23.86,0:04:26.24,yin,,0,0,0,, 所以 这是两种不同方法 \\N{\\fs12}So these would be two different methods.\r\nDialogue: 0,0:04:26.24,0:04:27.59,yin,,0,0,0,, 能理解吗 \\N{\\fs12}That make sense?\r\nDialogue: 0,0:04:27.59,0:04:31.71,yin,,0,0,0,, 好 我们再来看看 Deck 的实现 \\N{\\fs12}All right. So let’s talk about our implementation of our deck.\r\nDialogue: 0,0:04:31.71,0:04:34.48,yin,,0,0,0,,Deck 包含一些纸牌 \\N{\\fs12}So our deck is just going to contain a bunch of cards.\r\nDialogue: 0,0:04:34.48,0:04:38.29,yin,,0,0,0,, 我们需要某种内部数据结构来存储所有这些牌 \\N{\\fs12}We need some sort of internal data structure to store all our cards in.\r\nDialogue: 0,0:04:38.29,0:04:43.45,yin,,0,0,0,, 我们将会用到的是一个可变数组 \\N{\\fs12}And what we’re going do is we’re going to get a mutable array.\r\nDialogue: 0,0:04:43.45,0:04:47.59,yin,,0,0,0,, 你们已经见过 NSArray 类 这是一种基础类数组 \\N{\\fs12}So you’ve already seen the class NS array, which is the foundation class array,\r\nDialogue: 0,0:04:47.59,0:04:49.25,yin,,0,0,0,, 其中是一组对象 \\N{\\fs12}which is an array of objects.\r\nDialogue: 0,0:04:49.25,0:04:51.69,yin,,0,0,0,, 数组中这些对象可以是任何类的 \\N{\\fs12}Those objects, by the way, in array can be of any class.\r\nDialogue: 0,0:04:51.69,0:04:56.95,yin,,0,0,0,, 数组中是哪类对象没法指定 \\N{\\fs12}There’s really no way to specify what kind of class of object is in an array.\r\nDialogue: 0,0:04:56.95,0:04:58.46,yin,,0,0,0,, 有些语言让你这样做 \\N{\\fs12}Some languages allow you to do that.\r\nDialogue: 0,0:04:58.46,0:05:02.80,yin,,0,0,0,, 你可以指定”这是字符串数组” 它于是知道 \\N{\\fs12}You can specify “This is an array of strings” and it knows that.\r\nDialogue: 0,0:05:02.80,0:05:04.38,yin,,0,0,0,, 但 Objective-C 不能这样 \\N{\\fs12}But in Objective-C you can’t do that.\r\nDialogue: 0,0:05:04.38,0:05:06.97,yin,,0,0,0,, 我将讲到我们怎么处理这个 \\N{\\fs12}And we’re going to talk about how we deal with that.\r\nDialogue: 0,0:05:06.99,0:05:08.93,yin,,0,0,0,, 这在 Objective-C 中有些狂放 \\N{\\fs12}That’s a little bit of the wild west of Objective-C,\r\nDialogue: 0,0:05:08.93,0:05:11.75,yin,,0,0,0,, 不过如果想确保安全的话 \\N{\\fs12}but there are ways to kind of check and see what the objects\r\nDialogue: 0,0:05:11.75,0:05:14.46,yin,,0,0,0,, 我们有办法检查对象是什么 \\N{\\fs12}are if you want to be really safe about it.\r\nDialogue: 0,0:05:14.46,0:05:16.35,yin,,0,0,0,, 而这里 我们用这个可变数组 \\N{\\fs12}But in this case we just have this mutable array.\r\nDialogue: 0,0:05:16.35,0:05:18.95,yin,,0,0,0,, 可变意思是说我们可以给数组添加对象 \\N{\\fs12}And mutable means that we can add objects to the array.\r\nDialogue: 0,0:05:18.95,0:05:21.84,yin,,0,0,0,, 一般的 NSArray 都是不可变的 \\N{\\fs12}Normally an NS array is immutable.\r\nDialogue: 0,0:05:21.84,0:05:24.39,yin,,0,0,0,, 创建后 不管其中放入了什么对象 \\N{\\fs12}Once it’s created, whatever objects enter it,\r\nDialogue: 0,0:05:24.39,0:05:25.62,yin,,0,0,0,, 这些对象就永远在里面 \\N{\\fs12}that’s the objects that are in it forever –\r\nDialogue: 0,0:05:25.62,0:05:27.91,yin,,0,0,0,, 你无法将它们删除 也无法继续添加 \\N{\\fs12}you can’t take any out and you can’t put any in.\r\nDialogue: 0,0:05:27.91,0:05:29.80,yin,,0,0,0,, 如果我们希望数组能添加东西 \\N{\\fs12}So if we want array where we can add stuff,\r\nDialogue: 0,0:05:29.80,0:05:33.31,yin,,0,0,0,, 我们需要使用 NSArray 的子类 NSMutableArray\\N{\\fs12}we have to use this subclass of NS array called NS mutable array.\r\nDialogue: 0,0:05:33.31,0:05:35.79,yin,,0,0,0,, 可以看到 它是一个属性 \\N{\\fs12}You can see that it’s a property.\r\nDialogue: 0,0:05:35.79,0:05:38.53,yin,,0,0,0,, 它是强的 因为我们希望只要指着数组时 \\N{\\fs12}It’s strong because we want this array to stay in the heap\r\nDialogue: 0,0:05:38.53,0:05:40.55,yin,,0,0,0,, 它就应该保留在堆中 \\N{\\fs12}as long as we’re pointing at it.\r\nDialogue: 0,0:05:40.55,0:05:43.06,yin,,0,0,0,, 当然 还有我们总会加的非原子性 \\N{\\fs12}And of course, we always put nonatomic there.\r\nDialogue: 0,0:05:43.08,0:05:45.94,yin,,0,0,0,, 这就是一个纸牌的数组 \\N{\\fs12}So this is going to be an array of cards.\r\nDialogue: 0,0:05:45.94,0:05:49.84,yin,,0,0,0,, 有了这个之后 我们可以轻松实现 addCard\\N{\\fs12}Now that we have this, we could easily implement add card,\r\nDialogue: 0,0:05:49.84,0:05:54.38,yin,,0,0,0,, 例如 我们可以说 “如果在顶部 那么插入对象”\\N{\\fs12}for example, by just saying, “If at top, then insert object,”\r\nDialogue: 0,0:05:54.38,0:05:57.86,yin,,0,0,0,,card 是这个方法的第一个参数 \\N{\\fs12}the card, which is the argument to this method — first argument –\r\nDialogue: 0,0:05:57.86,0:05:59.20,yin,,0,0,0,, 在下标 0 处 \\N{\\fs12}”at index zero.”\r\nDialogue: 0,0:05:59.20,0:06:03.97,yin,,0,0,0,,insertObject atIndex 是 NSMutableArray 中的方法 \\N{\\fs12}So insert object at index is a method in NS mutable array,\r\nDialogue: 0,0:06:03.97,0:06:07.28,yin,,0,0,0,, 不是在 NSArray 中 而是 NSMutableArray 中 \\N{\\fs12}not in NS array — only in NS mutable array\r\nDialogue: 0,0:06:07.29,0:06:09.03,yin,,0,0,0,, 因为这会让数组变化 \\N{\\fs12}because that would be mutating it –\r\nDialogue: 0,0:06:09.03,0:06:11.99,yin,,0,0,0,, 该方法是将对象插入到数组指定下标处 \\N{\\fs12}that inserts the object at that index in the array\r\nDialogue: 0,0:06:11.99,0:06:13.74,yin,,0,0,0,, 下标 0 表示是在顶端 \\N{\\fs12}and index zero is going to be the top\r\nDialogue: 0,0:06:13.74,0:06:15.16,yin,,0,0,0,, 我们会定义的 \\N{\\fs12}that we’re going to define.\r\nDialogue: 0,0:06:15.16,0:06:17.06,yin,,0,0,0,, 如果我们不把它放到顶部 那就放在底部 \\N{\\fs12}And then otherwise if we’re not going to put it at the\r\nDialogue: 0,0:06:17.06,0:06:17.91,yin,,0,0,0,, 如果我们不把它放到顶部 那就放在底部 \\N{\\fs12}top, we’re going to put it at the bottom,\r\nDialogue: 0,0:06:17.91,0:06:21.14,yin,,0,0,0,, 这要用到另一个 NSMutableArray 方法 addObject\\N{\\fs12}we’re going to use a different NS mutable array method called add object.\r\nDialogue: 0,0:06:21.14,0:06:23.88,yin,,0,0,0,, 作用是将数组添加到数组末尾 \\N{\\fs12}And that just adds something at the end of the array.\r\nDialogue: 0,0:06:23.88,0:06:25.36,yin,,0,0,0,, 大家都明白了吗 \\N{\\fs12}So everyone cool with that?\r\nDialogue: 0,0:06:25.36,0:06:27.53,yin,,0,0,0,, 这里给出这些方法只是为了 \\N{\\fs12}So I mostly just put this method in here just\r\nDialogue: 0,0:06:27.53,0:06:30.73,yin,,0,0,0,, 展示给你们可变数组的不同方法 \\N{\\fs12}to show you there’s a couple of different methods on mutable array and,\r\nDialogue: 0,0:06:30.73,0:06:32.97,yin,,0,0,0,, 以及如何使用参数 \\N{\\fs12}you know, how we can use the arguments.\r\nDialogue: 0,0:06:32.97,0:06:35.02,yin,,0,0,0,, 这里并没有什么大不了 \\N{\\fs12}It’s no big thing here;\r\nDialogue: 0,0:06:35.03,0:06:38.21,yin,,0,0,0,, 只是为了让你们习惯这里的情况 \\N{\\fs12}it’s just kind of to get more used to what’s going on here.\r\nDialogue: 0,0:06:38.21,0:06:40.97,yin,,0,0,0,, 好 这是 addCard 非常非常简单 \\N{\\fs12}All right. So that’s add card. Very, very simple.\r\nDialogue: 0,0:06:40.97,0:06:43.14,yin,,0,0,0,, 不过有个问题 \\N{\\fs12}And there’s a problem, though.\r\nDialogue: 0,0:06:43.14,0:06:49.18,yin,,0,0,0,, 在这个 addCard 中 如果我们只是创建一个 Deck\\N{\\fs12}In this add card, if we just created a deck\r\nDialogue: 0,0:06:49.18,0:06:52.23,yin,,0,0,0,, 然后调用 addCard 它无法奏效 \\N{\\fs12}and then called add card, it would not work.\r\nDialogue: 0,0:06:52.23,0:06:53.93,yin,,0,0,0,, 它什么都做不了 \\N{\\fs12}It would do nothing.\r\nDialogue: 0,0:06:53.93,0:06:55.48,yin,,0,0,0,, 为什么呢 \\N{\\fs12}Why would it do nothing?\r\nDialogue: 0,0:06:55.48,0:06:58.78,yin,,0,0,0,, 因为属性 cards\\N{\\fs12}Because the property cards, okay –\r\nDialogue: 0,0:06:58.78,0:07:01.40,yin,,0,0,0,,self.cards 是我们访问属性的方式 \\N{\\fs12}self.cards is how we’re accessing our own property –\r\nDialogue: 0,0:07:01.40,0:07:05.23,yin,,0,0,0,, 其 getter 根据默认是那样的 \\N{\\fs12}its getter looks like that by default.\r\nDialogue: 0,0:07:05.23,0:07:07.63,yin,,0,0,0,, 如果我们不自定义 getter getter 就是那样 \\N{\\fs12}If we don’t give a getter, that’s what the getter looks like.\r\nDialogue: 0,0:07:07.63,0:07:10.58,yin,,0,0,0,, 它会返回这个_cards 实例变量 \\N{\\fs12}It’s just going to return this underbar cards instance variable.\r\nDialogue: 0,0:07:10.58,0:07:14.30,yin,,0,0,0,, 而这个_cards 实例变量最开始会是 0\\N{\\fs12}Well, that underbar cards instance variable’s going to start out at zero\r\nDialogue: 0,0:07:14.30,0:07:18.59,yin,,0,0,0,, 因为 Objective-C 中所有实例变量都从 0 开始 \\N{\\fs12}because all instance variables in an Objective-C object start out zero.\r\nDialogue: 0,0:07:18.59,0:07:19.44,yin,,0,0,0,, 所有 \\N{\\fs12}All of them.\r\nDialogue: 0,0:07:19.44,0:07:21.88,yin,,0,0,0,, 包括指针 \\N{\\fs12}So including pointers.\r\nDialogue: 0,0:07:21.88,0:07:24.90,yin,,0,0,0,, 那个指针会是 0 也就是 nil\\N{\\fs12}So that pointer will be zero, which is we call nil,\r\nDialogue: 0,0:07:24.90,0:07:29.37,yin,,0,0,0,, 也就是说它没有指向任何东西 也就是说没有数组 \\N{\\fs12}which means it doesn’t point to anything, which means there is no array.\r\nDialogue: 0,0:07:29.37,0:07:33.18,yin,,0,0,0,, 指向数组的指针现在什么都没指到 \\N{\\fs12}We got a pointer to an array that doesn’t point to anything right now.\r\nDialogue: 0,0:07:33.18,0:07:34.67,yin,,0,0,0,, 这是一个问题 \\N{\\fs12}So that’s a problem.\r\nDialogue: 0,0:07:34.67,0:07:36.85,yin,,0,0,0,, 所以当我们执行 addCard 中 \\N{\\fs12}So when we execute the code in add card\r\nDialogue: 0,0:07:36.85,0:07:39.67,yin,,0,0,0,,self.cards addObject:card 这样的代码时 \\N{\\fs12}like self.cards add object card,\r\nDialogue: 0,0:07:39.67,0:07:43.78,yin,,0,0,0,, 程序不会崩溃 但也不会做任何事情 \\N{\\fs12}that’s going to not crash but not do anything, either.\r\nDialogue: 0,0:07:43.78,0:07:47.44,yin,,0,0,0,, 因为我说过 你可以将消息发送给 nil\\N{\\fs12}Because I told you that you can send messages to nil,\r\nDialogue: 0,0:07:47.44,0:07:51.75,yin,,0,0,0,, 发送消息给没有指向任何对象的指针 \\N{\\fs12}send messages to pointers, to objects where it’s not pointing to one at the time,\r\nDialogue: 0,0:07:51.77,0:07:53.71,yin,,0,0,0,, 这不会崩溃掉 \\N{\\fs12}and it will not crash.\r\nDialogue: 0,0:07:53.71,0:07:58.35,yin,,0,0,0,, 如果发送返回某个值的消息 该消息不会执行任何代码 \\N{\\fs12}If you send a message that returns a value, that message will not execute any code\r\nDialogue: 0,0:07:58.35,0:07:59.89,yin,,0,0,0,, 它会返回 0\\N{\\fs12}but it will return zero.\r\nDialogue: 0,0:07:59.89,0:08:02.14,yin,,0,0,0,, 这里只是一堆 0 在飞舞 \\N{\\fs12}So a lot of zeros flying around here.\r\nDialogue: 0,0:08:02.14,0:08:04.05,yin,,0,0,0,, 这个如何修正呢 \\N{\\fs12}So how are we going to fix this?\r\nDialogue: 0,0:08:04.05,0:08:06.57,yin,,0,0,0,, 我们如何让 addCard 工作呢 \\N{\\fs12}How are we going make it so that add card works?\r\nDialogue: 0,0:08:06.57,0:08:09.49,yin,,0,0,0,, 我们可以在 addCard 最开始加这样一段 \\N{\\fs12}Well, we could put something at the beginning of add card that says,\r\nDialogue: 0,0:08:09.51,0:08:12.56,yin,,0,0,0,, 如果 self.cards 为 nil\\N{\\fs12}”If self.cards is nil,\r\nDialogue: 0,0:08:12.56,0:08:17.79,yin,,0,0,0,, 那么在堆中分配一个数组并指向它 我们会用到它 \\N{\\fs12}then go allocate an array in the heap and point to it, and then we’ll use it.”\r\nDialogue: 0,0:08:17.79,0:08:21.12,yin,,0,0,0,, 这就意味着每次使用 self.cards 时 \\N{\\fs12}But that would mean every single time we have to use self.cards\r\nDialogue: 0,0:08:21.12,0:08:23.56,yin,,0,0,0,, 我们都需要检验它是否为 nil\\N{\\fs12}we’d have to go around and check and make sure it’s not nil.\r\nDialogue: 0,0:08:23.56,0:08:25.35,yin,,0,0,0,, 这很让人不爽 \\N{\\fs12}And that would be very annoying.\r\nDialogue: 0,0:08:25.35,0:08:29.35,yin,,0,0,0,, 这很易于出错 易于产生 bug 我们可能忘记掉 \\N{\\fs12}That would be very error-prone, bug-prone, we forget to do it somewhere.\r\nDialogue: 0,0:08:29.35,0:08:30.31,yin,,0,0,0,, 所有这些 \\N{\\fs12}All these things.\r\nDialogue: 0,0:08:30.31,0:08:35.32,yin,,0,0,0,, 所以 加入这一段的最佳位置是在 getter 中 \\N{\\fs12}So a great place to do that little if check is in the getter.\r\nDialogue: 0,0:08:35.32,0:08:37.22,yin,,0,0,0,, 也就是 cards 的那个 getter\\N{\\fs12}That getter that we have right there for cards –\r\nDialogue: 0,0:08:37.22,0:08:40.27,yin,,0,0,0,, 这是私有属性 cards 的 getter\\N{\\fs12}that’s the getter for our private property cards –\r\nDialogue: 0,0:08:40.27,0:08:42.54,yin,,0,0,0,, 我们让这里不仅仅是返回_cards\\N{\\fs12}instead of just returning the cards,\r\nDialogue: 0,0:08:42.54,0:08:47.26,yin,,0,0,0,, 前面我们再加一行 如果_cards 为 nil\\N{\\fs12}let’s put a line right in front that says, “If the cards is nil,\r\nDialogue: 0,0:08:47.26,0:08:52.19,yin,,0,0,0,, 那么 我们就要在堆中分配空间 并赋值给实例变量 \\N{\\fs12}then let’s go allocate one in the heap and assign it to the instance variable.”\r\nDialogue: 0,0:08:52.19,0:08:57.73,yin,,0,0,0,, 这里在堆中分配数组的方式是用 \\N{\\fs12}So the way you allocate an array in the heap is\r\nDialogue: 0,0:08:57.73,0:09:00.39,yin,,0,0,0,,[[NSMutableArray alloc] init]\\N{\\fs12}you use NS mutable array alloc init.\r\nDialogue: 0,0:09:00.39,0:09:04.17,yin,,0,0,0,, 这是两个消息调用嵌套在一起 \\N{\\fs12}So that’s two message calls nested inside of each other.\r\nDialogue: 0,0:09:04.17,0:09:06.26,yin,,0,0,0,,alloc 在堆中分配内存 \\N{\\fs12}The alloc allocates the memory in the heap,\r\nDialogue: 0,0:09:06.26,0:09:10.54,yin,,0,0,0,,init 则用于初始化内存 让它成为一个合理的数组 \\N{\\fs12}and init initializes that memory so that it’s a, you know, sensible array.\r\nDialogue: 0,0:09:10.54,0:09:15.29,yin,,0,0,0,, 过几张幻灯片 我会讲到如何构建我们自己的初始化程序 \\N{\\fs12}And we’re going to see how we build our own initializer in a couple slides here.\r\nDialogue: 0,0:09:15.29,0:09:20.97,yin,,0,0,0,, 这样一来 每次调用 self.cards 都能保证它不是 nil\\N{\\fs12}So this way every single time you call self.cards, you can be sure that it’s not nil;\r\nDialogue: 0,0:09:20.97,0:09:23.69,yin,,0,0,0,, 它至少会是一个空数组 \\N{\\fs12}it’s at least going to be an empty array.\r\nDialogue: 0,0:09:23.71,0:09:25.91,yin,,0,0,0,, 大家都明白这段代码了吗 \\N{\\fs12}Does everyone understand this code?\r\nDialogue: 0,0:09:25.91,0:09:28.51,yin,,0,0,0,, 理解这个非常重要 请讲 \\N{\\fs12}It’s important to understand this. Yeah.\r\nDialogue: 0,0:09:28.51,0:09:37.47,yin,,0,0,0,,[学生提问 声音不清]\\N{\\fs12}> [Inaudible]\r\nDialogue: 0,0:09:37.48,0:09:39.61,yin,,0,0,0,,Paul Hegarty：好 问题是 \\N{\\fs12}> Paul Hegarty: Okay. So the question is:\r\nDialogue: 0,0:09:39.62,0:09:42.90,yin,,0,0,0,, 可不可以不将初始化代码放到这个 getter 中 \\N{\\fs12}Instead of having this initialization code be in this getter,\r\nDialogue: 0,0:09:42.90,0:09:48.97,yin,,0,0,0,, 而将初始化代码放到 Deck 的 init 中 放到 Deck 中 \\N{\\fs12}why don’t I make an initializer like in init for deck and put this inside deck?\r\nDialogue: 0,0:09:48.97,0:09:50.63,yin,,0,0,0,, 这是另一种可选做法 \\N{\\fs12}And that is another option.\r\nDialogue: 0,0:09:50.63,0:09:53.82,yin,,0,0,0,, 等下在 PlayingCardDeck 中 我会写一段初始化程序 \\N{\\fs12}And again, we’re going to see initializer for playing card deck,\r\nDialogue: 0,0:09:53.82,0:09:55.44,yin,,0,0,0,, 等下在 PlayingCardDeck 中 我会写一段初始化程序 \\N{\\fs12}we’re going to make an initializer.\r\nDialogue: 0,0:09:55.44,0:09:57.45,yin,,0,0,0,, 我们可以这样做 \\N{\\fs12}And we could do that. But\r\nDialogue: 0,0:09:57.45,0:10:01.10,yin,,0,0,0,, 但让这些的初始化更接近于 \\N{\\fs12}having the initialization of this thing be closer\r\nDialogue: 0,0:10:01.10,0:10:04.82,yin,,0,0,0,, 实际获得属性的地方更加…\\N{\\fs12}to the actual getting of the property is more –\r\nDialogue: 0,0:10:04.82,0:10:08.97,yin,,0,0,0,, 它让你的 init 中这样的垃圾更少 \\N{\\fs12}it makes your init less full of a bunch of junk like that.\r\nDialogue: 0,0:10:08.97,0:10:13.01,yin,,0,0,0,, 顺便说下 这样做被称作惰性实例化 \\N{\\fs12}And this is called lazy instantiation, by the way, doing it this way.\r\nDialogue: 0,0:10:13.01,0:10:18.18,yin,,0,0,0,, 我们是惰性地等到最后一秒再实例化 \\N{\\fs12}We are lazily waiting to the last second until we instantiate.\r\nDialogue: 0,0:10:18.18,0:10:21.25,yin,,0,0,0,, 这种做法是 Objective-C 中每个人都习惯的 \\N{\\fs12}This pattern is something everyone in Objective-C is used to,\r\nDialogue: 0,0:10:21.25,0:10:23.93,yin,,0,0,0,, 你们也应当用这个 而不是写到 init 中 \\N{\\fs12}and you should definitely use it rather than doing things in your init.\r\nDialogue: 0,0:10:23.93,0:10:27.53,yin,,0,0,0,,init 中 你希望设置各种 \\N{\\fs12}In init you want to, you know, set things, set values that,\r\nDialogue: 0,0:10:27.53,0:10:30.29,yin,,0,0,0,, 不能简单像这样初始化的值 \\N{\\fs12}you know, can’t easily be defaulted like this.\r\nDialogue: 0,0:10:30.29,0:10:32.47,yin,,0,0,0,, 不过你问得很好 \\N{\\fs12}But that’s a very good question.\r\nDialogue: 0,0:10:32.47,0:10:34.72,yin,,0,0,0,, 过几张幻灯我们就会看到 init\\N{\\fs12}And we’ll see init in a couple slides.\r\nDialogue: 0,0:10:34.72,0:10:37.86,yin,,0,0,0,, 这样我们就保证了 self.cards 不为 nil 请讲 \\N{\\fs12}So this way we’re guaranteed self.cards is never nil. Yeah?\r\nDialogue: 0,0:10:37.89,0:10:40.63,yin,,0,0,0,,[学生提问 声音不清]\\N{\\fs12}> [Inaudible]\r\nDialogue: 0,0:10:40.63,0:10:43.18,yin,,0,0,0,,Paul Hegarty：对 下划线来自上一讲 \\N{\\fs12}> Paul Hegarty: Yeah. So the underscore is from last lecture.\r\nDialogue: 0,0:10:43.18,0:10:46.53,yin,,0,0,0,, 记得吧 当我们创建一个属性时 \\N{\\fs12}Remember that when we create a property,\r\nDialogue: 0,0:10:46.53,0:10:48.67,yin,,0,0,0,,Objective-C 会自动给出 \\N{\\fs12}Objective-C automatically does this thing,\r\nDialogue: 0,0:10:48.67,0:10:51.85,yin,,0,0,0,,@synthesize cards = _cards\\N{\\fs12}@synthesize cards equals underbar cards.\r\nDialogue: 0,0:10:51.85,0:10:56.51,yin,,0,0,0,, 也就是说 这赋值了一个实例变量 叫下划线属性名 \\N{\\fs12}So in other words, it assigns an instance variable called underbar name of property\r\nDialogue: 0,0:10:56.51,0:10:58.57,yin,,0,0,0,, 作为该属性的存储空间 \\N{\\fs12}to be the storage space for that property.\r\nDialogue: 0,0:10:58.57,0:11:02.99,yin,,0,0,0,, 因此_cards 是自动创建的 这是幕后完成的 \\N{\\fs12}So that’s why underbar cards are automatically created for us there behind the scenes.\r\nDialogue: 0,0:11:02.99,0:11:06.85,yin,,0,0,0,,@synthesize 没出现在我的代码里 但它确实存在 \\N{\\fs12}That at sign synthesizes a pop up in our code, but it’s there behind the scenes.\r\nDialogue: 0,0:11:06.85,0:11:09.18,yin,,0,0,0,, 问得很好 \\N{\\fs12}That’s a very good question.\r\nDialogue: 0,0:11:09.18,0:11:11.86,yin,,0,0,0,, 这里还有问题吗 \\N{\\fs12}Any other questions about this?\r\nDialogue: 0,0:11:11.86,0:11:18.14,yin,,0,0,0,, 好 下面继续来看随机抽取纸牌方法 \\N{\\fs12}Okay. So let’s collapse down some of this stuff and look at draw a random card.\r\nDialogue: 0,0:11:18.14,0:11:24.52,yin,,0,0,0,, 随机抽取纸牌希望从 self.cards 中随机抽选一张牌 \\N{\\fs12}So draw a random card, all it wants to do is get a random card out of that self.cards.\r\nDialogue: 0,0:11:24.52,0:11:27.33,yin,,0,0,0,, 代码很简单 \\N{\\fs12}So that code is very simple as well.\r\nDialogue: 0,0:11:27.33,0:11:30.25,yin,,0,0,0,, 我们获取一个随机整数 \\N{\\fs12}So we just get a random integer.\r\nDialogue: 0,0:11:30.25,0:11:34.04,yin,,0,0,0,,arc4random 就是做这个的 它是一个 C 库函数 \\N{\\fs12}That’s what arc 4 random does if you don’t know. It’s just a C library function.\r\nDialogue: 0,0:11:34.04,0:11:35.53,yin,,0,0,0,, 用于获取一个随机整数 \\N{\\fs12}It gets a random integer.\r\nDialogue: 0,0:11:35.53,0:11:39.80,yin,,0,0,0,, 之后的 % 表示求余数 \\N{\\fs12}Then that little percent after it means mod — okay, integer modulo –\r\nDialogue: 0,0:11:39.80,0:11:42.09,yin,,0,0,0,, 然后 self.cards count 是 \\N{\\fs12}and then self.cards count is\r\nDialogue: 0,0:11:42.10,0:11:44.87,yin,,0,0,0,,self.cards 中纸牌的数目 \\N{\\fs12}the number of cards in our self.cards.\r\nDialogue: 0,0:11:44.87,0:11:49.17,yin,,0,0,0,, 这就得到随机数 index 作为 self.cards 的下标 \\N{\\fs12}So we’re just going to get a random index into self.cards,\r\nDialogue: 0,0:11:49.17,0:11:51.45,yin,,0,0,0,, 然后赋值给 randomCard\\N{\\fs12}then assign a random card\r\nDialogue: 0,0:11:51.45,0:11:55.39,yin,,0,0,0,,= self.cards[index]\\N{\\fs12}to be self.cards square brackets index.\r\nDialogue: 0,0:11:55.39,0:12:01.48,yin,,0,0,0,, 这里方括号是数组访问的标准语法 \\N{\\fs12}So this is that same square brackets to access an array kind of syntax.\r\nDialogue: 0,0:12:01.48,0:12:05.05,yin,,0,0,0,, 有趣的是 self.cards[index] 实际上 \\N{\\fs12}And it’s interesting, that self.cards square brackets index, actually,\r\nDialogue: 0,0:12:05.05,0:12:07.29,yin,,0,0,0,, 也是一个消息发送 信不信由你 \\N{\\fs12}that’s a message send believe it or not.\r\nDialogue: 0,0:12:07.29,0:12:12.45,yin,,0,0,0,, 这等价于 self.cards objectAtIndex:index\\N{\\fs12}That’s same as self.cards object at index index.\r\nDialogue: 0,0:12:12.45,0:12:15.80,yin,,0,0,0,, 这里只是一种特殊的语法甜头 \\N{\\fs12}It’s just some special syntax and syntactic sugar\r\nDialogue: 0,0:12:15.80,0:12:18.45,yin,,0,0,0,, 这样你就不需要写很长的 objectAtIndex 了 \\N{\\fs12}to make it so that you don’t have to have long object at index.\r\nDialogue: 0,0:12:18.45,0:12:22.46,yin,,0,0,0,, 不需要 objectAtIndexedSubscript 这样的长方法名 \\N{\\fs12}It’s actually object at subscripted index or something with a real long method name.\r\nDialogue: 0,0:12:22.46,0:12:26.10,yin,,0,0,0,, 这里只是一些简短美妙的语法 \\N{\\fs12}So this is just a beautiful, little simple syntax.\r\nDialogue: 0,0:12:26.10,0:12:30.82,yin,,0,0,0,, 不过这是一种消息发送 来得到数组该下标处的牌 \\N{\\fs12}But that is a message send to get the card at that index out of the array.\r\nDialogue: 0,0:12:30.82,0:12:35.56,yin,,0,0,0,, 然后我们还要从数组中删除这张牌 \\N{\\fs12}And then we’re also going to remove that card out of the array\r\nDialogue: 0,0:12:35.56,0:12:38.26,yin,,0,0,0,, 因为这张牌已经被抽出 \\N{\\fs12}because this is draw a random card.\r\nDialogue: 0,0:12:38.26,0:12:42.45,yin,,0,0,0,, 抽出后就不在这一叠牌中了 \\N{\\fs12}It’s draw the card out of the deck. So it’s not in the deck anymore, right?\r\nDialogue: 0,0:12:42.45,0:12:45.66,yin,,0,0,0,, 这段代码也有问题 也就是 \\N{\\fs12}Now, there’s a problem with this code as well, which is:\r\nDialogue: 0,0:12:45.66,0:12:48.50,yin,,0,0,0,, 如果这一叠牌是空的怎么办 \\N{\\fs12}What if the deck is empty?\r\nDialogue: 0,0:12:48.50,0:12:53.61,yin,,0,0,0,, 如果这一叠牌是空的 那么 unsigned index 将是 0\\N{\\fs12}If the deck is empty, then that unsigned index is going to be zero,\r\nDialogue: 0,0:12:53.63,0:12:56.91,yin,,0,0,0,, 这里将是 arc4random % 0\\N{\\fs12}right, because it’s going to be arc 4 random mod zero.\r\nDialogue: 0,0:12:56.91,0:12:58.78,yin,,0,0,0,, 这将是 0\\N{\\fs12}That’s going to be zero.\r\nDialogue: 0,0:12:58.80,0:13:02.18,yin,,0,0,0,, 于是后面就是 randomCard = self.cards[0]\\N{\\fs12}And so you’re going to say, “Random card equals self.card sub zero.”\r\nDialogue: 0,0:13:02.18,0:13:05.14,yin,,0,0,0,, 这会让你的程序崩溃掉 \\N{\\fs12}Well, that’s going to crash your program\r\nDialogue: 0,0:13:05.14,0:13:07.94,yin,,0,0,0,, 因为 self.cards 是一个空数组 \\N{\\fs12}because if self.cards is an empty array,\r\nDialogue: 0,0:13:07.94,0:13:12.38,yin,,0,0,0,, 那么下标 0 处将没有对象 这是数组下标越界错误 \\N{\\fs12}then there’s no object at index zero and you’re going to get array index out of bounds.\r\nDialogue: 0,0:13:12.38,0:13:14.47,yin,,0,0,0,, 小心这个 \\N{\\fs12}So be careful of that.\r\nDialogue: 0,0:13:14.47,0:13:18.71,yin,,0,0,0,, 数组在某下标处没有对象时 你就无法得到它 \\N{\\fs12}The index — you cannot get the index — if an array doesn’t have an object\r\nDialogue: 0,0:13:18.71,0:13:20.98,yin,,0,0,0,, 数组在某下标处没有对象时 你就无法得到它 \\N{\\fs12}of that index, you can’t get it.\r\nDialogue: 0,0:13:20.98,0:13:22.71,yin,,0,0,0,, 这很好修正 \\N{\\fs12}So that’s easy to fix, though.\r\nDialogue: 0,0:13:22.71,0:13:26.80,yin,,0,0,0,, 我们可以加上 if ([self.cards count])\\N{\\fs12}We’re just going to say, “If self.cards count,”\r\nDialogue: 0,0:13:26.80,0:13:29.76,yin,,0,0,0,, 也就是说 如果数组中有内容 那么我们就这样做 \\N{\\fs12}in other words if there are things in the array, “then we’ll do that.\r\nDialogue: 0,0:13:29.76,0:13:32.70,yin,,0,0,0,, 否则我们将返回 randomCard\\N{\\fs12}Otherwise we’re just going to return random card,” which I\r\nDialogue: 0,0:13:32.70,0:13:35.48,yin,,0,0,0,, 方法最开始时我就已经将其初始化为 nil 了 \\N{\\fs12}happily initialized to nil at the beginning of my method.\r\nDialogue: 0,0:13:35.50,0:13:37.55,yin,,0,0,0,, 所以我喜欢这样做 \\N{\\fs12}And that’s why I kind of like this thing of\r\nDialogue: 0,0:13:37.56,0:13:40.11,yin,,0,0,0,, 初始化得到你想要的默认值 \\N{\\fs12}initialize it to the default value you want,\r\nDialogue: 0,0:13:40.11,0:13:41.83,yin,,0,0,0,, 然后设置 然后返回 \\N{\\fs12}then set it, and then return.\r\nDialogue: 0,0:13:41.83,0:13:44.10,yin,,0,0,0,, 这样一来 如果设置不幸失败的话 \\N{\\fs12}And that way if the setting fails for some reason\r\nDialogue: 0,0:13:44.10,0:13:46.12,yin,,0,0,0,, 例如像这样 一叠牌根本就没牌 \\N{\\fs12}like this — it fails because there’s no cards in the deck –\r\nDialogue: 0,0:13:46.12,0:13:48.33,yin,,0,0,0,, 它会返回合适的默认值 \\N{\\fs12}it will return the reasonable default.\r\nDialogue: 0,0:13:48.33,0:13:50.61,yin,,0,0,0,, 这是一种编程风格 \\N{\\fs12}That’s just kind of a coding style thing.\r\nDialogue: 0,0:13:50.61,0:13:53.60,yin,,0,0,0,, 我们对 score 和 match 也做了相同的事情 \\N{\\fs12}We did that same thing with score and match.\r\nDialogue: 0,0:13:53.60,0:13:57.05,yin,,0,0,0,, 关于这个有问题吗 请讲 \\N{\\fs12}Any questions about that? Yeah?\r\nDialogue: 0,0:13:57.05,0:14:03.58,yin,,0,0,0,,[学生提问 声音不清]\\N{\\fs12}[Inaudible]\r\nDialogue: 0,0:14:03.58,0:14:04.96,yin,,0,0,0,,Paul Hegarty：问得很好 \\N{\\fs12}> Paul Hegarty: Great question.\r\nDialogue: 0,0:14:04.96,0:14:11.17,yin,,0,0,0,, 问题是 什么时候用 NSInteger 或 NSUInteger\\N{\\fs12}So the question is: When do I use NS integer or NSU integer\r\nDialogue: 0,0:14:11.17,0:14:15.37,yin,,0,0,0,, 而不用 int 甚至我们还没讲到过的 NSNumber\\N{\\fs12}versus int or even NS number, which is an object which we haven’t talked about yet?\r\nDialogue: 0,0:14:15.37,0:14:17.62,yin,,0,0,0,, 答案是 这是一个风格问题 \\N{\\fs12}And the answer is it’s a matter of style.\r\nDialogue: 0,0:14:17.62,0:14:20.92,yin,,0,0,0,, 我会简单讲到这种风格 以及何时使用这些 \\N{\\fs12}And we’ll talk a little bit about that style and when to use these things.\r\nDialogue: 0,0:14:20.92,0:14:24.01,yin,,0,0,0,, 只是在局部使用时 \\N{\\fs12}Here I don’t really want to use an NS number which is an object\r\nDialogue: 0,0:14:24.01,0:14:27.81,yin,,0,0,0,, 不要用 NSNumber 这种对象 \\N{\\fs12}when I’m just using it, you know, as a little local thing like that.\r\nDialogue: 0,0:14:27.81,0:14:28.63,yin,,0,0,0,, 不要那样 \\N{\\fs12}You would never do that.\r\nDialogue: 0,0:14:28.63,0:14:32.91,yin,,0,0,0,, 使用 NSNumber 通常是为了将其传递给方法 \\N{\\fs12}You’re using NS numbers basically to pass them to methods.\r\nDialogue: 0,0:14:32.93,0:14:35.55,yin,,0,0,0,, 哪怕这时你也可以传递 int 或 float 值 \\N{\\fs12}And even then you could pass ints, you know, and floats.\r\nDialogue: 0,0:14:35.55,0:14:41.81,yin,,0,0,0,, 下周讲 NSNumber 时这会变得很明显 \\N{\\fs12}So it will be become obvious as I talk about NS number, which we’ll do next week.\r\nDialogue: 0,0:14:41.81,0:14:43.60,yin,,0,0,0,, 这是 Deck\\N{\\fs12}Okay. So that’s it for deck.\r\nDialogue: 0,0:14:43.60,0:14:46.15,yin,,0,0,0,,Deck 也是很简单的类 \\N{\\fs12}Deck, very simple class as well.\r\nDialogue: 0,0:14:46.17,0:14:49.08,yin,,0,0,0,, 下面看另一个类 也就是 PlayingCard\\N{\\fs12}So let’s move onto another class, which is playing card.\r\nDialogue: 0,0:14:49.08,0:14:50.65,yin,,0,0,0,, 我展示 PlayingCard\\N{\\fs12}The reason I’m showing you playing cards,\r\nDialogue: 0,0:14:50.65,0:14:52.72,yin,,0,0,0,, 是为了跟你们讲解某一类的子类怎么写 \\N{\\fs12}I just want to show you what it looks like to make a subclass\r\nDialogue: 0,0:14:52.72,0:14:54.14,yin,,0,0,0,, 是为了跟你们讲解某一类的子类怎么写 \\N{\\fs12}of another class that you’ve written.\r\nDialogue: 0,0:14:54.14,0:14:56.74,yin,,0,0,0,,PlayingCard 是 Card 的子类 \\N{\\fs12}So playing card is a subclass of card.\r\nDialogue: 0,0:14:56.74,0:14:59.91,yin,,0,0,0,, 它专指扑克牌 例如红心 K\\N{\\fs12}And this is the specific card like king of hearts,\r\nDialogue: 0,0:14:59.91,0:15:02.98,yin,,0,0,0,, 方片 3 这些牌 \\N{\\fs12}three of diamonds, that kind of card.\r\nDialogue: 0,0:15:02.98,0:15:08.58,yin,,0,0,0,,PlayingCard 具有特有属性 suit 和 rank\\N{\\fs12}Now, it has properties that are specific to a playing card, which is the suit and rank.\r\nDialogue: 0,0:15:08.58,0:15:11.84,yin,,0,0,0,,rank 也就是大小 3 4 J K 这些 \\N{\\fs12}The rank being like a three, four, a jack, king, right?\r\nDialogue: 0,0:15:11.84,0:15:14.26,yin,,0,0,0,,suit 是花色 红心 方片 梅花 \\N{\\fs12}And the suit being hearts, diamonds, clubs.\r\nDialogue: 0,0:15:14.26,0:15:17.68,yin,,0,0,0,, 我将用单字符表示 suit\\N{\\fs12}And I’m going to represent the suit as a single character –\r\nDialogue: 0,0:15:17.68,0:15:19.50,yin,,0,0,0,, 红心字符 梅花字符 \\N{\\fs12}the hearts characters, the clubs character.\r\nDialogue: 0,0:15:19.50,0:15:23.34,yin,,0,0,0,, 我好像展示过扑克牌中梅花字符的输入 \\N{\\fs12}Remember I typed the clubs character I think in the card we might have shown that.\r\nDialogue: 0,0:15:23.34,0:15:25.19,yin,,0,0,0,, 反正 你可以输入一个字符 \\N{\\fs12}I don’t know. But you can type a single character.\r\nDialogue: 0,0:15:25.19,0:15:27.68,yin,,0,0,0,,Unicode 对这四种花色都有相应字符 \\N{\\fs12}Unicode has a character for each of the four suits.\r\nDialogue: 0,0:15:27.70,0:15:28.75,yin,,0,0,0,, 这是 suit\\N{\\fs12}So that’s what my suit is going to be.\r\nDialogue: 0,0:15:28.75,0:15:33.07,yin,,0,0,0,, 而 rank 是从 0 到 13 数字 \\N{\\fs12}And then the rank is going to be a number between zero and thirteen.\r\nDialogue: 0,0:15:33.07,0:15:34.64,yin,,0,0,0,,13 表示 K\\N{\\fs12}Is that king?\r\nDialogue: 0,0:15:34.64,0:15:36.62,yin,,0,0,0,, 这些表示大小 \\N{\\fs12}Yeah. Representing the rank.\r\nDialogue: 0,0:15:36.62,0:15:39.26,yin,,0,0,0,, 这就是公共 API 中的表示 \\N{\\fs12}So that’s how I’m going to represent in my public API.\r\nDialogue: 0,0:15:39.28,0:15:42.13,yin,,0,0,0,, 注意这里我用的是 NSUInteger\\N{\\fs12}And here I’m using notice NSU integer\r\nDialogue: 0,0:15:42.13,0:15:43.94,yin,,0,0,0,, 而不是 unsigned int\\N{\\fs12}instead of unsigned int.\r\nDialogue: 0,0:15:43.94,0:15:47.27,yin,,0,0,0,,NSUInteger 和 unsigned int 几乎是一回事 \\N{\\fs12}So NSU integer and unsigned int are almost exactly the same thing.\r\nDialogue: 0,0:15:47.27,0:15:50.12,yin,,0,0,0,,NSUInteger 唯一不同的是 它是一个 typedef\\N{\\fs12}The only thing about NSU integer is it’s typedef.\r\nDialogue: 0,0:15:50.12,0:15:52.54,yin,,0,0,0,, 它在不同平台下可能略有不同 \\N{\\fs12}It might be a little different on different platforms.\r\nDialogue: 0,0:15:52.54,0:15:56.52,yin,,0,0,0,, 例如新的 iPhone 5S 是 64 位处理器 \\N{\\fs12}For example, the new iPhone 5s are 64-bit processers.\r\nDialogue: 0,0:15:56.52,0:16:01.55,yin,,0,0,0,, 所以 NSUInteger 是 64 位无符号整型 \\N{\\fs12}So NSU integer is going to be a 64-bit int, unsigned int on an iPhone 5.\r\nDialogue: 0,0:16:01.55,0:16:05.32,yin,,0,0,0,, 而之前的 iPhone 则只有 32 位 \\N{\\fs12}And it might only about a 32-bit one back on an iPhone 4 and before.\r\nDialogue: 0,0:16:05.32,0:16:08.68,yin,,0,0,0,, 这里有些不同 \\N{\\fs12}So that’s a little bit different.\r\nDialogue: 0,0:16:08.68,0:16:10.43,yin,,0,0,0,, 很细枝末节 \\N{\\fs12}So a minor nit.\r\nDialogue: 0,0:16:10.43,0:16:12.47,yin,,0,0,0,, 我们可能要不了那么大的整数 \\N{\\fs12}We were probably not representing integers.\r\nDialogue: 0,0:16:12.47,0:16:14.41,yin,,0,0,0,, 显然 这里只是从 0 到 13\\N{\\fs12}Certainly here we’re only going zero to thirteen.\r\nDialogue: 0,0:16:14.41,0:16:15.80,yin,,0,0,0,, 问题不大 \\N{\\fs12}Probably doesn’t matter.\r\nDialogue: 0,0:16:15.80,0:16:19.03,yin,,0,0,0,, 要知道 我们用不到 33 位那么大的数 \\N{\\fs12}But, you know, we’re not representing integers that are so gigantic\r\nDialogue: 0,0:16:19.03,0:16:21.63,yin,,0,0,0,, 要知道 我们用不到 33 位那么大的数 \\N{\\fs12}that we’re going to be using the 33rd bit.\r\nDialogue: 0,0:16:22.66,0:16:25.11,yin,,0,0,0,, 注意到 PlayingCard 中 \\N{\\fs12}So notice that in playing card\r\nDialogue: 0,0:16:25.11,0:16:28.32,yin,,0,0,0,, 我们重写了 Card 方法 contents\\N{\\fs12}we’re overriding card method contents.\r\nDialogue: 0,0:16:28.32,0:16:30.98,yin,,0,0,0,, 我们从父类继承了 contents\\N{\\fs12}We inherit contents from our superclass.\r\nDialogue: 0,0:16:30.98,0:16:33.24,yin,,0,0,0,, 根据默认 contents 仅仅返回 \\N{\\fs12}And by default contents just returns\r\nDialogue: 0,0:16:33.24,0:16:36.31,yin,,0,0,0,,contents 属性的值 \\N{\\fs12}the value of whatever the contents property is.\r\nDialogue: 0,0:16:36.31,0:16:39.55,yin,,0,0,0,, 但这里在 PlayingCard 中 我们将重写 contents\\N{\\fs12}But here in the playing card we’re going to override contents\r\nDialogue: 0,0:16:39.55,0:16:43.92,yin,,0,0,0,, 基于其它两个属性来实际计算 contents\\N{\\fs12}to actually calculate our contents, based on these other two properties.\r\nDialogue: 0,0:16:43.92,0:16:46.63,yin,,0,0,0,, 我们重写 contents 的 getter\\N{\\fs12}So we’re overriding the getter of contents\r\nDialogue: 0,0:16:46.63,0:16:49.33,yin,,0,0,0,, 也就是这张扑克牌的内容 \\N{\\fs12}so that it always returns a string –\r\nDialogue: 0,0:16:49.33,0:16:53.54,yin,,0,0,0,, 让它总是返回一个计算自花色和大小的字符串 \\N{\\fs12}the contents of this playing card — that is calculated from the suit and rank.\r\nDialogue: 0,0:16:53.54,0:16:54.68,yin,,0,0,0,, 明白吗 \\N{\\fs12}You see what we’re doing here?\r\nDialogue: 0,0:16:54.68,0:16:58.33,yin,,0,0,0,, 我们从父类取存储 contents 的_contents\\N{\\fs12}So we’re basically taking the storage of contents — underbar contents –\r\nDialogue: 0,0:16:58.33,0:17:00.24,yin,,0,0,0,, 然后忽略它 \\N{\\fs12}from our superclass and ignoring it\r\nDialogue: 0,0:17:00.26,0:17:02.77,yin,,0,0,0,, 因为我们重写了其 getter\\N{\\fs12}because we’re overriding its getter.\r\nDialogue: 0,0:17:02.79,0:17:06.94,yin,,0,0,0,, 这就是使用这些属性的一个很好理由 \\N{\\fs12}So this is a perfectly valid reason why we do these properties as well\r\nDialogue: 0,0:17:06.94,0:17:10.06,yin,,0,0,0,, 因为我们可能有比单纯存储更好的做法 \\N{\\fs12}because we might have a better way to do things than the storage.\r\nDialogue: 0,0:17:10.06,0:17:13.35,yin,,0,0,0,, 这是可以进行实现的方式 我们可以返回一个字符串 \\N{\\fs12}Now, here’s a way we could implement it: We can just return a string.\r\nDialogue: 0,0:17:13.35,0:17:15.00,yin,,0,0,0,,NSString stringWithFormat\\N{\\fs12}NS string, string with format\r\nDialogue: 0,0:17:15.00,0:17:17.11,yin,,0,0,0,, 类似于 printf 一个字符串 \\N{\\fs12}just like printf-ing a string.\r\nDialogue: 0,0:17:17.11,0:17:19.78,yin,,0,0,0,, 别太担心这里的语法 \\N{\\fs12}Don’t worry about that syntax too much.\r\nDialogue: 0,0:17:19.78,0:17:22.95,yin,,0,0,0,,printf 字符串的格式是 %d%@\\N{\\fs12}And I’m printf-ing a string with percent D and percent at sign.\r\nDialogue: 0,0:17:22.95,0:17:26.70,yin,,0,0,0,,%d 表示整数 %@表示一个对象 \\N{\\fs12}So percent D means integer; percent at sign means an object.\r\nDialogue: 0,0:17:26.70,0:17:28.42,yin,,0,0,0,, 一个对象的字符串表示 \\N{\\fs12}A string representation of an object.\r\nDialogue: 0,0:17:28.42,0:17:31.03,yin,,0,0,0,, 然后我将使用 rank 和 suit\\N{\\fs12}And then I’m just using the rank and suit.\r\nDialogue: 0,0:17:31.03,0:17:32.84,yin,,0,0,0,, 这是处理 contents 的一种方式 \\N{\\fs12}So this would be one way to do my contents.\r\nDialogue: 0,0:17:32.84,0:17:35.38,yin,,0,0,0,, 这不是一个很好的方式 因为 \\N{\\fs12}It’s not a very good way because, for example,\r\nDialogue: 0,0:17:35.38,0:17:38.57,yin,,0,0,0,, 例如红心 J 是 11 红心 \\N{\\fs12}the jack of hearts would say 11 hearts.\r\nDialogue: 0,0:17:38.57,0:17:42.87,yin,,0,0,0,, 至少 J 我们想用 J 而不是 11\\N{\\fs12}It’s not going to say J at least; we want to say J, not 11.\r\nDialogue: 0,0:17:42.87,0:17:44.32,yin,,0,0,0,, 这个方式不怎么好 \\N{\\fs12}So this is not a very good way.\r\nDialogue: 0,0:17:44.32,0:17:47.45,yin,,0,0,0,, 所以我想让一个数组中 \\N{\\fs12}So instead I’m going to make an array\r\nDialogue: 0,0:17:47.45,0:17:51.31,yin,,0,0,0,, 有所有正确的东西 比如 A 表示 1\\N{\\fs12}that has all the right things like an A for a one,\r\nDialogue: 0,0:17:51.31,0:17:55.38,yin,,0,0,0,,J 表示 11 Q 表示 12 K 表示 13\\N{\\fs12}and a J for 11, and a Q for 12, and a K for 13, right?\r\nDialogue: 0,0:17:55.38,0:17:57.75,yin,,0,0,0,, 这里我创建一个数组 \\N{\\fs12}So I’m just making this array here.\r\nDialogue: 0,0:17:57.75,0:18:01.19,yin,,0,0,0,, 中间我需要删去 让它能够显示出来 \\N{\\fs12}In the middle there I had to cut out to make it fit, right?\r\nDialogue: 0,0:18:01.19,0:18:03.21,yin,,0,0,0,, 我还让 0 为问号 \\N{\\fs12}And I even made zero be question mark.\r\nDialogue: 0,0:18:03.21,0:18:07.22,yin,,0,0,0,, 如果 rank 为 0 它会是问号 如未设 \\N{\\fs12}So if your rank is zero, it’s going to be, like, question mark, like, unset.\r\nDialogue: 0,0:18:07.22,0:18:09.57,yin,,0,0,0,, 大小没有设定 \\N{\\fs12}You know, your rank is basically not set.\r\nDialogue: 0,0:18:09.57,0:18:12.22,yin,,0,0,0,, 然后我返回一个字符串 \\N{\\fs12}And then I return a string,\r\nDialogue: 0,0:18:12.22,0:18:15.29,yin,,0,0,0,, 它会取出那个数组中的 rank\\N{\\fs12}which is taking the rank out of that array\r\nDialogue: 0,0:18:15.31,0:18:18.34,yin,,0,0,0,, 然后追加表示 suit 的字符串 \\N{\\fs12}and appending onto it the little suit string,\r\nDialogue: 0,0:18:18.34,0:18:20.73,yin,,0,0,0,, 红心 梅花 方片这些 \\N{\\fs12}the heart, or the club, or the diamond.\r\nDialogue: 0,0:18:20.73,0:18:22.08,yin,,0,0,0,, 都明白吗 \\N{\\fs12}Everyone understand this?\r\nDialogue: 0,0:18:22.08,0:18:25.01,yin,,0,0,0,, 给你们讲这些是为了让你们明白 \\N{\\fs12}I’m kind of giving you this so you can see how we’re mixing\r\nDialogue: 0,0:18:25.01,0:18:31.75,yin,,0,0,0,, 如何无缝混合数组符号 消息发送所有这些东西 \\N{\\fs12}in the array notation, and message sending, and it all kind of seamlessly mixes in there.\r\nDialogue: 0,0:18:31.75,0:18:38.92,yin,,0,0,0,, 这时 contents 会返回 J 红心 或 5 方块这些 \\N{\\fs12}So now contents returns J hearts, or 5 diamonds, or whatever.\r\nDialogue: 0,0:18:38.92,0:18:41.96,yin,,0,0,0,, 注意到 rank 很棒 \\N{\\fs12}Notice that our rank is really nice\r\nDialogue: 0,0:18:41.96,0:18:45.78,yin,,0,0,0,, 因为在我们说 new PlayingCard 时 rank 会为 0\\N{\\fs12}because if our rank is zero, which it starts out being when we say new playing card –\r\nDialogue: 0,0:18:45.78,0:18:48.00,yin,,0,0,0,, 所有实例变量为 0 所以 rank 为 0\\N{\\fs12}all the instance variables are zero so rank would be zero –\r\nDialogue: 0,0:18:48.00,0:18:49.36,yin,,0,0,0,, 我们得到这个问号 \\N{\\fs12}we get this nice question mark.\r\nDialogue: 0,0:18:49.36,0:18:51.72,yin,,0,0,0,, 但 suit 开始时是 nil\\N{\\fs12}But our suit starts out as nil,\r\nDialogue: 0,0:18:51.72,0:18:56.79,yin,,0,0,0,, 如果 suit 在未设或为 nil 时也能返回问号就好了 \\N{\\fs12}and it would be nice if the suit also returned question mark if it was unset, if it was nil.\r\nDialogue: 0,0:18:56.79,0:18:59.35,yin,,0,0,0,, 所以这里我重写 suit 的 getter 如下 \\N{\\fs12}So here I’m just overriding the getter of suit to say,\r\nDialogue: 0,0:18:59.35,0:19:04.32,yin,,0,0,0,, 如果 suit 是 nil 那么返回问号 \\N{\\fs12}”If return, if my suit is nil, then return the question mark,\r\nDialogue: 0,0:19:04.32,0:19:07.66,yin,,0,0,0,, 否则当 suit 不是 nil 时 那么返回 suit 的实际值 \\N{\\fs12}otherwise when my suit’s not nil, then return what the suit is.”\r\nDialogue: 0,0:19:07.66,0:19:10.78,yin,,0,0,0,, 我是在保护我的 API\\N{\\fs12}So I’m just kind of protecting my API\r\nDialogue: 0,0:19:10.78,0:19:14.49,yin,,0,0,0,, 保证我在 rank 或 suit 未设时 总是返回问号 \\N{\\fs12}to make sure I always return question mark when the rank or suit is not set.\r\nDialogue: 0,0:19:14.50,0:19:15.01,yin,,0,0,0,, 请讲 \\N{\\fs12}Yeah.\r\nDialogue: 0,0:19:15.03,0:19:16.75,yin,,0,0,0,,[学生提问 声音不清]\\N{\\fs12}> [Inaudible]\r\nDialogue: 0,0:19:18.75,0:19:22.65,yin,,0,0,0,,Paul Hegarty：抱歉 你是说的红色 @号吗 \\N{\\fs12}> Paul Hegarty: Sorry. All little at signs — the red at signs, you mean?\r\nDialogue: 0,0:19:22.65,0:19:26.54,yin,,0,0,0,, 对 我们在 Card 中应该没碰到过这个 \\N{\\fs12}Yeah. Guess we didn’t get to that in card.\r\nDialogue: 0,0:19:26.54,0:19:28.05,yin,,0,0,0,, 也可能碰到过 \\N{\\fs12}But we might have. But\r\nDialogue: 0,0:19:28.09,0:19:28.94,yin,,0,0,0,, 记得吧 \\N{\\fs12}remember that\r\nDialogue: 0,0:19:28.94,0:19:32.79,yin,,0,0,0,, 我们这门课碰到的所有字符串都是字符串对象 \\N{\\fs12}all strings that we’re going to work with in this class are string objects,\r\nDialogue: 0,0:19:32.79,0:19:34.70,yin,,0,0,0,, 而非 const char\\N{\\fs12}not const char stars.\r\nDialogue: 0,0:19:34.70,0:19:36.26,yin,,0,0,0,, 它们是字符串对象 \\N{\\fs12}They’re string objects.\r\nDialogue: 0,0:19:36.26,0:19:39.06,yin,,0,0,0,, 如果你在字符串前加一个 @\\N{\\fs12}And the compiler, if you put an at sign in front of a string,\r\nDialogue: 0,0:19:39.06,0:19:42.00,yin,,0,0,0,, 编译器会为你创建字符串对象 \\N{\\fs12}it will make a string object for you.\r\nDialogue: 0,0:19:42.00,0:19:45.35,yin,,0,0,0,, 这些 @的作用是让所有字符串为字符串对象 \\N{\\fs12}So that’s what those at signs do, they make all those strings be string objects\r\nDialogue: 0,0:19:45.35,0:19:47.90,yin,,0,0,0,, 因为我们不能将 const char * 放到 NSArray 中 \\N{\\fs12}because we can’t put a const char star in an NS array.\r\nDialogue: 0,0:19:47.90,0:19:51.27,yin,,0,0,0,,NSArray 中只能是对象 所以只能用 NSString 这些 \\N{\\fs12}NS array is for objects, so we have to put objects in there like NS strings.\r\nDialogue: 0,0:19:51.27,0:19:53.67,yin,,0,0,0,, 这些才是对象 问得很好 \\N{\\fs12}Those are objects. Good question.\r\nDialogue: 0,0:19:53.67,0:19:55.51,yin,,0,0,0,, 请讲 \\N{\\fs12}Yeah?\r\nDialogue: 0,0:19:55.51,0:20:00.54,yin,,0,0,0,,[学生提问 声音不清]\\N{\\fs12}[Inaudible]\r\nDialogue: 0,0:20:09.54,0:20:11.82,yin,,0,0,0,,Paul Hegarty：对 好 问得很好 \\N{\\fs12}> Paul Hegarty: Yes. Okay. That’s a good question.\r\nDialogue: 0,0:20:11.82,0:20:16.18,yin,,0,0,0,, 如果我们用了 getter= 符号 \\N{\\fs12}If we had used that getter equals notation that we used\r\nDialogue: 0,0:20:16.18,0:20:18.91,yin,,0,0,0,, 就像 isChosen 和 isMatched 那样 来改名 \\N{\\fs12}for is chosen and is matched to change the name,\r\nDialogue: 0,0:20:18.91,0:20:21.82,yin,,0,0,0,, 那么重写时 我们就需要使用新名 \\N{\\fs12}then when we override we have to use the new name.\r\nDialogue: 0,0:20:21.82,0:20:25.17,yin,,0,0,0,, 我们就需要用 is 什么 这里不需要那样 \\N{\\fs12}We’d have to is whatever. Now, this is not the case here.\r\nDialogue: 0,0:20:25.17,0:20:28.96,yin,,0,0,0,, 但我知道你说的是什么 对 你需要用新名 \\N{\\fs12}But I know what you’re saying, and yes, you would have to use the new name.\r\nDialogue: 0,0:20:28.96,0:20:30.23,yin,,0,0,0,, 问得很好 \\N{\\fs12}Great question.\r\nDialogue: 0,0:20:30.23,0:20:32.29,yin,,0,0,0,, 这方面还有问题吗 \\N{\\fs12}Any other questions about this?\r\nDialogue: 0,0:20:32.29,0:20:37.85,yin,,0,0,0,, 好 这能帮助 suit 在为 nil 或未设时总是返回问号 \\N{\\fs12}Okay. So that helps the suit always return question mark if the suit is nil or not set.\r\nDialogue: 0,0:20:37.85,0:20:42.54,yin,,0,0,0,, 我们再加一层保护 以防有人错误设置了 suit\\N{\\fs12}Let’s also protect people setting the suit to something wrong.\r\nDialogue: 0,0:20:42.54,0:20:46.53,yin,,0,0,0,, 我们将只让人使用属性的公共 setter 来设置 suit\\N{\\fs12}Let’s only let people set the suit using this property,\r\nDialogue: 0,0:20:46.53,0:20:48.46,yin,,0,0,0,, 我们将只让人使用属性的公共 setter 来设置 suit\\N{\\fs12}the public setter of the property.\r\nDialogue: 0,0:20:48.46,0:20:53.20,yin,,0,0,0,,suit 将只被允许设置为四种花色之一 \\N{\\fs12}We’ll only let people set the suit to be one of the four suits.\r\nDialogue: 0,0:20:53.20,0:20:57.64,yin,,0,0,0,, 我简单在这里创建了四种花色的数组 \\N{\\fs12}So I just on the fly in the middle there created an array of those four suits.\r\nDialogue: 0,0:20:57.64,0:20:59.70,yin,,0,0,0,, 然后用到方法 containsObject\\N{\\fs12}And then I use this method contains object;\r\nDialogue: 0,0:20:59.70,0:21:04.55,yin,,0,0,0,, 从这里看 你们觉得 containsObject 是什么 \\N{\\fs12}what class do you think contains object is from that bit on?\r\nDialogue: 0,0:21:04.55,0:21:05.22,yin,,0,0,0,, 谁讲讲 \\N{\\fs12}Anyone?\r\nDialogue: 0,0:21:05.23,0:21:08.31,yin,,0,0,0,,[学生提问 声音不清]\\N{\\fs12}> [Inaudible]\r\nDialogue: 0,0:21:08.33,0:21:10.28,yin,,0,0,0,,Paul Hegarty：这是一种 NSArray 方法 正确 \\N{\\fs12}> Paul Hegarty: It’s an NS array method, exactly.\r\nDialogue: 0,0:21:10.28,0:21:12.24,yin,,0,0,0,,containsObject 是一种 NSArray 方法 \\N{\\fs12}So contains object is an NS array method.\r\nDialogue: 0,0:21:12.24,0:21:15.03,yin,,0,0,0,, 我将它送往我刚创建的数组 \\N{\\fs12}I’m sending it to the array that I create right in place there.\r\nDialogue: 0,0:21:15.03,0:21:18.44,yin,,0,0,0,, 包含红心 方片 黑桃 梅花的那个数组 \\N{\\fs12}The array that has hearts, diamonds, spades, and clubs in it.\r\nDialogue: 0,0:21:18.44,0:21:20.75,yin,,0,0,0,, 我问 你是否包含这个字符串 \\N{\\fs12}And I’m just asking: Do you contain this string?\r\nDialogue: 0,0:21:20.75,0:21:23.76,yin,,0,0,0,,containsObject 会使用 isEqual 方法对比 \\N{\\fs12}And that contains object is going to compare the contents\r\nDialogue: 0,0:21:23.76,0:21:27.29,yin,,0,0,0,, 这个字符串的内容和所有这些 \\N{\\fs12}of this string against all these using a method is equal.\r\nDialogue: 0,0:21:27.29,0:21:30.60,yin,,0,0,0,, 它会将 suit 作为参数用 isEqual 一一对比四个字符串 \\N{\\fs12}Actually, it’s going to say is equal to all four of them with the suit as the argument;\r\nDialogue: 0,0:21:30.60,0:21:32.76,yin,,0,0,0,, 不是 isEqualToString 而是 isEqual\\N{\\fs12}not is equal to string — is equal.\r\nDialogue: 0,0:21:32.76,0:21:35.57,yin,,0,0,0,,isEqual 是由 isEqualToString 来实现的 \\N{\\fs12}And in string is equal is implemented by calling is equal\r\nDialogue: 0,0:21:35.57,0:21:37.55,yin,,0,0,0,, 如果参数是字符串的话 \\N{\\fs12}to string if the argument’s a string.\r\nDialogue: 0,0:21:37.55,0:21:39.92,yin,,0,0,0,, 这里讲了太多无关紧要的细节 \\N{\\fs12}Anyway, more detail than you need probably there.\r\nDialogue: 0,0:21:39.92,0:21:41.39,yin,,0,0,0,, 这里显然能起到保护作用 \\N{\\fs12}But this is obviously protecting it.\r\nDialogue: 0,0:21:41.39,0:21:44.79,yin,,0,0,0,, 这样内部花色存储变量就无法设置为 \\N{\\fs12}So there’s no way we can set our internal suit storage variable\r\nDialogue: 0,0:21:44.79,0:21:48.51,yin,,0,0,0,, 这四种花色以外任何东西了 请讲 \\N{\\fs12}to anything except for those four suits. Yeah?\r\nDialogue: 0,0:21:48.51,0:21:58.94,yin,,0,0,0,,[学生提问 声音不清]\\N{\\fs12}[Inaudible]\r\nDialogue: 0,0:21:58.94,0:22:01.99,yin,,0,0,0,,Paul Hegarty：问得很棒 你们理解得真不错 \\N{\\fs12}> Paul Hegarty: Great question. You guys are right on top of it.\r\nDialogue: 0,0:22:01.99,0:22:04.83,yin,,0,0,0,, 每次我使用 @[这样的符号 \\N{\\fs12}So every time I use the at sign open square bracket --\r\nDialogue: 0,0:22:04.83,0:22:06.38,yin,,0,0,0,, 如这里蓝色的部分 \\N{\\fs12}the blue one -- to\r\nDialogue: 0,0:22:06.38,0:22:10.17,yin,,0,0,0,, 这实际是在创建新数组 每次都是这样 \\N{\\fs12}create an array, that's actually creating a new array every time.\r\nDialogue: 0,0:22:10.17,0:22:13.08,yin,,0,0,0,, 因为我讲过 @[…]\\N{\\fs12}Because I told you that that at sign square bracket\r\nDialogue: 0,0:22:13.08,0:22:15.79,yin,,0,0,0,, 及所有这些数组东西 只是在调用方法 \\N{\\fs12}and all this array stuff is really just calling methods?\r\nDialogue: 0,0:22:15.79,0:22:19.20,yin,,0,0,0,, 这就像是调用数组 对象这些的 alloc init 方法 \\N{\\fs12}Well, that’s calling a method like alloc init with array\r\nDialogue: 0,0:22:19.20,0:22:20.81,yin,,0,0,0,, 这就像是调用数组 对象这些的 alloc init 方法 \\N{\\fs12}with objects or something like that.\r\nDialogue: 0,0:22:20.81,0:22:21.83,yin,,0,0,0,, 这是在创建 \\N{\\fs12}Right? So it is creating it.\r\nDialogue: 0,0:22:21.83,0:22:25.25,yin,,0,0,0,, 将它移出来也很好 我们会这样做 \\N{\\fs12}So it would be nice to move it out, and we’re going to do that.\r\nDialogue: 0,0:22:25.25,0:22:28.38,yin,,0,0,0,, 不过 注意不要预优化 \\N{\\fs12}Although, again, be careful not to preoptimize.\r\nDialogue: 0,0:22:28.38,0:22:29.87,yin,,0,0,0,, 它可能不会有任何不同 \\N{\\fs12}It probably wouldn’t make any different.\r\nDialogue: 0,0:22:29.87,0:22:31.81,yin,,0,0,0,, 移出来只是为了让代码更简洁 \\N{\\fs12}I’m only going to move it out to make my code cleaner;\r\nDialogue: 0,0:22:31.81,0:22:34.68,yin,,0,0,0,, 移出来不是出于任何性能考虑 请讲 \\N{\\fs12}I’m not going to move it out for any performance reason. Yeah?\r\nDialogue: 0,0:22:34.71,0:22:38.01,yin,,0,0,0,,[学生提问 声音不清]\\N{\\fs12}> [Inaudible]\r\nDialogue: 0,0:22:38.01,0:22:39.18,yin,,0,0,0,,Paul Hegarty：问题是 \\N{\\fs12}> Paul Hegarty: The question is:\r\nDialogue: 0,0:22:39.18,0:22:41.43,yin,,0,0,0,,LLVM 会处理这个 为你优化好吗 \\N{\\fs12}Would LLVM just take care of that, optimize that out for you?\r\nDialogue: 0,0:22:41.43,0:22:44.00,yin,,0,0,0,, 它可能不会 因为这是一个消息发送 \\N{\\fs12}And it probably wouldn’t because that’s a message send;\r\nDialogue: 0,0:22:44.00,0:22:45.90,yin,,0,0,0,, 它不确定这样有没有副作用 \\N{\\fs12}it’s not sure what there might be side effects of it.\r\nDialogue: 0,0:22:45.90,0:22:48.99,yin,,0,0,0,, 无论如何 我们这样做是为了让代码更简洁 \\N{\\fs12}But in any case, we’re just going to do it just to make our code look cleaner.\r\nDialogue: 0,0:22:48.99,0:22:51.54,yin,,0,0,0,, 性能在这里可以忽略 \\N{\\fs12}And the performance would be negligible here.\r\nDialogue: 0,0:22:51.54,0:22:54.24,yin,,0,0,0,, 我们讲的是 UI 这相差很远 \\N{\\fs12}We’re talking about UI. It’s not even close.\r\nDialogue: 0,0:22:54.24,0:22:56.90,yin,,0,0,0,, 在这之前 还有一点要讲 \\N{\\fs12}One thing to note, though, before we do that is\r\nDialogue: 0,0:22:56.90,0:23:00.27,yin,,0,0,0,, 由于我们现在已经实现了 suit 的 setter 和 getter\\N{\\fs12}since we’ve implemented both the setter and the getter of suit,\r\nDialogue: 0,0:23:00.27,0:23:04.44,yin,,0,0,0,, 这就必须处理 @synthesize 了 \\N{\\fs12}we are now required to do the at sign synthesize.\r\nDialogue: 0,0:23:04.44,0:23:08.13,yin,,0,0,0,, 换言之 一般我们不需要处理 @synthesize\\N{\\fs12}In other words, normally we don’t have to do this at sign synthesize.\r\nDialogue: 0,0:23:08.13,0:23:09.07,yin,,0,0,0,, 它会自动生成 \\N{\\fs12}It gets done for us.\r\nDialogue: 0,0:23:09.07,0:23:12.67,yin,,0,0,0,, 但当同时实现 setter 和 getter 时 就需要处理了 \\N{\\fs12}But if we implement both the setter and the getter, now we do.\r\nDialogue: 0,0:23:12.67,0:23:15.87,yin,,0,0,0,, 这很容易 因为形式总是一样 \\N{\\fs12}It’s easy to do because it’s always of this exact same form.\r\nDialogue: 0,0:23:15.87,0:23:18.61,yin,,0,0,0,, 但容易也需要做 \\N{\\fs12}But we do have to do it.\r\nDialogue: 0,0:23:18.61,0:23:21.30,yin,,0,0,0,, 这里 做我刚才讲的事情 \\N{\\fs12}Okay. So here’s — let’s do what we were saying.\r\nDialogue: 0,0:23:21.30,0:23:26.82,yin,,0,0,0,, 我们将花色的数组放入到另一个方法中 \\N{\\fs12}Let’s take that little array of suits we have in there and put it in another method.\r\nDialogue: 0,0:23:26.82,0:23:29.87,yin,,0,0,0,, 我说过 这样做不会有任何性能好处 \\N{\\fs12}Now, again, I’m not getting any performance by doing this.\r\nDialogue: 0,0:23:29.87,0:23:32.02,yin,,0,0,0,, 这样做只是代码更简洁一些 \\N{\\fs12}I’m just getting code cleanliness by doing this\r\nDialogue: 0,0:23:32.02,0:23:35.17,yin,,0,0,0,, 因为每次调用 validSuits 时还是会重新创建 \\N{\\fs12}because I’m still — every time I call valid suits, it’s going to create it again.\r\nDialogue: 0,0:23:35.17,0:23:37.00,yin,,0,0,0,, 我可以使用一个静态变量 \\N{\\fs12}Now, I could use a static variable.\r\nDialogue: 0,0:23:37.00,0:23:39.32,yin,,0,0,0,, 这是 C 我可以存储这个数组 \\N{\\fs12}This is C. I could store this array.\r\nDialogue: 0,0:23:39.32,0:23:40.71,yin,,0,0,0,, 开始是 nil\\N{\\fs12}Started out being nil.\r\nDialogue: 0,0:23:40.71,0:23:44.24,yin,,0,0,0,, 如果是 nil 设置到这个数组 然后它只会创建一次 \\N{\\fs12}If it’s nil, set it to this array, and then it would only create it once.\r\nDialogue: 0,0:23:44.24,0:23:45.47,yin,,0,0,0,, 但要小心 \\N{\\fs12}But be careful.\r\nDialogue: 0,0:23:45.47,0:23:47.20,yin,,0,0,0,, 还是那句话 代码简洁性 \\N{\\fs12}Again, code cleanliness\r\nDialogue: 0,0:23:47.20,0:23:49.84,yin,,0,0,0,, 还有易理解性 比这样的性能重要十倍 \\N{\\fs12}and understandably ten times more important than performance like this.\r\nDialogue: 0,0:23:49.84,0:23:52.85,yin,,0,0,0,, 只要你不是在循环中上千次地调用 validSuits\\N{\\fs12}So unless you’re going to call valid suits in the inner loop thousands of times,\r\nDialogue: 0,0:23:52.85,0:23:54.42,yin,,0,0,0,, 这个影响都很小 \\N{\\fs12}it’s not really going to matter.\r\nDialogue: 0,0:23:54.42,0:23:57.79,yin,,0,0,0,, 我把它往上移动到一个不同方法中 \\N{\\fs12}But once I move that up into a different method,\r\nDialogue: 0,0:23:57.79,0:24:00.72,yin,,0,0,0,, 但这个方法有些不同 \\N{\\fs12}this kind of method that I moved it to is a little different.\r\nDialogue: 0,0:24:00.72,0:24:02.50,yin,,0,0,0,, 注意到它前面是个加号 \\N{\\fs12}Notice it has a plus.\r\nDialogue: 0,0:24:02.50,0:24:06.08,yin,,0,0,0,, 最开始是加号 而不是减号 看到了吗 \\N{\\fs12}You see a plus there instead of a minus starting it?\r\nDialogue: 0,0:24:06.08,0:24:08.38,yin,,0,0,0,,+ (NSArray *)validSuits\\N{\\fs12}Plus NS array valid suits?\r\nDialogue: 0,0:24:08.38,0:24:11.09,yin,,0,0,0,,+ 方法是一个类方法 \\N{\\fs12}Okay. A plus method is a class method.\r\nDialogue: 0,0:24:11.09,0:24:17.13,yin,,0,0,0,, 这意味着你将它发送给类 而不是对象实例 \\N{\\fs12}That means you send it to the class, not to an instance of an object.\r\nDialogue: 0,0:24:17.85,0:24:19.59,yin,,0,0,0,, 因为不是发送给一个实例 \\N{\\fs12}So since you’re not sending it to an instance,\r\nDialogue: 0,0:24:19.59,0:24:23.02,yin,,0,0,0,, 所以你不能使用任何实例变量 \\N{\\fs12}you can’t use any instance variables or anything like that.\r\nDialogue: 0,0:24:23.02,0:24:25.25,yin,,0,0,0,, 你只能做一些通用性的事情 \\N{\\fs12}You can only just kind of do generic stuff.\r\nDialogue: 0,0:24:25.25,0:24:30.14,yin,,0,0,0,, 实际上 + 方法 类方法只用于两种情况 \\N{\\fs12}So the only thing we really use plus methods for, class methods, is two things really:\r\nDialogue: 0,0:24:30.14,0:24:31.86,yin,,0,0,0,, 创建事物 \\N{\\fs12}Creating things\r\nDialogue: 0,0:24:31.86,0:24:36.01,yin,,0,0,0,, 例如上一张幻灯片中我们有带格式的字符串时 \\N{\\fs12}like in the previous slide when we had string with format –\r\nDialogue: 0,0:24:36.01,0:24:38.91,yin,,0,0,0,, 这是类方法 为我们创建一个字符串 \\N{\\fs12}that’s a class method that was creating a string for us;\r\nDialogue: 0,0:24:38.91,0:24:41.88,yin,,0,0,0,, 然后就是这样的工具方法 \\N{\\fs12}and then also utility methods like this,\r\nDialogue: 0,0:24:41.88,0:24:43.93,yin,,0,0,0,, 例如返回常数 \\N{\\fs12}like the return constants\r\nDialogue: 0,0:24:43.93,0:24:47.21,yin,,0,0,0,, 还有其它我们的类需要工具方法的情况 \\N{\\fs12}and things that, you know, our class wants and utility methods.\r\nDialogue: 0,0:24:47.21,0:24:48.26,yin,,0,0,0,, 这是一个例子 \\N{\\fs12}But here’s an example.\r\nDialogue: 0,0:24:48.26,0:24:50.25,yin,,0,0,0,, 再看调用类方法的方式 \\N{\\fs12}And the way we call the class method –\r\nDialogue: 0,0:24:50.25,0:24:52.16,yin,,0,0,0,, 你们已经看过我调用了一些 \\N{\\fs12}you’ve already seen me call a few of them –\r\nDialogue: 0,0:24:52.16,0:24:55.25,yin,,0,0,0,, 这里就是在调用它 首先是开方括号 \\N{\\fs12}but here’s calling it here is we put open square bracket,\r\nDialogue: 0,0:24:55.25,0:24:58.10,yin,,0,0,0,, 然后是类名 然后是方法名 \\N{\\fs12}the name of the class, the name of the method.\r\nDialogue: 0,0:24:58.10,0:25:00.54,yin,,0,0,0,, 同其它方法一样 它也可以有参数 \\N{\\fs12}And again, it could have arguments. It’s just like any other method.\r\nDialogue: 0,0:25:00.56,0:25:02.91,yin,,0,0,0,, 大家都能理解吗 \\N{\\fs12}But everyone understand this?\r\nDialogue: 0,0:25:03.69,0:25:05.63,yin,,0,0,0,, 好 回头几张幻灯片 \\N{\\fs12}Okay. And if you go back and look a couple slides\r\nDialogue: 0,0:25:05.63,0:25:09.14,yin,,0,0,0,, 你会看到 [NSString 带格式的字符串 \\N{\\fs12}and you see open square bracket NS string, string with format,\r\nDialogue: 0,0:25:09.14,0:25:12.03,yin,,0,0,0,, 完全相同的语法 \\N{\\fs12}same exact type of syntax.\r\nDialogue: 0,0:25:12.03,0:25:13.72,yin,,0,0,0,, 这就是类方法的样子 \\N{\\fs12}So that's what a class method looks like.\r\nDialogue: 0,0:25:13.72,0:25:19.35,yin,,0,0,0,, 用于创建事物 以及用作工具方法 \\N{\\fs12}Again, for creating things basically and for utility methods.\r\nDialogue: 0,0:25:19.35,0:25:20.46,yin,,0,0,0,, 我们会谈到 \\N{\\fs12}And we'll talk about the difference of:\r\nDialogue: 0,0:25:20.46,0:25:23.88,yin,,0,0,0,, 用类方法创建和用 alloc init 创建的不同 \\N{\\fs12}When do we create something with a class method versus alloc init?\r\nDialogue: 0,0:25:23.88,0:25:25.66,yin,,0,0,0,, 不久后我就会讲到 \\N{\\fs12}We'll talk about that soon.\r\nDialogue: 0,0:25:25.66,0:25:28.97,yin,,0,0,0,, 我还让 validSuits 是公共的 \\N{\\fs12}I'm also going to make valid suits public.\r\nDialogue: 0,0:25:28.97,0:25:33.36,yin,,0,0,0,, 这样 PlayingCard 的使用者就知道 validSuits 是什么 \\N{\\fs12}And that way people who are using my playing card know what the valid suits are.\r\nDialogue: 0,0:25:33.36,0:25:35.29,yin,,0,0,0,, 我只需要把它放到头文件中 \\N{\\fs12}And all I need to do is put it in the header file.\r\nDialogue: 0,0:25:35.29,0:25:36.77,yin,,0,0,0,, 现在就是公共的了 \\N{\\fs12}Boom, it's public now.\r\nDialogue: 0,0:25:36.77,0:25:41.42,yin,,0,0,0,, 这里对扑克牌大小字符串也做相同的事情 \\N{\\fs12}So let's do a similar thing here with those rank strings.\r\nDialogue: 0,0:25:41.42,0:25:45.79,yin,,0,0,0,, 我将把上面的大小字符串 \\N{\\fs12}So I'm going to take those ranks strings -- that array of rank strings right up there --\r\nDialogue: 0,0:25:45.79,0:25:48.90,yin,,0,0,0,, 放入到一个类方法中 \\N{\\fs12}and I'm going to put that in a class method.\r\nDialogue: 0,0:25:48.90,0:25:52.28,yin,,0,0,0,, 还是那句话 这是为了可读性 而非性能 \\N{\\fs12}And again, this is for readability, not for performance.\r\nDialogue: 0,0:25:52.28,0:25:56.68,yin,,0,0,0,, 因为每次调用 rankStrings 这都会重新创建 \\N{\\fs12}Because every time I call rank strings, it's still going to create that thing again.\r\nDialogue: 0,0:25:56.68,0:26:00.36,yin,,0,0,0,, 然后 我在这上面调用它 \\N{\\fs12}And then I call it instead up there.\r\nDialogue: 0,0:26:00.36,0:26:03.70,yin,,0,0,0,, 我不打算让 rankStrings 本身成为公共的 \\N{\\fs12}And I'm not going to make rank strings itself public,\r\nDialogue: 0,0:26:03.70,0:26:06.88,yin,,0,0,0,, 但我打算让另一个类方法 maxRank 成为公共的 \\N{\\fs12}but I am going to make another class method called max rank,\r\nDialogue: 0,0:26:06.88,0:26:09.71,yin,,0,0,0,, 这个方法考虑的是 rankStrings 中有多少字符串 \\N{\\fs12}which just looks at how many strings are in rank strings.\r\nDialogue: 0,0:26:09.71,0:26:13.08,yin,,0,0,0,, 我将把这作为公共方法返回 \\N{\\fs12}And I'm going to return that as a public method.\r\nDialogue: 0,0:26:13.08,0:26:16.51,yin,,0,0,0,, 这里有三个类方法 让你们钻研 \\N{\\fs12}So there's three class methods for you to sink your teeth\r\nDialogue: 0,0:26:16.51,0:26:19.88,yin,,0,0,0,, 两个是公共的 一个不是 \\N{\\fs12}into -- two of them public, one not.\r\nDialogue: 0,0:26:19.88,0:26:22.11,yin,,0,0,0,, 这些都是工具方法 \\N{\\fs12}All right. And so they're all utility methods, right?\r\nDialogue: 0,0:26:22.11,0:26:26.32,yin,,0,0,0,, 我们没有在任何这些方法中访问任何实例变量 \\N{\\fs12}We're not accessing any instance variables in any of those methods.\r\nDialogue: 0,0:26:26.32,0:26:28.70,yin,,0,0,0,, 我讲这些的唯一原因 \\N{\\fs12}That's the only reason I'm showing those,\r\nDialogue: 0,0:26:28.70,0:26:31.65,yin,,0,0,0,, 就是让你们了解类方法是怎样的 \\N{\\fs12}is just so you see what a class method looks like.\r\nDialogue: 0,0:26:33.17,0:26:35.88,yin,,0,0,0,, 我们还可以重写 rank 的 setter\\N{\\fs12}We also could override the setter of rank just\r\nDialogue: 0,0:26:35.88,0:26:38.21,yin,,0,0,0,, 来保证这里不允许 \\N{\\fs12}to be complete here to make sure it doesn't allow you\r\nDialogue: 0,0:26:38.21,0:26:40.97,yin,,0,0,0,, 设置错误的大小 例如 15\\N{\\fs12}to set a wrong rank like set rank 15 --\r\nDialogue: 0,0:26:40.97,0:26:42.32,yin,,0,0,0,, 没有大小为 15 的牌 \\N{\\fs12}there's no such card as 15.\r\nDialogue: 0,0:26:42.32,0:26:45.82,yin,,0,0,0,, 我们需要确保大小小于最大大小 \\N{\\fs12}So let's make sure that the rank is less than the max rank,\r\nDialogue: 0,0:26:45.82,0:26:47.61,yin,,0,0,0,, 刚那个工具方法做了这个 \\N{\\fs12}which is the utility method we just did.\r\nDialogue: 0,0:26:47.61,0:26:50.93,yin,,0,0,0,, 大家都理解了吗 \\N{\\fs12}Does that all come together for you, make sense?\r\nDialogue: 0,0:26:50.93,0:26:53.03,yin,,0,0,0,, 这里只是参考材料 \\N{\\fs12}So this is kind of reference material.\r\nDialogue: 0,0:26:53.03,0:26:56.50,yin,,0,0,0,, 你们的幻灯片中 有我讲的所有这些注释 \\N{\\fs12}You have these slides that have all the annotations of all the things I'm saying.\r\nDialogue: 0,0:26:56.50,0:26:59.21,yin,,0,0,0,, 你们可以回头看幻灯片当作复习 \\N{\\fs12}So feel free to go back and look at it and remind yourself\r\nDialogue: 0,0:26:59.21,0:27:01.95,yin,,0,0,0,, 关于这些 NSArray 语法 \\N{\\fs12}about all these NS array, syntax,\r\nDialogue: 0,0:27:01.95,0:27:04.49,yin,,0,0,0,, 这些类方法 等等 \\N{\\fs12}and all the class methods, all that stuff.\r\nDialogue: 0,0:27:04.49,0:27:08.51,yin,,0,0,0,, 最后我们要看的是 init 方法 \\N{\\fs12}Okay. The last thing we're going to look at is the init method business.\r\nDialogue: 0,0:27:08.51,0:27:12.08,yin,,0,0,0,, 这里我们还有一个类叫 PlayingCardDeck\\N{\\fs12}So we're going to have another class here called playing card deck.\r\nDialogue: 0,0:27:12.08,0:27:15.85,yin,,0,0,0,,PlayingCardDeck 是 Deck 的一个子类 \\N{\\fs12}And a playing card deck is a subclass of deck.\r\nDialogue: 0,0:27:15.85,0:27:18.97,yin,,0,0,0,, 它没有公共 API\\N{\\fs12}And it has no public API.\r\nDialogue: 0,0:27:18.97,0:27:25.34,yin,,0,0,0,, 它将只是重写一个间接继承自 NSObject 的方法 \\N{\\fs12}It's just going to override a method that it inherits indirectly from NS object --\r\nDialogue: 0,0:27:25.34,0:27:28.15,yin,,0,0,0,,NSObject 通过 Deck 这里没动它 \\N{\\fs12}okay, NS object through deck, which doesn't touch it --\r\nDialogue: 0,0:27:28.15,0:27:29.71,yin,,0,0,0,, 直到 PlayingCardDeck\\N{\\fs12}all the way to playing card deck.\r\nDialogue: 0,0:27:29.73,0:27:32.11,yin,,0,0,0,, 这个方法叫作 init\\N{\\fs12}And that method is called init.\r\nDialogue: 0,0:27:32.11,0:27:37.91,yin,,0,0,0,, 这个 init 同之前我们创建那个可变数组时所说的 \\N{\\fs12}So this is the same init, same kind of method that when we created that array --\r\nDialogue: 0,0:27:37.91,0:27:41.28,yin,,0,0,0,,[NSMutableArray alloc] init 中的 init 一样 \\N{\\fs12}that mutable array we said NS mutable array alloc init.\r\nDialogue: 0,0:27:41.28,0:27:45.00,yin,,0,0,0,, 有人需要调用这个 PlayingCardDeck init 方法 \\N{\\fs12}so someone is going to call this PlayingCardDeck init method –\r\nDialogue: 0,0:27:45.00,0:27:47.34,yin,,0,0,0,, 也就是你们 在作业中 \\N{\\fs12}namely you in your homework\r\nDialogue: 0,0:27:47.34,0:27:50.44,yin,,0,0,0,, 会通过 PlayingCardDeck alloc 调用这个 \\N{\\fs12}are going to call this by doing playing card deck alloc,\r\nDialogue: 0,0:27:50.44,0:27:52.78,yin,,0,0,0,, 然后外面再写 init\\N{\\fs12}and then on the outside, init.\r\nDialogue: 0,0:27:52.78,0:27:55.38,yin,,0,0,0,, 这就是创建一个 PlayingCardDeck 的方式 \\N{\\fs12}And that’s how you’re going to create a playing card deck.\r\nDialogue: 0,0:27:55.38,0:27:59.23,yin,,0,0,0,, 这就是我们创建大多数对象实例的方式 并非所有 \\N{\\fs12}And that is how we create most instances of objects — not all.\r\nDialogue: 0,0:27:59.23,0:28:02.14,yin,,0,0,0,, 有时我们会使用 NSString 带格式的字符串 \\N{\\fs12}Sometimes we do things like the NS string, string with format.\r\nDialogue: 0,0:28:02.14,0:28:04.07,yin,,0,0,0,, 但大多数时候 大于一半的时候 \\N{\\fs12}But most of the time — more than half the time –\r\nDialogue: 0,0:28:04.07,0:28:06.64,yin,,0,0,0,, 我们会用 alloc 然后外面用 init\\N{\\fs12}we do alloc and then on the outside init.\r\nDialogue: 0,0:28:06.64,0:28:08.04,yin,,0,0,0,, 听好 \\N{\\fs12}Listen carefully:\r\nDialogue: 0,0:28:08.04,0:28:13.03,yin,,0,0,0,, 除了外面有 init 时 永远别调用 alloc 那些东西 \\N{\\fs12}Never call that alloc thing without wrapping an init around it.\r\nDialogue: 0,0:28:13.03,0:28:14.35,yin,,0,0,0,, 不要犯忌 \\N{\\fs12}Don’t ever do that.\r\nDialogue: 0,0:28:14.35,0:28:18.52,yin,,0,0,0,, 不初始化就分配对象在堆中毫无意义 \\N{\\fs12}That makes no sense to have an object allocated in the heap that’s never been initialized.\r\nDialogue: 0,0:28:18.52,0:28:19.96,yin,,0,0,0,, 只有嵌套才对 \\N{\\fs12}Always have that nested.\r\nDialogue: 0,0:28:19.96,0:28:25.22,yin,,0,0,0,, 反之 除了里面有 alloc 外面也不要调用 init\\N{\\fs12}And vice versa: Never call that init except for when you wrap it around an alloc.\r\nDialogue: 0,0:28:25.22,0:28:27.79,yin,,0,0,0,, 而且一定不要超过一次地调用 init\\N{\\fs12}And definitely never call that init more than once.\r\nDialogue: 0,0:28:27.79,0:28:31.36,yin,,0,0,0,, 如果你按照我说的 只在里面有 alloc 时才调用 \\N{\\fs12}And if you obey my rule of only calling it wrapped around an alloc,\r\nDialogue: 0,0:28:31.36,0:28:32.87,yin,,0,0,0,, 调用就不可能超过一次 \\N{\\fs12}you can’t call it more than once.\r\nDialogue: 0,0:28:32.87,0:28:36.17,yin,,0,0,0,,init 没有说你能重新 init 的 \\N{\\fs12}Init is not something like you can re-init.\r\nDialogue: 0,0:28:36.17,0:28:39.58,yin,,0,0,0,,init 只能发生一次 紧接 alloc 之后 这就完了 \\N{\\fs12}Init happens once right after alloc, and that’s it.\r\nDialogue: 0,0:28:39.58,0:28:43.49,yin,,0,0,0,, 这是一条硬性规定 永远不要违反 \\N{\\fs12}That is a hard and fast rule we never break.\r\nDialogue: 0,0:28:43.49,0:28:45.06,yin,,0,0,0,, 这里我讲了 \\N{\\fs12}So you heard it here.\r\nDialogue: 0,0:28:45.06,0:28:46.11,yin,,0,0,0,, 别忘记 \\N{\\fs12}Don’t forget.\r\nDialogue: 0,0:28:46.63,0:28:50.92,yin,,0,0,0,, 好 我们来看看这个 init 方法的怪异返回类型 \\N{\\fs12}All right. Let’s look at the whacky return type to this init method.\r\nDialogue: 0,0:28:50.92,0:28:55.41,yin,,0,0,0,, 你也许会以为 init 方法会返回一个 PlayingCardDeck\\N{\\fs12}You might think this init method should return a playing card deck star\r\nDialogue: 0,0:28:55.43,0:28:58.90,yin,,0,0,0,, 因为它在初始化 也许会返回它自身 \\N{\\fs12}because it’s kind of initializing and maybe it returns itself.\r\nDialogue: 0,0:28:58.90,0:29:02.53,yin,,0,0,0,, 实际上 init 确实总返回 self\\N{\\fs12}And in fact, init does always return self.\r\nDialogue: 0,0:29:02.53,0:29:04.76,yin,,0,0,0,,init 总会返回自身 \\N{\\fs12}So init is always going to return self.\r\nDialogue: 0,0:29:04.76,0:29:07.03,yin,,0,0,0,, 这里比较怪异 我会讲到 \\N{\\fs12}Okay. More whackiness there, which I’m going to describe.\r\nDialogue: 0,0:29:07.03,0:29:10.32,yin,,0,0,0,, 方便起见 它总返回 self 让你能够写 \\N{\\fs12}Just for convenience, it always returns self so that you can do,\r\nDialogue: 0,0:29:10.32,0:29:14.32,yin,,0,0,0,,[PlayingCardDeck alloc] init 这些 发送一条消息 \\N{\\fs12}like, playing card deck alloc init, sent it a message.\r\nDialogue: 0,0:29:14.32,0:29:17.33,yin,,0,0,0,, 它返回 self 是很方便的 \\N{\\fs12}So it’s just convenience that it returns self.\r\nDialogue: 0,0:29:17.33,0:29:21.28,yin,,0,0,0,, 但它的返回类型不能是 PlayingCardDeck\\N{\\fs12}But it can’t really have its return type being playing card deck star\r\nDialogue: 0,0:29:21.30,0:29:23.48,yin,,0,0,0,, 因为这些它继承于 NSObject\\N{\\fs12}because it inherited this from NS object.\r\nDialogue: 0,0:29:23.48,0:29:28.48,yin,,0,0,0,, 而 NSObject 已经将其定义为 NSObject\\N{\\fs12}And NS object already defined it as NS object star.\r\nDialogue: 0,0:29:28.48,0:29:30.52,yin,,0,0,0,, 明白吗 所以说有些奇怪 \\N{\\fs12}You see? So it’s kind of weird\r\nDialogue: 0,0:29:30.52,0:29:32.79,yin,,0,0,0,, 你继承了一个方法 其返回值 \\N{\\fs12}that you’re inheriting a method whose return value would have\r\nDialogue: 0,0:29:32.79,0:29:36.87,yin,,0,0,0,, 需要在每次重写时发生变化 \\N{\\fs12}to change every time you, you know, overrode it.\r\nDialogue: 0,0:29:36.87,0:29:40.37,yin,,0,0,0,, 于是人们发明了这个新东西 这是 iOS7 的新属性 \\N{\\fs12}So they invented this new thing — this is new for iOS 7, by the way –\r\nDialogue: 0,0:29:40.39,0:29:42.01,yin,,0,0,0,, 叫实例类型 \\N{\\fs12}called instance type.\r\nDialogue: 0,0:29:42.01,0:29:43.94,yin,,0,0,0,, 实例类型也就是说 \\N{\\fs12}And what instance type means is this is going\r\nDialogue: 0,0:29:43.94,0:29:49.49,yin,,0,0,0,, 这会返回一个对象 具有相同类类型 \\N{\\fs12}to return an object that is of the same instance — same type, same class type –\r\nDialogue: 0,0:29:49.49,0:29:52.18,yin,,0,0,0,, 同这条消息要发送到的对象一样 \\N{\\fs12}as the object you sent this message to.\r\nDialogue: 0,0:29:52.18,0:29:54.75,yin,,0,0,0,, 这对 init 很有意义 \\N{\\fs12}Which makes perfect sense for inits.\r\nDialogue: 0,0:29:54.75,0:29:58.14,yin,,0,0,0,, 这门课上 只有这里会用到这个 \\N{\\fs12}And in this class that’s probably all you’re going to use this for right here.\r\nDialogue: 0,0:29:58.14,0:30:00.80,yin,,0,0,0,, 听不懂我刚讲的这些不要紧 我在幻灯片中也讲了 \\N{\\fs12}So if you don’t really understand what I just said — it’s explained in the slides –\r\nDialogue: 0,0:30:00.80,0:30:02.05,yin,,0,0,0,, 听不懂我刚讲的这些不要紧 我在幻灯片中也讲了 \\N{\\fs12}but if you don’t really understand it,\r\nDialogue: 0,0:30:02.05,0:30:04.08,yin,,0,0,0,, 你只需知道 凡是初始化时 \\N{\\fs12}just know that whenever you do an initializer,\r\nDialogue: 0,0:30:04.08,0:30:07.68,yin,,0,0,0,, 它都会返回实例类型作为返回类型 \\N{\\fs12}it’s going to return instance type as its return type\r\nDialogue: 0,0:30:07.68,0:30:10.02,yin,,0,0,0,, 你将总是返回 self\\N{\\fs12}and you’re always going to return self.\r\nDialogue: 0,0:30:11.67,0:30:14.49,yin,,0,0,0,, 还有一点 也是记住就行 \\N{\\fs12}Now, also just take my word for it.\r\nDialogue: 0,0:30:14.49,0:30:18.28,yin,,0,0,0,, 后面这几行代码也非常奇怪 \\N{\\fs12}We’re going to do these next lines of codes as well because they are really strange.\r\nDialogue: 0,0:30:18.28,0:30:21.88,yin,,0,0,0,, 第一行 self = [super init] 这很奇怪 \\N{\\fs12}That first line, self equals super init, that is weird.\r\nDialogue: 0,0:30:21.88,0:30:23.11,yin,,0,0,0,, 这非常奇怪 \\N{\\fs12}That is super weird.\r\nDialogue: 0,0:30:23.11,0:30:26.89,yin,,0,0,0,,Objective-C 中将什么东西复制给 self\\N{\\fs12}Assigning something to self in Objective-C –\r\nDialogue: 0,0:30:26.89,0:30:30.30,yin,,0,0,0,, 永远不要这样做 唯独除了 init 里 \\N{\\fs12}just never do that, except for this one time and that’s in your init.\r\nDialogue: 0,0:30:30.30,0:30:35.88,yin,,0,0,0,, 对 self 赋值 调用父类初始化器 \\N{\\fs12}You take self and you assign it to calling your superclasses initializer\r\nDialogue: 0,0:30:35.88,0:30:37.95,yin,,0,0,0,, 于是父类会被初始化 \\N{\\fs12}so that your superclass gets initialized.\r\nDialogue: 0,0:30:37.95,0:30:40.99,yin,,0,0,0,, 为什么将结果赋值给 self 呢 \\N{\\fs12}Why do we assign the result to self?\r\nDialogue: 0,0:30:40.99,0:30:42.99,yin,,0,0,0,, 可以说是古老的历史残留 \\N{\\fs12}It’s kind of ancient history\r\nDialogue: 0,0:30:42.99,0:30:45.44,yin,,0,0,0,, 因为人们这样做了很长时间 \\N{\\fs12}as to why this has been done for a long time.\r\nDialogue: 0,0:30:45.44,0:30:48.85,yin,,0,0,0,, 一般 我们会检验父类 init 的返回 \\N{\\fs12}Basically we’re checking the return of our superclasses init\r\nDialogue: 0,0:30:48.85,0:30:50.67,yin,,0,0,0,, 确保它正确被初始化 \\N{\\fs12}to make sure it properly initialized.\r\nDialogue: 0,0:30:50.67,0:30:55.08,yin,,0,0,0,, 因为任何初始化器无法初始化自身的时候 \\N{\\fs12}Because at any time if your initializer cannot initialize itself,\r\nDialogue: 0,0:30:55.08,0:30:56.99,yin,,0,0,0,, 它应返回 nil\\N{\\fs12}it should return nil.\r\nDialogue: 0,0:30:56.99,0:31:00.31,yin,,0,0,0,, 这让所有人知道 你的任意子类 \\N{\\fs12}And that lets everybody know any of your subclasses\r\nDialogue: 0,0:31:00.31,0:31:02.67,yin,,0,0,0,, 或任何人尝试分配和初始化你 \\N{\\fs12}or anyone trying to alloc and initialize you,\r\nDialogue: 0,0:31:02.67,0:31:05.09,yin,,0,0,0,, 你无法创建一个结构良好的对象 \\N{\\fs12}you could not create a well-formed object.\r\nDialogue: 0,0:31:05.09,0:31:07.54,yin,,0,0,0,, 你可以看到 这个代码很奇怪 \\N{\\fs12}So you can see how this code, strange as it is –\r\nDialogue: 0,0:31:07.54,0:31:09.56,yin,,0,0,0,,self = [super init] 然后 if (self)\\N{\\fs12}self equals super init, and then if self,\r\nDialogue: 0,0:31:09.56,0:31:12.50,yin,,0,0,0,, 我将初始化自身 返回 self\\N{\\fs12}I’m going to initialize myself, return self –\r\nDialogue: 0,0:31:12.50,0:31:16.80,yin,,0,0,0,, 这将能确保 当我的父类在我调用 init 时 \\N{\\fs12}that’s going to ensure that I don’t even try to initialize myself if my superclass,\r\nDialogue: 0,0:31:16.80,0:31:21.37,yin,,0,0,0,, 如果无法初始化自身 我就不用尝试初始化我自己 \\N{\\fs12}when I call its init, you know, can’t initialize itself.\r\nDialogue: 0,0:31:21.37,0:31:24.27,yin,,0,0,0,, 照做就行了 \\N{\\fs12}So just do it.\r\nDialogue: 0,0:31:24.27,0:31:27.73,yin,,0,0,0,, 不懂不要紧 照做就行了 \\N{\\fs12}If you don’t understand it, don’t worry about it too much. Just do it.\r\nDialogue: 0,0:31:27.73,0:31:31.14,yin,,0,0,0,, 有一点我要讲明 init 没有参数 \\N{\\fs12}Now, one thing here is we’re talking about init with no arguments.\r\nDialogue: 0,0:31:31.14,0:31:33.83,yin,,0,0,0,, 让初始化器有参数是完全有可能的 \\N{\\fs12}It is possible to have initializers with arguments\r\nDialogue: 0,0:31:33.83,0:31:36.94,yin,,0,0,0,, 因为有时你需要参数来恰当地初始化一个类 \\N{\\fs12}because sometimes you need arguments to properly initialize a class.\r\nDialogue: 0,0:31:36.94,0:31:40.05,yin,,0,0,0,, 周一我会进一步讲到这个 \\N{\\fs12}And we’re going to talk about that a little more on Monday.\r\nDialogue: 0,0:31:40.05,0:31:43.05,yin,,0,0,0,, 今天只讲解 init 的梗概 \\N{\\fs12}So today we’re just going to kind of bare bones init.\r\nDialogue: 0,0:31:43.05,0:31:45.11,yin,,0,0,0,, 这个 init 需要做什么 \\N{\\fs12}So what does this init need to do?\r\nDialogue: 0,0:31:45.11,0:31:46.32,yin,,0,0,0,, 我需要怎样做 \\N{\\fs12}What do I need to do\r\nDialogue: 0,0:31:46.32,0:31:48.56,yin,,0,0,0,, 才能得到初始化良好的 PlayingCardDeck\\N{\\fs12}to have a well-formed initialized playing card deck?\r\nDialogue: 0,0:31:48.56,0:31:53.30,yin,,0,0,0,,PlayingCardDeck 有 52 张牌 一样一张 \\N{\\fs12}Well, a playing card deck has 52 cards in it, one of each kind of card.\r\nDialogue: 0,0:31:53.30,0:31:57.75,yin,,0,0,0,, 梅花 K 方片 3 总共 52 张 \\N{\\fs12}King of clubs, three of diamonds — all 52 of them.\r\nDialogue: 0,0:31:57.75,0:32:03.16,yin,,0,0,0,, 我只需要遍历所有花色 遍历所有大小 \\N{\\fs12}So I just need to iterate to all the suits, and then iterate through all the ranks,\r\nDialogue: 0,0:32:03.16,0:32:06.24,yin,,0,0,0,, 创建一张牌 然后添加到我自身 \\N{\\fs12}and create a card, and add it to myself.\r\nDialogue: 0,0:32:06.24,0:32:09.81,yin,,0,0,0,, 这里我遍历花色 遍历大小 \\N{\\fs12}So here’s me iterating through the suits, iterating through the ranks.\r\nDialogue: 0,0:32:09.81,0:32:12.38,yin,,0,0,0,, 大家都明白吗 \\N{\\fs12}Everyone cool with that?\r\nDialogue: 0,0:32:12.38,0:32:16.02,yin,,0,0,0,, 然后我将导入 PlayingCard\\N{\\fs12}Then I’m going to import playing card\r\nDialogue: 0,0:32:16.02,0:32:18.57,yin,,0,0,0,, 因为我要创建一张 PlayingCard\\N{\\fs12}because I’m going to create a playing card,\r\nDialogue: 0,0:32:18.58,0:32:20.52,yin,,0,0,0,,[PlayingCard alloc] init\\N{\\fs12}playing card alloc init.\r\nDialogue: 0,0:32:20.52,0:32:23.83,yin,,0,0,0,, 然后我要设置这张牌的大小 设置花色 \\N{\\fs12}Then I’m going to set that card’s rank, set that card’s suit.\r\nDialogue: 0,0:32:23.83,0:32:28.40,yin,,0,0,0,,rank 和 suit 是这里的迭代变量 \\N{\\fs12}Rank and suit are my little iteration variables there.\r\nDialogue: 0,0:32:28.40,0:32:31.05,yin,,0,0,0,, 然后我把它加到我自身 \\N{\\fs12}And then I’m going to add it to myself.\r\nDialogue: 0,0:32:31.05,0:32:35.50,yin,,0,0,0,, 我是一个 Deck 这很好 \\N{\\fs12}I’m a deck, so that’s perfectly fine.\r\nDialogue: 0,0:32:35.50,0:32:39.36,yin,,0,0,0,, 大家都明白这段代码吗 \\N{\\fs12}Everybody cool with that code?\r\nDialogue: 0,0:32:39.36,0:32:42.93,yin,,0,0,0,, 现在我就得到一个结构良好的 PlayingCardDeck\\N{\\fs12}So now I’m a well-formed playing card deck and I can be used\r\nDialogue: 0,0:32:42.93,0:32:45.39,yin,,0,0,0,, 可以被用于随机抽取纸牌 等等动作 \\N{\\fs12}to draw random cards and all that stuff,\r\nDialogue: 0,0:32:45.39,0:32:47.45,yin,,0,0,0,, 这将是你们的作业内容 \\N{\\fs12}which you will need to do for your homework.\r\nDialogue: 0,0:32:48.50,0:32:51.66,yin,,0,0,0,, 实际上 你们的作业是将所有这四个类补全 \\N{\\fs12}And in fact, for your homework you’re going to have to type all four of these classes in.\r\nDialogue: 0,0:32:51.66,0:32:54.57,yin,,0,0,0,, 我希望你们体会到录入类 键入内容 \\N{\\fs12}I want you to get experience entering classes, typing a thing,\r\nDialogue: 0,0:32:54.57,0:32:59.78,yin,,0,0,0,, 观看 Xcode 抱怨你的错误 等等 \\N{\\fs12}watching as Xcode complains at you as you mistype things, and stuff like that.\r\nDialogue: 0,0:32:59.78,0:33:03.52,yin,,0,0,0,, 然后你们将会使用 PlayingCardDeck 和 PlayingCard\\N{\\fs12}And then you’re going to be using playing card deck and playing card.\r\nDialogue: 0,0:33:03.52,0:33:06.22,yin,,0,0,0,,PlayingCardDeck 和 Card 是你们作业中 \\N{\\fs12}Well, playing card deck and card really are the two main ones\r\nDialogue: 0,0:33:06.22,0:33:08.40,yin,,0,0,0,, 主要要用到的两个类 \\N{\\fs12}you’re going to be using to do your homework.\r\nDialogue: 0,0:33:09.39,0:33:11.88,yin,,0,0,0,, 对此有问题吗 \\N{\\fs12}Questions about that?\r\nDialogue: 0,0:33:11.88,0:33:14.22,yin,,0,0,0,, 幻灯片就到这里 \\N{\\fs12}Okay. So that’s it for the slides.\r\nDialogue: 0,0:33:14.22,0:33:16.97,yin,,0,0,0,, 下面我将给出一个大而古老的 demo\\N{\\fs12}So now I’m going to do a big old demo.\r\nDialogue: 0,0:33:16.97,0:33:21.29,yin,,0,0,0,, 这个 demo 将综合你们到目前为止看到过的一切 \\N{\\fs12}And this demo is going to integrate everything you’ve seen so far.\r\nDialogue: 0,0:33:21.29,0:33:23.68,yin,,0,0,0,, 尤其是我们谈过的 MVC 内容 \\N{\\fs12}Most notably that MVC stuff we talked about,\r\nDialogue: 0,0:33:23.68,0:33:26.94,yin,,0,0,0,, 例如目标动作 设置目标 发射动作 \\N{\\fs12}like target action, you know, dropping the target and shooting the action\r\nDialogue: 0,0:33:26.94,0:33:30.07,yin,,0,0,0,, 还有绿色箭头的 outlet 指向相反方向 \\N{\\fs12}or the green arrow outlet that points the other way.\r\nDialogue: 0,0:33:30.07,0:33:34.22,yin,,0,0,0,, 我们会展示这些在 Xcode 中是怎样 \\N{\\fs12}We’re going to show you what that actually looks like in Xcode.\r\nDialogue: 0,0:33:34.22,0:33:37.19,yin,,0,0,0,, 我问你们谁用过 Xcode 时 \\N{\\fs12}I think when I asked who of you have done Xcode,\r\nDialogue: 0,0:33:37.19,0:33:39.24,yin,,0,0,0,, 几乎所有人都举手了 \\N{\\fs12}almost every single one of you raised your hands.\r\nDialogue: 0,0:33:39.24,0:33:42.16,yin,,0,0,0,, 所以我不打算讲解 Xcode 中的所有按钮 \\N{\\fs12}So I’m not going to spend too much time talking about all the buttons in Xcode.\r\nDialogue: 0,0:33:42.16,0:33:44.68,yin,,0,0,0,, 我将很快略过这些 \\N{\\fs12}I think I’ll quickly pass over those.\r\nDialogue: 0,0:33:44.68,0:33:49.75,yin,,0,0,0,, 没有用过 Xcode 的人 课程幻灯片中有详细介绍 \\N{\\fs12}But if you haven’t used Xcode, it’s in very much detail in the lecture slides.\r\nDialogue: 0,0:33:49.75,0:33:51.44,yin,,0,0,0,, 你们可以看看 \\N{\\fs12}There’s kind of this walkthrough.\r\nDialogue: 0,0:33:51.44,0:33:54.19,yin,,0,0,0,, 你可以跟随课程幻灯片一起看 \\N{\\fs12}By the way, if you’re following along in the lecture slides,\r\nDialogue: 0,0:33:54.19,0:33:57.07,yin,,0,0,0,, 不过我的 demo 同幻灯片中不完全一样 \\N{\\fs12}my demo’s not going to be exactly like what’s in the slides.\r\nDialogue: 0,0:33:57.07,0:34:00.86,yin,,0,0,0,, 幻灯片要多于我这里 40 分钟可以讲的内容 \\N{\\fs12}The slides cover a little bit more than I can cover in forty minutes here.\r\nDialogue: 0,0:34:00.86,0:34:03.48,yin,,0,0,0,, 而且它也是参考材料 \\N{\\fs12}And it’s also reference material.\r\nDialogue: 0,0:34:03.48,0:34:07.33,yin,,0,0,0,, 如果我在 demo 中讲的东西让你觉得 \\N{\\fs12}So if I do something today in this demo and you’re like,\r\nDialogue: 0,0:34:07.33,0:34:08.43,yin,,0,0,0,, 哦 他怎么做的 \\N{\\fs12}”Oh, how did he do that?”\r\nDialogue: 0,0:34:08.43,0:34:10.70,yin,,0,0,0,, 你可以去查幻灯片 它会告诉你 \\N{\\fs12}if you go look in those slides, it will tell you.\r\nDialogue: 0,0:34:10.70,0:34:13.03,yin,,0,0,0,, 所以不要觉得 我要逐一记下 \\N{\\fs12}So do not feel like, “I got to furiously write\r\nDialogue: 0,0:34:13.03,0:34:15.63,yin,,0,0,0,, 他在这 40 分钟里面要讲的每一个细节 \\N{\\fs12}down every button click he’s going to do in the next forty minutes.”\r\nDialogue: 0,0:34:15.63,0:34:16.68,yin,,0,0,0,, 不用这样 \\N{\\fs12}No way. Okay?\r\nDialogue: 0,0:34:16.68,0:34:19.24,yin,,0,0,0,, 你可以边看幻灯片边看 demo\\N{\\fs12}Follow along in those slides if you want,\r\nDialogue: 0,0:34:19.24,0:34:23.50,yin,,0,0,0,, 也可以关掉笔记本 只看我讲 然后理解 \\N{\\fs12}or just close your laptop, and watch, and let it sink in\r\nDialogue: 0,0:34:23.52,0:34:26.12,yin,,0,0,0,, 因为你们作业中需要再现 \\N{\\fs12}because you’re going to have to reproduce what I’m doing\r\nDialogue: 0,0:34:26.12,0:34:28.40,yin,,0,0,0,, 我这 40 分钟所要讲的内容 \\N{\\fs12}in the next forty minutes for your homework.\r\nDialogue: 0,0:34:28.40,0:34:31.34,yin,,0,0,0,, 而幻灯片中会一步步告诉你怎么做 \\N{\\fs12}And those slides are going to walk you through step by step how to do it.\r\nDialogue: 0,0:34:31.34,0:34:35.30,yin,,0,0,0,, 现在你们什么都不需要做 只需要仔细听我讲 \\N{\\fs12}So do not feel like you need to do anything right now but let this all sink in.\r\nDialogue: 0,0:34:35.30,0:34:37.69,yin,,0,0,0,, 感受一下发生了什么 \\N{\\fs12}Get a feel for what’s going on.\r\nDialogue: 0,0:34:37.69,0:34:42.96,yin,,0,0,0,, 然后当你要坐下来做时 还有幻灯片可查 \\N{\\fs12}And then when you sit down to do it, you’ll be guided through it.\r\nDialogue: 0,0:34:42.96,0:34:46.22,yin,,0,0,0,, 下周 我将更详细讲到 Objective-C\\N{\\fs12}Next week we’re going to talk a lot more about Objective-C,\r\nDialogue: 0,0:34:46.22,0:34:47.79,yin,,0,0,0,, 详细回答 NSNumber 等同学们提出的一些问题 \\N{\\fs12}answer some of these more detailed questions\r\nDialogue: 0,0:34:47.79,0:34:50.41,yin,,0,0,0,, 详细回答 NSNumber 等同学们提出的一些问题 \\N{\\fs12}like NS number and some of these other things people are asking.\r\nDialogue: 0,0:34:50.41,0:34:54.90,yin,,0,0,0,, 而且我会讲到 Objective-C 中的一些特定内容 \\N{\\fs12}And we’ll talk about some of the specific things about Objective-C\r\nDialogue: 0,0:34:54.91,0:34:57.74,yin,,0,0,0,, 例如动态绑定 协议 \\N{\\fs12}like dynamic binding, and protocols,\r\nDialogue: 0,0:34:57.74,0:35:00.03,yin,,0,0,0,, 这些东西一般在其它语言中是没有的 \\N{\\fs12}and things that you don’t generally see as much\r\nDialogue: 0,0:35:00.03,0:35:02.84,yin,,0,0,0,, 这些东西一般在其它语言中是没有的 \\N{\\fs12}in other languages or don’t exist in other languages.\r\nDialogue: 0,0:35:02.84,0:35:04.06,yin,,0,0,0,, 我会讲给你们 \\N{\\fs12}So we’ll try and cover all that.\r\nDialogue: 0,0:35:04.06,0:35:07.44,yin,,0,0,0,, 在下周末最后 等你们熟悉了 Objective-C\\N{\\fs12}So by the end of next week you’re up to speed in Objective-C.\r\nDialogue: 0,0:35:07.44,0:35:10.17,yin,,0,0,0,, 熟悉了 Xcode\\N{\\fs12}You’re starting to really run with Xcode.\r\nDialogue: 0,0:35:10.17,0:35:13.77,yin,,0,0,0,, 之后我们就可以开始真正做点什么了 \\N{\\fs12}And so the week after that we can really start doing some,\r\nDialogue: 0,0:35:13.77,0:35:17.26,yin,,0,0,0,, 进行强大的 iOS7 编程 \\N{\\fs12}you know, high power iOS 7 stuff.\r\nDialogue: 0,0:35:18.08,0:35:20.57,yin,,0,0,0,, 好 开始 demo\\N{\\fs12}Okay. So demo here.\r\nDialogue: 0,0:35:23.14,0:35:25.79,yin,,0,0,0,,demo 我将用 Xcode 来进行 \\N{\\fs12}So the demo I’m going to run in Xcode.\r\nDialogue: 0,0:35:25.79,0:35:27.75,yin,,0,0,0,, 启动 Xcode\\N{\\fs12}So I’m just going to launch Xcode.\r\nDialogue: 0,0:35:27.75,0:35:32.49,yin,,0,0,0,,Xcode 需要到 Mac app 商店 \\N{\\fs12}So Xcode you get by running — going to your Mac app store.\r\nDialogue: 0,0:35:32.49,0:35:34.93,yin,,0,0,0,, 也就是这个 \\N{\\fs12}That’s this thing down here, right?\r\nDialogue: 0,0:35:34.93,0:35:37.67,yin,,0,0,0,, 用 Mac 登陆 app 商店 然后搜索 Xcode\\N{\\fs12}Get the app store on your Mac, and you just search for Xcode, find it.\r\nDialogue: 0,0:35:37.67,0:35:40.68,yin,,0,0,0,, 它是免费的 下载运行即可 很简单 \\N{\\fs12}It’s free. You download it and you run it. It’s as simple as that.\r\nDialogue: 0,0:35:40.70,0:35:44.85,yin,,0,0,0,, 第一次使用时它的界面是这样的 \\N{\\fs12}This is what it’s going to look like when you first bring it up,\r\nDialogue: 0,0:35:44.85,0:35:46.22,yin,,0,0,0,, 这是启动画面 \\N{\\fs12}this splash screen here.\r\nDialogue: 0,0:35:46.24,0:35:50.09,yin,,0,0,0,, 随着学期的进行 这里将充满你所做的各种项目 \\N{\\fs12}As the quarter goes on, this will fill up with all the projects that you’re doing.\r\nDialogue: 0,0:35:50.09,0:35:52.25,yin,,0,0,0,, 用过 Xcode 的人应该会很习惯 \\N{\\fs12}You’re probably used to that if you know Xcode.\r\nDialogue: 0,0:35:52.25,0:35:55.02,yin,,0,0,0,, 今天我们要创建一个新项目 \\N{\\fs12}And what we’re going to do today is create a new project.\r\nDialogue: 0,0:35:55.02,0:35:59.51,yin,,0,0,0,, 你可以到源控制中查看已有项目 \\N{\\fs12}You can either check an existing project out of source control\r\nDialogue: 0,0:35:59.51,0:36:00.85,yin,,0,0,0,, 你也可以创建新的 \\N{\\fs12}or you can create a new one.\r\nDialogue: 0,0:36:00.87,0:36:02.28,yin,,0,0,0,, 我们要创建新的 \\N{\\fs12}And so we’re going to create a new one.\r\nDialogue: 0,0:36:02.28,0:36:06.83,yin,,0,0,0,, 创建新项目时 它会尝试给我们一点帮助 \\N{\\fs12}So when we create a new one, it wants to give us a little bit of help\r\nDialogue: 0,0:36:06.85,0:36:10.48,yin,,0,0,0,, 它会给我们提供不同应用的模板 \\N{\\fs12}by offering to create a template for different kinds of applications\r\nDialogue: 0,0:36:10.48,0:36:12.81,yin,,0,0,0,, 比如 openGL 游戏 \\N{\\fs12}like an openGL game.\r\nDialogue: 0,0:36:12.83,0:36:16.49,yin,,0,0,0,, 它会为你创建某种框架 \\N{\\fs12}Okay. It will create some framework for that for you.\r\nDialogue: 0,0:36:16.49,0:36:18.22,yin,,0,0,0,,Master-Detail 应用 \\N{\\fs12}Master detail applications,\r\nDialogue: 0,0:36:18.22,0:36:19.74,yin,,0,0,0,, 这是我们这学期晚些时候要做的 \\N{\\fs12}something we’re going to do later in the quarter,\r\nDialogue: 0,0:36:19.74,0:36:21.51,yin,,0,0,0,, 只是我们会自己写代码 \\N{\\fs12}although we’re going to build all the code ourselves;\r\nDialogue: 0,0:36:21.51,0:36:23.46,yin,,0,0,0,, 我们不会用这个模板 \\N{\\fs12}we’re not going to use this template.\r\nDialogue: 0,0:36:23.46,0:36:29.25,yin,,0,0,0,, 这里的单视图应用就是一单个 MVC\\N{\\fs12}And this single view application one right here is basically a single MVC,\r\nDialogue: 0,0:36:29.26,0:36:32.55,yin,,0,0,0,, 课上我们的所有应用都将由此开始 \\N{\\fs12}which is how we’re going it start all of our applications in this classroom –\r\nDialogue: 0,0:36:32.55,0:36:35.64,yin,,0,0,0,, 首先是单个 MVC 之后再添加更多 MVC\\N{\\fs12}with a single MVC. Then we’re going to add more MVCs and build up.\r\nDialogue: 0,0:36:35.64,0:36:39.48,yin,,0,0,0,, 这是基本的单 MVC app\\N{\\fs12}So this is your basic single MVC app.\r\nDialogue: 0,0:36:39.50,0:36:41.20,yin,,0,0,0,, 点击这个 \\N{\\fs12}So I’m going to click that.\r\nDialogue: 0,0:36:41.22,0:36:43.60,yin,,0,0,0,, 这里它会要求一些相关信息 \\N{\\fs12}And here it’s going to ask for some information about it\r\nDialogue: 0,0:36:43.60,0:36:45.81,yin,,0,0,0,, 例如 你想给该 app 起什么名 \\N{\\fs12}like what do you want to call this app?\r\nDialogue: 0,0:36:45.81,0:36:49.86,yin,,0,0,0,, 这是一个扑克牌匹配游戏 我打算叫它 Machismo\\N{\\fs12}This is a card matching game I have decided to call Machismo.\r\nDialogue: 0,0:36:50.72,0:36:53.68,yin,,0,0,0,, 这是我们 app 的名称 起个有趣的名字 \\N{\\fs12}So that’s going to be the name of our app just for fun.\r\nDialogue: 0,0:36:53.68,0:36:55.75,yin,,0,0,0,, 组织名可以任选 \\N{\\fs12}And organization name can be anything you want.\r\nDialogue: 0,0:36:55.75,0:36:59.99,yin,,0,0,0,, 它会显示在你创建的所有类的头文件之中 \\N{\\fs12}It’s going to appear in the headers of all the classes that you create.\r\nDialogue: 0,0:36:59.99,0:37:01.74,yin,,0,0,0,, 我这里写斯坦福大学 \\N{\\fs12}So I make mine be Stanford University.\r\nDialogue: 0,0:37:01.74,0:37:05.61,yin,,0,0,0,, 你们也可以写 Bob’s Game House 什么都行 \\N{\\fs12}You can make yours be Bob’s Game House or whatever.\r\nDialogue: 0,0:37:05.61,0:37:09.50,yin,,0,0,0,, 这个标识符对你需要是唯一的 \\N{\\fs12}This identifier should be unique to you.\r\nDialogue: 0,0:37:09.50,0:37:13.31,yin,,0,0,0,, 我的是 edu.Stanford.cs193p.instructor\\N{\\fs12}So I have edu.Stanford.cs193p.instructor.\r\nDialogue: 0,0:37:13.31,0:37:16.79,yin,,0,0,0,, 你的可以是 edu.Stanford.cs193p. 你的 SUNet ID\\N{\\fs12}You might have edu.Stanford.cs193p dot your SUNet ID.\r\nDialogue: 0,0:37:16.81,0:37:19.28,yin,,0,0,0,, 这肯定是独一无二的 \\N{\\fs12}That will be completely unique.\r\nDialogue: 0,0:37:19.28,0:37:23.33,yin,,0,0,0,, 这些反的 DNS 能给出很好的唯一名称 \\N{\\fs12}These reverse DNS is a really good way to create a unique name.\r\nDialogue: 0,0:37:23.33,0:37:26.03,yin,,0,0,0,, 它还会为这个 app 创建一个唯一名称 \\N{\\fs12}And it’s going to create a unique name for this app\r\nDialogue: 0,0:37:26.03,0:37:28.31,yin,,0,0,0,, 通过将这个和名称结合 \\N{\\fs12}by combining this with the names.\r\nDialogue: 0,0:37:28.31,0:37:31.45,yin,,0,0,0,, 如这里的包标识符 \\N{\\fs12}So you can see it’s done that here, this bundle identifier.\r\nDialogue: 0,0:37:31.45,0:37:32.98,yin,,0,0,0,, 然后这个类前缀 \\N{\\fs12}And then this class prefix –\r\nDialogue: 0,0:37:32.98,0:37:38.40,yin,,0,0,0,, 这一模板将为我们创建一个视图和一个控制器 \\N{\\fs12}this template is going to create a view and a controller for us.\r\nDialogue: 0,0:37:38.40,0:37:42.17,yin,,0,0,0,, 这里说的是 你希望你的控制器类名为什么 \\N{\\fs12}And this is saying, “What do you want the name of your controller class to be?”\r\nDialogue: 0,0:37:42.17,0:37:45.64,yin,,0,0,0,, 默认情况下 它会被叫作 ViewController\\N{\\fs12}By default it’s going to be called “view controller,” okay?\r\nDialogue: 0,0:37:45.64,0:37:49.12,yin,,0,0,0,, 但如果这里你键入诸如 CardGame\\N{\\fs12}But if you type something here like “card game,” now\r\nDialogue: 0,0:37:49.12,0:37:51.44,yin,,0,0,0,, 它就会叫作 CardGameViewController\\N{\\fs12}it’s going to be called “card game view controller,”\r\nDialogue: 0,0:37:51.44,0:37:53.15,yin,,0,0,0,, 这个名字对我们更好 \\N{\\fs12}which is a little better name for us.\r\nDialogue: 0,0:37:53.15,0:37:55.50,yin,,0,0,0,, 它为你创建这个控制器时 会加上这个前缀 \\N{\\fs12}So that’s just the prefix it’s going to put on the name\r\nDialogue: 0,0:37:55.50,0:37:57.33,yin,,0,0,0,, 它为你创建这个控制器时 会加上这个前缀 \\N{\\fs12}of your controller that it creates for you.\r\nDialogue: 0,0:37:57.35,0:38:00.18,yin,,0,0,0,, 最后这里我们可以让创建的 app\\N{\\fs12}And then finally here we can create an app here just\r\nDialogue: 0,0:38:00.18,0:38:02.55,yin,,0,0,0,, 只适用于 iPad 只适用于 iPhone\\N{\\fs12}for iPad, or just for iPhone,\r\nDialogue: 0,0:38:02.55,0:38:05.45,yin,,0,0,0,, 或能够运行在两个平台上的通用 app\\N{\\fs12}or a universal app that will run on both platforms.\r\nDialogue: 0,0:38:05.45,0:38:10.18,yin,,0,0,0,, 创建通用 app 时 UI 仍然需要单独设计 \\N{\\fs12}Now, when you create a universal app, you still have to design your UI’s separately\r\nDialogue: 0,0:38:10.18,0:38:13.46,yin,,0,0,0,, 因为屏幕规则更多时 你需要设计不同的 UI\\N{\\fs12}because if you have more screen rules, you’re just going to design a different UI.\r\nDialogue: 0,0:38:13.46,0:38:15.55,yin,,0,0,0,,iPad 不只是一个大 iPhone\\N{\\fs12}iPad is not just a big iPhone.\r\nDialogue: 0,0:38:15.55,0:38:18.82,yin,,0,0,0,, 有更多屏幕空间时 你可以做更多事情 \\N{\\fs12}You can do a lot more stuff if you have more screen real estate.\r\nDialogue: 0,0:38:18.82,0:38:23.06,yin,,0,0,0,, 但你仍然可以让很多 MVC 共享 \\N{\\fs12}But you still might have a lot of your MVC’s shared, right,\r\nDialogue: 0,0:38:23.06,0:38:26.61,yin,,0,0,0,, 因为 iPad 中在 MVC 中可能有一些小的子区域 \\N{\\fs12}because that iPad might have little subareas that are in MVC\r\nDialogue: 0,0:38:26.61,0:38:29.52,yin,,0,0,0,, 同 iPhone 完全相同 或非常非常相似 \\N{\\fs12}that are exactly the same as on an iPhone or very, very similar.\r\nDialogue: 0,0:38:29.52,0:38:34.42,yin,,0,0,0,,iOS7 中完全支持让创建的 app 同时针对两大平台 \\N{\\fs12}So totally supported in iOS 7 to build apps that target both platforms\r\nDialogue: 0,0:38:34.42,0:38:38.29,yin,,0,0,0,, 也有很棒的工具让你能单独创建两个 UI\\N{\\fs12}and has great tools for letting you build your two UI’s separately\r\nDialogue: 0,0:38:38.29,0:38:40.47,yin,,0,0,0,, 并共享下面的所有 MVC\\N{\\fs12}and share all the MVCs underneath.\r\nDialogue: 0,0:38:40.47,0:38:42.59,yin,,0,0,0,, 这里我们只针对 iPhone 编程 \\N{\\fs12}We’re going to do iPhone only here just\r\nDialogue: 0,0:38:42.59,0:38:46.51,yin,,0,0,0,, 因为这样屏幕更小 而我只有这么大的屏幕空间 \\N{\\fs12}because it keeps the screen small and I only have so much real estate here.\r\nDialogue: 0,0:38:46.51,0:38:52.15,yin,,0,0,0,,[学生提问 声音不清]\\N{\\fs12}[Inaudible]\r\nDialogue: 0,0:38:52.15,0:38:54.39,yin,,0,0,0,,Paul Hegarty：问题是 我在 iPad 上能否 \\N{\\fs12}> Paul Hegarty: Yeah. So the question is: If I’m on my iPad\r\nDialogue: 0,0:38:54.39,0:38:56.70,yin,,0,0,0,, 运行只针对 iPhone 的 app 能 \\N{\\fs12}and I run an app that’s iPhone only, yes,\r\nDialogue: 0,0:38:56.70,0:39:00.88,yin,,0,0,0,, 这里可以说有一个仿真模式 \\N{\\fs12}there’s an emulation mode essentially that will kind\r\nDialogue: 0,0:39:00.88,0:39:04.20,yin,,0,0,0,, 将一个大的 iPhone 状东西放到 iPad 屏幕上 \\N{\\fs12}of make a big iPhone-shaped thing on the iPad screen.\r\nDialogue: 0,0:39:04.20,0:39:05.89,yin,,0,0,0,, 这里我选 iPhone\\N{\\fs12}So we’re going to do iPhone here.\r\nDialogue: 0,0:39:05.89,0:39:07.57,yin,,0,0,0,, 然后点下一步 \\N{\\fs12}So that’s it. I’m going to hit next.\r\nDialogue: 0,0:39:07.57,0:39:10.24,yin,,0,0,0,, 下一步它想知道 “你要把这个项目放在哪”\\N{\\fs12}Next it wants to know, “Where are you going it put this project?”\r\nDialogue: 0,0:39:10.24,0:39:13.66,yin,,0,0,0,, 我强烈推荐放在主目录中 \\N{\\fs12}I strongly recommend putting it in your home directory –\r\nDialogue: 0,0:39:13.66,0:39:17.12,yin,,0,0,0,, 一个叫作 developer(开发者) 的目录内 \\N{\\fs12}in a directory called “developer” in your home directory.\r\nDialogue: 0,0:39:17.12,0:39:19.67,yin,,0,0,0,, 除非你要使用不同的类 \\N{\\fs12}Unless maybe we’re working on different class.\r\nDialogue: 0,0:39:19.67,0:39:23.06,yin,,0,0,0,, 也许你有 cs193p 在主目录下 然后其它类 \\N{\\fs12}Maybe you have the CS 193P in your home directory and then other class.\r\nDialogue: 0,0:39:23.06,0:39:25.34,yin,,0,0,0,, 总之 把它放到主目录中 \\N{\\fs12}But bottom line: Put it in your home directory;\r\nDialogue: 0,0:39:25.35,0:39:28.05,yin,,0,0,0,, 不要放到根或类似的地方 \\N{\\fs12}do not put it, like, in root or somewhere like that.\r\nDialogue: 0,0:39:28.05,0:39:31.35,yin,,0,0,0,, 这在原来导致过问题 \\N{\\fs12}That has in the past caused problems.\r\nDialogue: 0,0:39:31.35,0:39:34.68,yin,,0,0,0,, 放在这里很好 这是我的主目录 这是 cs193p\\N{\\fs12}But a great place to put it here. This is my home directory, CS 193P there.\r\nDialogue: 0,0:39:34.68,0:39:37.03,yin,,0,0,0,, 主目录 developer\\N{\\fs12}I see home directory, developer.\r\nDialogue: 0,0:39:37.03,0:39:39.51,yin,,0,0,0,, 我将把它放到这里 这里还没有任何项目 \\N{\\fs12}This is where I’m going to put it. I don’t have any projects yet.\r\nDialogue: 0,0:39:39.51,0:39:43.05,yin,,0,0,0,, 这下面有一个小内容 叫源控制 我会讲到这个 \\N{\\fs12}This little thing down here, source control, we will be talking about that.\r\nDialogue: 0,0:39:43.05,0:39:45.68,yin,,0,0,0,, 它很好地整合到了 Xcode 中 \\N{\\fs12}It’s really nicely integrated into Xcode,\r\nDialogue: 0,0:39:45.68,0:39:47.07,yin,,0,0,0,, 不过今天我不打算讲 \\N{\\fs12}but we’re not going to talk about it today.\r\nDialogue: 0,0:39:47.07,0:39:49.42,yin,,0,0,0,, 这个不选 \\N{\\fs12}So leave that unclicked.\r\nDialogue: 0,0:39:51.58,0:39:53.78,yin,,0,0,0,, 这是我们的新项目 \\N{\\fs12}And so here’s our new project.\r\nDialogue: 0,0:39:53.78,0:39:55.81,yin,,0,0,0,, 它会显示这个屏幕 \\N{\\fs12}You can see it shows us this screen,\r\nDialogue: 0,0:39:55.81,0:39:58.63,yin,,0,0,0,, 可以通过点上面这个来得到 \\N{\\fs12}which you get to by clicking on this very top thing up here.\r\nDialogue: 0,0:39:58.63,0:40:00.47,yin,,0,0,0,, 这是我们的项目设置 \\N{\\fs12}So this is kind of like our project settings.\r\nDialogue: 0,0:40:00.47,0:40:02.31,yin,,0,0,0,, 这里有很多设置 \\N{\\fs12}And there’s a whole bunch of settings here.\r\nDialogue: 0,0:40:02.31,0:40:04.59,yin,,0,0,0,, 这学期我会讲到所有这些 \\N{\\fs12}We’ll be talk being all this stuff as the quarter goes on.\r\nDialogue: 0,0:40:04.59,0:40:08.53,yin,,0,0,0,, 但今天我不打算讲 因为我要将焦点集中在 MVC 上 \\N{\\fs12}But today we’re not going to talk about any of it because we want to focus on our MVC.\r\nDialogue: 0,0:40:08.53,0:40:15.86,yin,,0,0,0,, 我们的 MVC 中 这里这个 Main.storyboard 是我们的视图 \\N{\\fs12}And our MVC, this right here, main.storyboard, is our view.\r\nDialogue: 0,0:40:15.86,0:40:18.14,yin,,0,0,0,, 这是 MVC 中的视图 \\N{\\fs12}That’s our view of our MVC.\r\nDialogue: 0,0:40:18.16,0:40:21.16,yin,,0,0,0,, 然后这里有 CardGameViewController.m 和.h\\N{\\fs12}And then you see this card game view controller M and H?\r\nDialogue: 0,0:40:21.16,0:40:23.01,yin,,0,0,0,, 这是我们的控制器 \\N{\\fs12}That’s our controller.\r\nDialogue: 0,0:40:23.01,0:40:24.44,yin,,0,0,0,, 这里没有模型 \\N{\\fs12}There’s no model here.\r\nDialogue: 0,0:40:24.44,0:40:27.04,yin,,0,0,0,, 模型将是那四个类 \\N{\\fs12}Your model is going to be those four classes –\r\nDialogue: 0,0:40:27.04,0:40:29.42,yin,,0,0,0,,Deck Card PlayingCard PlayingCardDeck\\N{\\fs12}deck, card, playing card, playing card deck –\r\nDialogue: 0,0:40:29.42,0:40:31.12,yin,,0,0,0,, 这将是你的模型 \\N{\\fs12}that’s going to be your model.\r\nDialogue: 0,0:40:31.12,0:40:32.44,yin,,0,0,0,, 你需要输入这些 \\N{\\fs12}So you’ll have to enter that in.\r\nDialogue: 0,0:40:32.44,0:40:35.10,yin,,0,0,0,, 最后我会展示如何做到 \\N{\\fs12}I’ll show you at the end how to do that.\r\nDialogue: 0,0:40:35.10,0:40:38.77,yin,,0,0,0,, 这里的 CardGameAppDelegate.h 和.m\\N{\\fs12}This little thing here, card game app delegate dot H and M,\r\nDialogue: 0,0:40:38.77,0:40:44.46,yin,,0,0,0,, 这个我在讲多任务处理这些时会简要讲到 \\N{\\fs12}we’ll talk about that briefly, especially when we start talking about things like multitasking.\r\nDialogue: 0,0:40:44.46,0:40:46.86,yin,,0,0,0,, 这里我不想看到它们 \\N{\\fs12}But I like to just move those out of the way.\r\nDialogue: 0,0:40:46.86,0:40:49.92,yin,,0,0,0,, 我通常把它们放到支持文件文件夹中 \\N{\\fs12}So I often put them down here in this supporting files folder.\r\nDialogue: 0,0:40:49.92,0:40:53.05,yin,,0,0,0,, 顺便说下 文件可以直接拖动 拖到哪都行 \\N{\\fs12}And you can just pick up any file, by the way, and move them anywhere you want\r\nDialogue: 0,0:40:53.05,0:40:55.26,yin,,0,0,0,, 这是为了屏幕上更简洁 \\N{\\fs12}here to kind of clean up your view.\r\nDialogue: 0,0:40:55.26,0:41:00.78,yin,,0,0,0,, 这里于是就只显示有视图和控制器了 \\N{\\fs12}So here I’ve got my view and my controller only showing here.\r\nDialogue: 0,0:41:00.78,0:41:04.77,yin,,0,0,0,, 我们直接到视图 看它是怎样的 \\N{\\fs12}So let’s go straight to the view and see what that looks like.\r\nDialogue: 0,0:41:04.77,0:41:09.23,yin,,0,0,0,, 这是我的视图 一个空 iPhone5 大小的空间 \\N{\\fs12}So here’s my view. It’s a blank iPhone 5 sized, right?\r\nDialogue: 0,0:41:09.23,0:41:12.77,yin,,0,0,0,, 一个又高又窄的视图 \\N{\\fs12}A tall and thin view.\r\nDialogue: 0,0:41:12.77,0:41:15.81,yin,,0,0,0,, 而且它是空的 什么都没有 空白一片 \\N{\\fs12}And it’s blank. Nothing new. It’s white.\r\nDialogue: 0,0:41:15.81,0:41:19.36,yin,,0,0,0,, 顺便说下 这里用来点击文件的地方 \\N{\\fs12}This area on the left, by the way, where we clicked on these files,\r\nDialogue: 0,0:41:19.36,0:41:20.91,yin,,0,0,0,, 叫作导航栏 \\N{\\fs12}that’s called the “navigator.”\r\nDialogue: 0,0:41:20.91,0:41:23.03,yin,,0,0,0,, 你不仅可以浏览所有文件 \\N{\\fs12}And you can not only navigate all your files here,\r\nDialogue: 0,0:41:23.03,0:41:25.23,yin,,0,0,0,, 你还可以浏览断点 \\N{\\fs12}but you can navigate your break points,\r\nDialogue: 0,0:41:25.23,0:41:28.20,yin,,0,0,0,, 创建问题 类层次结构 \\N{\\fs12}and build problems, and your class hierarchies.\r\nDialogue: 0,0:41:28.20,0:41:29.15,yin,,0,0,0,, 这些都在这上面 \\N{\\fs12}All that stuff up here.\r\nDialogue: 0,0:41:29.15,0:41:32.60,yin,,0,0,0,, 大多数人用过 Xcode 应该都知道这些 \\N{\\fs12}So again, most of you know Xcode, so you probably know most of this stuff.\r\nDialogue: 0,0:41:32.60,0:41:35.70,yin,,0,0,0,, 我们在这学期的过程中会不断演示 \\N{\\fs12}We’ll be demoing all this as the quarter goes on.\r\nDialogue: 0,0:41:35.70,0:41:38.95,yin,,0,0,0,, 而这块区域叫作”工具区”\\N{\\fs12}And this area over here is called the “utilities area.”\r\nDialogue: 0,0:41:38.95,0:41:43.63,yin,,0,0,0,, 这里会显示中间这里的细节情况 \\N{\\fs12}And this is where you basically find out detail about what’s going on here.\r\nDialogue: 0,0:41:43.63,0:41:48.62,yin,,0,0,0,, 例如属性 尺寸 连接检查器 \\N{\\fs12}So inspectors for attributes, and dimensions, and connections,\r\nDialogue: 0,0:41:48.62,0:41:50.25,yin,,0,0,0,, 这些都在这里 \\N{\\fs12}and things like that go here.\r\nDialogue: 0,0:41:50.25,0:41:53.43,yin,,0,0,0,, 而且这里还可以拖出这些东西 \\N{\\fs12}And this is also where you can drag out the things\r\nDialogue: 0,0:41:53.43,0:41:56.07,yin,,0,0,0,, 用于构建你的用户界面 \\N{\\fs12}that you’re going to use to build your user interface\r\nDialogue: 0,0:41:56.07,0:41:59.61,yin,,0,0,0,, 因为我们将要完全图形化地创建视图 \\N{\\fs12}because we’re going to build our view entirely graphically.\r\nDialogue: 0,0:41:59.61,0:42:02.77,yin,,0,0,0,, 我们大多数时候会写代码来创建视图 \\N{\\fs12}We’re not going to write code, for the most part, to build our view.\r\nDialogue: 0,0:42:02.77,0:42:06.43,yin,,0,0,0,, 随着学期进行 我们会更多地学到如何写代码来创建视图 \\N{\\fs12}As the quarter goes on, we’ll learn a little more about how to build our view in code,\r\nDialogue: 0,0:42:06.44,0:42:10.73,yin,,0,0,0,, 但最开始 我们将只使用图形化操作来创建视图 \\N{\\fs12}but we’re going to start out just purely doing our view by graphically\r\nDialogue: 0,0:42:10.73,0:42:12.39,yin,,0,0,0,, 将事物拖入 连起 \\N{\\fs12}dragging things out and wiring them up.\r\nDialogue: 0,0:42:12.39,0:42:14.67,yin,,0,0,0,, 然后我们再在控制器中写代码 \\N{\\fs12}And we’ll put our code in our controller.\r\nDialogue: 0,0:42:14.67,0:42:21.15,yin,,0,0,0,, 这两个边栏可以通过这两个按钮来隐藏和显示 \\N{\\fs12}This two sides can be hidden and shown with these two buttons.\r\nDialogue: 0,0:42:21.15,0:42:24.65,yin,,0,0,0,, 看到了吗 你可以隐藏它们 \\N{\\fs12}See? You can hide those.\r\nDialogue: 0,0:42:25.16,0:42:29.03,yin,,0,0,0,, 这个按钮也可以点 显示出的这个区域 \\N{\\fs12}This might appear also, this area right here, this little button down here.\r\nDialogue: 0,0:42:29.03,0:42:30.57,yin,,0,0,0,, 叫作”文档大纲”\\N{\\fs12}This is called the “document outline.”\r\nDialogue: 0,0:42:30.57,0:42:32.36,yin,,0,0,0,, 这也很有用 \\N{\\fs12}This is really handy dandy.\r\nDialogue: 0,0:42:32.36,0:42:33.92,yin,,0,0,0,, 但我今天不打算讲 \\N{\\fs12}But again, we’re not going it talk about that today.\r\nDialogue: 0,0:42:33.92,0:42:35.78,yin,,0,0,0,, 一次我只能讲那么多 \\N{\\fs12}We can only talk about so much at once.\r\nDialogue: 0,0:42:35.78,0:42:37.36,yin,,0,0,0,, 文档大纲 \\N{\\fs12}The document outline.\r\nDialogue: 0,0:42:37.36,0:42:42.44,yin,,0,0,0,, 它会将视图中所有对象实例以大纲形式展示出来 \\N{\\fs12}This just shows you all the instances of objects in your view in a common outline form.\r\nDialogue: 0,0:42:42.44,0:42:45.70,yin,,0,0,0,, 这样你就能够很轻松地弄清它们之间的相互关系 \\N{\\fs12}So you can really easily find them and their relationships to each other.\r\nDialogue: 0,0:42:45.70,0:42:50.30,yin,,0,0,0,, 另外你还可以说 我不想要 iPhone5 的屏幕大小 \\N{\\fs12}The other thing you can do is I don’t want this iPhone 5 sized\r\nDialogue: 0,0:42:50.30,0:42:54.69,yin,,0,0,0,, 因为我的屏幕没有这么大 这里我是为了配合投影仪 \\N{\\fs12}thing because my screen is low resolution here so it works on the projector.\r\nDialogue: 0,0:42:54.69,0:42:57.01,yin,,0,0,0,, 这时可以点这个按钮 \\N{\\fs12}So I’m going to click this little button down here,\r\nDialogue: 0,0:42:57.01,0:43:01.77,yin,,0,0,0,, 这可以将屏幕缩小到 iPhone4 或 4S 的大小 \\N{\\fs12}which reduces me down to iPhone 4 size. Or iPhone 4S.\r\nDialogue: 0,0:43:01.77,0:43:03.66,yin,,0,0,0,, 而非又高又窄 \\N{\\fs12}Not tall and thin.\r\nDialogue: 0,0:43:03.66,0:43:07.36,yin,,0,0,0,, 你可以点这个来回切换 \\N{\\fs12}But you can click back and forth and move them back forth.\r\nDialogue: 0,0:43:07.36,0:43:10.99,yin,,0,0,0,, 我这里只是想让它更好地匹配投影仪大小 \\N{\\fs12}And I’m just trying to make everything fit on screen here.\r\nDialogue: 0,0:43:10.99,0:43:14.70,yin,,0,0,0,, 好 让我们开始真正构建视图 \\N{\\fs12}Okay. So let’s just dive right into building our view here.\r\nDialogue: 0,0:43:14.70,0:43:21.30,yin,,0,0,0,, 今天我们的视图将是一张上面写有梅花 A 的纸牌 \\N{\\fs12}What our view is going to be today is a single card with an ace of clubs written on it.\r\nDialogue: 0,0:43:21.30,0:43:23.22,yin,,0,0,0,, 就这些了 \\N{\\fs12}That’s going to be it.\r\nDialogue: 0,0:43:23.22,0:43:25.14,yin,,0,0,0,, 而且我能点击纸牌 \\N{\\fs12}And I’m going to be able to click on the card\r\nDialogue: 0,0:43:25.14,0:43:27.32,yin,,0,0,0,, 它会翻过来 显示背面 \\N{\\fs12}and it will flip over, show the back of the card,\r\nDialogue: 0,0:43:27.32,0:43:30.16,yin,,0,0,0,, 再点击 它会翻回来 显示正面的梅花 A\\N{\\fs12}and then click on it again, it will flip back to show me the ace of club again –\r\nDialogue: 0,0:43:30.16,0:43:31.38,yin,,0,0,0,, 来回来回 \\N{\\fs12}back and forth, back and forth.\r\nDialogue: 0,0:43:31.38,0:43:33.63,yin,,0,0,0,, 而你们的作业是 \\N{\\fs12}And your homework is going to be to make it\r\nDialogue: 0,0:43:33.63,0:43:36.26,yin,,0,0,0,, 当纸牌翻转时 显示的不是梅花 A\\N{\\fs12}so when the card flips up it doesn’t show the ace of clubs,\r\nDialogue: 0,0:43:36.26,0:43:39.05,yin,,0,0,0,, 而是从牌堆中随机抽取的牌 \\N{\\fs12}it shows a random card drawn from the deck.\r\nDialogue: 0,0:43:39.06,0:43:42.49,yin,,0,0,0,, 这是周一要交的作业的全部内容 \\N{\\fs12}That’s going to be your entire homework that’s due on Monday.\r\nDialogue: 0,0:43:42.49,0:43:44.71,yin,,0,0,0,, 好 我们来做这个 很简单 \\N{\\fs12}Okay. So let’s do this. Really simple.\r\nDialogue: 0,0:43:44.71,0:43:47.51,yin,,0,0,0,, 我们到这里 这个对象库 \\N{\\fs12}We go to this area right here, this object library.\r\nDialogue: 0,0:43:47.51,0:43:50.29,yin,,0,0,0,, 也就是这里第三个按钮 显示对象库 \\N{\\fs12}That’s the third button over here, show object library.\r\nDialogue: 0,0:43:50.29,0:43:52.10,yin,,0,0,0,, 对象都在这里 \\N{\\fs12}And this is where all our objects are.\r\nDialogue: 0,0:43:52.10,0:43:54.64,yin,,0,0,0,, 只看这里 你还看不到这些对象 \\N{\\fs12}If you look in here and you don’t see these objects,\r\nDialogue: 0,0:43:54.64,0:43:56.62,yin,,0,0,0,, 你要点击视图 \\N{\\fs12}it might be worth clicking on your view.\r\nDialogue: 0,0:43:56.62,0:44:00.52,yin,,0,0,0,, 有时 Xcode 想知道目的地在哪 \\N{\\fs12}Sometimes Xcode wants to know what the destination is\r\nDialogue: 0,0:44:00.52,0:44:02.76,yin,,0,0,0,, 你要把东西拖放到哪 \\N{\\fs12}that you’re going to be dragging things into.\r\nDialogue: 0,0:44:02.76,0:44:04.79,yin,,0,0,0,, 点击之后 你会看到这些东西 \\N{\\fs12}So if you click on it, then you’ll see these things.\r\nDialogue: 0,0:44:04.79,0:44:06.95,yin,,0,0,0,, 我们将抓取这里的一个按钮 \\N{\\fs12}And we’re just going to grab one of these buttons right here.\r\nDialogue: 0,0:44:06.95,0:44:09.73,yin,,0,0,0,, 我选取这个按钮 并拖出 \\N{\\fs12}So I’m going to pick this button up and drag it out.\r\nDialogue: 0,0:44:09.73,0:44:11.41,yin,,0,0,0,, 注意到 当我拖出它时 \\N{\\fs12}And notice, as I drag it out,\r\nDialogue: 0,0:44:11.41,0:44:13.87,yin,,0,0,0,, 这些蓝色的参考线会显示出来 \\N{\\fs12}these little blue lines appear — these guidelines.\r\nDialogue: 0,0:44:13.87,0:44:16.78,yin,,0,0,0,, 这些参考线非常重要 \\N{\\fs12}Okay. These guidelines are super important.\r\nDialogue: 0,0:44:16.78,0:44:18.43,yin,,0,0,0,, 它们除了方便 \\N{\\fs12}They seem just like a convenience\r\nDialogue: 0,0:44:18.43,0:44:21.89,yin,,0,0,0,, 帮你将对象放到中间或右下角这些地方以外 \\N{\\fs12}for helping you put it right in the middle or right in the right-hand corner.\r\nDialogue: 0,0:44:21.89,0:44:25.81,yin,,0,0,0,, 它们的重要性还体现在 帮你确保 \\N{\\fs12}And they are, but they’re really important for making sure\r\nDialogue: 0,0:44:25.81,0:44:29.60,yin,,0,0,0,, 视图中的所有东西都相隔标准距离 \\N{\\fs12}that all the things in your view are kind of, like, standard space apart.\r\nDialogue: 0,0:44:29.60,0:44:31.61,yin,,0,0,0,, 并在边缘处对齐 \\N{\\fs12}And lined up against edges.\r\nDialogue: 0,0:44:31.61,0:44:34.30,yin,,0,0,0,, 当用户从一个 app 到另一个时 \\N{\\fs12}So that as the users go from one app to another,\r\nDialogue: 0,0:44:34.30,0:44:38.61,yin,,0,0,0,, 事物将以可预测的距离分开 一切都会保持一致 \\N{\\fs12}things will all be separated by predictable spaces and everything will be consistent.\r\nDialogue: 0,0:44:38.61,0:44:39.65,yin,,0,0,0,, 这很重要 \\N{\\fs12}It’s really important.\r\nDialogue: 0,0:44:39.65,0:44:42.19,yin,,0,0,0,, 这里还有一个机制 可以看到这里有个开关 \\N{\\fs12}And there’s a mechanism — you can see this switch right here,\r\nDialogue: 0,0:44:42.19,0:44:45.21,yin,,0,0,0,, 使用自动布局 这是在 iOS6 中引入的 \\N{\\fs12}use auto layout, which was introduced in iOS 6\r\nDialogue: 0,0:44:45.21,0:44:48.46,yin,,0,0,0,, 在 iOS7 中 特别是 Xcode 中得到了大幅提升 \\N{\\fs12}and vastly improved in iOS 7, especially in Xcode –\r\nDialogue: 0,0:44:48.46,0:44:52.76,yin,,0,0,0,, 这使得 当你的用户界面改变大小时 \\N{\\fs12}that allows when your user interface changes size,\r\nDialogue: 0,0:44:52.76,0:44:55.37,yin,,0,0,0,, 例如从 iPhone4 到 iPhone5\\N{\\fs12}like it goes from being an iPhone 4 to an iPhone 5,\r\nDialogue: 0,0:44:55.37,0:44:59.33,yin,,0,0,0,, 或者从竖直旋转为水平 \\N{\\fs12}or it rotates from being vertical to being horizontal,\r\nDialogue: 0,0:44:59.33,0:45:02.23,yin,,0,0,0,, 或是在 iPad 上 有更大空间 \\N{\\fs12}or it’s on an iPad in a bigger space.\r\nDialogue: 0,0:45:02.23,0:45:06.46,yin,,0,0,0,, 这会让所有按钮等元件合理地移动到新位置 \\N{\\fs12}For all the buttons and everything to kind of move to a new position that makes sense\r\nDialogue: 0,0:45:06.46,0:45:08.12,yin,,0,0,0,, 至少大多数移到合理位置 \\N{\\fs12}or at least most of them, right?\r\nDialogue: 0,0:45:08.12,0:45:10.41,yin,,0,0,0,, 还有一些 你可能需要手工移动 \\N{\\fs12}And then maybe you might have to move a few of them by hand,\r\nDialogue: 0,0:45:10.41,0:45:11.75,yin,,0,0,0,, 取决于具体情况 \\N{\\fs12}depending on what’s going on. But\r\nDialogue: 0,0:45:11.77,0:45:14.00,yin,,0,0,0,, 但基本上是自动布局 \\N{\\fs12}it mostly automatically lays it out.\r\nDialogue: 0,0:45:14.00,0:45:15.05,yin,,0,0,0,, 这很重要 \\N{\\fs12}And this is really important\r\nDialogue: 0,0:45:15.05,0:45:18.01,yin,,0,0,0,, 因为设备将不断变换大小 \\N{\\fs12}because I’m sure devices will continue to be differing sizes\r\nDialogue: 0,0:45:18.01,0:45:20.67,yin,,0,0,0,, 每年都会有新设备出来 \\N{\\fs12}as new, you know, devices come out over the years.\r\nDialogue: 0,0:45:20.67,0:45:23.12,yin,,0,0,0,, 所以 使用自动布局很重要 \\N{\\fs12}So doing auto layout is important,\r\nDialogue: 0,0:45:23.12,0:45:26.56,yin,,0,0,0,, 而这些蓝色参考线对于自动布局是第一重要的东西 \\N{\\fs12}and these blue guidelines are the number one most important thing for auto layout.\r\nDialogue: 0,0:45:26.56,0:45:29.82,yin,,0,0,0,, 我会详细讲解自动布局 它有很多内容 \\N{\\fs12}We’re going to cover auto layout in detail, and there’s a lot to it.\r\nDialogue: 0,0:45:29.82,0:45:33.33,yin,,0,0,0,, 下面所有这些按钮都与自动布局有关 \\N{\\fs12}All these buttons down here have to do with auto layout.\r\nDialogue: 0,0:45:33.33,0:45:36.53,yin,,0,0,0,, 得到这些蓝色参考线 确保元件所放位置 \\N{\\fs12}But getting those blue guidelines, making sure you drop things\r\nDialogue: 0,0:45:36.53,0:45:39.67,yin,,0,0,0,, 至少能够显示出一条蓝色参考线 非常重要 \\N{\\fs12}with at least one blue guideline somewhere is really important\r\nDialogue: 0,0:45:39.67,0:45:43.79,yin,,0,0,0,, 这能让你的元件在 UI 自动布局时找到正确的位置 \\N{\\fs12}to kind get you going down the right path with the properly auto laid out UI.\r\nDialogue: 0,0:45:43.79,0:45:45.69,yin,,0,0,0,, 这里有个按钮 \\N{\\fs12}So we have this button here.\r\nDialogue: 0,0:45:45.69,0:45:47.99,yin,,0,0,0,, 当然 我们可以到这里 \\N{\\fs12}But before — and of course, we can go over here\r\nDialogue: 0,0:45:47.99,0:45:50.82,yin,,0,0,0,, 这里是属性检查器 点击它 \\N{\\fs12}to this is the attributes inspector and click on it.\r\nDialogue: 0,0:45:50.82,0:45:52.69,yin,,0,0,0,, 这里有各种属性 \\N{\\fs12}And we’ll see all kinds of attributes.\r\nDialogue: 0,0:45:52.69,0:45:56.40,yin,,0,0,0,, 我可以隐藏这个 这里有该按钮各式各样的属性 \\N{\\fs12}In fact, if I hide this, tons and tons of attributes for this button.\r\nDialogue: 0,0:45:56.40,0:45:58.13,yin,,0,0,0,, 不只是按钮本身 \\N{\\fs12}Not just the button itself,\r\nDialogue: 0,0:45:58.13,0:46:00.89,yin,,0,0,0,, 它的父类也有属性 \\N{\\fs12}but actually its superclass has attributes.\r\nDialogue: 0,0:46:00.89,0:46:02.23,yin,,0,0,0,,Control 是它的父类 \\N{\\fs12}Control is its superclass,\r\nDialogue: 0,0:46:02.23,0:46:05.61,yin,,0,0,0,, 然后 View 是 Control 的父类 它也有属性 \\N{\\fs12}and then view is control’s superclass and it has attributes.\r\nDialogue: 0,0:46:05.61,0:46:08.40,yin,,0,0,0,, 这是一个面向对象的检查器 \\N{\\fs12}Okay. So this is an object-oriented inspector\r\nDialogue: 0,0:46:08.40,0:46:14.00,yin,,0,0,0,, 它会显示出继承层次下的所有属性 \\N{\\fs12}that will show all the attributes of all the things through the inheritance hierarchy.\r\nDialogue: 0,0:46:14.00,0:46:20.15,yin,,0,0,0,, 这里我们所做的 实际上是编辑一个按钮的实例 \\N{\\fs12}And what’s happening here is we’re actually editing an instance of a button here.\r\nDialogue: 0,0:46:20.15,0:46:21.57,yin,,0,0,0,, 我们不是… 我知道 \\N{\\fs12}So we are not — and I know\r\nDialogue: 0,0:46:21.57,0:46:24.99,yin,,0,0,0,, 某些系统中 你布局按钮 设定大小 设定属性 \\N{\\fs12}in some systems you layout the button, you set the size, and you set the attributes.\r\nDialogue: 0,0:46:24.99,0:46:27.35,yin,,0,0,0,, 然后在幕后 \\N{\\fs12}And then, you know, behind the scenes a bunch\r\nDialogue: 0,0:46:27.35,0:46:30.52,yin,,0,0,0,, 一堆代码会生成出来 创建按钮 \\N{\\fs12}of code is being generated to create the button.\r\nDialogue: 0,0:46:30.52,0:46:31.77,yin,,0,0,0,, 这里不是这样 \\N{\\fs12}That’s not what we’re doing here.\r\nDialogue: 0,0:46:31.77,0:46:33.67,yin,,0,0,0,, 我们是在编辑活动对象 \\N{\\fs12}We’re actually editing live objects.\r\nDialogue: 0,0:46:33.67,0:46:35.67,yin,,0,0,0,, 它们就像是速冻咖啡粉末 \\N{\\fs12}They’re essentially going to be freeze dried.\r\nDialogue: 0,0:46:35.69,0:46:39.56,yin,,0,0,0,,app 运行就像加水 它们会被注入生命 \\N{\\fs12}And then when your app runs, add water, they come to life, okay,\r\nDialogue: 0,0:46:39.56,0:46:42.04,yin,,0,0,0,, 它们的属性会被设置 它们的大小和位置 \\N{\\fs12}with their attributes set, and all their sizes and positions,\r\nDialogue: 0,0:46:42.04,0:46:44.98,yin,,0,0,0,, 以及所有的自动布局信息都在对象中 \\N{\\fs12}and all their auto layout information in the object.\r\nDialogue: 0,0:46:44.98,0:46:50.03,yin,,0,0,0,, 这有些不同于其它系统中你们所习惯的情况 \\N{\\fs12}So it’s a little different than you might be used to in some other systems.\r\nDialogue: 0,0:46:50.03,0:46:52.65,yin,,0,0,0,, 无论如何 在我们编辑这个按钮的属性前 \\N{\\fs12}So anyway, before we edit the attributes of this button,\r\nDialogue: 0,0:46:52.65,0:46:56.25,yin,,0,0,0,, 我们先来换个背景 因为这是一个扑克牌游戏 \\N{\\fs12}though, let’s change our background because this is a card game.\r\nDialogue: 0,0:46:56.25,0:46:59.45,yin,,0,0,0,, 而大多数扑克牌游戏都是绿色绒布 对吧 \\N{\\fs12}And most card games are on, like, green felt, right?\r\nDialogue: 0,0:46:59.45,0:47:01.65,yin,,0,0,0,, 让我们把背景换得更像绿色绒布 \\N{\\fs12}So let’s make our background be more like a green felt.\r\nDialogue: 0,0:47:01.65,0:47:03.58,yin,,0,0,0,, 我将点击背景 \\N{\\fs12}So I’m just going to click on the background,\r\nDialogue: 0,0:47:03.58,0:47:06.81,yin,,0,0,0,, 也就是这个 View 可以看到它的属性 \\N{\\fs12}which is this view right here, and you can see its properties.\r\nDialogue: 0,0:47:06.81,0:47:10.49,yin,,0,0,0,, 我将改变这个背景属性 \\N{\\fs12}So I’m going to change a couple — or just one of its properties — which is the background.\r\nDialogue: 0,0:47:10.49,0:47:12.94,yin,,0,0,0,, 这里背景还是白色 \\N{\\fs12}You see this background white color right here?\r\nDialogue: 0,0:47:12.94,0:47:15.95,yin,,0,0,0,, 点击这里 这里有一些最近使用过的颜色 \\N{\\fs12}So if I click on this, I have some recently used colors.\r\nDialogue: 0,0:47:15.95,0:47:18.15,yin,,0,0,0,, 我有所有这些黑白颜色 \\N{\\fs12}I have all these kind of black and white colors.\r\nDialogue: 0,0:47:18.15,0:47:19.49,yin,,0,0,0,, 这里还有其它颜色 \\N{\\fs12}And I also have other.\r\nDialogue: 0,0:47:19.49,0:47:22.57,yin,,0,0,0,, 点其它会出现这些蜡笔 \\N{\\fs12}And I bring up other, brings up the crayons.\r\nDialogue: 0,0:47:22.57,0:47:26.14,yin,,0,0,0,, 还有其它选择颜色的方式 不过我喜欢蜡笔 \\N{\\fs12}It also brings up other ways to choose colors, but I like the crayons.\r\nDialogue: 0,0:47:26.14,0:47:29.93,yin,,0,0,0,, 我的蜡笔呢 \\N{\\fs12}And so where are my crayons?\r\nDialogue: 0,0:47:29.93,0:47:30.77,yin,,0,0,0,, 这里 \\N{\\fs12}There they are.\r\nDialogue: 0,0:47:30.77,0:47:34.45,yin,,0,0,0,, 我们来选一种绿色 青苔色是很好的绿色 \\N{\\fs12}So let’s pick a green, like, moss is a good green.\r\nDialogue: 0,0:47:34.45,0:47:36.03,yin,,0,0,0,, 苜蓿色 我更喜欢青苔色 \\N{\\fs12}Clover. I kind of like moss better.\r\nDialogue: 0,0:47:36.03,0:47:39.13,yin,,0,0,0,, 这是纸牌游戏的背景 \\N{\\fs12}So that’s kind of a card game background.\r\nDialogue: 0,0:47:39.13,0:47:42.97,yin,,0,0,0,, 这就行了 我们设置好了 View 的背景颜色 \\N{\\fs12}And that’s it. So we’ve set the background color of our views.\r\nDialogue: 0,0:47:42.97,0:47:45.34,yin,,0,0,0,, 所有的属性设置都和这类似 \\N{\\fs12}And all the attribute setting is just like this:\r\nDialogue: 0,0:47:45.34,0:47:48.14,yin,,0,0,0,, 设置好了就可以不用管了 \\N{\\fs12}You just set it and forget it.\r\nDialogue: 0,0:47:48.14,0:47:50.98,yin,,0,0,0,, 我们回到按钮和它的属性 \\N{\\fs12}So let’s go back to the button and its properties.\r\nDialogue: 0,0:47:50.98,0:47:53.24,yin,,0,0,0,, 按钮我希望它像一张纸牌 \\N{\\fs12}Okay. The button I want to look like a card.\r\nDialogue: 0,0:47:53.24,0:47:58.73,yin,,0,0,0,,iOS7 中的按钮比较像网页中的超链接 \\N{\\fs12}Well, a button in iOS 7 basically looks a lot like a hyperlink on a web page,\r\nDialogue: 0,0:47:58.73,0:48:02.14,yin,,0,0,0,, 就像这个按钮所做的 这个蓝色按钮 \\N{\\fs12}just like that button does right there. That blue button.\r\nDialogue: 0,0:48:02.14,0:48:04.49,yin,,0,0,0,, 这不是我们想要的 \\N{\\fs12}That’s not really appropriate for what we want.\r\nDialogue: 0,0:48:04.49,0:48:08.27,yin,,0,0,0,, 我们希望它是一张牌 有圆角矩形边框和白色背景 \\N{\\fs12}We want it to look like a card with a little rounded rect and a white background, right?\r\nDialogue: 0,0:48:08.27,0:48:10.15,yin,,0,0,0,, 我希望纸牌背面都一样 \\N{\\fs12}And I want the back of the card to look the same\r\nDialogue: 0,0:48:10.15,0:48:13.51,yin,,0,0,0,, 而且具有某种图样设计 \\N{\\fs12}but have some kind of design on it or something like that.\r\nDialogue: 0,0:48:13.51,0:48:18.23,yin,,0,0,0,, 所以 我将为我的按钮设置一个背景图 \\N{\\fs12}So the way I’m going to do that is I’m going to set a background image for my button.\r\nDialogue: 0,0:48:18.23,0:48:20.36,yin,,0,0,0,, 一个圆角矩形的背景图 \\N{\\fs12}A background image that’s like a rounded rect.\r\nDialogue: 0,0:48:20.36,0:48:22.28,yin,,0,0,0,, 这里我们先简单讲一下 \\N{\\fs12}So let’s take a little aside here and talk about:\r\nDialogue: 0,0:48:22.28,0:48:25.48,yin,,0,0,0,, 如何将图像置入到 app 中 \\N{\\fs12}How do we get images into our app?\r\nDialogue: 0,0:48:25.48,0:48:28.94,yin,,0,0,0,,app 中经常会用到图像 \\N{\\fs12}Okay. We want to use images in our app; it’s very common to want to use images\r\nDialogue: 0,0:48:28.94,0:48:31.16,yin,,0,0,0,, 手机程序一般都是图形程序 \\N{\\fs12}in a graphical application like on a phone.\r\nDialogue: 0,0:48:31.16,0:48:32.02,yin,,0,0,0,, 那如何做到呢 \\N{\\fs12}So how do you do it?\r\nDialogue: 0,0:48:32.02,0:48:35.81,yin,,0,0,0,, 答案是 你可以到下面这个地方 它叫作 \\N{\\fs12}And the answer is you go down here to this place called the\r\nDialogue: 0,0:48:35.81,0:48:38.61,yin,,0,0,0,, 图像资源库 Images.xcassets\\N{\\fs12}”image asset library” — images.xc assets\r\nDialogue: 0,0:48:38.61,0:48:40.06,yin,,0,0,0,,xcassets 也就是 Xcode 资源 \\N{\\fs12}or Xcode assets.\r\nDialogue: 0,0:48:40.06,0:48:43.09,yin,,0,0,0,, 可以看到这里已经有一些图标槽位存在 \\N{\\fs12}And you can see there’s already a couple of slots for icons here.\r\nDialogue: 0,0:48:43.09,0:48:45.72,yin,,0,0,0,, 你可以在这里设置 app 图标 \\N{\\fs12}They’re not set, but this is the app icon.\r\nDialogue: 0,0:48:45.72,0:48:48.09,yin,,0,0,0,, 你还可以设置一个启动画面 \\N{\\fs12}And also you can have a launch image that will appear instantly\r\nDialogue: 0,0:48:48.09,0:48:51.59,yin,,0,0,0,, 程序启动后需要初始化 启动画面会立刻显示 \\N{\\fs12}when someone launches your app. And then as you’re initializing,\r\nDialogue: 0,0:48:51.60,0:48:54.39,yin,,0,0,0,, 初始化后再才显示出实际的 UI\\N{\\fs12}having behind the launch image, and then it will show you are actual UI.\r\nDialogue: 0,0:48:54.39,0:48:56.45,yin,,0,0,0,, 这是一个快速的启动画面 \\N{\\fs12}So it’s kind of quick launch image.\r\nDialogue: 0,0:48:56.45,0:48:58.17,yin,,0,0,0,, 周一我会讲到这个 \\N{\\fs12}And we’ll talk about this on Monday.\r\nDialogue: 0,0:48:58.17,0:49:00.81,yin,,0,0,0,, 这里我们将为 Machismo 设置背景 \\N{\\fs12}We’ll set the app background for Machismo here.\r\nDialogue: 0,0:49:00.81,0:49:04.82,yin,,0,0,0,, 我将拖入其它图像 \\N{\\fs12}But I’m going to actually drag in some other image.\r\nDialogue: 0,0:49:04.82,0:49:06.78,yin,,0,0,0,, 这里我有一些图像 \\N{\\fs12}So I have some images here.\r\nDialogue: 0,0:49:06.80,0:49:11.76,yin,,0,0,0,, 例如 这里我有这个斯坦福的 logo\\N{\\fs12}And for example, I’ve got this Stanford logo right here.\r\nDialogue: 0,0:49:11.76,0:49:14.17,yin,,0,0,0,, 我将把这个斯坦福的 logo 拖入 \\N{\\fs12}So I’m going to drag that Stanford logo in\r\nDialogue: 0,0:49:14.17,0:49:15.46,yin,,0,0,0,, 因为我要用它 \\N{\\fs12}because I want to use it.\r\nDialogue: 0,0:49:15.46,0:49:16.83,yin,,0,0,0,, 把它拖到这里就行了 \\N{\\fs12}And that’s it; you just drag it in here.\r\nDialogue: 0,0:49:16.83,0:49:17.91,yin,,0,0,0,, 这是斯坦福 logo\\N{\\fs12}It says Stanford.\r\nDialogue: 0,0:49:17.91,0:49:21.49,yin,,0,0,0,, 但注意到 这里有很奇怪的 1x 和 2x\\N{\\fs12}But notice that it kind of has this weird thing here, this 1X and 2X.\r\nDialogue: 0,0:49:21.49,0:49:26.61,yin,,0,0,0,, 看到了吗 这是因为 iOS 中你们要用到的每张图像 \\N{\\fs12}You see that? And that’s because every image that you’re going to use in iOS\r\nDialogue: 0,0:49:26.63,0:49:30.18,yin,,0,0,0,, 需要有一个普通分辨率版本 \\N{\\fs12}wants to have a normal resolution version that’s going\r\nDialogue: 0,0:49:30.18,0:49:33.72,yin,,0,0,0,, 用于 iPhone4 这样的非视网膜屏 \\N{\\fs12}to be used like on the iPhone 4 — nonretina displays basically.\r\nDialogue: 0,0:49:33.72,0:49:38.14,yin,,0,0,0,, 而 2x 是两倍高分辨率版本 用于视网膜屏 \\N{\\fs12}And then a 2X, twice as high resolution — one that will be used on retina.\r\nDialogue: 0,0:49:38.14,0:49:41.51,yin,,0,0,0,, 系统会自动选择正确的图像 取决于运行于什么设备 \\N{\\fs12}And it will automatically pick the right one, depending on what you’re running on.\r\nDialogue: 0,0:49:41.51,0:49:43.34,yin,,0,0,0,, 你不需要做任何事 \\N{\\fs12}You don’t have to do anything about it.\r\nDialogue: 0,0:49:43.34,0:49:45.75,yin,,0,0,0,, 但你需要提供这些高清版本 \\N{\\fs12}But you do want to provide these higher res ones.\r\nDialogue: 0,0:49:45.75,0:49:50.08,yin,,0,0,0,, 这些高清版本并不一定要是原来一样的图像 \\N{\\fs12}And these higher res ones aren’t just necessarily the same exact image,\r\nDialogue: 0,0:49:50.09,0:49:53.21,yin,,0,0,0,, 只是分辨率更高一些 \\N{\\fs12}just, you know, made more high resolution.\r\nDialogue: 0,0:49:53.21,0:49:54.35,yin,,0,0,0,, 它们可以不同 \\N{\\fs12}They might allow you to do –\r\nDialogue: 0,0:49:54.35,0:49:57.32,yin,,0,0,0,, 例如这里 我有一个带树的斯坦福 logo\\N{\\fs12}for example, here I’ve got a Stanford logo with the little tree.\r\nDialogue: 0,0:49:57.32,0:49:58.95,yin,,0,0,0,, 看到树了吗 \\N{\\fs12}See? See the tree in there?\r\nDialogue: 0,0:49:58.95,0:50:01.93,yin,,0,0,0,, 也许这里由于分辨率太低 树不是很好看 \\N{\\fs12}So maybe this is too low resolution to really get a good-looking tree.\r\nDialogue: 0,0:50:01.93,0:50:05.12,yin,,0,0,0,, 但在高分辨率下我可以加个树 所以我加了 \\N{\\fs12}But I can get the tree in at a higher resolution, so I put it in there.\r\nDialogue: 0,0:50:05.12,0:50:07.88,yin,,0,0,0,, 两个图像不一样的情况并不常见 \\N{\\fs12}So it’s not that common that the two ones would be actually\r\nDialogue: 0,0:50:07.88,0:50:09.53,yin,,0,0,0,, 但它们确实可以不同 \\N{\\fs12}different-looking but they could be.\r\nDialogue: 0,0:50:09.53,0:50:11.40,yin,,0,0,0,, 这肯定是允许的 \\N{\\fs12}Certainly allowed they could be.\r\nDialogue: 0,0:50:11.40,0:50:14.11,yin,,0,0,0,, 我也不想把这个叫斯坦福 \\N{\\fs12}I also don’t want to really call this “Stanford.”\r\nDialogue: 0,0:50:14.11,0:50:17.29,yin,,0,0,0,, 我将把这用作纸牌的背面 \\N{\\fs12}I’m going to use this as my backup card.\r\nDialogue: 0,0:50:17.29,0:50:19.61,yin,,0,0,0,, 纸牌背面我将不使用某种花纹 \\N{\\fs12}Instead of having, you know, some kind of design,\r\nDialogue: 0,0:50:19.61,0:50:21.89,yin,,0,0,0,, 而使用斯坦福的 logo\\N{\\fs12}I’m going to have the Stanford logo be the back of my card.\r\nDialogue: 0,0:50:21.89,0:50:24.35,yin,,0,0,0,, 纸牌翻过来时 我会看到背面的斯坦福 logo\\N{\\fs12}When my card’s flipped down and I see the back, I’m going to see the Stanford logo.\r\nDialogue: 0,0:50:24.35,0:50:26.99,yin,,0,0,0,, 所以我将给它取名为 cardback\\N{\\fs12}So I’m going to call this “card back.”\r\nDialogue: 0,0:50:26.99,0:50:29.60,yin,,0,0,0,, 其实叫什么都行 \\N{\\fs12}I can call it anything I want.\r\nDialogue: 0,0:50:29.60,0:50:32.06,yin,,0,0,0,, 正面我也有个图像 \\N{\\fs12}I also have things for the front here.\r\nDialogue: 0,0:50:32.06,0:50:33.45,yin,,0,0,0,, 这个 \\N{\\fs12}This one right here.\r\nDialogue: 0,0:50:33.45,0:50:35.93,yin,,0,0,0,, 这是带有圆角的空纸牌 \\N{\\fs12}This is blank card with a rounded corner.\r\nDialogue: 0,0:50:35.93,0:50:36.48,yin,,0,0,0,, 这里 \\N{\\fs12}There it is.\r\nDialogue: 0,0:50:36.48,0:50:38.01,yin,,0,0,0,, 哦 你们看不到 \\N{\\fs12}You can’t see it.\r\nDialogue: 0,0:50:38.01,0:50:40.10,yin,,0,0,0,, 因为这是白色纸牌 所以你们看不到 \\N{\\fs12}Because it’s a white card so you can’t see it.\r\nDialogue: 0,0:50:40.10,0:50:43.43,yin,,0,0,0,, 但我将使用它 取名为 cardfront\\N{\\fs12}But I’m going to use that. I’m going to call this “card front.”\r\nDialogue: 0,0:50:43.43,0:50:48.81,yin,,0,0,0,, 我还将有一个高清版的 \\N{\\fs12}And I’m also going to have a high-res version of that as well.\r\nDialogue: 0,0:50:48.81,0:50:50.62,yin,,0,0,0,, 好 这很不错 \\N{\\fs12}Okay. So that’s good.\r\nDialogue: 0,0:50:50.62,0:50:53.51,yin,,0,0,0,, 它只能显示成这样 \\N{\\fs12}So as much as we can see of it.\r\nDialogue: 0,0:50:53.51,0:50:56.14,yin,,0,0,0,, 以上一些图像 \\N{\\fs12}Okay. So now I got some images.\r\nDialogue: 0,0:50:56.14,0:50:58.72,yin,,0,0,0,, 下面我将把它们用到我的视图中 \\N{\\fs12}And now I want to use them in my view.\r\nDialogue: 0,0:50:58.74,0:51:00.89,yin,,0,0,0,, 我将设置纸牌 来使用这个 \\N{\\fs12}I kind of want to set this card to use this.\r\nDialogue: 0,0:51:00.89,0:51:05.82,yin,,0,0,0,, 程序运行时 我希望纸牌最开始是正面朝上 \\N{\\fs12}So I’m going to start with my card here being face up when it runs.\r\nDialogue: 0,0:51:05.82,0:51:08.74,yin,,0,0,0,,app 运行时 纸牌最开始是正面朝上 \\N{\\fs12}When my app runs, the card’s going to start face up.\r\nDialogue: 0,0:51:08.74,0:51:12.59,yin,,0,0,0,, 在作业 app 中 你们需要让它正面朝下 \\N{\\fs12}In your app when you get your homework you’re probably going to want to start it facedown.\r\nDialogue: 0,0:51:12.59,0:51:15.80,yin,,0,0,0,, 原因在于 我的 app 只显示一张牌 \\N{\\fs12}The reason for that is my app only shows one card:\r\nDialogue: 0,0:51:15.80,0:51:16.88,yin,,0,0,0,, 梅花 A\\N{\\fs12}Ace of clubs.\r\nDialogue: 0,0:51:16.88,0:51:19.11,yin,,0,0,0,, 所以最开始梅花 A 朝上没有关系 \\N{\\fs12}So it’s fine if it comes up with ace of clubs.\r\nDialogue: 0,0:51:19.11,0:51:22.14,yin,,0,0,0,, 但你们显然不希望一开始就是梅花 A\\N{\\fs12}But you don’t want your card to come up ace of clubs for sure.\r\nDialogue: 0,0:51:22.14,0:51:25.36,yin,,0,0,0,, 而且代码上 你们也需要更多工作 \\N{\\fs12}And it might be a little more work for you coding-wise\r\nDialogue: 0,0:51:25.36,0:51:27.86,yin,,0,0,0,, 才能初始化它 得到随机的牌 \\N{\\fs12}to initialize it to come up with some random card.\r\nDialogue: 0,0:51:27.86,0:51:30.91,yin,,0,0,0,, 所以你们应该让它正面朝下 这会更容易一些 \\N{\\fs12}So you’ll just have it come up facedown. Make it a lot easier on you.\r\nDialogue: 0,0:51:30.91,0:51:33.80,yin,,0,0,0,, 这如何设置呢 \\N{\\fs12}So how do we set that?\r\nDialogue: 0,0:51:33.80,0:51:34.55,yin,,0,0,0,, 很简单 \\N{\\fs12}Really simple.\r\nDialogue: 0,0:51:34.55,0:51:36.03,yin,,0,0,0,, 这里有已选定的按钮 \\N{\\fs12}I’ve got the button selected here.\r\nDialogue: 0,0:51:36.03,0:51:37.28,yin,,0,0,0,, 这是它的属性 \\N{\\fs12}Here’s its properties.\r\nDialogue: 0,0:51:37.28,0:51:40.13,yin,,0,0,0,, 一个属性是它的背景图像 \\N{\\fs12}One of its properties is its background image.\r\nDialogue: 0,0:51:40.13,0:51:42.50,yin,,0,0,0,, 我要点击这里 可以看到 \\N{\\fs12}So I’m just going to click here, and you can see\r\nDialogue: 0,0:51:42.50,0:51:45.53,yin,,0,0,0,, 资源库中的所有图像都在这里 \\N{\\fs12}that all images that are in my assets library will be here.\r\nDialogue: 0,0:51:45.53,0:51:48.86,yin,,0,0,0,, 有很多的话 你可以键入字符 它会自行匹配 \\N{\\fs12}And if there was a really lot of them, you can type and it will match it.\r\nDialogue: 0,0:51:48.86,0:51:51.75,yin,,0,0,0,, 我将把它设为 cardfront\\N{\\fs12}So I’m going to make it be the card front.\r\nDialogue: 0,0:51:51.75,0:51:55.39,yin,,0,0,0,, 这就设为了正面 但圆角矩形在哪 \\N{\\fs12}So it made it the card front, but I don’t see — where’s the rounded rect?\r\nDialogue: 0,0:51:55.39,0:51:58.58,yin,,0,0,0,, 我看不到圆角矩形 这是因为它太小了 \\N{\\fs12}I can’t see the rounded rect. And that’s because it’s too small\r\nDialogue: 0,0:51:58.58,0:52:01.58,yin,,0,0,0,, 圆角看不大清楚 \\N{\\fs12}to see the rounded corners very well here.\r\nDialogue: 0,0:52:01.58,0:52:04.59,yin,,0,0,0,, 这里你可以将它拉大一些 \\N{\\fs12}So you can just take this thing and resize it.\r\nDialogue: 0,0:52:04.59,0:52:06.87,yin,,0,0,0,, 我希望让它…\\N{\\fs12}And I’m going to make it –\r\nDialogue: 0,0:52:06.87,0:52:12.91,yin,,0,0,0,, 这里我希望比例是 2:3 我将使用 64×96\\N{\\fs12}I want it to be about two to three ratio. So I’m going to make it 64 by 96.\r\nDialogue: 0,0:52:12.91,0:52:15.91,yin,,0,0,0,, 这是一个很好的尺寸 我调整了它的大小 \\N{\\fs12}I know this happens to be a very good size, and I’ve resized it.\r\nDialogue: 0,0:52:15.91,0:52:18.15,yin,,0,0,0,, 这时就可以看到圆角了 \\N{\\fs12}And now you can see the little rounded corners.\r\nDialogue: 0,0:52:18.15,0:52:20.80,yin,,0,0,0,, 看到了吗 这就是我刚才拖入的图像 \\N{\\fs12}You see? So this is that image I dragged in\r\nDialogue: 0,0:52:20.80,0:52:22.28,yin,,0,0,0,, 上面写有 Button\\N{\\fs12}with button written on top of it.\r\nDialogue: 0,0:52:22.28,0:52:24.35,yin,,0,0,0,, 我还可以将它移动一下 \\N{\\fs12}And of course, I moved it a little so I can put it back\r\nDialogue: 0,0:52:24.35,0:52:27.50,yin,,0,0,0,, 放到蓝色参考线的中间 \\N{\\fs12}in the middle using my blue guidelines, right?\r\nDialogue: 0,0:52:27.50,0:52:30.05,yin,,0,0,0,, 当然 我不希望纸牌上写有 Button\\N{\\fs12}And of course, I don’t want my card to say “button” it;\r\nDialogue: 0,0:52:30.05,0:52:33.17,yin,,0,0,0,, 我希望这里是梅花 A 我可以双击它 \\N{\\fs12}I want the ace of clubs on here. So I’m going to just double-click on it.\r\nDialogue: 0,0:52:33.17,0:52:34.86,yin,,0,0,0,, 我也可以在这上面编辑 \\N{\\fs12}I could also edit that up here.\r\nDialogue: 0,0:52:34.86,0:52:36.14,yin,,0,0,0,, 看到了吗 这里写的是 Button\\N{\\fs12}You see right here where it says “button”?\r\nDialogue: 0,0:52:36.14,0:52:36.86,yin,,0,0,0,, 点击这里 \\N{\\fs12}Click it here.\r\nDialogue: 0,0:52:36.86,0:52:38.71,yin,,0,0,0,, 我将直接双击它 \\N{\\fs12}I’m just going to double-click directly on it.\r\nDialogue: 0,0:52:38.71,0:52:39.98,yin,,0,0,0,, 我将输入 A\\N{\\fs12}I’m going to type “ace.”\r\nDialogue: 0,0:52:39.98,0:52:42.18,yin,,0,0,0,, 如何输入梅花 有人知道吗 \\N{\\fs12}And how do I type clubs, anyone know?\r\nDialogue: 0,0:52:43.22,0:52:45.42,yin,,0,0,0,,Alt+ 什么 我喜欢这样做 \\N{\\fs12}Alt something or other. I like to do this way.\r\nDialogue: 0,0:52:45.42,0:52:49.81,yin,,0,0,0,, 到编辑菜单 选特殊字符 弹出这个窗口 \\N{\\fs12}I go to edit menu, special characters, get this magic thing.\r\nDialogue: 0,0:52:49.81,0:52:51.32,yin,,0,0,0,, 看过这个吗 很酷吧 \\N{\\fs12}You ever seen this, kind of cool?\r\nDialogue: 0,0:52:51.32,0:52:55.86,yin,,0,0,0,, 双击 找到梅花 然后双击 \\N{\\fs12}Just double-click — find the clubs and double-click.\r\nDialogue: 0,0:52:55.86,0:52:58.16,yin,,0,0,0,, 好 这就是我的梅花 A 了 \\N{\\fs12}All right. So there’s my ace of clubs.\r\nDialogue: 0,0:52:58.16,0:53:00.61,yin,,0,0,0,, 不过这也不是很好 \\N{\\fs12}Now but, you know, that’s not quite right, either.\r\nDialogue: 0,0:53:00.61,0:53:04.05,yin,,0,0,0,, 我不喜欢这个蓝 A 我希望 A 是黑色的 \\N{\\fs12}I don’t really like that blue A. I really want the A to be black.\r\nDialogue: 0,0:53:04.05,0:53:06.75,yin,,0,0,0,, 而且它可以更大一些 这里还有更大空间 \\N{\\fs12}And it could be a little bigger. There’s more room for it.\r\nDialogue: 0,0:53:06.75,0:53:09.76,yin,,0,0,0,, 我可以到这里 来改变字体 \\N{\\fs12}So I can go over here, for example, and change the font.\r\nDialogue: 0,0:53:09.76,0:53:12.66,yin,,0,0,0,, 我可以点这个 让它更大 \\N{\\fs12}I can change it by clicking this little thing to make it bigger,\r\nDialogue: 0,0:53:12.66,0:53:16.76,yin,,0,0,0,, 我也可以点击这个 T 设置它为哪一种字体 \\N{\\fs12}or I can actually click on this T and even set which font it is.\r\nDialogue: 0,0:53:16.76,0:53:20.61,yin,,0,0,0,,iOS7 中很重要的一点是排版 \\N{\\fs12}One thing that’s really important in iOS 7 is the typography.\r\nDialogue: 0,0:53:20.61,0:53:25.63,yin,,0,0,0,, 选择正确的文本样式在 iOS7 中非常非常重要 \\N{\\fs12}Picking the right text styles is really, really important in iOS 7.\r\nDialogue: 0,0:53:25.63,0:53:27.20,yin,,0,0,0,, 这里我不打算细讲 \\N{\\fs12}And we’re not going to really talk about it here;\r\nDialogue: 0,0:53:27.20,0:53:28.81,yin,,0,0,0,, 我将使用系统字体 \\N{\\fs12}we’re just going to use the system font.\r\nDialogue: 0,0:53:28.81,0:53:31.59,yin,,0,0,0,, 不过以后课上我会讲到 \\N{\\fs12}But that’s something we’ll talk about in lecture,\r\nDialogue: 0,0:53:31.59,0:53:34.25,yin,,0,0,0,, 确保正确地方使用了正确字体 \\N{\\fs12}is making sure you pick the right fonts in the right places\r\nDialogue: 0,0:53:34.25,0:53:36.05,yin,,0,0,0,, 才能让 UI 看起来更漂亮 \\N{\\fs12}to make the UI look really nice.\r\nDialogue: 0,0:53:36.05,0:53:40.23,yin,,0,0,0,, 这里我可以改变字符大小 也许 24 点就差不多了 \\N{\\fs12}I can change the size here, maybe 24 point or something like that.\r\nDialogue: 0,0:53:40.23,0:53:41.39,yin,,0,0,0,, 这就行了 \\N{\\fs12}That will still fit.\r\nDialogue: 0,0:53:41.39,0:53:44.29,yin,,0,0,0,, 然后我不要蓝色 点这里换字符颜色 \\N{\\fs12}And then I don’t want this blue, so that’s this text color.\r\nDialogue: 0,0:53:44.29,0:53:46.28,yin,,0,0,0,, 我们要把这个换成黑色 \\N{\\fs12}So let’s go ahead and make that black.\r\nDialogue: 0,0:53:46.28,0:53:49.00,yin,,0,0,0,, 好 这样牌就弄成了我想要的样子 \\N{\\fs12}All right. So I got the card looking the way I want.\r\nDialogue: 0,0:53:49.00,0:53:49.89,yin,,0,0,0,, 这很好 \\N{\\fs12}That’s good.\r\nDialogue: 0,0:53:49.89,0:53:52.77,yin,,0,0,0,, 顺便说下 我们设置的所有这些属性 \\N{\\fs12}All these properties that we’re setting, by the way,\r\nDialogue: 0,0:53:52.77,0:53:55.57,yin,,0,0,0,,Button 下面可以看到这个状态配置 \\N{\\fs12}if you look at button, you see this state config right here?\r\nDialogue: 0,0:53:55.57,0:53:58.97,yin,,0,0,0,, 这是默认 我们可以设置所有不同状态 \\N{\\fs12}Default? We can actually set all these things differently\r\nDialogue: 0,0:53:58.97,0:54:03.01,yin,,0,0,0,, 包括按钮的高亮状态 或选择状态 或禁用状态 \\N{\\fs12}for the highlighted state of the button, or a selected state, or disabled state.\r\nDialogue: 0,0:54:03.01,0:54:05.31,yin,,0,0,0,, 不过这里我们设置的是默认 \\N{\\fs12}But we’re setting these as the default.\r\nDialogue: 0,0:54:05.31,0:54:09.65,yin,,0,0,0,, 所有按钮都总会显示出默认状态 \\N{\\fs12}So all our buttons always going to be displaying the default state.\r\nDialogue: 0,0:54:09.65,0:54:11.64,yin,,0,0,0,, 按钮非常强大 \\N{\\fs12}So buttons are pretty powerful.\r\nDialogue: 0,0:54:11.64,0:54:14.04,yin,,0,0,0,, 你可以让它们在高亮或别的状态中有所不同 \\N{\\fs12}You can have them look different as they highlight or whatever,\r\nDialogue: 0,0:54:14.04,0:54:16.01,yin,,0,0,0,, 但我们这里用到的将是 \\N{\\fs12}but we’re going to be working all in what’s called the\r\nDialogue: 0,0:54:16.01,0:54:18.45,yin,,0,0,0,,”正常”或”默认”状态下的按钮 \\N{\\fs12}”normal” or “default” state of the button.\r\nDialogue: 0,0:54:18.45,0:54:20.39,yin,,0,0,0,, 看代码时你们会看到这个 \\N{\\fs12}You’ll see that when we get to the code.\r\nDialogue: 0,0:54:20.39,0:54:22.18,yin,,0,0,0,, 我们现在就可以运行这个了 \\N{\\fs12}So we can actually run this right now.\r\nDialogue: 0,0:54:22.18,0:54:22.79,yin,,0,0,0,, 运行 \\N{\\fs12}So running.\r\nDialogue: 0,0:54:22.79,0:54:24.67,yin,,0,0,0,, 你们大多数人用过 Xcode\\N{\\fs12}You’ve all — most, again, done Xcode.\r\nDialogue: 0,0:54:24.67,0:54:26.76,yin,,0,0,0,, 知道如何运行 也就是这个小的播放按钮 \\N{\\fs12}You know how to run. It’s this little play button.\r\nDialogue: 0,0:54:26.76,0:54:27.95,yin,,0,0,0,, 下拉列表里还有 \\N{\\fs12}You can actually hold it down,\r\nDialogue: 0,0:54:27.95,0:54:30.87,yin,,0,0,0,, 测试和分析等其它这些东西 \\N{\\fs12}and there’s other things you can do like test and analyze.\r\nDialogue: 0,0:54:30.87,0:54:31.84,yin,,0,0,0,, 这里我们要运行 \\N{\\fs12}But we’re just going to run.\r\nDialogue: 0,0:54:31.84,0:54:36.11,yin,,0,0,0,, 点运行 它会在模拟器中运行 \\N{\\fs12}So I click run, and it’s going to run this in a simulator.\r\nDialogue: 0,0:54:36.11,0:54:38.52,yin,,0,0,0,, 这就是了 \\N{\\fs12}And here it is.\r\nDialogue: 0,0:54:38.52,0:54:42.36,yin,,0,0,0,, 可以看到 模拟器很大 我的屏幕放不下 \\N{\\fs12}And you can see that the simulator’s so big it doesn’t even fit on my screen.\r\nDialogue: 0,0:54:42.36,0:54:44.94,yin,,0,0,0,, 所以我需要滚动 \\N{\\fs12}So I kind of have to scroll around in it.\r\nDialogue: 0,0:54:44.94,0:54:48.03,yin,,0,0,0,, 点击它 它什么都做不了 \\N{\\fs12}And when I click it, it doesn’t do anything.\r\nDialogue: 0,0:54:48.03,0:54:49.70,yin,,0,0,0,, 这个不好 \\N{\\fs12}So that’s not good.\r\nDialogue: 0,0:54:49.70,0:54:52.46,yin,,0,0,0,, 因为控制器中我还没有加入任何代码 \\N{\\fs12}Because I haven’t put any code in my controller\r\nDialogue: 0,0:54:52.46,0:54:54.84,yin,,0,0,0,, 来对点击作出响应 \\N{\\fs12}to respond to that thing being touched.\r\nDialogue: 0,0:54:54.84,0:54:57.73,yin,,0,0,0,, 这将是我们下面的工作 \\N{\\fs12}So that’s what we’re going to do next.\r\nDialogue: 0,0:54:57.73,0:55:00.13,yin,,0,0,0,, 回到这里来 停止 \\N{\\fs12}So let’s go back here and stop.\r\nDialogue: 0,0:55:03.79,0:55:05.39,yin,,0,0,0,, 那么 怎么做到呢 \\N{\\fs12}So how do we do that?\r\nDialogue: 0,0:55:05.39,0:55:07.68,yin,,0,0,0,, 这个做起来会非常有趣 \\N{\\fs12}Well, it’s pretty interesting how we do that, actually.\r\nDialogue: 0,0:55:07.68,0:55:09.95,yin,,0,0,0,, 我这里留一些空间出来 \\N{\\fs12}I’m going to make some more space here.\r\nDialogue: 0,0:55:09.95,0:55:14.07,yin,,0,0,0,, 我们需要把它同控制器联系起来 \\N{\\fs12}And what we need to do is connect up to our controller.\r\nDialogue: 0,0:55:14.07,0:55:19.69,yin,,0,0,0,, 做法是对照视图 并排加入控制器代码 \\N{\\fs12}And we do that by putting our controller’s code side by side with our view.\r\nDialogue: 0,0:55:19.69,0:55:21.83,yin,,0,0,0,, 我将点击这个小按钮 \\N{\\fs12}So I’m going to click this little button right here,\r\nDialogue: 0,0:55:21.83,0:55:25.00,yin,,0,0,0,, 这个按钮图标 表示并排显示 \\N{\\fs12}this button icon, and that puts side by side.\r\nDialogue: 0,0:55:25.00,0:55:27.82,yin,,0,0,0,, 默认情况下 如果视图在左边 \\N{\\fs12}And by default if you have a view up here on the left,\r\nDialogue: 0,0:55:27.82,0:55:30.74,yin,,0,0,0,, 控制器代码会显示在右边 \\N{\\fs12}it’s going to put that controller’s code on the right.\r\nDialogue: 0,0:55:30.74,0:55:34.15,yin,,0,0,0,, 我们可以移动这个 给代码腾出更大空间 \\N{\\fs12}And you can move this to get more space for the code if you want.\r\nDialogue: 0,0:55:34.15,0:55:37.76,yin,,0,0,0,, 这里还可以在处理公共内容的头文件 \\N{\\fs12}You can also switch between the header if you want to do public stuff\r\nDialogue: 0,0:55:37.77,0:55:40.27,yin,,0,0,0,, 和实现之间来回切换 \\N{\\fs12}or the implementation.\r\nDialogue: 0,0:55:41.76,0:55:43.14,yin,,0,0,0,, 这很棒 \\N{\\fs12}So that’s good.\r\nDialogue: 0,0:55:43.14,0:55:46.24,yin,,0,0,0,, 这段代码是视图控制器生命周期的部分 \\N{\\fs12}Now, this code right here is part of the view controller lifecycle,\r\nDialogue: 0,0:55:46.24,0:55:48.39,yin,,0,0,0,, 我们会在两三周后谈到 \\N{\\fs12}which we’re going to talk about in two or three weeks.\r\nDialogue: 0,0:55:48.39,0:55:53.11,yin,,0,0,0,, 不过今天我不打算讲它 让我把它删掉 \\N{\\fs12}But today we’re not going to talk about it. So we can just get rid of it.\r\nDialogue: 0,0:55:53.11,0:55:57.42,yin,,0,0,0,, 今天我只想说 \\N{\\fs12}And let’s just start by saying,\r\nDialogue: 0,0:55:57.42,0:56:01.18,yin,,0,0,0,, 这个按钮被触碰到时 我们希望它翻个面 \\N{\\fs12}”When this button gets touched, we want it to flip over.”\r\nDialogue: 0,0:56:01.18,0:56:04.60,yin,,0,0,0,, 我们需要将视图和控制器连接起来 \\N{\\fs12}So we need to make a connection between our view and the controller.\r\nDialogue: 0,0:56:04.60,0:56:08.98,yin,,0,0,0,, 我们会将目标挂出去 然后将箭发射 \\N{\\fs12}And we’re going to do that thing where we hang the target out and shoot the arrow.\r\nDialogue: 0,0:56:08.98,0:56:10.38,yin,,0,0,0,, 这是目标 动作 \\N{\\fs12}Called “target action.”\r\nDialogue: 0,0:56:10.38,0:56:11.89,yin,,0,0,0,, 这会有些怪异 \\N{\\fs12}And this is going to be kind of whacky.\r\nDialogue: 0,0:56:11.89,0:56:14.48,yin,,0,0,0,, 看到这个时 你可能都不敢相信自己的眼睛 \\N{\\fs12}You’re probably not even going to believe this when you see it.\r\nDialogue: 0,0:56:14.48,0:56:16.86,yin,,0,0,0,, 做法是按住 Control 键 \\N{\\fs12}The way to do this is you hold down the control key.\r\nDialogue: 0,0:56:16.86,0:56:21.91,yin,,0,0,0,, 我按住 Control 键 然后拖一条线 \\N{\\fs12}So I’m holding down the control key, and I’m dragging a line\r\nDialogue: 0,0:56:21.91,0:56:25.71,yin,,0,0,0,, 从视图直接拖到代码中 \\N{\\fs12}from the view directly into our code.\r\nDialogue: 0,0:56:27.07,0:56:28.48,yin,,0,0,0,, 让后松手 \\N{\\fs12}And I let go.\r\nDialogue: 0,0:56:28.48,0:56:33.24,yin,,0,0,0,, 然后它说 哦 你想在视图和控制器之间建立连接 对吧 \\N{\\fs12}And it says, “Oh, you want a connection between your view and your controller, do you?\r\nDialogue: 0,0:56:33.24,0:56:34.68,yin,,0,0,0,, 这就是我需要知道的 \\N{\\fs12}Here’s what I need to know.”\r\nDialogue: 0,0:56:34.68,0:56:37.33,yin,,0,0,0,, 它问我们 你希望给这个连接取名叫什么 \\N{\\fs12}So it’s asking us, “What you do you want to call this connection?”\r\nDialogue: 0,0:56:37.33,0:56:38.67,yin,,0,0,0,, 这将是方法名 \\N{\\fs12}So this is going to be the name of the method.\r\nDialogue: 0,0:56:38.67,0:56:42.05,yin,,0,0,0,, 它会创建一个在按钮被触碰到时调用的方法 \\N{\\fs12}It’s actually going to create a method here that gets called when the button gets touched.\r\nDialogue: 0,0:56:42.05,0:56:44.31,yin,,0,0,0,, 这里我给它取名叫 touchCardButton(触摸纸牌按钮)\\N{\\fs12}I’m going to call it “touch card button.”\r\nDialogue: 0,0:56:44.31,0:56:45.53,yin,,0,0,0,, 这个名字不错 \\N{\\fs12}That’s a good name.\r\nDialogue: 0,0:56:45.53,0:56:48.20,yin,,0,0,0,, 这里它问的是 你希望参数类型是什么 \\N{\\fs12}Here it’s saying, “What you do you want the type of the argument to be?”\r\nDialogue: 0,0:56:48.20,0:56:49.13,yin,,0,0,0,, 以后我会讲到 \\N{\\fs12}We’ll talk about this later,\r\nDialogue: 0,0:56:49.13,0:56:51.75,yin,,0,0,0,, 不过这里 我们显然希望参数是 \\N{\\fs12}but for now we obviously want the argument to be\r\nDialogue: 0,0:56:51.75,0:56:54.63,yin,,0,0,0,, 发送给我们这个动作的按钮 \\N{\\fs12}the button that is sending us this action.\r\nDialogue: 0,0:56:54.63,0:56:55.98,yin,,0,0,0,, 我们能够回头告诉它翻过来 这会很好 \\N{\\fs12}Which is going to be nice because then we’re going\r\nDialogue: 0,0:56:55.98,0:56:58.73,yin,,0,0,0,, 我们能够回头告诉它翻过来 这会很好 \\N{\\fs12}to talk back to it and tell it to flip itself over.\r\nDialogue: 0,0:56:58.73,0:57:00.19,yin,,0,0,0,, 这里我们还可以设置 \\N{\\fs12}There’s other things we can set here like:\r\nDialogue: 0,0:57:00.19,0:57:03.26,yin,,0,0,0,, 你想在哪一类事件下发送这个动作 \\N{\\fs12}What kind of event do you want to send this action?\r\nDialogue: 0,0:57:03.26,0:57:05.76,yin,,0,0,0,, 你可以设置为无参数 \\N{\\fs12}And you can actually set it so there’s no argument,\r\nDialogue: 0,0:57:05.76,0:57:08.53,yin,,0,0,0,, 它会发送 touchCardButton 不带参数 \\N{\\fs12}it just sends touch card button with no arguments.\r\nDialogue: 0,0:57:08.53,0:57:11.01,yin,,0,0,0,, 但这里我们希望 Sender 这一参数 \\N{\\fs12}But here we want it to have the argument of the sender,\r\nDialogue: 0,0:57:11.01,0:57:12.52,yin,,0,0,0,, 即发送这一消息的按钮 \\N{\\fs12}the button sending this message.\r\nDialogue: 0,0:57:12.52,0:57:14.09,yin,,0,0,0,, 你还可以发送触摸事件 \\N{\\fs12}You can even send the touch event along,\r\nDialogue: 0,0:57:14.09,0:57:17.34,yin,,0,0,0,, 但我们几乎从不这样做 使用率小于 0.1%\\N{\\fs12}but we almost never do that — a tenth of a percent of the time.\r\nDialogue: 0,0:57:17.34,0:57:18.94,yin,,0,0,0,, 这里选 Sender\\N{\\fs12}So here I’m going to have the sender.\r\nDialogue: 0,0:57:18.94,0:57:21.76,yin,,0,0,0,, 我点击连接时 它会创建一个新方法 \\N{\\fs12}So when I click connect, it creates a new method.\r\nDialogue: 0,0:57:21.76,0:57:24.50,yin,,0,0,0,, 这一方法同这一按钮接通起来 \\N{\\fs12}And that method is wired up to that button.\r\nDialogue: 0,0:57:24.50,0:57:26.50,yin,,0,0,0,, 看到这个圆圈了吗 \\N{\\fs12}In fact, you see this little round circle?\r\nDialogue: 0,0:57:26.50,0:57:31.52,yin,,0,0,0,, 鼠标放到上面 它就会告诉你 它连接到的是什么 \\N{\\fs12}If I mouse over it, it will show you that’s what it’s connected to.\r\nDialogue: 0,0:57:31.52,0:57:35.47,yin,,0,0,0,, 这是一个非常普通的方法 \\N{\\fs12}So this is just some pretty normal-looking method right here.\r\nDialogue: 0,0:57:35.47,0:57:40.13,yin,,0,0,0,, 返回类型 IBAction 这实际上是 typedef void\\N{\\fs12}The return type, IB action, that’s actually typedef void.\r\nDialogue: 0,0:57:40.13,0:57:42.10,yin,,0,0,0,, 这个方法实际返回 void\\N{\\fs12}This method actually returns void.\r\nDialogue: 0,0:57:42.10,0:57:45.04,yin,,0,0,0,,Xcode 之所以加上 IBAction\\N{\\fs12}The reason that Xcode puts IB action there\r\nDialogue: 0,0:57:45.04,0:57:48.27,yin,,0,0,0,, 将 IBAction 类型定义到 void 只是为了便于分辨 \\N{\\fs12}and typedef’s IB action to void, it’s just so that it can tell\r\nDialogue: 0,0:57:48.27,0:57:50.12,yin,,0,0,0,, 哪个方法是目标动作 \\N{\\fs12}which methods are target action\r\nDialogue: 0,0:57:50.12,0:57:52.89,yin,,0,0,0,, 于是它可以做这样的事情 \\N{\\fs12}so that it can do stuff like this.\r\nDialogue: 0,0:57:52.89,0:57:54.29,yin,,0,0,0,, 鼠标悬停 \\N{\\fs12}The mouse over.\r\nDialogue: 0,0:57:54.29,0:57:55.56,yin,,0,0,0,, 但编译器会忽略它 \\N{\\fs12}But the compiler ignores it.\r\nDialogue: 0,0:57:55.56,0:57:58.38,yin,,0,0,0,, 编译器会把它看作 void 因为它被类型定义为 void\\N{\\fs12}The compiler sees it as void because it’s typedef to void.\r\nDialogue: 0,0:57:58.38,0:58:01.12,yin,,0,0,0,,IBAction 完全是为 Xcode 考虑 \\N{\\fs12}It’s purely an Xcode thing to this IB action thing.\r\nDialogue: 0,0:58:01.12,0:58:05.26,yin,,0,0,0,, 然后这个方法有一个参数 也就是 sender\\N{\\fs12}And then you can see this method has one argument, which is the sender.\r\nDialogue: 0,0:58:05.26,0:58:06.98,yin,,0,0,0,, 这是发送我们这一消息的按钮 \\N{\\fs12}That’s the button sending us this message.\r\nDialogue: 0,0:58:06.98,0:58:11.77,yin,,0,0,0,, 每次按钮被触摸时 它都会发送这一消息 \\N{\\fs12}And it’s going to send this message every time a touch goes up inside the button.\r\nDialogue: 0,0:58:11.77,0:58:13.79,yin,,0,0,0,, 事件是触摸按钮 \\N{\\fs12}Touch up inside, right? That was the event.\r\nDialogue: 0,0:58:13.79,0:58:15.59,yin,,0,0,0,, 这时它会发送这一消息 \\N{\\fs12}So that’s when it’s going to send this message.\r\nDialogue: 0,0:58:15.59,0:58:17.03,yin,,0,0,0,, 这很完美 这就是我们要的 \\N{\\fs12}So that’s perfect. That’s what we want.\r\nDialogue: 0,0:58:17.03,0:58:19.72,yin,,0,0,0,, 每次发生这个时 我们想要做什么 \\N{\\fs12}So every time this happens, what do we want to do?\r\nDialogue: 0,0:58:19.72,0:58:22.32,yin,,0,0,0,, 我们希望将纸牌翻过来 \\N{\\fs12}Well, we want to flip the card over.\r\nDialogue: 0,0:58:22.32,0:58:24.57,yin,,0,0,0,, 我们首先来考虑如何翻到反面 \\N{\\fs12}Okay. So let’s start by just flipping it over to the back.\r\nDialogue: 0,0:58:24.57,0:58:27.12,yin,,0,0,0,, 为此 我们将创建一个局部变量 \\N{\\fs12}And the way we’re going to do that is we’re going to create a local variable\r\nDialogue: 0,0:58:27.12,0:58:29.18,yin,,0,0,0,, 叫 cardImage(纸牌图像)\\N{\\fs12}called “card image.”\r\nDialogue: 0,0:58:29.18,0:58:31.51,yin,,0,0,0,, 可以看到 它正为我提供键入帮助 这里会有很多帮助 \\N{\\fs12}Okay. And you noticed it was trying to help me type there,\r\nDialogue: 0,0:58:31.51,0:58:34.51,yin,,0,0,0,, 可以看到 它正为我提供键入帮助 这里会有很多帮助 \\N{\\fs12}and you’re going to see a lot of helping here.\r\nDialogue: 0,0:58:34.51,0:58:39.34,yin,,0,0,0,,UIImage 是 iOS 中的另一个类 就像 UIButton 一样 \\N{\\fs12}And UI image is another class in iOS, okay, just like UI button is a class.\r\nDialogue: 0,0:58:39.34,0:58:42.25,yin,,0,0,0,,UIImage 顾名思义 是用来存储图像的 \\N{\\fs12}UI image is the class, as you can imagine, stores an image.\r\nDialogue: 0,0:58:42.25,0:58:44.83,yin,,0,0,0,, 可以是 JPEG 图像 可以是 GIF 动画 \\N{\\fs12}Could be a JPEG image, could be an animated GIF,\r\nDialogue: 0,0:58:44.83,0:58:47.05,yin,,0,0,0,, 可以是 TIFF 图像 这些都行 \\N{\\fs12}it could be a TIFF image, whatever.\r\nDialogue: 0,0:58:47.05,0:58:50.89,yin,,0,0,0,, 这是一种很强大的容纳图像的类 \\N{\\fs12}So it’s very powerful image holding class.\r\nDialogue: 0,0:58:50.89,0:58:54.80,yin,,0,0,0,, 它有一个类方法 叫 imageNamed(图像名叫)\\N{\\fs12}And it has a class method called “image named,”\r\nDialogue: 0,0:58:54.80,0:59:00.46,yin,,0,0,0,, 你给它一个字符串 例如 cardfront 或 cardback\\N{\\fs12}and you give it a string like card front or card back, right?\r\nDialogue: 0,0:59:00.46,0:59:04.84,yin,,0,0,0,, 它会到资源库并给出一个分辨率正确的图像 \\N{\\fs12}And it will look in the assets library and give an image of the right resolution,\r\nDialogue: 0,0:59:04.85,0:59:06.59,yin,,0,0,0,, 实际上 它会给你两种分辨率的图像 \\N{\\fs12}depending on whether it’s going to be go on –\r\nDialogue: 0,0:59:06.59,0:59:08.70,yin,,0,0,0,, 实际上 它会给你两种分辨率的图像 \\N{\\fs12}actually, it will give you an image with both resolutions.\r\nDialogue: 0,0:59:08.70,0:59:11.22,yin,,0,0,0,, 然后取决于是否在视网膜屏上显示 \\N{\\fs12}And then depending on where you display it, it will, you know,\r\nDialogue: 0,0:59:11.22,0:59:13.86,yin,,0,0,0,, 它会为你选出正确分辨率的图像 \\N{\\fs12}pick the right resolution, whether it’s on a retina or not.\r\nDialogue: 0,0:59:13.86,0:59:15.38,yin,,0,0,0,, 这很酷 我们得到了图像 \\N{\\fs12}So that’s cool. We got the image.\r\nDialogue: 0,0:59:15.38,0:59:18.37,yin,,0,0,0,, 然后我们要告诉按钮把这个 \\N{\\fs12}So now we’re just going to tell the button to set this\r\nDialogue: 0,0:59:18.37,0:59:20.12,yin,,0,0,0,, 设置为背景图像 \\N{\\fs12}as its background image\r\nDialogue: 0,0:59:20.12,0:59:21.99,yin,,0,0,0,, 替换现在它上面的图像 \\N{\\fs12}instead of whatever’s on it right now.\r\nDialogue: 0,0:59:21.99,0:59:26.10,yin,,0,0,0,, 要同按钮通信 我们用 [sender\\N{\\fs12}So to talk to the button, we do open square bracket sender.\r\nDialogue: 0,0:59:26.10,0:59:30.65,yin,,0,0,0,,sender 也就是发送这一消息的按钮 \\N{\\fs12}Right? You see that the sender is the button sending us this message.\r\nDialogue: 0,0:59:31.73,0:59:36.13,yin,,0,0,0,, 设置背景 这里键入 setBackground…\\N{\\fs12}Set. Okay, I’m going to start typing set background.\r\nDialogue: 0,0:59:36.13,0:59:41.39,yin,,0,0,0,, 注意在我键入的过程中 Xcode 会为我提供一些建议 \\N{\\fs12}And you see as I start to type, Xcode is suggesting to me what I might want.\r\nDialogue: 0,0:59:41.39,0:59:43.64,yin,,0,0,0,, 它知道 sender 是一个 UIButton\\N{\\fs12}Now, it knows that the sender’s a UI button,\r\nDialogue: 0,0:59:43.64,0:59:48.75,yin,,0,0,0,, 所以它这里只会给我推荐以 setB 开头的按钮方法 \\N{\\fs12}so it’s only suggesting button methods here that start with set B –\r\nDialogue: 0,0:59:48.75,0:59:50.36,yin,,0,0,0,,setBackgroundColor setBackgroundImage\\N{\\fs12}set background color, set background image,\r\nDialogue: 0,0:59:50.36,0:59:51.55,yin,,0,0,0,, 和 setBounds\\N{\\fs12}and set bounds.\r\nDialogue: 0,0:59:51.55,0:59:54.60,yin,,0,0,0,, 注意下方还有一些帮助信息 \\N{\\fs12}Notice I’m also getting some help at the bottom.\r\nDialogue: 0,0:59:54.60,0:59:55.40,yin,,0,0,0,, 很酷吧 \\N{\\fs12}See, isn’t that cool?\r\nDialogue: 0,0:59:55.40,0:59:57.05,yin,,0,0,0,, 有一两行的简短帮助 \\N{\\fs12}A little one or two lines of help?\r\nDialogue: 0,0:59:57.05,0:59:58.19,yin,,0,0,0,, 我还可以点这个链接 \\N{\\fs12}And I could click on this link\r\nDialogue: 0,0:59:58.19,0:59:59.66,yin,,0,0,0,, 这会让我看到说明文档 \\N{\\fs12}and it would take me to the documentation.\r\nDialogue: 0,0:59:59.66,1:00:01.94,yin,,0,0,0,, 由于时间原因 我这里就不点了 \\N{\\fs12}We’re not going to do that for time reasons.\r\nDialogue: 0,1:00:01.94,1:00:06.23,yin,,0,0,0,, 不过我可以选择一个 它会写出这一个 \\N{\\fs12}But I can also just click one and it picks that one\r\nDialogue: 0,1:00:06.23,1:00:08.30,yin,,0,0,0,, 并立刻选择第一个参数 \\N{\\fs12}and immediately selects the first argument.\r\nDialogue: 0,1:00:08.30,1:00:10.05,yin,,0,0,0,, 我可以填入这个 \\N{\\fs12}So I can take that.\r\nDialogue: 0,1:00:10.05,1:00:11.28,yin,,0,0,0,, 我要这样做 \\N{\\fs12}So I’ll do that.\r\nDialogue: 0,1:00:11.28,1:00:12.25,yin,,0,0,0,,cardImage\\N{\\fs12}Card image.\r\nDialogue: 0,1:00:12.25,1:00:15.95,yin,,0,0,0,, 注意到 当我键入 ca 时 这里给出了很多东西 \\N{\\fs12}And notice here when I type CA, there’s a lot of things\r\nDialogue: 0,1:00:15.95,1:00:18.28,yin,,0,0,0,, 所有 ca 开头的都在这里 \\N{\\fs12}that start with CA that could go there.\r\nDialogue: 0,1:00:18.28,1:00:20.00,yin,,0,0,0,, 但 Xcode 很聪明 \\N{\\fs12}But Xcode’s pretty smart.\r\nDialogue: 0,1:00:20.00,1:00:23.82,yin,,0,0,0,, 它知道局部变量更可能是你要的 \\N{\\fs12}It knows that a local variable is much more likely what you want here\r\nDialogue: 0,1:00:23.83,1:00:27.66,yin,,0,0,0,, 相比其它这些 ca 开头的函数 \\N{\\fs12}than all these other CA — functions that start with CA.\r\nDialogue: 0,1:00:27.66,1:00:30.27,yin,,0,0,0,, 于是它自动给我选了这个 \\N{\\fs12}So it automatically selects that for me.\r\nDialogue: 0,1:00:30.27,1:00:31.83,yin,,0,0,0,, 如果我按 Tab 键 \\N{\\fs12}And if I hit tab, by the way,\r\nDialogue: 0,1:00:31.83,1:00:35.25,yin,,0,0,0,, 它会自动给我补全 Tab 用于补全 \\N{\\fs12}it’s going to basically escape complete it. Tab, complete it.\r\nDialogue: 0,1:00:35.27,1:00:37.41,yin,,0,0,0,, 再点一下 Tab 它会跳到这里 \\N{\\fs12}And if I hit another tab, it goes over here.\r\nDialogue: 0,1:00:37.41,1:00:40.60,yin,,0,0,0,, 这里 forState 也就是我刚才讲过的内容 \\N{\\fs12}This little forState thing is just what I was talking about where\r\nDialogue: 0,1:00:40.60,1:00:43.26,yin,,0,0,0,, 你可以设置为高亮状态 \\N{\\fs12}you can set this for the highlighted state,\r\nDialogue: 0,1:00:43.26,1:00:45.39,yin,,0,0,0,, 或选择状态 或禁用状态 \\N{\\fs12}or the selected state, or disabled state.\r\nDialogue: 0,1:00:45.39,1:00:49.28,yin,,0,0,0,, 我们将选择按钮的正常或默认状态 \\N{\\fs12}We’re just going to do the normal or default state of this button.\r\nDialogue: 0,1:00:49.28,1:00:52.53,yin,,0,0,0,, 我们在设置这个按钮的背景图像 \\N{\\fs12}So we’re setting the background image for this button.\r\nDialogue: 0,1:00:52.53,1:00:56.10,yin,,0,0,0,, 我们还需要设置标题 因为我们不希望 \\N{\\fs12}And we also need to set the title because we don’t want\r\nDialogue: 0,1:00:56.10,1:00:58.44,yin,,0,0,0,, 翻过来后还能看到梅花 A\\N{\\fs12}to see that ace of clubs when we flip it over backwards.\r\nDialogue: 0,1:00:58.44,1:01:01.12,yin,,0,0,0,, 我将把它设为这个 \\N{\\fs12}So I’m just going to set it to that.\r\nDialogue: 0,1:01:01.12,1:01:04.16,yin,,0,0,0,, 这是空字符串 这里我也可以用 nil\\N{\\fs12}Okay. That’s the empty string. I could also say nil there.\r\nDialogue: 0,1:01:04.16,1:01:07.24,yin,,0,0,0,, 不过我这里要写空字符串 让你们看看是怎样的 \\N{\\fs12}Okay. But I’m saying empty string just to see what empty string looks like.\r\nDialogue: 0,1:01:07.24,1:01:09.45,yin,,0,0,0,, 我们可以运行这个 \\N{\\fs12}So actually if we run this,\r\nDialogue: 0,1:01:12.84,1:01:14.01,yin,,0,0,0,,Command 3\\N{\\fs12}command three.\r\nDialogue: 0,1:01:14.01,1:01:14.93,yin,,0,0,0,, 好 我试试 \\N{\\fs12}Okay, let’s try that.\r\nDialogue: 0,1:01:14.93,1:01:16.42,yin,,0,0,0,, 哦 酷 \\N{\\fs12}Oh, cool.\r\nDialogue: 0,1:01:18.21,1:01:19.49,yin,,0,0,0,, 好了 \\N{\\fs12}So there you go.\r\nDialogue: 0,1:01:19.49,1:01:21.38,yin,,0,0,0,, 这是一个缩小的版本 \\N{\\fs12}So there’s a miniature version of it.\r\nDialogue: 0,1:01:21.38,1:01:22.94,yin,,0,0,0,, 这是我们的纸牌 \\N{\\fs12}Okay. So here’s our card.\r\nDialogue: 0,1:01:22.94,1:01:25.05,yin,,0,0,0,, 如果我点它一下 \\N{\\fs12}And if I click on it,\r\nDialogue: 0,1:01:25.05,1:01:26.73,yin,,0,0,0,, 哦耶 它翻过来了 \\N{\\fs12}oh yeah, it flips over.\r\nDialogue: 0,1:01:26.73,1:01:29.18,yin,,0,0,0,, 很好 带树的斯坦福 logo\\N{\\fs12}Yes. Stanford logo with the tree.\r\nDialogue: 0,1:01:29.18,1:01:33.03,yin,,0,0,0,, 但我再点它 它就不动了 永远是反面 \\N{\\fs12}But now if I click, it doesn’t do anything else; it always flips over to the back,\r\nDialogue: 0,1:01:33.03,1:01:35.53,yin,,0,0,0,, 这正是我们代码的效果 \\N{\\fs12}which is exactly what our code does, right?\r\nDialogue: 0,1:01:35.53,1:01:36.41,yin,,0,0,0,, 这很好 \\N{\\fs12}So that’s good.\r\nDialogue: 0,1:01:36.41,1:01:39.47,yin,,0,0,0,, 我们来调整一下代码 让它能两面翻动 \\N{\\fs12}So let’s fix it so that it flips both ways.\r\nDialogue: 0,1:01:39.47,1:01:43.32,yin,,0,0,0,, 我可以这样写 加上 if\\N{\\fs12}And I’m going to do that by saying if the –\r\nDialogue: 0,1:01:43.32,1:01:45.89,yin,,0,0,0,, 我还是先做另外一件事吧 \\N{\\fs12}actually, I’m going to do one other thing first\r\nDialogue: 0,1:01:45.89,1:01:47.70,yin,,0,0,0,, 让代码更简单一些 \\N{\\fs12}to make this code a little simpler is instead\r\nDialogue: 0,1:01:47.70,1:01:49.32,yin,,0,0,0,, 这里我可以不用这个局部变量 \\N{\\fs12}of having this local variable,\r\nDialogue: 0,1:01:49.32,1:01:52.58,yin,,0,0,0,, 我可以直接把这些写到这里来 \\N{\\fs12}I can just take this and pop it right in there.\r\nDialogue: 0,1:01:52.58,1:01:55.10,yin,,0,0,0,, 这是很常见的做法 \\N{\\fs12}And that’s very common to do that.\r\nDialogue: 0,1:01:55.10,1:01:58.87,yin,,0,0,0,, 如果要换行 太长的话它会自动换行 \\N{\\fs12}And if I wanted to wrap it, it will automatically wrap if I make this too short.\r\nDialogue: 0,1:01:58.87,1:02:00.88,yin,,0,0,0,, 不过我也可以键入一个回车 \\N{\\fs12}But I can also put a return in there.\r\nDialogue: 0,1:02:00.88,1:02:02.97,yin,,0,0,0,, 这样做后 注意冒号的情况 \\N{\\fs12}And when I do, look what it does with the colons.\r\nDialogue: 0,1:02:02.97,1:02:05.60,yin,,0,0,0,, 看到冒号对齐起来了吗 \\N{\\fs12}See how it lines the colons up?\r\nDialogue: 0,1:02:05.60,1:02:06.90,yin,,0,0,0,, 它总会这样做 \\N{\\fs12}It will always do that.\r\nDialogue: 0,1:02:06.90,1:02:10.42,yin,,0,0,0,, 如果你在多参数的信息发送中间敲了回车 \\N{\\fs12}If you press return in the middle of a message send that has multiple arguments,\r\nDialogue: 0,1:02:10.42,1:02:12.24,yin,,0,0,0,, 它会为所有参数对齐冒号 \\N{\\fs12}it will line the colons up for all the arguments.\r\nDialogue: 0,1:02:12.24,1:02:12.91,yin,,0,0,0,, 非常酷 \\N{\\fs12}Really cool.\r\nDialogue: 0,1:02:12.91,1:02:16.55,yin,,0,0,0,, 这时所有参数都会像这样左右排列对齐 \\N{\\fs12}So you can see all the arguments lined up left and right.\r\nDialogue: 0,1:02:16.55,1:02:21.87,yin,,0,0,0,, 无论如何 我将检验当前标题 \\N{\\fs12}So anyway, I’m going to check to see if the current title –\r\nDialogue: 0,1:02:21.87,1:02:24.10,yin,,0,0,0,, 这是一个按钮方法 \\N{\\fs12}okay, that’s a button method –\r\nDialogue: 0,1:02:24.10,1:02:25.47,yin,,0,0,0,, 如果它是字符串 \\N{\\fs12}if it’s a string.\r\nDialogue: 0,1:02:25.47,1:02:32.39,yin,,0,0,0,, 如果这个长度不为 0\\N{\\fs12}If that length, okay, is nonzero, okay –\r\nDialogue: 0,1:02:32.39,1:02:35.19,yin,,0,0,0,, 这是用于检验长度是否不为 0\\N{\\fs12}so that’s testing there to see if the length of nonzero –\r\nDialogue: 0,1:02:35.19,1:02:37.49,yin,,0,0,0,, 这样做很酷 因为这会在 \\N{\\fs12}that’s a cool way to do it because that will work\r\nDialogue: 0,1:02:37.49,1:02:41.38,yin,,0,0,0,, 按钮标题为 nil 或为空字符串时执行 \\N{\\fs12}if the button title is nil or if it’s the empty string.\r\nDialogue: 0,1:02:41.38,1:02:43.20,yin,,0,0,0,, 因为按钮标题默认值是 nil\\N{\\fs12}Because the button title starts out nil.\r\nDialogue: 0,1:02:43.20,1:02:45.00,yin,,0,0,0,, 不设置为任何东西 最开始就是 nil\\N{\\fs12}If you don’t set it to anything, it starts out nil.\r\nDialogue: 0,1:02:45.00,1:02:48.77,yin,,0,0,0,, 这里通过一行代码 我同时检验了两种可能的初始状态 \\N{\\fs12}So here with one line of code I’ve checked both the initial state possibly –\r\nDialogue: 0,1:02:48.77,1:02:50.95,yin,,0,0,0,, 这里不是如此 因为我们把标题设为了梅花 A\\N{\\fs12}not in our case because we set the title to the A club –\r\nDialogue: 0,1:02:50.95,1:02:53.10,yin,,0,0,0,, 不过你们的情况中 可能会是这样 \\N{\\fs12}but in your case it might be.\r\nDialogue: 0,1:02:53.10,1:02:57.04,yin,,0,0,0,, 然后我们让它执行一段代码 否则执行另一段 \\N{\\fs12}Then we’ll set it to one thing, else we’ll set it to the other thing.\r\nDialogue: 0,1:02:57.04,1:03:00.58,yin,,0,0,0,, 我们希望把这个设置到这里 \\N{\\fs12}So we just wanted to set this to this.\r\nDialogue: 0,1:03:00.58,1:03:03.41,yin,,0,0,0,, 如果按钮上有标题 \\N{\\fs12}So if there’s a title on the button,\r\nDialogue: 0,1:03:03.41,1:03:07.28,yin,,0,0,0,, 换言之 它上面有梅花 A 那我们就将翻到反面 \\N{\\fs12}in other words it has the ace of clubs, then we’re going to switch over to the back.\r\nDialogue: 0,1:03:07.28,1:03:13.34,yin,,0,0,0,, 如果按钮上没有标题 那么我们就将翻回正面 \\N{\\fs12}And if there’s no title on the button, then we’re going to switch back to the front.\r\nDialogue: 0,1:03:13.34,1:03:17.63,yin,,0,0,0,, 梅花 A\\N{\\fs12}Ace of clubs.\r\nDialogue: 0,1:03:20.34,1:03:27.16,yin,,0,0,0,, 之后我们如果运行 纸牌就能来回翻动了 \\N{\\fs12}So now when we run, our card will flip both ways.\r\nDialogue: 0,1:03:27.16,1:03:32.43,yin,,0,0,0,, 将视图同控制器连接起来做你想做的事 其实很简单 \\N{\\fs12}So really simple to wire stuff into your controller to do what you want.\r\nDialogue: 0,1:03:32.43,1:03:37.43,yin,,0,0,0,, 下面我们再来看这个 \\N{\\fs12}The next thing we’re going to do is in the –\r\nDialogue: 0,1:03:37.43,1:03:40.33,yin,,0,0,0,, 这里我将快速展示一下 \\N{\\fs12}okay, I’ll show you really quickly here.\r\nDialogue: 0,1:03:40.33,1:03:42.91,yin,,0,0,0,, 按住 Option 键 这个很重要的键 \\N{\\fs12}If you hold down the option key, a very important key,\r\nDialogue: 0,1:03:42.91,1:03:46.19,yin,,0,0,0,, 看到它让光标变成问号 并开始高亮显示一些东西吗 \\N{\\fs12}do you see how it puts a question mark and starts highlighting things?\r\nDialogue: 0,1:03:46.21,1:03:48.99,yin,,0,0,0,, 这让你能够转到说明文档 \\N{\\fs12}That’s going to allow to you to transition into the documentation.\r\nDialogue: 0,1:03:48.99,1:03:51.45,yin,,0,0,0,, 如果关于这个 currentTitle 我想知道更多 \\N{\\fs12}So if I want to know more about this current title,\r\nDialogue: 0,1:03:51.45,1:03:53.85,yin,,0,0,0,, 我可以 Option 点击它 \\N{\\fs12}if I hit option, click on it –\r\nDialogue: 0,1:03:53.85,1:03:55.41,yin,,0,0,0,, 这里可以得到一些帮助 \\N{\\fs12}see, I get a little bit of help right here.\r\nDialogue: 0,1:03:55.41,1:03:58.06,yin,,0,0,0,, 它是一种属性 它是只读的 非原子的 \\N{\\fs12}It’s a property. It’s read-only, it’s nonatomic.\r\nDialogue: 0,1:03:58.06,1:04:02.03,yin,,0,0,0,, 记住 说明文档中凡是出现 retain 都表示 strong\\N{\\fs12}By the way, if you see “retain” in the documentation, that’s the same as “strong.”\r\nDialogue: 0,1:04:02.03,1:04:04.63,yin,,0,0,0,,retain 其实说的也就是强 \\N{\\fs12}Retain is the same as strong basically.\r\nDialogue: 0,1:04:04.63,1:04:07.40,yin,,0,0,0,, 这里有些描述 然后还有超链接 \\N{\\fs12}Little bit of description here but also hyperlinks.\r\nDialogue: 0,1:04:07.40,1:04:10.11,yin,,0,0,0,, 如果我点击其中一个超链接 例如这个 \\N{\\fs12}And if I click on one of these hyperlinks, like this one,\r\nDialogue: 0,1:04:10.11,1:04:11.52,yin,,0,0,0,, 我会进入说明文档 \\N{\\fs12}it takes me into the documentation.\r\nDialogue: 0,1:04:11.52,1:04:13.85,yin,,0,0,0,, 这是一个单独打开的窗口 \\N{\\fs12}This is a separate window right here.\r\nDialogue: 0,1:04:13.85,1:04:16.90,yin,,0,0,0,, 你可以在这个说明文档中进行浏览 \\N{\\fs12}And you can navigate around in this documentation.\r\nDialogue: 0,1:04:16.90,1:04:18.96,yin,,0,0,0,, 所有这些你们都需要熟悉 \\N{\\fs12}You really want to get familiar with all this.\r\nDialogue: 0,1:04:18.96,1:04:21.75,yin,,0,0,0,, 由于时间限制 我今天无法全部展示 \\N{\\fs12}I can’t really show it all to you today for time constraints,\r\nDialogue: 0,1:04:21.75,1:04:26.31,yin,,0,0,0,, 不过你可以搜索 例如我可以搜索 UIButton\\N{\\fs12}but you can do things like search, like I can go find UI button here.\r\nDialogue: 0,1:04:26.31,1:04:27.62,yin,,0,0,0,, 这是 UIButton\\N{\\fs12}Okay. There’s UI button.\r\nDialogue: 0,1:04:27.62,1:04:30.87,yin,,0,0,0,, 我可以往下滚动到 例如 \\N{\\fs12}I might scroll down and go to, for example,\r\nDialogue: 0,1:04:30.87,1:04:35.36,yin,,0,0,0,, 我们刚看到过的 setBackgroundImage:forState\\N{\\fs12}set background image or set background image for state, which we just saw.\r\nDialogue: 0,1:04:35.36,1:04:37.52,yin,,0,0,0,, 我还可以点击进入 UIImage\\N{\\fs12}Maybe I’ll click to go UI image.\r\nDialogue: 0,1:04:37.52,1:04:38.94,yin,,0,0,0,, 所有这些都在这里 \\N{\\fs12}You see all this.\r\nDialogue: 0,1:04:38.94,1:04:40.91,yin,,0,0,0,, 一开始有对类的良好描述 \\N{\\fs12}There’s nice descriptions of the class in the beginning\r\nDialogue: 0,1:04:40.91,1:04:43.10,yin,,0,0,0,, 然后所有方法 等等 \\N{\\fs12}and then all the methods, etc., etc.\r\nDialogue: 0,1:04:43.10,1:04:46.56,yin,,0,0,0,, 你们必须掌握说明文档的使用方法 \\N{\\fs12}So definitely you want to become a master of that documentation.\r\nDialogue: 0,1:04:46.56,1:04:48.29,yin,,0,0,0,, 你还可以 Option 双击 \\N{\\fs12}You can also option double-click on things\r\nDialogue: 0,1:04:48.29,1:04:49.73,yin,,0,0,0,, 这会直接进入说明文档 \\N{\\fs12}and it will send you straight to the documentation.\r\nDialogue: 0,1:04:49.73,1:04:52.71,yin,,0,0,0,, 不会给出小帮助提示 而是直接跳到说明文档 \\N{\\fs12}If you don’t want to get the little help one first, you can go straight in.\r\nDialogue: 0,1:04:52.71,1:04:57.00,yin,,0,0,0,,Option 是这里关键的键 \\N{\\fs12}So option is the key one for that.\r\nDialogue: 0,1:04:57.00,1:04:58.85,yin,,0,0,0,, 然后再看 \\N{\\fs12}Let’s go ahead — okay.\r\nDialogue: 0,1:04:58.85,1:05:02.81,yin,,0,0,0,, 下面这里有一些空白区域 \\N{\\fs12}Notice that this little space along the bottom here appeared\r\nDialogue: 0,1:05:02.81,1:05:05.37,yin,,0,0,0,, 运行应用时 注意到了吗 \\N{\\fs12}when we ran the application — you see that?\r\nDialogue: 0,1:05:05.37,1:05:10.34,yin,,0,0,0,, 左边这里是调试器 右边是控制台 \\N{\\fs12}This is the debugger on the left, and this is the console on the right.\r\nDialogue: 0,1:05:10.34,1:05:15.68,yin,,0,0,0,, 课上你们肯定会用到调试器和控制台 \\N{\\fs12}And you are definitely going to be using the debugger and the console both in this class.\r\nDialogue: 0,1:05:15.68,1:05:19.37,yin,,0,0,0,, 我也许没有时间演示控制台的用法 \\N{\\fs12}And actually, I might not have time to do a quick — show you how to do the console.\r\nDialogue: 0,1:05:19.37,1:05:22.01,yin,,0,0,0,, 无论如何 你可以通过拖动将它隐藏起来 \\N{\\fs12}But anyway, you can hide it by dragging it down or also\r\nDialogue: 0,1:05:22.01,1:05:23.40,yin,,0,0,0,, 或通过点击这个 \\N{\\fs12}by clicking this thing.\r\nDialogue: 0,1:05:24.77,1:05:27.71,yin,,0,0,0,, 好 下面我们将要 \\N{\\fs12}All right. So the next thing we’re going to do is we’re going\r\nDialogue: 0,1:05:27.71,1:05:31.86,yin,,0,0,0,, 在 UI 上加上一个记录数翻牌次数的小标签 \\N{\\fs12}to put a little label on our UI that counts the flips.\r\nDialogue: 0,1:05:31.86,1:05:35.72,yin,,0,0,0,, 每次翻牌时 标签上的数字都会加一 \\N{\\fs12}A little incremental thing that increments every time there’s a flip.\r\nDialogue: 0,1:05:35.72,1:05:43.95,yin,,0,0,0,, 要做这个 我们可以回到这里 抓取一个标签 \\N{\\fs12}And we do that by going back to here and grabbing ourselves a label.\r\nDialogue: 0,1:05:43.95,1:05:47.78,yin,,0,0,0,, 标签是一段只读文本 不可编辑文本 \\N{\\fs12}So a label is a read-only piece of text, noneditable text.\r\nDialogue: 0,1:05:47.80,1:05:50.74,yin,,0,0,0,, 我要把它拖放到左下角 \\N{\\fs12}And I’m just going to drag it over here and put it in the lower left.\r\nDialogue: 0,1:05:50.74,1:05:54.09,yin,,0,0,0,, 双击它 改为 Flip: 0\\N{\\fs12}I’m going to double-click on it to call it “flips colon zero.”\r\nDialogue: 0,1:05:54.09,1:05:57.73,yin,,0,0,0,, 这是 UI 刚启动时我想要的效果 \\N{\\fs12}This is what I want it to look like when my UI first launches.\r\nDialogue: 0,1:05:57.73,1:06:00.15,yin,,0,0,0,, 这个 我永远不会敲击它 \\N{\\fs12}Now here, I’m never going to be tapping on this\r\nDialogue: 0,1:06:00.15,1:06:04.08,yin,,0,0,0,, 进而导致按钮那样的消息发送 它是反过来的 \\N{\\fs12}and causing a message to be sent like the button; it’s the other way around.\r\nDialogue: 0,1:06:04.08,1:06:08.17,yin,,0,0,0,, 我的控制器希望同它通信 在翻牌进行时告诉它 \\N{\\fs12}My controller wants to talk to this and tell it when the flips changes all the time.\r\nDialogue: 0,1:06:08.17,1:06:13.17,yin,,0,0,0,, 也许你会认为可以从代码拖到这个标签 \\N{\\fs12}So you might think that you would drag from your code down to this flips,\r\nDialogue: 0,1:06:13.17,1:06:15.22,yin,,0,0,0,, 很不幸的是 你不能这样 \\N{\\fs12}but unfortunately you don’t do that.\r\nDialogue: 0,1:06:15.22,1:06:19.17,yin,,0,0,0,, 你还是按住 Control 从这里开始拖动 \\N{\\fs12}You still hold down control and drag from here.\r\nDialogue: 0,1:06:19.17,1:06:22.02,yin,,0,0,0,, 但不是拖到实现区 \\N{\\fs12}But instead of dragging it down into your implementation area,\r\nDialogue: 0,1:06:22.02,1:06:23.86,yin,,0,0,0,, 而是拖到接口区 \\N{\\fs12}you drag it into the interface area\r\nDialogue: 0,1:06:23.86,1:06:28.90,yin,,0,0,0,, 因为你要创建一个同该标签连接的属性 \\N{\\fs12}because you’re going to create a property that connects to that label basically.\r\nDialogue: 0,1:06:28.90,1:06:30.54,yin,,0,0,0,, 我们这样做后得到这个 \\N{\\fs12}So we do that. We get a thing here.\r\nDialogue: 0,1:06:30.54,1:06:32.08,yin,,0,0,0,, 问的问题略有不同 \\N{\\fs12}It’s asking us a little bit different questions:\r\nDialogue: 0,1:06:32.08,1:06:33.81,yin,,0,0,0,, 属性名是什么 \\N{\\fs12}”What’s the name of this property?”\r\nDialogue: 0,1:06:33.81,1:06:36.23,yin,,0,0,0,, 我将称其为 flipsLabel(翻牌标签)\\N{\\fs12}I’m going to call it “flips label.”\r\nDialogue: 0,1:06:36.23,1:06:38.98,yin,,0,0,0,, 注意到 该属性是弱的 \\N{\\fs12}Notice that this property is weak.\r\nDialogue: 0,1:06:38.98,1:06:43.20,yin,,0,0,0,, 我点击连接时 它会创建一个弱属性 \\N{\\fs12}When I click connect, it’s going to make a property here and it’s going to be weak.\r\nDialogue: 0,1:06:43.20,1:06:46.53,yin,,0,0,0,, 这是我们首次用弱代替强 \\N{\\fs12}This is the first time we’ve seen weak versus strong.\r\nDialogue: 0,1:06:46.53,1:06:48.75,yin,,0,0,0,, 选弱的原因在于 \\N{\\fs12}The reason this is weak is because\r\nDialogue: 0,1:06:48.76,1:06:53.37,yin,,0,0,0,, 该标签由视图本身很强地保持着 \\N{\\fs12}this label is held strongly by the view itself.\r\nDialogue: 0,1:06:53.37,1:06:56.84,yin,,0,0,0,, 所以我们不需要用强指针指着它 来保证它在堆中 \\N{\\fs12}So we don’t need to have a strong pointer to it, to keep it in the heap.\r\nDialogue: 0,1:06:56.84,1:06:57.74,yin,,0,0,0,, 视图会做这个 \\N{\\fs12}The view will.\r\nDialogue: 0,1:06:57.74,1:07:02.01,yin,,0,0,0,, 如果该标签离开视图 它就会被清除出堆 \\N{\\fs12}And if this label ever leaves the view, it will get cleaned out from the heap.\r\nDialogue: 0,1:07:02.01,1:07:04.60,yin,,0,0,0,, 而这个属性 这个指着它的指针 \\N{\\fs12}And this property — this pointer to it –\r\nDialogue: 0,1:07:04.60,1:07:06.84,yin,,0,0,0,, 就会被设为 nil 这正是我们想要的 \\N{\\fs12}will get set to nil, which is exactly what we want.\r\nDialogue: 0,1:07:06.84,1:07:09.19,yin,,0,0,0,, 因为当 flipsLabel 不在视图中时 \\N{\\fs12}Because if that flips label’s not in the view, we don’t want\r\nDialogue: 0,1:07:09.19,1:07:11.63,yin,,0,0,0,, 我们就不想再更新和发消息给它了 \\N{\\fs12}to be updating it and sending messages to it.\r\nDialogue: 0,1:07:11.63,1:07:15.63,yin,,0,0,0,, 所以说 这里对弱的使用很精妙 \\N{\\fs12}So it’s a great use of weak right here.\r\nDialogue: 0,1:07:15.63,1:07:19.60,yin,,0,0,0,, 这里是你们很熟悉的通常属性 也许除了 IBOutlet\\N{\\fs12}This is normal property that you’re used to except for maybe this IB outlet.\r\nDialogue: 0,1:07:19.60,1:07:21.61,yin,,0,0,0,, 这同 IBAction 类似 \\N{\\fs12}That’s just like IB action.\r\nDialogue: 0,1:07:21.61,1:07:26.49,yin,,0,0,0,, 这是无意义的 编译器会忽略 Xcode 使用它 \\N{\\fs12}It’s a meaningless thing the compiler ignores that Xcode is using.\r\nDialogue: 0,1:07:26.49,1:07:28.50,yin,,0,0,0,, 这是用来做这个的 \\N{\\fs12}So that it can do this –\r\nDialogue: 0,1:07:28.50,1:07:31.40,yin,,0,0,0,, 在鼠标悬停时显示连接到什么 \\N{\\fs12}show you what it’s connected to when you mouse over it.\r\nDialogue: 0,1:07:31.40,1:07:36.27,yin,,0,0,0,, 你还可以通过右键点击来看所有连接 \\N{\\fs12}By the way, you can see all the connections by also right-clicking on things.\r\nDialogue: 0,1:07:36.27,1:07:40.64,yin,,0,0,0,, 这里我右键点击了按钮 你可以看到它的连接 \\N{\\fs12}So here I just right-clicked on the button and you can see its connections.\r\nDialogue: 0,1:07:40.64,1:07:42.24,yin,,0,0,0,, 如果你想重命名 \\N{\\fs12}If you ever want to rename –\r\nDialogue: 0,1:07:42.24,1:07:45.45,yin,,0,0,0,, 例如我不喜欢 touchCardButton 我想重命名 \\N{\\fs12}like if I don’t like touch card button, I want to rename it to something,\r\nDialogue: 0,1:07:45.45,1:07:47.67,yin,,0,0,0,, 很不幸 你不能重命名 \\N{\\fs12}you can’t just rename unfortunately.\r\nDialogue: 0,1:07:47.67,1:07:52.99,yin,,0,0,0,, 你需要到这里 右键 使用这个小东西来断开连接 \\N{\\fs12}You have to go in here, right-click, use this little thing to disconnect it,\r\nDialogue: 0,1:07:52.99,1:07:55.55,yin,,0,0,0,, 然后重新 Control 拖动 \\N{\\fs12}and then control drag again.\r\nDialogue: 0,1:07:55.55,1:07:57.52,yin,,0,0,0,, 大家都明白了吗 \\N{\\fs12}Everybody got that?\r\nDialogue: 0,1:07:57.52,1:07:58.21,yin,,0,0,0,, 很不幸 \\N{\\fs12}It’s unfortunate.\r\nDialogue: 0,1:07:58.21,1:08:00.91,yin,,0,0,0,, 如果 Xcode 能跟踪这个就好了 可惜它不能 \\N{\\fs12}It would be really nice if Xcode could track that for you but it can’t.\r\nDialogue: 0,1:08:00.91,1:08:03.31,yin,,0,0,0,, 所以 如果你想重命名什么东西 \\N{\\fs12}So if you ever want to rename something,\r\nDialogue: 0,1:08:03.31,1:08:06.24,yin,,0,0,0,, 你需要通过右键点击来断开连接 \\N{\\fs12}you have to disconnect it here by right-clicking on it,\r\nDialogue: 0,1:08:06.24,1:08:10.63,yin,,0,0,0,, 然后 Control 拖动一个新的 这样来设置名称 \\N{\\fs12}and then control drag a new one and set the name that way.\r\nDialogue: 0,1:08:10.63,1:08:13.59,yin,,0,0,0,, 你还可以右键点击这个 \\N{\\fs12}You can also right-click on this little guy\r\nDialogue: 0,1:08:13.59,1:08:16.77,yin,,0,0,0,, 这会显示出控制器的所有连接 \\N{\\fs12}and it will show you all the connections for your controller.\r\nDialogue: 0,1:08:16.77,1:08:17.79,yin,,0,0,0,, 展开这个窗口 \\N{\\fs12}Brings up this window.\r\nDialogue: 0,1:08:17.79,1:08:19.45,yin,,0,0,0,, 我可以看到标签 \\N{\\fs12}And I can see the label. You see?\r\nDialogue: 0,1:08:19.47,1:08:21.52,yin,,0,0,0,, 鼠标现在在按钮上 \\N{\\fs12}I’m mousing over the button.\r\nDialogue: 0,1:08:21.52,1:08:22.24,yin,,0,0,0,, 标签 \\N{\\fs12}Label.\r\nDialogue: 0,1:08:22.24,1:08:25.82,yin,,0,0,0,, 这里还有一个属性 你们没有见过这个 \\N{\\fs12}There’s also this little property here, which is something you haven’t seen,\r\nDialogue: 0,1:08:25.82,1:08:29.49,yin,,0,0,0,, 这是从控制器指向整个视图的属性 \\N{\\fs12}which is basically a property that points to the entire view from your controller.\r\nDialogue: 0,1:08:29.49,1:08:31.19,yin,,0,0,0,, 这是到控制器的连接 \\N{\\fs12}So this is the connections to your controllers.\r\nDialogue: 0,1:08:31.19,1:08:33.75,yin,,0,0,0,, 看到了吗 这里显示有纸牌游戏视图控制器 \\N{\\fs12}See, it says “card game view controller”?\r\nDialogue: 0,1:08:33.75,1:08:35.23,yin,,0,0,0,, 这是右键点击 \\N{\\fs12}So that’s right-clicking.\r\nDialogue: 0,1:08:35.23,1:08:38.21,yin,,0,0,0,, 我右键点击了这里 \\N{\\fs12}I’m right-clicking over here.\r\nDialogue: 0,1:08:38.21,1:08:40.62,yin,,0,0,0,, 我们怎么让这个 flipsLabel 工作呢 \\N{\\fs12}So how are we going to make this flips label work?\r\nDialogue: 0,1:08:40.62,1:08:45.32,yin,,0,0,0,, 我们先把它放一放 \\N{\\fs12}We are going to put it aside for a second.\r\nDialogue: 0,1:08:45.32,1:08:46.59,yin,,0,0,0,, 先不想它 \\N{\\fs12}Let’s not think about it.\r\nDialogue: 0,1:08:46.59,1:08:49.68,yin,,0,0,0,, 先来看另一个属性 \\N{\\fs12}Let’s instead do another property.\r\nDialogue: 0,1:08:50.69,1:08:53.48,yin,,0,0,0,, 属性 它是非原子的 \\N{\\fs12}Property. Which is nonatomic,\r\nDialogue: 0,1:08:53.48,1:08:55.30,yin,,0,0,0,, 它只是一个 int 型整数 \\N{\\fs12}which is just going to be an int,\r\nDialogue: 0,1:08:55.30,1:08:57.85,yin,,0,0,0,, 命名为 flipCount(翻牌计数)\\N{\\fs12}which I’m going to call “flip count.”\r\nDialogue: 0,1:08:57.85,1:09:02.04,yin,,0,0,0,,flipCount 是一个整数 用于记录翻牌次数 \\N{\\fs12}So flip count is just an integer that’s going to keep the count of flips.\r\nDialogue: 0,1:09:02.04,1:09:05.27,yin,,0,0,0,, 再看这个 \\N{\\fs12}And watch this.\r\nDialogue: 0,1:09:05.27,1:09:07.41,yin,,0,0,0,, 这里需要更多空间 \\N{\\fs12}Some more space here.\r\nDialogue: 0,1:09:07.43,1:09:09.17,yin,,0,0,0,, 过来一些 \\N{\\fs12}Go there.\r\nDialogue: 0,1:09:09.17,1:09:14.18,yin,,0,0,0,, 这里我只需要写 self.flipCount++\\N{\\fs12}I’m just going to go down here and say self.flip count plus plus.\r\nDialogue: 0,1:09:14.18,1:09:20.33,yin,,0,0,0,, 这调用的是 flipCount 的 setter 还是 getter\\N{\\fs12}Now, does that call the setter or the getter for flip count?\r\nDialogue: 0,1:09:20.33,1:09:21.78,yin,,0,0,0,, 两者都 对 \\N{\\fs12}Both. Exactly.\r\nDialogue: 0,1:09:21.78,1:09:23.49,yin,,0,0,0,, 这同时调用了 setter 和 getter\\N{\\fs12}That is calling both the setter and the getter.\r\nDialogue: 0,1:09:23.49,1:09:25.61,yin,,0,0,0,, 调用 getter 来获得 flipCount\\N{\\fs12}It’s calling the getter to get the flip count,\r\nDialogue: 0,1:09:25.61,1:09:27.40,yin,,0,0,0,, 然后对它进行 ++\\N{\\fs12}then it’s plus plussing it;\r\nDialogue: 0,1:09:27.40,1:09:29.70,yin,,0,0,0,, 然后调用 setter 来设置值 \\N{\\fs12}and then it’s calling the setter to set it back.\r\nDialogue: 0,1:09:29.70,1:09:32.05,yin,,0,0,0,, 这是一种很别致的代码写法 \\N{\\fs12}Okay. So that’s kind of a funky lining of code right there.\r\nDialogue: 0,1:09:32.05,1:09:34.98,yin,,0,0,0,, 等价于 self.flipCount=self.flipCount+1\\N{\\fs12}That’s the same as saying self.flip count equals self.flip count plus one.\r\nDialogue: 0,1:09:34.98,1:09:36.91,yin,,0,0,0,, 它会调用 getter 和 setter\\N{\\fs12}So it’s calling the getter and the setter.\r\nDialogue: 0,1:09:36.91,1:09:39.03,yin,,0,0,0,, 好 现在我们有了这个很好的 flipCount\\N{\\fs12}Okay. So now we’ve got this nice flip count.\r\nDialogue: 0,1:09:39.03,1:09:43.63,yin,,0,0,0,, 它记录计数值 如何将它同这个联系起来呢 \\N{\\fs12}It’s keeping track of the count; how do we hook that up to this thing over here?\r\nDialogue: 0,1:09:43.63,1:09:45.92,yin,,0,0,0,, 这个我要弄大一些 \\N{\\fs12}Which I’m going to make a little bigger, by the way.\r\nDialogue: 0,1:09:45.92,1:09:48.91,yin,,0,0,0,, 如何同这个联系起来 让它改写为 Flips: 1\\N{\\fs12}Okay. How do we hook that up so that says flips colon one,\r\nDialogue: 0,1:09:48.91,1:09:50.60,yin,,0,0,0,,Flips: 2 及 Flips: 3 这些 \\N{\\fs12}flips colon two, flips colon three?\r\nDialogue: 0,1:09:50.60,1:09:57.23,yin,,0,0,0,, 我们将使用 flipCount 的 setter 来做到这个 \\N{\\fs12}Well, we’re going to do it using the setter for flip count.\r\nDialogue: 0,1:09:57.23,1:10:00.65,yin,,0,0,0,, 普通情况下 flipCount 的 setter 是这样的 \\N{\\fs12}So normally a setter for flip count would look like this.\r\nDialogue: 0,1:10:00.65,1:10:05.20,yin,,0,0,0,, 这是 setter 和 getter 的另一妙用 \\N{\\fs12}And here’s another great use of setters and getters,\r\nDialogue: 0,1:10:05.20,1:10:08.36,yin,,0,0,0,, 也就是让 UI 同属性保持同步 \\N{\\fs12}which is to keep UI in sync with a property.\r\nDialogue: 0,1:10:08.36,1:10:16.94,yin,,0,0,0,, 这里我要写 self.flipsLabel.text =…\\N{\\fs12}And I’ll just do this by saying self.flips label.text equals –\r\nDialogue: 0,1:10:16.95,1:10:20.66,yin,,0,0,0,, 哦 抱歉 站着打字很不方便 \\N{\\fs12}oops, sorry. It’s hard to type standing up.\r\nDialogue: 0,1:10:20.66,1:10:23.55,yin,,0,0,0,,= NSString stringWithFormat…\\N{\\fs12}Equals NS string, string with format,\r\nDialogue: 0,1:10:23.55,1:10:27.94,yin,,0,0,0,, 这个你们见过 Flips: %d\\N{\\fs12}which you’ve seen before, flips colon percent D\r\nDialogue: 0,1:10:27.95,1:10:30.89,yin,,0,0,0,,self.flipCount\\N{\\fs12}self.flip count.\r\nDialogue: 0,1:10:30.89,1:10:35.13,yin,,0,0,0,, 这样 每次 flipCount 变动时 我们都会更新 UI\\N{\\fs12}So now every time flip count is changed we’re going to update the UI.\r\nDialogue: 0,1:10:36.46,1:10:39.86,yin,,0,0,0,, 能明白吗 这里有任何问题吗 \\N{\\fs12}Make sense? Any questions about that?\r\nDialogue: 0,1:10:39.86,1:10:41.98,yin,,0,0,0,, 好 我们来运行 \\N{\\fs12}Okay. So let’s run.\r\nDialogue: 0,1:10:44.63,1:10:45.89,yin,,0,0,0,, 好的 程序运行 \\N{\\fs12}Okay. Here’s our thing.\r\nDialogue: 0,1:10:45.89,1:10:49.23,yin,,0,0,0,, 点击 翻面 翻牌计数更新了 \\N{\\fs12}So click, flips over, flip count updates.\r\nDialogue: 0,1:10:49.23,1:10:50.50,yin,,0,0,0,, 翻 翻 翻 翻 \\N{\\fs12}Flip, flip, flip, flip.\r\nDialogue: 0,1:10:50.50,1:10:53.32,yin,,0,0,0,, 来回都行 而 flipCount 正确记录着 \\N{\\fs12}Back and forth working, and the flip count is keeping track\r\nDialogue: 0,1:10:53.32,1:10:54.55,yin,,0,0,0,, 翻了多少次 \\N{\\fs12}of how many flips we’re doing.\r\nDialogue: 0,1:10:54.55,1:10:58.68,yin,,0,0,0,, 可以看到 这些很容易连接起来 \\N{\\fs12}So you can see this stuff is really simple to wire up.\r\nDialogue: 0,1:10:58.68,1:11:02.64,yin,,0,0,0,, 在你开始创建更复杂的应用时 \\N{\\fs12}And, you know, when you get into building even complicated applications,\r\nDialogue: 0,1:11:02.64,1:11:04.76,yin,,0,0,0,, 因为你总是在使用相同的目标动作和 outlet 机制 \\N{\\fs12}because you’re always going to use these same mechanisms\r\nDialogue: 0,1:11:04.76,1:11:06.47,yin,,0,0,0,, 因为你总是在使用相同的目标动作和 outlet 机制 \\N{\\fs12}with target action and outlets\r\nDialogue: 0,1:11:06.47,1:11:08.93,yin,,0,0,0,, 而且你将使用 setter 和 getter 来保持事物同步 \\N{\\fs12}and you’re going to be using setters and getters to keep things in sync,\r\nDialogue: 0,1:11:08.93,1:11:11.19,yin,,0,0,0,, 这会让人们更容易理解你的代码如何工作 \\N{\\fs12}it’s going to be easy for people to understand how your code works.\r\nDialogue: 0,1:11:11.19,1:11:14.39,yin,,0,0,0,, 他们知道在哪去看的 UI 更新发生 \\N{\\fs12}They know where to look to see where UI updating happens,\r\nDialogue: 0,1:11:14.39,1:11:17.31,yin,,0,0,0,, 等等 这里我还要做一件事 \\N{\\fs12}etc. I’m going to do one other thing here.\r\nDialogue: 0,1:11:17.31,1:11:19.66,yin,,0,0,0,, 花点时间展示 NSLog\\N{\\fs12}Take a minute and show you NS log.\r\nDialogue: 0,1:11:19.66,1:11:22.70,yin,,0,0,0,, 我说过 你可以在控制台中记录日志 \\N{\\fs12}Okay. I told you that you could log something in the console.\r\nDialogue: 0,1:11:22.70,1:11:25.80,yin,,0,0,0,, 这里每次有变化时 让我们都用 NSLog 进行记录 \\N{\\fs12}So let’s do every time this thing changes, let’s do an NS log.\r\nDialogue: 0,1:11:25.80,1:11:27.37,yin,,0,0,0,, 这只是一个 C 函数 \\N{\\fs12}So it’s just a C function.\r\nDialogue: 0,1:11:27.39,1:11:29.96,yin,,0,0,0,, 像 printf 一样给它一个格式字符串 \\N{\\fs12}And you give it a format string like printf.\r\nDialogue: 0,1:11:29.96,1:11:34.09,yin,,0,0,0,, 这里我用 flipCount = %d\\N{\\fs12}So I’ll say flip count equals percent d\r\nDialogue: 0,1:11:34.09,1:11:35.98,yin,,0,0,0,,self.flipCount\\N{\\fs12}self.flip count.\r\nDialogue: 0,1:11:35.98,1:11:38.47,yin,,0,0,0,, 这就加入了这个 NSLog\\N{\\fs12}So you just put that NS log in there,\r\nDialogue: 0,1:11:38.47,1:11:42.01,yin,,0,0,0,, 于是运行时 你就会在控制台看到它 \\N{\\fs12}and now when we run you’re going to see it in the console.\r\nDialogue: 0,1:11:42.01,1:11:45.75,yin,,0,0,0,, 我点击时 它会出现在这里 显示发生了什么 \\N{\\fs12}It’s going to come up when I click, and it’s going to say what happened here.\r\nDialogue: 0,1:11:45.75,1:11:48.87,yin,,0,0,0,, 当然 我也可以把它拉宽一些 \\N{\\fs12}By the way, of course, I can make that wider.\r\nDialogue: 0,1:11:48.87,1:11:53.57,yin,,0,0,0,, 回到模拟器 看 \\N{\\fs12}And go back to the simulator. Let’s see.\r\nDialogue: 0,1:11:53.57,1:11:57.00,yin,,0,0,0,,NSLog 是一种很棒的调试方式 \\N{\\fs12}So NS logging — awesome way to debug.\r\nDialogue: 0,1:11:57.00,1:11:59.88,yin,,0,0,0,, 有时比设置断点要容易很多 \\N{\\fs12}Sometimes a lot easier than setting a breakpoint\r\nDialogue: 0,1:11:59.88,1:12:01.85,yin,,0,0,0,, 这里会给你打印出来 \\N{\\fs12}and then when you get there looking at the variables and stuff.\r\nDialogue: 0,1:12:01.85,1:12:03.58,yin,,0,0,0,, 你可以随时观察 \\N{\\fs12}It just prints out what’s going on and you can watch it.\r\nDialogue: 0,1:12:03.58,1:12:07.94,yin,,0,0,0,, 特别是在 UI 中 有时会是动画 它们随时间发生 \\N{\\fs12}Especially in the UI things are sometimes animated, they’re happening over time.\r\nDialogue: 0,1:12:07.94,1:12:09.51,yin,,0,0,0,, 在动画中间设置断点会很困难 \\N{\\fs12}It’s sometimes hard to set a breakpoint in the middle\r\nDialogue: 0,1:12:09.51,1:12:10.99,yin,,0,0,0,, 在动画中间设置断点会很困难 \\N{\\fs12}of an animation to see what’s going on.\r\nDialogue: 0,1:12:10.99,1:12:14.54,yin,,0,0,0,, 但使用 NSLog 你就能看到程序是怎么在运行了 \\N{\\fs12}but if you do some NS logs, you can kind of see how things progress.\r\nDialogue: 0,1:12:14.54,1:12:20.10,yin,,0,0,0,, 我要展示的最后一点内容是 如何为 app 添加一个新类 \\N{\\fs12}The last thing I’m going to show you here is how to add a new class to your app\r\nDialogue: 0,1:12:20.10,1:12:22.91,yin,,0,0,0,, 因为你们到时要在这个基础上自行添加四个类 \\N{\\fs12}because you’re going to need to do that. You’re going to add four classes to this.\r\nDialogue: 0,1:12:22.91,1:12:24.89,yin,,0,0,0,, 你们将从这个开始 \\N{\\fs12}You’re going to start with this, okay,\r\nDialogue: 0,1:12:24.89,1:12:27.73,yin,,0,0,0,, 然后添加四个类 \\N{\\fs12}and then you’re going to add four classes –\r\nDialogue: 0,1:12:27.73,1:12:29.55,yin,,0,0,0,,Card Deck 等等 \\N{\\fs12}card, deck, etc.\r\nDialogue: 0,1:12:29.55,1:12:33.20,yin,,0,0,0,, 添加一个类的做法如下 \\N{\\fs12}And the way you add a class is you –\r\nDialogue: 0,1:12:33.20,1:12:37.69,yin,,0,0,0,, 实际上 往项目中添加任何文件的方式都是这样 \\N{\\fs12}and in fact, the way you add any file to your project –\r\nDialogue: 0,1:12:37.69,1:12:41.21,yin,,0,0,0,, 也就是到文件菜单 点选新 文件 \\N{\\fs12}is you go to the file menu, new file.\r\nDialogue: 0,1:12:41.21,1:12:44.33,yin,,0,0,0,, 这里你可以添加各种东西 \\N{\\fs12}And there’s all different kinds of things you can add here,\r\nDialogue: 0,1:12:44.33,1:12:46.49,yin,,0,0,0,, 数据库文件 架构文件等等 \\N{\\fs12}database file, schema files and everything.\r\nDialogue: 0,1:12:46.49,1:12:51.02,yin,,0,0,0,, 不过你所需要的是左上角这个 Objective-C 类 \\N{\\fs12}But you want this one top-left Objective-C class.\r\nDialogue: 0,1:12:51.02,1:12:53.83,yin,,0,0,0,, 这里你要键入类名 \\N{\\fs12}Here you’re just going to type the name of the class.\r\nDialogue: 0,1:12:53.83,1:12:58.28,yin,,0,0,0,, 例如 这里我要添加的是 Card 然后是父类名 \\N{\\fs12}So for example, if I’m going to add card and the name of the superclass.\r\nDialogue: 0,1:12:58.28,1:13:01.22,yin,,0,0,0,, 如果是 PlayingCard 这里可以键入 Card\\N{\\fs12}Okay. If you are doing playing card, you can type card here.\r\nDialogue: 0,1:13:01.22,1:13:05.24,yin,,0,0,0,, 并不一定要从这个列表中选择 iOS 默认的 \\N{\\fs12}It doesn’t have to be something that’s chosen from this list, which are the iOS ones.\r\nDialogue: 0,1:13:05.24,1:13:07.99,yin,,0,0,0,, 这里我要创建的是 Card\\N{\\fs12}So here I’m going to make card.\r\nDialogue: 0,1:13:07.99,1:13:09.49,yin,,0,0,0,, 我可以把 Card 放到这里 \\N{\\fs12}I could put card right here.\r\nDialogue: 0,1:13:09.49,1:13:10.78,yin,,0,0,0,, 它问我在哪存储这个 \\N{\\fs12}It’s asking where to store this.\r\nDialogue: 0,1:13:10.78,1:13:15.19,yin,,0,0,0,, 我可以放到同纸牌游戏控制器相同的位置 \\N{\\fs12}I could put it right in the same place that my card game controller is, you see?\r\nDialogue: 0,1:13:15.19,1:13:17.38,yin,,0,0,0,, 但我不大推崇 \\N{\\fs12}But I’m actually a big fan\r\nDialogue: 0,1:13:17.38,1:13:20.38,yin,,0,0,0,, 将模型放到它自身的目录下 \\N{\\fs12}of putting your model in its own directory.\r\nDialogue: 0,1:13:20.38,1:13:23.44,yin,,0,0,0,, 我希望你们使用新文件夹 \\N{\\fs12}So you would use new folder down here.\r\nDialogue: 0,1:13:23.44,1:13:25.55,yin,,0,0,0,, 例如可以创建一个 Model 目录 \\N{\\fs12}Let’s create like a model directory,\r\nDialogue: 0,1:13:25.55,1:13:28.52,yin,,0,0,0,, 于是这里有了一个 Model 目录 \\N{\\fs12}and that creates a model directory here.\r\nDialogue: 0,1:13:28.52,1:13:31.09,yin,,0,0,0,, 这是控制器 这是模型目录 \\N{\\fs12}There’s a controller, here’s the model directory.\r\nDialogue: 0,1:13:31.09,1:13:32.46,yin,,0,0,0,, 创建 \\N{\\fs12}And so create.\r\nDialogue: 0,1:13:32.46,1:13:35.35,yin,,0,0,0,, 这会创建 Card.h 和.m\\N{\\fs12}So that’s going to create card dot H and M.\r\nDialogue: 0,1:13:35.35,1:13:39.05,yin,,0,0,0,, 这是 Card.h 和.m 目前还是空白 \\N{\\fs12}Here’s card dot H and M, okay, kind of blank versions of them.\r\nDialogue: 0,1:13:39.05,1:13:41.20,yin,,0,0,0,, 你可以在它们之间来回切换 \\N{\\fs12}You can switch back and forth between them here.\r\nDialogue: 0,1:13:41.20,1:13:44.93,yin,,0,0,0,, 注意到 如果我改变左边 右边会随之变化 \\N{\\fs12}Notice that if I switch the left, the right changes to match.\r\nDialogue: 0,1:13:44.93,1:13:47.50,yin,,0,0,0,, 看到了吗 改变这个 这个随之变化 \\N{\\fs12}You see? Change this, this matches.\r\nDialogue: 0,1:13:47.50,1:13:49.67,yin,,0,0,0,, 这是因为这里我选了 counterparts(对应)\\N{\\fs12}That’s because I have counterparts chosen right here.\r\nDialogue: 0,1:13:49.67,1:13:52.56,yin,,0,0,0,, 如果使用 manual 手动设置这个 \\N{\\fs12}If you go to manual and pick this file manually,\r\nDialogue: 0,1:13:52.56,1:13:54.18,yin,,0,0,0,, 这时它就不会这样做了 \\N{\\fs12}then it won’t be doing that magic anymore.\r\nDialogue: 0,1:13:54.18,1:13:57.69,yin,,0,0,0,, 不过你总是可以选回 counterparts 这会保持同步 \\N{\\fs12}But you can always go back to counterparts and it will keep them in sync.\r\nDialogue: 0,1:13:57.69,1:14:00.85,yin,,0,0,0,, 有些人喜欢让头文件在左 \\N{\\fs12}Okay. So you can have — some people like their header file on the left,\r\nDialogue: 0,1:14:00.85,1:14:02.73,yin,,0,0,0,, 有些人则喜欢在右 \\N{\\fs12}some on the right, whatever.\r\nDialogue: 0,1:14:02.73,1:14:04.55,yin,,0,0,0,, 还要注意到这里 \\N{\\fs12}Also, notice over here\r\nDialogue: 0,1:14:04.55,1:14:07.57,yin,,0,0,0,, 这些在导航栏中能够组起来 这很棒 \\N{\\fs12}it would be nice if I can also group these things in the navigator.\r\nDialogue: 0,1:14:07.57,1:14:12.13,yin,,0,0,0,, 我只需要选择它们 右键点击 新组 \\N{\\fs12}And I can by having them selected right-click new group.\r\nDialogue: 0,1:14:12.13,1:14:13.54,yin,,0,0,0,, 命名为 Model\\N{\\fs12}Say model.\r\nDialogue: 0,1:14:13.54,1:14:17.66,yin,,0,0,0,, 这样我就将我的模型放到了这个小地方 \\N{\\fs12}Right here. And now I’ve put my model in its own little place right here.\r\nDialogue: 0,1:14:17.66,1:14:20.29,yin,,0,0,0,, 我可以将它移动到下面这里 诸如此类 \\N{\\fs12}I can even move this around, put it down here, whatever.\r\nDialogue: 0,1:14:20.29,1:14:22.86,yin,,0,0,0,, 我可以把所有四个类都放到这里 \\N{\\fs12}I could put all my four classes in there.\r\nDialogue: 0,1:14:22.86,1:14:27.73,yin,,0,0,0,, 还可以将这个组同文件系统连起来 \\N{\\fs12}It is possible to link this group to the file system.\r\nDialogue: 0,1:14:27.73,1:14:31.85,yin,,0,0,0,, 实际上 你可以点击文件 在这里打开检查器 \\N{\\fs12}In fact, if you just click on a file and bring up the inspector on it right here,\r\nDialogue: 0,1:14:31.87,1:14:33.69,yin,,0,0,0,, 可以看到有这些可供选择 \\N{\\fs12}you can see that it’s got this location\r\nDialogue: 0,1:14:33.69,1:14:36.33,yin,,0,0,0,, 你可以指定是绝对路径 \\N{\\fs12}where you can specify whether it’s an absolute path,\r\nDialogue: 0,1:14:36.33,1:14:38.80,yin,,0,0,0,, 还是相对于它所在的组 等等 \\N{\\fs12}or relevant to the group it’s in, or whatever.\r\nDialogue: 0,1:14:38.80,1:14:41.00,yin,,0,0,0,, 这是可以控制的 \\N{\\fs12}So you can control that.\r\nDialogue: 0,1:14:41.00,1:14:42.84,yin,,0,0,0,, 就这些了 \\N{\\fs12}And that’s it.\r\nDialogue: 0,1:14:42.84,1:14:44.58,yin,,0,0,0,, 知道这些就能开始做作业了 \\N{\\fs12}So I think that’s all you need to do your homework.\r\nDialogue: 0,1:14:44.58,1:14:48.29,yin,,0,0,0,, 你们需要键入 Card 的所有代码 并加入另三个类 \\N{\\fs12}You’re just going to type in all your code here for card and add your three other ones.\r\nDialogue: 0,1:14:48.29,1:14:49.52,yin,,0,0,0,, 键入所有代码 \\N{\\fs12}Type all that code in.\r\nDialogue: 0,1:14:49.53,1:14:52.83,yin,,0,0,0,, 你们要让纸牌不是总显示梅花 A\\N{\\fs12}And then all you got to do is make that card instead of showing ace of clubs all the time,\r\nDialogue: 0,1:14:52.83,1:14:55.64,yin,,0,0,0,, 你需要在牌堆中抽取 \\N{\\fs12}needs to go through the deck.\r\nDialogue: 0,1:14:55.64,1:14:58.59,yin,,0,0,0,, 我发布有详细的作业指南 \\N{\\fs12}There’s a detailed homework write up posted.\r\nDialogue: 0,1:14:58.61,1:15:02.65,yin,,0,0,0,, 其中有各种提示和帮助 告诉你需要做哪些任务 \\N{\\fs12}It has all kinds of hints and help, and tells you about what the required tasks are,\r\nDialogue: 0,1:15:02.65,1:15:04.93,yin,,0,0,0,, 还有评定标准 等等所有这些 \\N{\\fs12}and evaluation criteria, and all that stuff.\r\nDialogue: 0,1:15:04.93,1:15:07.14,yin,,0,0,0,, 所以请务必仔细阅读 \\N{\\fs12}So definitely read that thing in detail.\r\nDialogue: 0,1:15:07.14,1:15:09.94,yin,,0,0,0,, 不要跳过 不要直接做作业 \\N{\\fs12}Don’t skip that stuff and just try to go straight to doing it.\r\nDialogue: 0,1:15:09.96,1:15:13.57,yin,,0,0,0,, 有问题的 现在可以来提 下课 \\N{\\fs12}And if you have questions, I’ll be here. That’s it.\r\nDialogue: 0,1:15:13.57,1:15:17.57,yin,,0,0,0,, 更多内容 请访问我校官网 stanford.edu\\N{\\fs12}For more, please visit us at Stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/3. Objective-C.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.1.2\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\nLast Style Storage: Default\r\nAegisub Scroll Position: 0\r\nAegisub Active Line: 2\r\nAegisub Video Zoom Percent: 1.000000\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.25,0:00:07.43,yin,,0,0,0,, 斯坦福大学 \\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:08.81,0:00:14.91,yin,,0,0,0,, 欢迎来到 2013/14 学年秋季 CS193P 课程第三讲 \\N{\\fs12}Okay, well welcome to Lecture number 3 of CS193p for fall of 2013/14.\r\nDialogue: 0,0:00:14.91,0:00:18.67,yin,,0,0,0,, 今天我将直接跳到一个 demo\\N{\\fs12}Today I’m going to jump right into a demo and then\r\nDialogue: 0,0:00:18.67,0:00:20.92,yin,,0,0,0,, 然后我有一些幻灯片 \\N{\\fs12}after that I have some slides, time permitting,\r\nDialogue: 0,0:00:20.92,0:00:25.89,yin,,0,0,0,, 假设 demo 不需要整堂课时间 \\N{\\fs12}assuming the demo doesn’t take the whole time here,\r\nDialogue: 0,0:00:25.89,0:00:28.19,yin,,0,0,0,,demo 要做的是 \\N{\\fs12}and after, the demo I’m going to do is I’m going\r\nDialogue: 0,0:00:28.19,0:00:33.99,yin,,0,0,0,, 将上周我们做的纸牌工作用到真正的纸牌匹配游戏 \\N{\\fs12}to take the little card thing we did last week and turn it into a real card matching game\r\nDialogue: 0,0:00:33.99,0:00:37.71,yin,,0,0,0,, 我们将真正开始匹配 而不只是翻来翻去 \\N{\\fs12}where we’re actually matching cards, okay, rather than just flipping them over.\r\nDialogue: 0,0:00:37.71,0:00:39.64,yin,,0,0,0,, 如果时间允许 \\N{\\fs12}And, like I say, if I have the time\r\nDialogue: 0,0:00:39.64,0:00:42.64,yin,,0,0,0,, 我还会进一步讲 Objective-C\\N{\\fs12}I’ll talk a little bit more about objective-C and we’re really going to go\r\nDialogue: 0,0:00:42.64,0:00:46.05,yin,,0,0,0,, 周三我将非常详细地讲到 Objective-C\\N{\\fs12}into objective-C on Wednesday in quite a bit of detail.\r\nDialogue: 0,0:00:46.05,0:00:50.83,yin,,0,0,0,, 我还附上了一些复习幻灯片在最后 \\N{\\fs12}I also included on the stuff I posted some review slides at the end just kind\r\nDialogue: 0,0:00:50.83,0:00:54.18,yin,,0,0,0,, 复习前三讲我们所学的内容 \\N{\\fs12}of reviewing what we will have learned in the first three lectures,\r\nDialogue: 0,0:00:54.18,0:00:56.74,yin,,0,0,0,, 让你们能够快速回顾 并问自己是否理解 \\N{\\fs12}just so you can kind of look through it real quick and say oh yeah, do I know that?\r\nDialogue: 0,0:00:56.74,0:00:57.86,yin,,0,0,0,, 让你们能够快速回顾 并问自己是否理解 \\N{\\fs12}Yeah I do,\r\nDialogue: 0,0:00:57.86,0:01:02.64,yin,,0,0,0,, 如果不记得 你显然需要发帖向我们提问 \\N{\\fs12}and if not, then you can obviously post and ask us questions about it.\r\nDialogue: 0,0:01:02.64,0:01:07.33,yin,,0,0,0,, 好 我们来做这个 demo\\N{\\fs12}OK. So, let’s do this demo.\r\nDialogue: 0,0:01:07.33,0:01:08.95,yin,,0,0,0,,demo 是这样的 \\N{\\fs12}So for the demo,\r\nDialogue: 0,0:01:08.95,0:01:12.82,yin,,0,0,0,, 实际上 在 demo 最开始 \\N{\\fs12}I’m going to start this demo actually\r\nDialogue: 0,0:01:12.82,0:01:17.16,yin,,0,0,0,, 我将公布作业的答案 \\N{\\fs12}by giving you the solution to the homework,\r\nDialogue: 0,0:01:17.16,0:01:20.54,yin,,0,0,0,, 我讲过我要做这个的 本学期只有一次我会这样做 \\N{\\fs12}I told you I was going to do this, this is the only time\r\nDialogue: 0,0:01:20.54,0:01:23.35,yin,,0,0,0,, 我讲过我要做这个的 本学期只有一次我会这样做 \\N{\\fs12}that I’m going to do this this quarter.\r\nDialogue: 0,0:01:23.35,0:01:25.60,yin,,0,0,0,, 一般我不会讲答案 \\N{\\fs12}Normally I don’t go over the solution,\r\nDialogue: 0,0:01:25.60,0:01:29.50,yin,,0,0,0,, 但这里答案很简单 而且需要知道这些答案 \\N{\\fs12}but the solution’s so simple and because obviously we need the solution of this\r\nDialogue: 0,0:01:29.50,0:01:32.92,yin,,0,0,0,, 我们才能继续今天后面的内容 \\N{\\fs12}to move on to what I’m going to do today.\r\nDialogue: 0,0:01:32.92,0:01:34.70,yin,,0,0,0,, 所以先看答案 \\N{\\fs12}We’ll do the solution first.\r\nDialogue: 0,0:01:34.70,0:01:36.71,yin,,0,0,0,, 这里我启动了 XCode\\N{\\fs12}So here I’m just launching XCode, you can see now\r\nDialogue: 0,0:01:36.71,0:01:40.63,yin,,0,0,0,, 最近文件中有上次编辑的 Machismo\\N{\\fs12}in my recents I have this machismo from last time.\r\nDialogue: 0,0:01:40.63,0:01:43.54,yin,,0,0,0,, 打开这个 \\N{\\fs12}So, we’ll bring that up.\r\nDialogue: 0,0:01:43.54,0:01:45.92,yin,,0,0,0,, 好了 确保我们使用了 \\N{\\fs12}There it is. Make sure that we’re using\r\nDialogue: 0,0:01:45.92,0:01:49.13,yin,,0,0,0,, 尽量多的屏幕空间 \\N{\\fs12}as much screen real estate as we can here.\r\nDialogue: 0,0:01:49.13,0:01:52.93,yin,,0,0,0,, 把这些线挪开 \\N{\\fs12}Get these wires out of my way.\r\nDialogue: 0,0:01:52.93,0:01:59.70,yin,,0,0,0,, 好 从上次结束的地方开始 你们做过作业 应该记得 \\N{\\fs12}Okay. So, from where we left off, hopefully you remember because you did your homework.\r\nDialogue: 0,0:01:59.70,0:02:02.07,yin,,0,0,0,, 我们有这一张牌 \\N{\\fs12}We just have this single, this card, single card,\r\nDialogue: 0,0:02:02.07,0:02:04.64,yin,,0,0,0,, 它在梅花 A 和反面间来回翻动 \\N{\\fs12}and it flips back and forth between the ace and the clubs,\r\nDialogue: 0,0:02:04.64,0:02:08.70,yin,,0,0,0,, 你们的作业是在课上模型的基础上 \\N{\\fs12}and your homework was to use the model that we worked on in lecture\r\nDialogue: 0,0:02:08.70,0:02:11.81,yin,,0,0,0,, 让它从整个牌堆中抽牌翻转 \\N{\\fs12}to make it flip through an entire deck.\r\nDialogue: 0,0:02:11.81,0:02:15.20,yin,,0,0,0,, 这个答案非常简单 \\N{\\fs12}So, the solution to that is quite straightforward.\r\nDialogue: 0,0:02:15.20,0:02:18.34,yin,,0,0,0,, 我们显然需要牌堆 \\N{\\fs12}We obviously need a deck so I’m just going\r\nDialogue: 0,0:02:18.34,0:02:22.51,yin,,0,0,0,, 我将添加一个属性 强属性 必须是强的 \\N{\\fs12}to add a property here, strong property, should be strong\r\nDialogue: 0,0:02:22.51,0:02:25.39,yin,,0,0,0,, 因为我们需要牌堆一直存在 \\N{\\fs12}because we need that deck to, to stay around, and it’s going\r\nDialogue: 0,0:02:25.39,0:02:27.84,yin,,0,0,0,, 它是牌堆 取名 deck\\N{\\fs12}to be a deck and I’m going to call it deck.\r\nDialogue: 0,0:02:27.84,0:02:31.28,yin,,0,0,0,, 因为 deck 这里有个错误 \\N{\\fs12}Now we have an error here because of deck,\r\nDialogue: 0,0:02:31.28,0:02:34.68,yin,,0,0,0,, 所以我们需要到上面这里 导入 Deck\\N{\\fs12}so we have to go up here and import deck.\r\nDialogue: 0,0:02:34.68,0:02:36.51,yin,,0,0,0,, 这样错误就没有了 \\N{\\fs12}Alright? To make that error go away.\r\nDialogue: 0,0:02:36.51,0:02:39.44,yin,,0,0,0,, 现在我们有了这个属性 这很酷 \\N{\\fs12}So now we got this property that’s cool,\r\nDialogue: 0,0:02:39.44,0:02:43.82,yin,,0,0,0,, 显然 我们希望使用惰性实例化来实例化这一属性 \\N{\\fs12}obviously we want to use lazy instantiation to instantiate that property,\r\nDialogue: 0,0:02:43.82,0:02:46.70,yin,,0,0,0,, 所以我在这里输入 (Deck *)deck\\N{\\fs12}so I’m going to do that, that’s a deck star deck,\r\nDialogue: 0,0:02:46.71,0:02:51.18,yin,,0,0,0,, 我要看我的实例变量是否为 nil\\N{\\fs12}and I’m just going to see if my instance variable is null\r\nDialogue: 0,0:02:51.18,0:02:54.14,yin,,0,0,0,, 基本上也就是 是否为 0\\N{\\fs12}or nil, rather, the 0, basically.\r\nDialogue: 0,0:02:54.14,0:02:59.81,yin,,0,0,0,, 然后是_deck =\\N{\\fs12}Then I’m going to say, sorry, underbar, underbar deck, equals,\r\nDialogue: 0,0:02:59.81,0:03:03.15,yin,,0,0,0,, 我将使用另一个方法来创建 deck\\N{\\fs12}and I’m actually going to create deck using another method here,\r\nDialogue: 0,0:03:03.15,0:03:07.62,yin,,0,0,0,, 等下你们就知道为什么了 然后返回_deck\\N{\\fs12}you’ll see why in a second and then I’m going to return underbar deck.\r\nDialogue: 0,0:03:07.62,0:03:12.92,yin,,0,0,0,,createDeck 将会创建一个牌堆 \\N{\\fs12}And create deck is just going to create a deck.\r\nDialogue: 0,0:03:12.92,0:03:16.68,yin,,0,0,0,,createDeck 我将创建一个扑克牌堆 \\N{\\fs12}Create deck and I’m going to create a playing card deck,\r\nDialogue: 0,0:03:16.68,0:03:19.45,yin,,0,0,0,, 因为这就是我要求你们做的 \\N{\\fs12}because that’s what you were asked to do\r\nDialogue: 0,0:03:19.45,0:03:22.30,yin,,0,0,0,, 这里用 alloc init 来做这个 \\N{\\fs12}so I’m just going to do alloc init to do that.\r\nDialogue: 0,0:03:22.30,0:03:26.28,yin,,0,0,0,, 这里有个错误 因为只导入 Deck 是不行的 \\N{\\fs12}I got an error because not only do I need to import deck,\r\nDialogue: 0,0:03:26.28,0:03:28.41,yin,,0,0,0,, 我们需要导入 PlayingCardDeck\\N{\\fs12}but playing card deck, and it’s actually kind\r\nDialogue: 0,0:03:28.41,0:03:33.42,yin,,0,0,0,, 很不幸的是 这里我要创建一个通用的纸牌游戏 \\N{\\fs12}of unfortunate here that in this nice, generic card game that I’m building,\r\nDialogue: 0,0:03:33.42,0:03:36.31,yin,,0,0,0,, 结果却要导入扑克牌堆 \\N{\\fs12}that I’m importing a playing card deck.\r\nDialogue: 0,0:03:36.31,0:03:38.06,yin,,0,0,0,, 为什么说这很不幸呢 \\N{\\fs12}Why is that unfortunate?\r\nDialogue: 0,0:03:38.06,0:03:40.85,yin,,0,0,0,, 这里我要尝试创建一个纸牌游戏 \\N{\\fs12}Well, I’m going to try and build a card game here\r\nDialogue: 0,0:03:40.85,0:03:43.38,yin,,0,0,0,, 它同扑克牌没有任何关系 \\N{\\fs12}that has nothing to do with playing cards.\r\nDialogue: 0,0:03:43.38,0:03:44.86,yin,,0,0,0,, 它是通用的 \\N{\\fs12}It’s going to be a generic,\r\nDialogue: 0,0:03:44.86,0:03:48.01,yin,,0,0,0,, 应该对任何牌堆都适用 \\N{\\fs12}should work with any kind of deck, okay, a deck of any kind\r\nDialogue: 0,0:03:48.01,0:03:50.76,yin,,0,0,0,, 实际上 在你们的作业中 \\N{\\fs12}of cards and, in fact, in your homework, you’re going\r\nDialogue: 0,0:03:50.76,0:03:55.98,yin,,0,0,0,, 你们下周会被要求考虑不同牌堆 来增强游戏 \\N{\\fs12}to be asked to enhanced the game next week to play a different deck.\r\nDialogue: 0,0:03:55.98,0:03:59.66,yin,,0,0,0,, 所以说 这里需要这样做是很不幸的 \\N{\\fs12}So it’s unfortunate that I have to do this and in lecture,\r\nDialogue: 0,0:03:59.66,0:04:05.02,yin,,0,0,0,, 在周三或周一 我将讨论如何把这个除掉 \\N{\\fs12}either on Wednesday or probably on Monday, we will talk about how we can get rid of this.\r\nDialogue: 0,0:04:05.02,0:04:07.34,yin,,0,0,0,, 不再导入 PlayingCardDeck\\N{\\fs12}Okay, get this import playing card deck\r\nDialogue: 0,0:04:07.34,0:04:11.99,yin,,0,0,0,, 让这个 createDeck 方法更具通用性 \\N{\\fs12}and this create deck method to be more generic, okay,\r\nDialogue: 0,0:04:11.99,0:04:15.67,yin,,0,0,0,, 而不仅仅适用于扑克牌 \\N{\\fs12}not be so specific to playing cards.\r\nDialogue: 0,0:04:15.67,0:04:18.66,yin,,0,0,0,, 无论如何 这里我有了这个 deck\\N{\\fs12}But anyway, so now I have this deck\r\nDialogue: 0,0:04:18.66,0:04:21.56,yin,,0,0,0,, 它是惰性实例化的 有了 deck 后 \\N{\\fs12}and it’s lazily instantiated so now that I have a deck,\r\nDialogue: 0,0:04:21.56,0:04:27.62,yin,,0,0,0,, 我就可以用它来替换这个梅花 A 了 \\N{\\fs12}I can use it to get rid of this little ace of clubs thing right here.\r\nDialogue: 0,0:04:27.62,0:04:34.16,yin,,0,0,0,, 我可以这样做 这里加入 Card *card\\N{\\fs12}And, I’m going to do that by saying here card star card\r\nDialogue: 0,0:04:34.16,0:04:37.74,yin,,0,0,0,,= [self.deck drawRandomCard]\\N{\\fs12}equals self dot deck, draw random card.\r\nDialogue: 0,0:04:37.74,0:04:40.34,yin,,0,0,0,, 我将从牌堆中随机抽取一张牌 \\N{\\fs12}So I’m going to draw a random card out of the deck\r\nDialogue: 0,0:04:40.34,0:04:42.32,yin,,0,0,0,, 然后这里不再是梅花 A\\N{\\fs12}and then instead of putting ace of clubs here,\r\nDialogue: 0,0:04:42.32,0:04:45.20,yin,,0,0,0,, 将它改为纸牌内容 \\N{\\fs12}I’m going to put the cards contents.\r\nDialogue: 0,0:04:45.20,0:04:49.44,yin,,0,0,0,, 这就是你们所有的作业内容 \\N{\\fs12}And that’s really your entire homework assignment,\r\nDialogue: 0,0:04:49.44,0:04:54.58,yin,,0,0,0,, 这里我还要做两个小的改动 \\N{\\fs12}there’s one other minor thing that I’m going to do here, actually two minor things.\r\nDialogue: 0,0:04:54.58,0:04:57.47,yin,,0,0,0,, 因为我们的答案不是能够工作就行 \\N{\\fs12}Because we don’t want just a solution that works,\r\nDialogue: 0,0:04:57.47,0:05:00.40,yin,,0,0,0,, 运行这个确实能够工作 \\N{\\fs12}this will work if we run this.\r\nDialogue: 0,0:05:00.42,0:05:03.78,yin,,0,0,0,, 能够工作 但并不优雅 \\N{\\fs12}We’re going to see it work, but it’s kind of not very elegant\r\nDialogue: 0,0:05:03.78,0:05:07.17,yin,,0,0,0,, 这不能算一个很好的答案 \\N{\\fs12}and not really, it’s not really a really very good solution\r\nDialogue: 0,0:05:07.17,0:05:09.99,yin,,0,0,0,, 虽然它能够达到目的 \\N{\\fs12}to the problem, even though it functions, you see, it’s,\r\nDialogue: 0,0:05:09.99,0:05:12.61,yin,,0,0,0,, 可以看到 它会随机出牌 \\N{\\fs12}it’s going through the random cards here.\r\nDialogue: 0,0:05:12.61,0:05:15.27,yin,,0,0,0,, 但有几点比较让人不爽 \\N{\\fs12}But it was kind of annoying, a couple of things.\r\nDialogue: 0,0:05:15.27,0:05:18.82,yin,,0,0,0,, 一是它会从梅花 A 开始 这很毛糙 \\N{\\fs12}One, it started out with the ace of clubs, that was kind of gross,\r\nDialogue: 0,0:05:18.82,0:05:20.64,yin,,0,0,0,, 因为一直点击这里 \\N{\\fs12}okay, because if I keep clicking here,\r\nDialogue: 0,0:05:20.64,0:05:24.36,yin,,0,0,0,, 最终我会重新得到梅花 A 这就是了 \\N{\\fs12}eventually I’m going to get the ace of clubs, there it was, back again,\r\nDialogue: 0,0:05:24.36,0:05:26.29,yin,,0,0,0,, 这很糟糕 \\N{\\fs12}so that’s kind of bad.\r\nDialogue: 0,0:05:26.29,0:05:28.86,yin,,0,0,0,, 另一点是 当牌堆为空时 \\N{\\fs12}The other thing is when this deck is empty,\r\nDialogue: 0,0:05:28.86,0:05:34.24,yin,,0,0,0,, 这个将没法善终 \\N{\\fs12}this is not going to particularly elegantly, you know, finish off,\r\nDialogue: 0,0:05:34.24,0:05:36.49,yin,,0,0,0,, 我们需要优雅的答案 \\N{\\fs12}and we want to have some elegant solution and I said\r\nDialogue: 0,0:05:36.49,0:05:38.87,yin,,0,0,0,, 提示中就涉及到过 \\N{\\fs12}in the hints come up with an elegant solution.\r\nDialogue: 0,0:05:38.87,0:05:43.17,yin,,0,0,0,, 然后是翻转计数 纸牌用完后 它还会持续计数 \\N{\\fs12}Also, this flips thing here, once I flip through the whole deck, it’s going to keep flipping.\r\nDialogue: 0,0:05:43.17,0:05:47.82,yin,,0,0,0,, 它会增加到 102 103 104 105 这不很优雅 \\N{\\fs12}You know, it’s going to be 102, 103, 104, 105, that’s not very elegant either.\r\nDialogue: 0,0:05:47.82,0:05:52.48,yin,,0,0,0,, 让我们来修正上述三点 得到简单优雅的答案 \\N{\\fs12}So let’s fix all three of those things with simple, elegant solutions.\r\nDialogue: 0,0:05:52.48,0:05:55.40,yin,,0,0,0,, 对于梅花 A 我的简单优雅答案 \\N{\\fs12}So my simple, elegant solution to the ace of clubs\r\nDialogue: 0,0:05:55.40,0:06:00.34,yin,,0,0,0,, 是从反面开始 这个我其实提示过 \\N{\\fs12}which I hinted at for you is simply to start it face down.\r\nDialogue: 0,0:06:00.34,0:06:03.73,yin,,0,0,0,, 我将用到 cardback 除掉梅花 A\\N{\\fs12}So I’m going to get the card back here, get rid of the ace of clubs,\r\nDialogue: 0,0:06:03.73,0:06:05.72,yin,,0,0,0,, 这时就是从反面开始了 \\N{\\fs12}and now this card starts out facedown.\r\nDialogue: 0,0:06:05.72,0:06:08.81,yin,,0,0,0,, 我根本都不需要写任何代码 \\N{\\fs12}So I didn’t have to write any code and I just use my brain\r\nDialogue: 0,0:06:08.81,0:06:13.45,yin,,0,0,0,, 直接在这里点几下就行了 \\N{\\fs12}over my brawn to make sure that this works, right?\r\nDialogue: 0,0:06:13.45,0:06:17.00,yin,,0,0,0,, 这是解决那一问题的优雅方式 \\N{\\fs12}So, that’s kind of the elegant way of thinking about solving that problem.\r\nDialogue: 0,0:06:17.00,0:06:18.69,yin,,0,0,0,, 我们将从正面朝下开始 \\N{\\fs12}So we’ll just start it face down, there\r\nDialogue: 0,0:06:18.69,0:06:21.99,yin,,0,0,0,, 没有人要求一定要梅花 A 正面朝上 \\N{\\fs12}was no required task that said you had to start with the ace of clubs face up,\r\nDialogue: 0,0:06:21.99,0:06:24.31,yin,,0,0,0,, 这是很好的解决办法 \\N{\\fs12}so that’s a good solution.\r\nDialogue: 0,0:06:24.31,0:06:26.81,yin,,0,0,0,, 而对于纸牌用完的情况 \\N{\\fs12}When it comes to running out of cards,\r\nDialogue: 0,0:06:26.81,0:06:31.16,yin,,0,0,0,, 我认为最优雅的解决办法是 这时就停止翻动 \\N{\\fs12}I think an elegant solution is it just will stop flipping at that point.\r\nDialogue: 0,0:06:31.16,0:06:34.30,yin,,0,0,0,, 你当然也可以再加载一副牌 \\N{\\fs12}I mean, you could make arguments, load up another deck,\r\nDialogue: 0,0:06:34.30,0:06:37.59,yin,,0,0,0,, 不过我认为最简单的解决办法是 \\N{\\fs12}other stuff, but I think a simple solution is just once you\r\nDialogue: 0,0:06:37.59,0:06:40.27,yin,,0,0,0,, 牌用完时 再点就不翻了 \\N{\\fs12}run out of cards, you keep clicking, and it stops flipping.\r\nDialogue: 0,0:06:40.27,0:06:42.33,yin,,0,0,0,, 这怎么做到呢 \\N{\\fs12}So how are we going to do that?\r\nDialogue: 0,0:06:42.33,0:06:44.87,yin,,0,0,0,, 我知道你们有些人会说 \\N{\\fs12}Well, I know some of you are going to say something like,\r\nDialogue: 0,0:06:44.87,0:06:48.54,yin,,0,0,0,, 如果翻转次数为 102 那么停止翻动 \\N{\\fs12}if number of flips equals 102, then stop flipping,\r\nDialogue: 0,0:06:48.54,0:06:50.21,yin,,0,0,0,, 这非常糟糕 \\N{\\fs12}and that’s really, really bad.\r\nDialogue: 0,0:06:50.21,0:06:52.06,yin,,0,0,0,, 这是非常糟糕的设计 \\N{\\fs12}That’s a very bad design,\r\nDialogue: 0,0:06:52.06,0:06:56.01,yin,,0,0,0,, 因为 102 就像一个你加入到程序中的神奇数字 \\N{\\fs12}because that 102 is like a magic number you just put into your program\r\nDialogue: 0,0:06:56.01,0:06:59.15,yin,,0,0,0,, 而且这种糟糕设计完全没有理由 \\N{\\fs12}and there’s completely no reason for that bad design either.\r\nDialogue: 0,0:06:59.15,0:07:02.75,yin,,0,0,0,, 你只需要说 if (card)\\N{\\fs12}All you need to do is just say if card,\r\nDialogue: 0,0:07:02.75,0:07:05.64,yin,,0,0,0,, 那么翻转 \\N{\\fs12}then flip it,\r\nDialogue: 0,0:07:05.64,0:07:08.47,yin,,0,0,0,, 这些表示翻转 \\N{\\fs12}okay, so I’m going to flip it here,\r\nDialogue: 0,0:07:08.47,0:07:11.65,yin,,0,0,0,, 空出一点空间 这样更清楚一些 \\N{\\fs12}I’ll make some more space so you can see.\r\nDialogue: 0,0:07:11.65,0:07:14.75,yin,,0,0,0,, 否则 牌就不会翻动 \\N{\\fs12}Otherwise, I’m not going to flip it.\r\nDialogue: 0,0:07:14.75,0:07:19.22,yin,,0,0,0,, 这是超级优雅的解决办法 \\N{\\fs12}So I’m just, this is a super elegant solution to,\r\nDialogue: 0,0:07:19.22,0:07:23.54,yin,,0,0,0,, 牌堆中牌用完时 这里就将不再翻动 \\N{\\fs12}you know, not continuing to flip this thing over when the deck runs out,\r\nDialogue: 0,0:07:23.54,0:07:26.87,yin,,0,0,0,, 我们知道 drawRandomCard 会返回 nil\\N{\\fs12}and we know that draw random card returns nil,\r\nDialogue: 0,0:07:26.87,0:07:30.36,yin,,0,0,0,, 根据实现 它在 deck 为空时会返回 nil\\N{\\fs12}if you remember from our implementation it returns nil when the deck is empty,\r\nDialogue: 0,0:07:30.36,0:07:31.44,yin,,0,0,0,, 很完美 \\N{\\fs12}so, perfect!\r\nDialogue: 0,0:07:31.44,0:07:35.18,yin,,0,0,0,, 为 nil 时 牌就不会翻到有内容的那一面了 \\N{\\fs12}Once it’s nil, it’s just not going to flip back over to the contents sides,\r\nDialogue: 0,0:07:35.18,0:07:36.77,yin,,0,0,0,, 它会维持在反面 \\N{\\fs12}it’s going to always stay on the backside.\r\nDialogue: 0,0:07:36.77,0:07:37.58,yin,,0,0,0,, 有问题吗 \\N{\\fs12}Question?\r\nDialogue: 0,0:07:39.27,0:07:43.10,yin,,0,0,0,, 翻牌计数是不大优雅的第三个内容 如何修正呢 \\N{\\fs12}And flip count is the third thing that was kind of not very elegant, so how can we fix that?\r\nDialogue: 0,0:07:43.10,0:07:45.60,yin,,0,0,0,, 这方面可以有多种解决办法 \\N{\\fs12}Well, you know, there’s a number of ways to go at that,\r\nDialogue: 0,0:07:45.60,0:07:48.36,yin,,0,0,0,, 不过我认为最简单的是 \\N{\\fs12}but I think a simple way is to only\r\nDialogue: 0,0:07:48.36,0:07:55.58,yin,,0,0,0,, 仅在真正翻动时才计数 \\N{\\fs12}flip, sorry, when we actually do the flipping over.\r\nDialogue: 0,0:07:55.58,0:07:58.24,yin,,0,0,0,, 这其实并不是很棒的解决办法 \\N{\\fs12}Now, this is kind of not a great solution\r\nDialogue: 0,0:07:58.24,0:08:01.87,yin,,0,0,0,, 因为这里 我们并没有实际翻牌 \\N{\\fs12}because here we’re not actually flipping over, you know, if,\r\nDialogue: 0,0:08:01.87,0:08:06.02,yin,,0,0,0,, 如果我们在反面 那么这里我们要翻牌 \\N{\\fs12}if we’re on the card back, then we’re flipping over here,\r\nDialogue: 0,0:08:06.02,0:08:10.84,yin,,0,0,0,, 这个不算很好 因为我们是在…\\N{\\fs12}so this one’s kind of not so good, because we kind of gonna,\r\nDialogue: 0,0:08:10.84,0:08:17.46,yin,,0,0,0,, 一旦翻到反面 我们没有问题 因为我们开始…\\N{\\fs12}once we flip over to the back, we’ll be okay because when we start to do,\r\nDialogue: 0,0:08:17.46,0:08:19.72,yin,,0,0,0,, 我们将反复执行这段代码 \\N{\\fs12}we’ll be executing this code over and over right here\r\nDialogue: 0,0:08:19.72,0:08:21.60,yin,,0,0,0,, 因为我们总在背面 \\N{\\fs12}because we’ll always be on the back.\r\nDialogue: 0,0:08:21.60,0:08:24.92,yin,,0,0,0,, 我认为这样能行 这是好的解决办法吗 \\N{\\fs12}So I think this’ll work, right? Is that a good solution?\r\nDialogue: 0,0:08:24.92,0:08:27.40,yin,,0,0,0,, 我不喜欢它的原因在于 \\N{\\fs12}The reason I don’t like it is I don’t like having this line\r\nDialogue: 0,0:08:27.40,0:08:29.74,yin,,0,0,0,, 一段代码同时出现在两处 \\N{\\fs12}of code in two different places, kind of eh.\r\nDialogue: 0,0:08:29.74,0:08:32.57,yin,,0,0,0,, 我们还可以做很多别的事 \\N{\\fs12}I could have done a lot of other things here,\r\nDialogue: 0,0:08:32.57,0:08:37.86,yin,,0,0,0,, 我们可以将图像和字符串提出到单独局部变量 \\N{\\fs12}we could have factored out the image and the string into separate local variables\r\nDialogue: 0,0:08:37.86,0:08:40.60,yin,,0,0,0,, 用 if 应用这些 等等 \\N{\\fs12}and had our if, apply those, and stuff like that.\r\nDialogue: 0,0:08:40.60,0:08:44.81,yin,,0,0,0,, 不过这些就有点过头了 \\N{\\fs12}I think all of that would have been a little bit of overkill.\r\nDialogue: 0,0:08:44.81,0:08:47.44,yin,,0,0,0,, 我们来看看这能否奏效 \\N{\\fs12}So, let’s see if this works.\r\nDialogue: 0,0:08:47.44,0:08:50.37,yin,,0,0,0,, 程序开始时 牌是朝下的 \\N{\\fs12}So here’s our thing here, so it started facedown.\r\nDialogue: 0,0:08:50.37,0:08:52.37,yin,,0,0,0,, 点完整副牌 \\N{\\fs12}Let’s click through the deck here,\r\nDialogue: 0,0:08:52.37,0:08:54.05,yin,,0,0,0,, 快速点它 \\N{\\fs12}I’ll click through it quickly.\r\nDialogue: 0,0:08:54.05,0:08:56.60,yin,,0,0,0,, 可以看到 我点得很快 \\N{\\fs12}So I’m clicking so quickly through, you’ll notice\r\nDialogue: 0,0:08:56.60,0:09:01.24,yin,,0,0,0,, 以致于动画都不能完全展示出来 \\N{\\fs12}that I’m not giving time for the thing to finish animating.\r\nDialogue: 0,0:09:01.24,0:09:04.59,yin,,0,0,0,, 下下周我们会开始讨论动画 \\N{\\fs12}And we’re going to start talking about animation in the week after next.\r\nDialogue: 0,0:09:04.59,0:09:08.65,yin,,0,0,0,, 动画中可能发生的一个情况就是 \\N{\\fs12}And one thing about animation is\r\nDialogue: 0,0:09:08.65,0:09:13.37,yin,,0,0,0,, 它会同实际发生的情况有些不同步 \\N{\\fs12}it’s going to happen a little bit out of band with what’s actually happening.\r\nDialogue: 0,0:09:13.37,0:09:16.58,yin,,0,0,0,, 这里我在快速翻牌 \\N{\\fs12}So I am actually flipping here and all that flipping is happening,\r\nDialogue: 0,0:09:16.58,0:09:19.89,yin,,0,0,0,, 但动画却慢半拍 动画有些滞后 \\N{\\fs12}but the animation is kind of slow and it’s staying behind,\r\nDialogue: 0,0:09:19.89,0:09:21.74,yin,,0,0,0,, 很不幸 它就是这样 \\N{\\fs12}and that’s kind of just, unfortunately, the way it is,\r\nDialogue: 0,0:09:21.74,0:09:23.78,yin,,0,0,0,, 动画最终会赶上 \\N{\\fs12}the animation will eventually catch up,\r\nDialogue: 0,0:09:23.78,0:09:25.93,yin,,0,0,0,, 这里我们到了最后一张牌 \\N{\\fs12}but here we go to our last card,\r\nDialogue: 0,0:09:25.93,0:09:29.71,yin,,0,0,0,, 然后正面朝下 再点就没反应了 \\N{\\fs12}then we get facedown, and now we click, and it’s not clicking over\r\nDialogue: 0,0:09:29.71,0:09:32.34,yin,,0,0,0,, 停在 104\\N{\\fs12}and it’s stopped at 104.\r\nDialogue: 0,0:09:32.34,0:09:35.75,yin,,0,0,0,, 关于这个解决方案有任何问题吗 \\N{\\fs12}Any questions about this solution?\r\nDialogue: 0,0:09:37.45,0:09:38.70,yin,,0,0,0,, 很简单 \\N{\\fs12}Pretty straightforward.\r\nDialogue: 0,0:09:38.70,0:09:42.64,yin,,0,0,0,, 优雅性 简洁性 这是你们在作业中要追求的 \\N{\\fs12}Again, elegance, simplicity, that’s what you’re shooting for in your homework.\r\nDialogue: 0,0:09:42.64,0:09:46.56,yin,,0,0,0,, 加入很多 API 的复杂解决方案我们不推崇 \\N{\\fs12}Big, overwrought solutions where you’re adding a bunch of API and checking\r\nDialogue: 0,0:09:46.56,0:09:50.43,yin,,0,0,0,, 我们推崇更简介优雅的解决方案 \\N{\\fs12}a lot of things are generally not preferred over more simple solutions,\r\nDialogue: 0,0:09:50.43,0:09:53.17,yin,,0,0,0,, 就算像这样有两行做相同事情的代码 \\N{\\fs12}so like this, even if you have something where you kinda have these\r\nDialogue: 0,0:09:53.17,0:09:55.38,yin,,0,0,0,, 都显得有些不够优雅 \\N{\\fs12}2 lines of code that are doing the same thing,\r\nDialogue: 0,0:09:55.38,0:09:58.52,yin,,0,0,0,, 也许你不应该像这样复制 \\N{\\fs12}maybe shouldn’t be replicated like this,\r\nDialogue: 0,0:09:58.52,0:10:01.35,yin,,0,0,0,, 这只能勉强算优雅 \\N{\\fs12}it’s a close call as to the really perfect elegance,\r\nDialogue: 0,0:10:01.36,0:10:03.26,yin,,0,0,0,, 不过这里还要考虑简单 \\N{\\fs12}but I was going for simplicity here too\r\nDialogue: 0,0:10:03.26,0:10:06.74,yin,,0,0,0,, 因为我只有这么多时间 \\N{\\fs12}because I only have so much time.\r\nDialogue: 0,0:10:06.74,0:10:07.61,yin,,0,0,0,, 好 \\N{\\fs12}Alright.\r\nDialogue: 0,0:10:07.61,0:10:13.99,yin,,0,0,0,, 下面 我们将要进入纸牌匹配游戏的下一阶段 \\N{\\fs12}So now, we’re going to go into doing the next phase of our card matching game,\r\nDialogue: 0,0:10:13.99,0:10:16.79,yin,,0,0,0,, 也就是实际进行游戏 \\N{\\fs12}which is to make the game actually play.\r\nDialogue: 0,0:10:16.79,0:10:19.98,yin,,0,0,0,, 游戏的进行是我们模型的一部分 \\N{\\fs12}Now the playing of the game is part of our model.\r\nDialogue: 0,0:10:19.99,0:10:21.63,yin,,0,0,0,, 理解这个很重要 \\N{\\fs12}It’s really important to understand,\r\nDialogue: 0,0:10:21.63,0:10:25.13,yin,,0,0,0,, 它不是控制器的一部分 而是模型的一部分 \\N{\\fs12}it’s not part of our controller, its part of our model.\r\nDialogue: 0,0:10:25.13,0:10:28.66,yin,,0,0,0,, 因为我讲过 模型是关于游戏是什么 \\N{\\fs12}Because I told you that the model is the what your game is.\r\nDialogue: 0,0:10:28.66,0:10:30.08,yin,,0,0,0,, 这是什么 \\N{\\fs12}Well, what is this?\r\nDialogue: 0,0:10:30.08,0:10:33.17,yin,,0,0,0,, 这是一个纸牌匹配游戏 “什么”需要放在模型中 \\N{\\fs12}It’s a card matching game, so the what better be in the model.\r\nDialogue: 0,0:10:33.17,0:10:36.54,yin,,0,0,0,, 所以 我们将在模型中创建一个类 \\N{\\fs12}So we’re going to create a class in our model\r\nDialogue: 0,0:10:36.54,0:10:39.69,yin,,0,0,0,, 封装游戏进行的逻辑 \\N{\\fs12}that is going to encapsulate the logic of the game playing\r\nDialogue: 0,0:10:39.69,0:10:42.70,yin,,0,0,0,, 它将对用户界面一无所知 \\N{\\fs12}and it’s not going to know anything about user interface.\r\nDialogue: 0,0:10:42.70,0:10:46.28,yin,,0,0,0,, 它其中没有任何同用户界面相关的事物 \\N{\\fs12}It’s not going to have any things in it that have anything to do with user interface\r\nDialogue: 0,0:10:46.28,0:10:48.55,yin,,0,0,0,, 这是一个非常重要的区分 \\N{\\fs12}and that’s a really important distinction to make.\r\nDialogue: 0,0:10:48.55,0:10:50.92,yin,,0,0,0,, 我们来创建这个新类 \\N{\\fs12}So, let’s create that new class,\r\nDialogue: 0,0:10:50.92,0:10:55.50,yin,,0,0,0,, 创建新类的方式同今天作业中一样 \\N{\\fs12}remember that we always create new class the same way you did with your assignment today\r\nDialogue: 0,0:10:55.50,0:10:57.20,yin,,0,0,0,, 点击新文件 \\N{\\fs12}by saying new file.\r\nDialogue: 0,0:10:57.20,0:11:00.24,yin,,0,0,0,, 我们想要一个 Objective-C 类 \\N{\\fs12}And we want an objective-C class and I’m going\r\nDialogue: 0,0:11:00.24,0:11:04.50,yin,,0,0,0,, 命名为 CardMatchingGame\\N{\\fs12}to call it card matching game.\r\nDialogue: 0,0:11:04.50,0:11:11.30,yin,,0,0,0,, 它将继承自 NSObject 和所有基本类一样 \\N{\\fs12}And it’s going to inherit from NSObject as all of our kind of base classes do,\r\nDialogue: 0,0:11:11.30,0:11:16.13,yin,,0,0,0,, 我将把这个类同模型中其它类放到相同目录下 \\N{\\fs12}and I’m going to put this thing in the same directory as the rest of my model\r\nDialogue: 0,0:11:16.13,0:11:20.82,yin,,0,0,0,, 我还将用导航栏将它放到模型的同一个组中 \\N{\\fs12}and I’m also going to put it in the same group in the navigator as my model, as well.\r\nDialogue: 0,0:11:20.82,0:11:24.52,yin,,0,0,0,, 它和所有这些一起在这个组中 \\N{\\fs12}So it goes with all these guys and it goes in this group.\r\nDialogue: 0,0:11:24.52,0:11:27.84,yin,,0,0,0,, 记得这样做是很好的 \\N{\\fs12}It’s a nice thing to remember to do.\r\nDialogue: 0,0:11:27.84,0:11:29.42,yin,,0,0,0,, 好 我们创建了它 \\N{\\fs12}Alright? So we create it.\r\nDialogue: 0,0:11:29.42,0:11:30.84,yin,,0,0,0,, 这就是了 \\N{\\fs12}Here it is.\r\nDialogue: 0,0:11:30.84,0:11:34.61,yin,,0,0,0,, 这是它的头文件 \\N{\\fs12}Here’s its header file right here and I’m going\r\nDialogue: 0,0:11:34.61,0:11:39.97,yin,,0,0,0,, 我将使用这个自动对照 来显示实现 \\N{\\fs12}to use this counterparts, automatic counterparts, to show the implementation.\r\nDialogue: 0,0:11:39.97,0:11:43.45,yin,,0,0,0,, 这是头文件及实现 \\N{\\fs12}So there is its header file and its implementation,\r\nDialogue: 0,0:11:43.45,0:11:47.49,yin,,0,0,0,, 我在设计新类时 我总喜欢 \\N{\\fs12}and I always, when I design a new class, I always try\r\nDialogue: 0,0:11:47.49,0:11:51.21,yin,,0,0,0,, 首先处理公共 API\\N{\\fs12}to give my first crack at its public API first.\r\nDialogue: 0,0:11:51.21,0:11:53.75,yin,,0,0,0,, 稍后再考虑它的实现 \\N{\\fs12}I’ll go do its implementation later,\r\nDialogue: 0,0:11:53.75,0:11:57.92,yin,,0,0,0,, 我会先思考 人们会怎样使用我的类 \\N{\\fs12}but I want to kind of think of how are people going to use my class first?\r\nDialogue: 0,0:11:57.92,0:12:00.87,yin,,0,0,0,, 以此驱动我的总体设计 \\N{\\fs12}Just to drive my overall design.\r\nDialogue: 0,0:12:00.87,0:12:02.42,yin,,0,0,0,, 这里类很简单 \\N{\\fs12}And that’s for a simple class like this,\r\nDialogue: 0,0:12:02.42,0:12:04.18,yin,,0,0,0,, 如果类更复杂一些 \\N{\\fs12}if you get into a more complicated class,\r\nDialogue: 0,0:12:04.18,0:12:07.21,yin,,0,0,0,, 你可能需要同团队开意义重大的设计会议 \\N{\\fs12}you might be having significant design meetings which are teamed\r\nDialogue: 0,0:12:07.21,0:12:10.00,yin,,0,0,0,, 来理解这是什么对象 它如何融入到世界中 \\N{\\fs12}to understand what’s this object, how does it fit into the world,\r\nDialogue: 0,0:12:10.00,0:12:12.62,yin,,0,0,0,, 但如果只是一个简单直接的类 \\N{\\fs12}but if you’re just doing a simple straightforward class,\r\nDialogue: 0,0:12:12.62,0:12:14.70,yin,,0,0,0,, 特别是在初次编写时 \\N{\\fs12}especially if you’re doing its first iteration,\r\nDialogue: 0,0:12:14.70,0:12:18.42,yin,,0,0,0,, 有时 想想其 API 是什么就足够了 \\N{\\fs12}it sometimes nice to just think what is it’s API, we call it,\r\nDialogue: 0,0:12:18.42,0:12:24.16,yin,,0,0,0,,API 在这里也就是类的公共应用程序接口 \\N{\\fs12}okay, API is the Public Programming Interface for a class.\r\nDialogue: 0,0:12:24.16,0:12:28.00,yin,,0,0,0,, 我需要思考这个纸牌匹配游戏需要做什么 \\N{\\fs12}So, I need to think of what this card matching game needs to do.\r\nDialogue: 0,0:12:28.00,0:12:31.11,yin,,0,0,0,, 首先 我知道它需要一个初始化器 \\N{\\fs12}Well, one thing I know it needs is an initializer.\r\nDialogue: 0,0:12:31.11,0:12:32.81,yin,,0,0,0,, 一个 init\\N{\\fs12}An init.\r\nDialogue: 0,0:12:32.81,0:12:34.87,yin,,0,0,0,, 当我考虑我的纸牌匹配游戏时 \\N{\\fs12}But when I think about my card matching game,\r\nDialogue: 0,0:12:34.87,0:12:38.12,yin,,0,0,0,, 它有一些东西需要知道去初始化 \\N{\\fs12}there’s a couple of things it just has to know to initialize.\r\nDialogue: 0,0:12:38.12,0:12:41.57,yin,,0,0,0,, 它不能只像 PlayingCardDeck 那样初始化自身 \\N{\\fs12}It can’t just initialize itself like a playing card deck can.\r\nDialogue: 0,0:12:41.57,0:12:43.83,yin,,0,0,0,,PlayingCardDeck 在开始时知道 \\N{\\fs12}A playing card deck knows everything it needs to know about\r\nDialogue: 0,0:12:43.83,0:12:45.98,yin,,0,0,0,, 关于扑克牌堆它需要知道的一切 \\N{\\fs12}a playing card deck when it’s started,\r\nDialogue: 0,0:12:45.98,0:12:47.66,yin,,0,0,0,, 但这个不知道这些 \\N{\\fs12}but this doesn’t really know that, so,\r\nDialogue: 0,0:12:47.66,0:12:50.17,yin,,0,0,0,, 我需要一些东西 其中一个是 \\N{\\fs12}I need a couple of things. One thing I need is\r\nDialogue: 0,0:12:50.17,0:12:53.29,yin,,0,0,0,, 玩家玩的有多少张牌 \\N{\\fs12}how many cards are we playing with?\r\nDialogue: 0,0:12:53.29,0:12:57.01,yin,,0,0,0,, 玩家被允许总共匹配多少张纸牌 \\N{\\fs12}How many cards are, is the person allowed to match total?\r\nDialogue: 0,0:12:57.01,0:12:58.23,yin,,0,0,0,, 总共多少张 \\N{\\fs12}Right? What’s the total amount of cards?\r\nDialogue: 0,0:12:58.23,0:12:59.18,yin,,0,0,0,, 我们需要这个 \\N{\\fs12}So we need that.\r\nDialogue: 0,0:12:59.18,0:13:03.61,yin,,0,0,0,, 所以这里我说 initWithCardCount(初始化 带纸牌计数)\\N{\\fs12}So I’m going to say, init with card count,\r\nDialogue: 0,0:13:03.61,0:13:06.68,yin,,0,0,0,, 这里使用 NSUInteger\\N{\\fs12}and we’ll make an NSUInteger.\r\nDialogue: 0,0:13:06.68,0:13:11.49,yin,,0,0,0,, 实际上 计数至少需要是 2 你们应该能想到 \\N{\\fs12}Really, that count has got to be at least two, you would think,\r\nDialogue: 0,0:13:11.49,0:13:16.28,yin,,0,0,0,, 所以我在初始化器中 也许应该验证 确保它大于 1\\N{\\fs12}so I’d probably, in my initializer, should check to make sure it’s greater than one\r\nDialogue: 0,0:13:16.28,0:13:18.50,yin,,0,0,0,, 如若不然 我将从 self 返回 nil\\N{\\fs12}and if it’s not I’ll probably return nil from self.\r\nDialogue: 0,0:13:18.50,0:13:21.89,yin,,0,0,0,, 换言之 我将不初始化 我的 alloc init 会返回 nil\\N{\\fs12}In other words, I won’t initialize, my alloc init will return nil.\r\nDialogue: 0,0:13:21.89,0:13:25.50,yin,,0,0,0,, 确实 我们会选一种返回 nil 的方式 \\N{\\fs12}And we’ll, actually, we’ll pick one way where it does return nil,\r\nDialogue: 0,0:13:25.50,0:13:27.63,yin,,0,0,0,, 但我们也应该验证这个 \\N{\\fs12}but we should probably check that too.\r\nDialogue: 0,0:13:27.63,0:13:31.32,yin,,0,0,0,, 我需要的第二个东西是一个牌堆 \\N{\\fs12}The second thing that I need is a deck, a deck of cards,\r\nDialogue: 0,0:13:31.32,0:13:33.45,yin,,0,0,0,, 因为我要发这些牌 \\N{\\fs12}because I got to deal these cards out, right?\r\nDialogue: 0,0:13:33.45,0:13:38.48,yin,,0,0,0,, 我发牌后 你要选择一些来匹配 \\N{\\fs12}I’m going to deal them out and then you’re going to be able to pick some of them and do it.\r\nDialogue: 0,0:13:38.48,0:13:42.97,yin,,0,0,0,, 所以这里我说 usingDeck(使用牌堆)\\N{\\fs12}So, I’m going to say using deck.\r\nDialogue: 0,0:13:42.97,0:13:45.41,yin,,0,0,0,,(Deck *)deck\\N{\\fs12}Deck star deck.\r\nDialogue: 0,0:13:45.41,0:13:48.24,yin,,0,0,0,, 这里是初始化器 \\N{\\fs12}Okay, so there’s the initializer, and, of course,\r\nDialogue: 0,0:13:48.24,0:13:52.24,yin,,0,0,0,, 为了这个 我需要导入 Deck\\N{\\fs12}to do that I need to import deck, alright?\r\nDialogue: 0,0:13:52.24,0:13:54.25,yin,,0,0,0,, 这很好 \\N{\\fs12}So that’s pretty good.\r\nDialogue: 0,0:13:54.25,0:13:55.42,yin,,0,0,0,, 从这里开始 \\N{\\fs12}Start there.\r\nDialogue: 0,0:13:55.42,0:13:57.58,yin,,0,0,0,, 我的游戏还需要什么 \\N{\\fs12}What else do I need for my game?\r\nDialogue: 0,0:13:57.58,0:14:02.46,yin,,0,0,0,, 这是一个游戏 它当然应该有分数 \\N{\\fs12}Well it’s a game, so I think it should have a score.\r\nDialogue: 0,0:14:03.39,0:14:06.68,yin,,0,0,0,, 这里用 NSInteger 来表示分数 \\N{\\fs12}Eh, we’ll say NSInteger score.\r\nDialogue: 0,0:14:06.69,0:14:08.68,yin,,0,0,0,, 重申一次 使用 NSInteger NSUInteger\\N{\\fs12}And, again, NSInteger, NSUInteger\r\nDialogue: 0,0:14:08.69,0:14:10.96,yin,,0,0,0,, 而不用 unsigned int 只是风格问题 \\N{\\fs12}versus unsigned int is kind of a style thing,\r\nDialogue: 0,0:14:10.96,0:14:12.85,yin,,0,0,0,, 上面用了 NSUInteger\\N{\\fs12}I used NSUInteger above,\r\nDialogue: 0,0:14:12.85,0:14:16.39,yin,,0,0,0,, 这里我用 NSInteger 保持一致 \\N{\\fs12}I’m going to use NSInteger to be consistent here\r\nDialogue: 0,0:14:16.39,0:14:18.57,yin,,0,0,0,, 分数其实也可能为负 \\N{\\fs12}and my score can be negative possibly.\r\nDialogue: 0,0:14:18.57,0:14:21.28,yin,,0,0,0,, 所以不是 NSUInteger 它可以为负 \\N{\\fs12}So that’s why it’s not an NSUInteger, it can be negative.\r\nDialogue: 0,0:14:21.28,0:14:23.50,yin,,0,0,0,, 注意 这里我让该属性为只读 \\N{\\fs12}And notice I made this property read only.\r\nDialogue: 0,0:14:23.50,0:14:25.17,yin,,0,0,0,, 我们第一次看到这个 \\N{\\fs12}It’s the first time we’ve seen that.\r\nDialogue: 0,0:14:25.17,0:14:26.24,yin,,0,0,0,, 为什么呢 \\N{\\fs12}And why is that?\r\nDialogue: 0,0:14:26.24,0:14:28.38,yin,,0,0,0,, 这是因为 我是游戏逻辑 \\N{\\fs12}Well that’s because I’m the game logic,\r\nDialogue: 0,0:14:28.38,0:14:30.13,yin,,0,0,0,, 我需要决定分数是多少 \\N{\\fs12}I get to determine what the score is,\r\nDialogue: 0,0:14:30.13,0:14:33.53,yin,,0,0,0,, 没人能够设置分数 我会告诉你分数是什么 \\N{\\fs12}nobody can set the score, I tell you what the score is.\r\nDialogue: 0,0:14:33.53,0:14:36.56,yin,,0,0,0,, 因此 任何人都不能够设置该属性 \\N{\\fs12}Therefore, there should be no setter for this property.\r\nDialogue: 0,0:14:36.56,0:14:38.19,yin,,0,0,0,, 至少公共上 \\N{\\fs12}At least not publicly.\r\nDialogue: 0,0:14:38.19,0:14:41.88,yin,,0,0,0,, 等下你们会看到 私有上 我们可以改写它 \\N{\\fs12}You’re going to see in a moment, privately, we’re going to make this rewrite\r\nDialogue: 0,0:14:41.88,0:14:43.67,yin,,0,0,0,, 从而进行私有设置 \\N{\\fs12}so that we can set it privately, right?\r\nDialogue: 0,0:14:43.67,0:14:45.86,yin,,0,0,0,, 因为我们需要一直更新分数 \\N{\\fs12}Because we obviously need to be updating our score all the time\r\nDialogue: 0,0:14:45.86,0:14:50.48,yin,,0,0,0,, 用户翻牌并匹配正确后会得分 我们需要更新 \\N{\\fs12}as people flip these cards over and get matches, they get points, we need to update it.\r\nDialogue: 0,0:14:50.48,0:14:53.74,yin,,0,0,0,, 但公共上 我们希望它是只读的 \\N{\\fs12}But publicly, we want it to be a read only.\r\nDialogue: 0,0:14:55.72,0:14:58.11,yin,,0,0,0,, 剩下我还需要解决一件事 \\N{\\fs12}The only other thing I need to do is\r\nDialogue: 0,0:14:58.11,0:15:01.61,yin,,0,0,0,, 玩家需要点击这些牌 牌会翻面 \\N{\\fs12}someone’s going to be clicking on these cards; they’re going to be flipping over\r\nDialogue: 0,0:15:01.61,0:15:04.14,yin,,0,0,0,, 它们被选择 可能会匹配 \\N{\\fs12}and being chosen and possibly matching,\r\nDialogue: 0,0:15:04.14,0:15:07.80,yin,,0,0,0,, 所以我需要有某种方法 让玩家选择一张牌 \\N{\\fs12}so I need some sort of method to let somebody choose a card.\r\nDialogue: 0,0:15:07.80,0:15:15.99,yin,,0,0,0,, 这里我将其称作 chooseCardAtIndex(在某下标处选牌)\\N{\\fs12}So, I’m going to call this choose card at index,\r\nDialogue: 0,0:15:15.99,0:15:19.20,yin,,0,0,0,, 还是 NSUInteger 类型 index\\N{\\fs12}NSUInteger, again, index.\r\nDialogue: 0,0:15:19.20,0:15:24.20,yin,,0,0,0,,API 中有很多方式能让玩家选牌 \\N{\\fs12}So, there’s a lot of ways in API you could have for letting someone choose a card.\r\nDialogue: 0,0:15:24.20,0:15:27.70,yin,,0,0,0,, 创建这一纸牌匹配游戏的对象 例如控制器 \\N{\\fs12}The person who creates this card matching game, not the person,\r\nDialogue: 0,0:15:27.70,0:15:29.53,yin,,0,0,0,, 创建这一纸牌匹配游戏的对象 例如控制器 \\N{\\fs12}but the other object, like a controller\r\nDialogue: 0,0:15:29.53,0:15:32.85,yin,,0,0,0,, 创建这一模型类的对象 知道计数 \\N{\\fs12}that creates this model class, knows the count,\r\nDialogue: 0,0:15:32.85,0:15:35.42,yin,,0,0,0,, 因为它指定了牌的计数 \\N{\\fs12}because it specified the count of cards.\r\nDialogue: 0,0:15:35.42,0:15:39.42,yin,,0,0,0,, 所以 这样指定一个下标很合理 \\N{\\fs12}So, it’s pretty reasonable to have them specify an index,\r\nDialogue: 0,0:15:39.42,0:15:42.11,yin,,0,0,0,, 在 0 和这个 count-1 之间 \\N{\\fs12}between 0 and this count minus 1,\r\nDialogue: 0,0:15:42.11,0:15:44.17,yin,,0,0,0,, 只要玩家选择了一张牌 \\N{\\fs12}anytime someone chooses a card.\r\nDialogue: 0,0:15:44.17,0:15:49.36,yin,,0,0,0,, 这就是明确玩家选择哪张牌的一种简单方式 \\N{\\fs12}So this is just a simple way of specifying which card did the user choose?\r\nDialogue: 0,0:15:49.36,0:15:56.31,yin,,0,0,0,, 类似地 我需要能够返回一张给定下标处的牌 \\N{\\fs12}And similarly, I actually need to be able to return a card at a given index,\r\nDialogue: 0,0:15:56.31,0:15:58.36,yin,,0,0,0,, 为什么需要这样呢 \\N{\\fs12}and why do I need this?\r\nDialogue: 0,0:15:58.36,0:16:01.78,yin,,0,0,0,, 因为我需要弄清游戏状态 \\N{\\fs12}Well, I need to be able to find out the state of the game\r\nDialogue: 0,0:16:01.78,0:16:04.60,yin,,0,0,0,, 在任何时候 我需要知道 \\N{\\fs12}at any given time, I mean, how is my controller going\r\nDialogue: 0,0:16:04.60,0:16:08.48,yin,,0,0,0,, 我的控制器如何为该游戏显示一个 UI\\N{\\fs12}to display a UI for this game if it can’t, you know,\r\nDialogue: 0,0:16:08.48,0:16:12.00,yin,,0,0,0,, 如果它无法弄清纸牌状态是怎样的 那就麻烦了 \\N{\\fs12}if it can’t find out what the cards, what the state of the cards is,\r\nDialogue: 0,0:16:12.00,0:16:14.27,yin,,0,0,0,, 这里只是为了让它得到纸牌 \\N{\\fs12}so this is just a little way for it to get the cards,\r\nDialogue: 0,0:16:14.28,0:16:17.52,yin,,0,0,0,, 它可以遍历所有这些纸牌 获得全部 全部更新 \\N{\\fs12}and it could iterate through all the cards and get them all, and update them all,\r\nDialogue: 0,0:16:17.52,0:16:19.72,yin,,0,0,0,, 它也可以得到特定下标处的牌 \\N{\\fs12}or it can get one in a particular index\r\nDialogue: 0,0:16:19.72,0:16:24.95,yin,,0,0,0,, 做它所需要做的最合适的事情 \\N{\\fs12}and could kind of, whatever fits best to what we’re doing.\r\nDialogue: 0,0:16:24.95,0:16:27.19,yin,,0,0,0,, 好 这是我的公共 API\\N{\\fs12}Alright, so, that’s my public API.\r\nDialogue: 0,0:16:27.19,0:16:30.49,yin,,0,0,0,, 我在这里编写实现之前 \\N{\\fs12}Now before I go and do my implementation over here,\r\nDialogue: 0,0:16:30.49,0:16:33.35,yin,,0,0,0,, 你们可以看到这里有一条警告 它怎么说 \\N{\\fs12}you can see that I got this warning right here and what’s this warning saying,\r\nDialogue: 0,0:16:33.35,0:16:36.91,yin,,0,0,0,, 它说有三条 你可以点击这个 3 来展开 \\N{\\fs12}it’s saying there’s actually three of them, you can click on this little three by the way,\r\nDialogue: 0,0:16:36.91,0:16:40.18,yin,,0,0,0,, 它说 你没有实现这些 \\N{\\fs12}it’s saying you have not implemented these,\r\nDialogue: 0,0:16:40.18,0:16:43.91,yin,,0,0,0,, 你使之成为公共的三个方法 这个警告很好 \\N{\\fs12}these three methods that you made public, so that, that’s a good warning.\r\nDialogue: 0,0:16:43.91,0:16:45.34,yin,,0,0,0,, 我需要这样做 \\N{\\fs12}I need to go do that.\r\nDialogue: 0,0:16:45.34,0:16:49.59,yin,,0,0,0,, 但在这样做之前 我要先回到我的控制器 \\N{\\fs12}But before I do that, I’m going to go back to my controller,\r\nDialogue: 0,0:16:49.59,0:16:52.09,yin,,0,0,0,, 我要展示给你们 \\N{\\fs12}I want to show you\r\nDialogue: 0,0:16:52.09,0:16:55.46,yin,,0,0,0,, 这里我们需要有怎样的 UI\\N{\\fs12}how we’re going to, what kind of UI we’re going to have over here so that\r\nDialogue: 0,0:16:55.46,0:16:57.64,yin,,0,0,0,, 使得我们进行实现时 \\N{\\fs12}as we’re doing our implementation, you can kind\r\nDialogue: 0,0:16:57.64,0:16:59.61,yin,,0,0,0,, 你能想象它们如何一同工作 \\N{\\fs12}of imagine how they’re going to work together,\r\nDialogue: 0,0:16:59.61,0:17:01.40,yin,,0,0,0,, 但我不一定需要 \\N{\\fs12}but I actually wouldn’t necessarily have\r\nDialogue: 0,0:17:01.40,0:17:04.01,yin,,0,0,0,, 在 CardMatchingGame 之前做这个 UI\\N{\\fs12}to do the UI before I do the card matching game\r\nDialogue: 0,0:17:04.01,0:17:06.65,yin,,0,0,0,, 有人甚至认为 我应该先做 CardMatchingGame\\N{\\fs12}and one could argue I should do the card matching game first\r\nDialogue: 0,0:17:06.65,0:17:11.07,yin,,0,0,0,, 设计模型时不要受 UI 太大影响 \\N{\\fs12}and not be influenced by the UI so much when I’m designing my model.\r\nDialogue: 0,0:17:11.07,0:17:15.52,yin,,0,0,0,, 但是 要知道 这个模型将会同 UI 一同工作 \\N{\\fs12}But, you know, this model is going to be served by some UI\r\nDialogue: 0,0:17:15.52,0:17:19.70,yin,,0,0,0,, 所以我们将一同做 让你们能够更好地想象 \\N{\\fs12}so we’re going to do them at the same time so you can imagine it a little better.\r\nDialogue: 0,0:17:19.70,0:17:22.66,yin,,0,0,0,, 这个 UI 需要什么呢 \\N{\\fs12}So what do we need for this UI?\r\nDialogue: 0,0:17:22.66,0:17:25.11,yin,,0,0,0,, 一点就是 我们需要很多牌 \\N{\\fs12}Well one thing is we need a lot more cards, okay,\r\nDialogue: 0,0:17:25.11,0:17:27.55,yin,,0,0,0,, 这张牌无法和任何东西进行匹配 \\N{\\fs12}this one card, it can’t be matched against anything else,\r\nDialogue: 0,0:17:27.55,0:17:30.78,yin,,0,0,0,, 让我们弄更多牌 这很简单 \\N{\\fs12}so let’s make more cards, this is very easy to do.\r\nDialogue: 0,0:17:30.78,0:17:33.91,yin,,0,0,0,, 我只需要把这张牌移到角落里 \\N{\\fs12}I’m just going to move this card up into the corner here\r\nDialogue: 0,0:17:33.91,0:17:38.41,yin,,0,0,0,, 然后复制粘贴 选择它 复制粘贴 \\N{\\fs12}and I’m just going to copy and paste it, so I can select it and copy and paste.\r\nDialogue: 0,0:17:38.41,0:17:40.87,yin,,0,0,0,, 使用蓝色参考线来放置 \\N{\\fs12}Place it, use the nice blue guidelines there.\r\nDialogue: 0,0:17:40.87,0:17:43.89,yin,,0,0,0,, 我还可以复制两张并粘贴 \\N{\\fs12}I can even copy two and paste them.\r\nDialogue: 0,0:17:43.89,0:17:48.28,yin,,0,0,0,, 然后复制四张并粘贴 \\N{\\fs12}Or copy four, and paste them.\r\nDialogue: 0,0:17:48.28,0:17:52.58,yin,,0,0,0,, 我将有 12 张牌 这是很好的纸牌数量 \\N{\\fs12}So now I’m going to have 12 cards, that’s a good number of cards.\r\nDialogue: 0,0:17:52.58,0:17:55.42,yin,,0,0,0,, 实际上 我不再需要翻牌计数 \\N{\\fs12}I actually don’t need this flips thing anymore, I’m not going\r\nDialogue: 0,0:17:55.42,0:17:57.30,yin,,0,0,0,, 这里不再是翻牌 而是要匹配 \\N{\\fs12}to be just flipping cards, I’m going to be matching cards,\r\nDialogue: 0,0:17:57.30,0:18:00.63,yin,,0,0,0,, 也许我需要展示分数 但这是之后的事情 \\N{\\fs12}I’m probably going to need something for the score which we’ll do a little bit later.\r\nDialogue: 0,0:18:00.63,0:18:03.27,yin,,0,0,0,, 不过这就基本上是我的整个 UI 了 \\N{\\fs12}But that’s pretty much my entire UI, I’m just going\r\nDialogue: 0,0:18:03.27,0:18:06.45,yin,,0,0,0,, 我有这些牌 我将点击它们 \\N{\\fs12}to have these cards and I’m going to click on them,\r\nDialogue: 0,0:18:06.45,0:18:08.69,yin,,0,0,0,, 它会显示出一张牌 \\N{\\fs12}it’s going to show a card and then I’m going,\r\nDialogue: 0,0:18:08.69,0:18:12.74,yin,,0,0,0,, 然后我可以再点一下 让它正面朝下 取消选择 \\N{\\fs12}I could either click on it again to turn it back facedown, un-choose it,\r\nDialogue: 0,0:18:12.74,0:18:14.46,yin,,0,0,0,, 我也可以点另外一张牌 \\N{\\fs12}or I could click on another card\r\nDialogue: 0,0:18:14.46,0:18:16.37,yin,,0,0,0,, 如果匹配成功 我将得到一些分数 \\N{\\fs12}and if it matches I should get some points\r\nDialogue: 0,0:18:16.37,0:18:21.07,yin,,0,0,0,, 否则的话 我之前选的那张将会翻回去 正面朝下 \\N{\\fs12}and if it doesn’t match, the other one, the last one I had is going to flip facedown.\r\nDialogue: 0,0:18:21.07,0:18:25.83,yin,,0,0,0,, 这同你们所熟悉的 Concentration 游戏不同 \\N{\\fs12}Now those of you who are used to a game like Concentration, it’s a little different,\r\nDialogue: 0,0:18:25.83,0:18:28.44,yin,,0,0,0,, 通常你选一张牌 然后再选另一张 \\N{\\fs12}usually you pick a card, then you pick another card,\r\nDialogue: 0,0:18:28.44,0:18:29.97,yin,,0,0,0,, 相匹配你会得分 \\N{\\fs12}and if they match you get points,\r\nDialogue: 0,0:18:29.97,0:18:33.73,yin,,0,0,0,, 否则两者都会翻回去 \\N{\\fs12}if they don’t match they usually both turn back over.\r\nDialogue: 0,0:18:33.73,0:18:36.92,yin,,0,0,0,, 这是很酷的 UI 但我还没教你们怎么做动画 \\N{\\fs12}Which would be a cool UI, but I haven’t taught you how to do animation\r\nDialogue: 0,0:18:36.92,0:18:38.05,yin,,0,0,0,, 这是这里所必须的 \\N{\\fs12}and that’s what you would need there\r\nDialogue: 0,0:18:38.05,0:18:41.25,yin,,0,0,0,, 因为第二张牌需要正面朝上 在屏幕上显示一段时间 \\N{\\fs12}because that second card, when it comes up, would need to be on screen for a little bit\r\nDialogue: 0,0:18:41.25,0:18:42.57,yin,,0,0,0,, 然后两者才会同时翻回正面朝下 \\N{\\fs12}before they both went down\r\nDialogue: 0,0:18:42.57,0:18:44.38,yin,,0,0,0,, 因为这个你需要看一段时间 \\N{\\fs12}because you got to at least get to see this one.\r\nDialogue: 0,0:18:44.38,0:18:47.42,yin,,0,0,0,, 因为你们没学过动画 所以点击第二张牌时 \\N{\\fs12}So since you don’t have animation, when you click on that second one, it’s going\r\nDialogue: 0,0:18:47.42,0:18:50.43,yin,,0,0,0,, 如果不匹配 我们将让之前那张正面朝下 \\N{\\fs12}to facedown the previous one if they don’t match.\r\nDialogue: 0,0:18:50.43,0:18:52.61,yin,,0,0,0,, 然后你不断点击 \\N{\\fs12}And then you just keep clicking around trying\r\nDialogue: 0,0:18:52.61,0:18:56.33,yin,,0,0,0,, 找到相匹配的牌就能得分 我来展示下 \\N{\\fs12}to find matches and you get points, and we’ll show you,\r\nDialogue: 0,0:18:56.33,0:18:58.65,yin,,0,0,0,, 我要使用的分数系统 \\N{\\fs12}kind of the point system that I’m going to use.\r\nDialogue: 0,0:18:58.65,0:19:00.68,yin,,0,0,0,, 这就是我的整个 UI\\N{\\fs12}So this is my entire UI.\r\nDialogue: 0,0:19:00.68,0:19:03.43,yin,,0,0,0,, 这是一个非常以内容为中心的 UI\\N{\\fs12}Very, it’s a very content-central UI, right?\r\nDialogue: 0,0:19:03.43,0:19:06.89,yin,,0,0,0,,UI 集中在这些纸牌上 \\N{\\fs12}The UI is really focused on these cards, there’s not a lot\r\nDialogue: 0,0:19:06.89,0:19:09.24,yin,,0,0,0,, 周围没有很多装饰 \\N{\\fs12}of adornments and other stuff around it.\r\nDialogue: 0,0:19:09.24,0:19:11.67,yin,,0,0,0,, 实际上 也几乎没有别的东西了 \\N{\\fs12}And we’re really not going to have much other stuff except\r\nDialogue: 0,0:19:11.67,0:19:14.77,yin,,0,0,0,, 除了分数 你们还需要加一个重新发牌的按钮 \\N{\\fs12}for the score and you’re going to add like a redeal button\r\nDialogue: 0,0:19:14.77,0:19:20.28,yin,,0,0,0,, 也许还有一些关于状态的内容 这些是作业 \\N{\\fs12}and maybe a little bit of stuff about some status about what’s going on in your homework,\r\nDialogue: 0,0:19:20.28,0:19:23.81,yin,,0,0,0,, 不过 UI 的基础就是这些了 \\N{\\fs12}but this is the fundamental basis of the UI.\r\nDialogue: 0,0:19:23.81,0:19:27.60,yin,,0,0,0,, 下面回到我们的 CardMatchingGame\\N{\\fs12}So now let’s go back to our card matching game,\r\nDialogue: 0,0:19:27.60,0:19:32.62,yin,,0,0,0,, 我们来讲讲如何实现这个 \\N{\\fs12}and let’s talk about how we’re going to implement this thing.\r\nDialogue: 0,0:19:32.62,0:19:35.41,yin,,0,0,0,, 这里选择自动 \\N{\\fs12}I’m going to go back to automatic here.\r\nDialogue: 0,0:19:35.41,0:19:36.84,yin,,0,0,0,, 把这个弄回来 \\N{\\fs12}Get this thing back.\r\nDialogue: 0,0:19:36.84,0:19:39.63,yin,,0,0,0,, 为了让这更漂亮一些 我要这样 \\N{\\fs12}Just to make this look nicer, I’m going to go like that.\r\nDialogue: 0,0:19:39.63,0:19:43.97,yin,,0,0,0,, 我将把这个头文件留在这里 \\N{\\fs12}And I’m going to leave this header file up while we go\r\nDialogue: 0,0:19:43.97,0:19:46.43,yin,,0,0,0,, 同时来编写实现 \\N{\\fs12}and do the implementation so you can kind of see\r\nDialogue: 0,0:19:46.43,0:19:50.60,yin,,0,0,0,, 这样你们就能对照着看 我们要做什么 \\N{\\fs12}where we’re shooting, this is what we’re shooting for.\r\nDialogue: 0,0:19:50.60,0:19:57.74,yin,,0,0,0,, 首先我要让这个只在实现中为读写 \\N{\\fs12}So, the first thing I want to do is make this be readwrite in my implementation only.\r\nDialogue: 0,0:19:57.74,0:20:01.19,yin,,0,0,0,, 做法是通过这个私有接口 \\N{\\fs12}And I do that with this little, private interface,\r\nDialogue: 0,0:20:01.19,0:20:04.05,yin,,0,0,0,, 记得吧 这个我讲过 你可以使用 \\N{\\fs12}remember I showed you about this, that you can have one\r\nDialogue: 0,0:20:04.05,0:20:06.34,yin,,0,0,0,, 这种开闭括号表示 \\N{\\fs12}of these with the little open parentheses, close parentheses\r\nDialogue: 0,0:20:06.34,0:20:09.57,yin,,0,0,0,, 像这样 现在你可以声明你自己的东西 \\N{\\fs12}like that, and now you can declare your own things.\r\nDialogue: 0,0:20:09.57,0:20:11.93,yin,,0,0,0,, 我将重新声明这个 \\N{\\fs12}Well, I’m going to redeclare this thing\r\nDialogue: 0,0:20:11.93,0:20:17.38,yin,,0,0,0,, 为非原子 读写 NSInteger score\\N{\\fs12}to be nonatomic readwrite, NSInteger score.\r\nDialogue: 0,0:20:18.06,0:20:23.20,yin,,0,0,0,, 这个读写 我们不怎么使用 因为它是默认 \\N{\\fs12}Now this readwrite, we don’t use that very much because it’s the default, right?\r\nDialogue: 0,0:20:23.20,0:20:27.97,yin,,0,0,0,,isChosen 记得 Card 中的 chosen 和 matched 属性吗 \\N{\\fs12}Is chosen, remember the properties chosen and matched that are in card.\r\nDialogue: 0,0:20:27.97,0:20:30.91,yin,,0,0,0,, 它们没说是读写 但它们有 setter 和 getter\\N{\\fs12}Those didn’t say readwrite, but they had a setter and a getter.\r\nDialogue: 0,0:20:30.91,0:20:32.67,yin,,0,0,0,, 它们是读写的 \\N{\\fs12}They were readwrite.\r\nDialogue: 0,0:20:32.67,0:20:34.55,yin,,0,0,0,, 这个只使用在 \\N{\\fs12}We really only use this when we’re trying\r\nDialogue: 0,0:20:34.55,0:20:38.31,yin,,0,0,0,, 重新声明公共中的只读为私有中的读写时 \\N{\\fs12}to redeclare a readonly one from public to private,\r\nDialogue: 0,0:20:38.31,0:20:41.11,yin,,0,0,0,, 这是我们使用这个的唯一情况 \\N{\\fs12}this is about the only time we really use this.\r\nDialogue: 0,0:20:41.11,0:20:42.88,yin,,0,0,0,, 也有一些编程风格 \\N{\\fs12}There are probably programming styles\r\nDialogue: 0,0:20:42.88,0:20:45.08,yin,,0,0,0,, 有人喜欢一直加上读写 \\N{\\fs12}where people put readwrite all the time,\r\nDialogue: 0,0:20:45.08,0:20:48.10,yin,,0,0,0,, 虽然这是默认 有些人对强是这样做的 \\N{\\fs12}even though it’s the default, some people do that with strong\r\nDialogue: 0,0:20:48.10,0:20:49.83,yin,,0,0,0,, 强也是默认 \\N{\\fs12}since strong is the default.\r\nDialogue: 0,0:20:49.83,0:20:52.23,yin,,0,0,0,, 我就喜欢在任何地方都指明强 \\N{\\fs12}I like to specify strong everywhere just\r\nDialogue: 0,0:20:52.23,0:20:56.02,yin,,0,0,0,, 这样我脑袋里能更清楚知道发生了什么 \\N{\\fs12}so it’s really clear what’s going on in my mind.\r\nDialogue: 0,0:20:56.02,0:21:00.36,yin,,0,0,0,, 但读写一般都没必要特别指出 除了这里需要重新定义 \\N{\\fs12}But readwrite, not necessary for most things except for here where we’re redefining it.\r\nDialogue: 0,0:21:00.36,0:21:02.27,yin,,0,0,0,, 大家都理解这里我做了什么吗 \\N{\\fs12}So everyone understand what I’m doing here?\r\nDialogue: 0,0:21:02.27,0:21:04.89,yin,,0,0,0,, 这是 score 和前面完全一样的分数 \\N{\\fs12}This is score, this is exactly the same score,\r\nDialogue: 0,0:21:04.89,0:21:08.11,yin,,0,0,0,, 也就是说 这里将会有 setter\\N{\\fs12}it’s just that this says there’s going to be a setter,\r\nDialogue: 0,0:21:08.11,0:21:10.65,yin,,0,0,0,, 但我只能在私有条件下调用 setter\\N{\\fs12}but I’m only going to be able to call that setter, at least not\r\nDialogue: 0,0:21:10.65,0:21:13.78,yin,,0,0,0,, 至少在实现中编译器不会提出警告 \\N{\\fs12}without a compiler warning in my implementation.\r\nDialogue: 0,0:21:13.78,0:21:16.50,yin,,0,0,0,, 因为我这里声明了读写 \\N{\\fs12}Okay, because I declared the readwrite part here.\r\nDialogue: 0,0:21:16.50,0:21:20.19,yin,,0,0,0,, 没有公共理由能够设置这一分数 \\N{\\fs12}No public person is going to be able to set the score,\r\nDialogue: 0,0:21:20.19,0:21:23.80,yin,,0,0,0,, 调用 setScore 而不让编译器提出警告 \\N{\\fs12}call set score, without compiler giving a warning.\r\nDialogue: 0,0:21:25.31,0:21:26.88,yin,,0,0,0,, 下一步 我想考虑这个纸牌游戏的内部数据结构 \\N{\\fs12}So the next thing I want to do is\r\nDialogue: 0,0:21:26.88,0:21:29.79,yin,,0,0,0,, 下一步 我想考虑这个纸牌游戏的内部数据结构 \\N{\\fs12}I want to think about my internal data structure for my card game\r\nDialogue: 0,0:21:29.79,0:21:30.66,yin,,0,0,0,, 非常简单 \\N{\\fs12}really simple,\r\nDialogue: 0,0:21:30.66,0:21:32.61,yin,,0,0,0,, 不过是一个纸牌的数组 \\N{\\fs12}it’s just an array of cards.\r\nDialogue: 0,0:21:32.61,0:21:34.41,yin,,0,0,0,, 我将有一个纸牌的数组 \\N{\\fs12}I’m going to have an array of cards,\r\nDialogue: 0,0:21:34.41,0:21:37.71,yin,,0,0,0,, 它将有这么多张牌 我将从牌堆中抽出它们 \\N{\\fs12}it’s going to be this many cards, I’m going to pull them out of this deck,\r\nDialogue: 0,0:21:37.71,0:21:44.28,yin,,0,0,0,, 玩家将能选择这些牌 可以看这些牌 \\N{\\fs12}and, people are going to be able to choose those cards, someone can go look at the cards,\r\nDialogue: 0,0:21:44.28,0:21:47.88,yin,,0,0,0,, 我们会在玩家选择对牌时进行加分 \\N{\\fs12}and we’ll adjust the score as people choose the cards.\r\nDialogue: 0,0:21:47.88,0:21:50.50,yin,,0,0,0,, 我需要这种内部数据结构 这是内部的 \\N{\\fs12}So I need that internal data structure, it’s internal,\r\nDialogue: 0,0:21:50.50,0:21:53.64,yin,,0,0,0,, 所以这里我需要说 非原子 强 \\N{\\fs12}so I’m going to put it here, nonatomic, strong.\r\nDialogue: 0,0:21:53.64,0:21:57.55,yin,,0,0,0,, 它将是一个可变的 NSMutableArray\\N{\\fs12}It’s going to be an NSMutableArray.\r\nDialogue: 0,0:21:57.55,0:22:01.42,yin,,0,0,0,, 这同我们在 Deck 中看到的情况类似 \\N{\\fs12}And this is similar to what we had in deck.\r\nDialogue: 0,0:22:01.42,0:22:06.52,yin,,0,0,0,, 这里我总喜欢注释一下 说是 Card 的 \\N{\\fs12}Alright? And I always like to put of card just to say what’s\r\nDialogue: 0,0:22:06.52,0:22:07.88,yin,,0,0,0,, 因为 我说过 \\N{\\fs12}in here because as we said,\r\nDialogue: 0,0:22:07.88,0:22:13.17,yin,,0,0,0,,Objective-C 没有办法让编译器强制说这里是什么 \\N{\\fs12}there’s no way in objective-C to kind of have the compiler enforce what’s in here.\r\nDialogue: 0,0:22:13.17,0:22:16.22,yin,,0,0,0,, 位于这个可变数组中的不过是对象 \\N{\\fs12}The things that are in this MutableArray are just objects.\r\nDialogue: 0,0:22:16.22,0:22:19.45,yin,,0,0,0,, 编译器不知道它们是什么类 \\N{\\fs12}And the compiler does not know what class they are.\r\nDialogue: 0,0:22:19.45,0:22:22.26,yin,,0,0,0,, 所以你需要确保没有将消息 \\N{\\fs12}So it’s up to you to make sure you don’t send messages\r\nDialogue: 0,0:22:22.26,0:22:24.42,yin,,0,0,0,, 发送给错误的事物 \\N{\\fs12}to things you pull out of it that are wrong.\r\nDialogue: 0,0:22:24.42,0:22:29.86,yin,,0,0,0,, 这里我们至少要让读代码的人知道我们的意图 \\N{\\fs12}So here, we are trying to at least give the person reading our code know our intent,\r\nDialogue: 0,0:22:29.86,0:22:32.43,yin,,0,0,0,, 我们希望这里是纸牌的数组 \\N{\\fs12}our intent is for this to be an array of cards.\r\nDialogue: 0,0:22:32.43,0:22:38.51,yin,,0,0,0,, 当然 我们希望进行惰性实例化 \\N{\\fs12}And, of course, we want our lazy instantiation.\r\nDialogue: 0,0:22:45.58,0:22:47.01,yin,,0,0,0,, 这很好 \\N{\\fs12}So that’s good.\r\nDialogue: 0,0:22:47.01,0:22:52.09,yin,,0,0,0,, 现在我们有了这个纸牌的数组 我们可以随时使用它 \\N{\\fs12}So now we have this array of cards, we can use it anytime we want.\r\nDialogue: 0,0:22:52.09,0:22:56.01,yin,,0,0,0,, 还是那句话 我们可以在初始化器中进行这个初始化 \\N{\\fs12}Again, we could do this initialization in the initializer, right,\r\nDialogue: 0,0:22:56.01,0:22:58.34,yin,,0,0,0,, 我们可以在这里做这个 alloc init\\N{\\fs12}we can do this alloc init in here,\r\nDialogue: 0,0:22:58.34,0:23:01.34,yin,,0,0,0,, 不过我更喜欢惰性实例化 \\N{\\fs12}but I happen to like using the lazy instantiation, I think it,\r\nDialogue: 0,0:23:01.34,0:23:06.21,yin,,0,0,0,, 我认为它让初始化器的代码看起来更简洁 \\N{\\fs12}it’s kind of, makes the code in our initializer look a little cleaner.\r\nDialogue: 0,0:23:06.21,0:23:08.31,yin,,0,0,0,, 下面让我们来写初始化器 \\N{\\fs12}So let’s do our initializer next though.\r\nDialogue: 0,0:23:08.31,0:23:12.01,yin,,0,0,0,, 我将要复制粘贴 \\N{\\fs12}So I’m just going to copy and paste here.\r\nDialogue: 0,0:23:12.01,0:23:14.89,yin,,0,0,0,, 也许没必要复制粘贴 \\N{\\fs12}You know, it probably not necessary to copy and paste\r\nDialogue: 0,0:23:14.89,0:23:17.96,yin,,0,0,0,, 因为键入时 它会自动补全 \\N{\\fs12}because if you just start typing this, it’s going to complete it,\r\nDialogue: 0,0:23:17.96,0:23:20.72,yin,,0,0,0,, 其它方法中 我会展示这个的 \\N{\\fs12}we’ll do that with the other method just to show you that one.\r\nDialogue: 0,0:23:20.72,0:23:24.12,yin,,0,0,0,, 然后 我们都知道我们做了这个奇怪的事 \\N{\\fs12}And then we all know that we do this weird thing here,\r\nDialogue: 0,0:23:24.12,0:23:25.94,yin,,0,0,0,,self = [super init]\\N{\\fs12}self equals super init.\r\nDialogue: 0,0:23:25.94,0:23:29.26,yin,,0,0,0,, 这是我们类的指定初始化器 \\N{\\fs12}Now, this is our classes designated initializer,\r\nDialogue: 0,0:23:29.26,0:23:31.88,yin,,0,0,0,, 换句话说 你需要调用这个初始化器 \\N{\\fs12}in other words, you have to call this initializer\r\nDialogue: 0,0:23:31.88,0:23:34.60,yin,,0,0,0,, 否则我们的类将无法正常初始化 \\N{\\fs12}or our class will not be properly initialized,\r\nDialogue: 0,0:23:34.60,0:23:37.86,yin,,0,0,0,, 我们可以有其它能调用这个的初始化器 \\N{\\fs12}we can have other initializers that could call this one, okay,\r\nDialogue: 0,0:23:37.86,0:23:40.18,yin,,0,0,0,, 如果有方法能够默认设置这些 \\N{\\fs12}if there were ways to default things or whatever.\r\nDialogue: 0,0:23:40.18,0:23:41.90,yin,,0,0,0,, 这里没有办法默认设置 \\N{\\fs12}There is no way to do that, default it,\r\nDialogue: 0,0:23:41.90,0:23:44.52,yin,,0,0,0,, 所以这个必须是我们的指定初始化器 \\N{\\fs12}so this has to be our designated initializer, so,\r\nDialogue: 0,0:23:44.52,0:23:47.93,yin,,0,0,0,, 我将在公共头文件中加一段注释 \\N{\\fs12}I’m actually going to put a comment in my public header file\r\nDialogue: 0,0:23:47.94,0:23:50.97,yin,,0,0,0,, 注明这是我的指定初始化器 \\N{\\fs12}saying this is my designated initializer.\r\nDialogue: 0,0:23:50.97,0:23:53.90,yin,,0,0,0,, 这样任何为 CardMatchingGame 编写子类的人 \\N{\\fs12}That way if anyone ever subclassed my card matching game,\r\nDialogue: 0,0:23:53.90,0:23:56.53,yin,,0,0,0,, 就知道在他们的指定初始化器中 \\N{\\fs12}they would know that in their designating initializer,\r\nDialogue: 0,0:23:56.53,0:24:00.00,yin,,0,0,0,, 他们需要调用 super 我们的指定初始化器 \\N{\\fs12}they’d have to call super, our designated initializer.\r\nDialogue: 0,0:24:00.00,0:24:02.06,yin,,0,0,0,, 这就是指定初始化器的工作方式 \\N{\\fs12}Okay, that’s the way designated initializers work.\r\nDialogue: 0,0:24:02.06,0:24:04.43,yin,,0,0,0,, 你需要从你的指定初始化器 \\N{\\fs12}You have to call your super designated initializer\r\nDialogue: 0,0:24:04.43,0:24:06.43,yin,,0,0,0,, 调用你的 super 指定初始化器 \\N{\\fs12}from your designated initializer.\r\nDialogue: 0,0:24:07.04,0:24:07.75,yin,,0,0,0,, 有问题 \\N{\\fs12}Question?\r\nDialogue: 0,0:24:11.34,0:24:14.02,yin,,0,0,0,, 指定初始化器吗 不 编译器不知道 \\N{\\fs12}Designated initializer? No, the compiler does not know.\r\nDialogue: 0,0:24:14.02,0:24:17.69,yin,,0,0,0,, 这纯粹是注释 它类似于这类注释 \\N{\\fs12}This is a purely commented thing, it’s similar to this kind of comment thing.\r\nDialogue: 0,0:24:17.69,0:24:21.06,yin,,0,0,0,, 很不幸 编译器不知道 没有关键字说 \\N{\\fs12}It’s unfortunate that the compiler does not, there’s no key word or anything\r\nDialogue: 0,0:24:21.06,0:24:23.44,yin,,0,0,0,, 这是我的指定初始化器 \\N{\\fs12}that says this is my designated initializer.\r\nDialogue: 0,0:24:23.44,0:24:25.68,yin,,0,0,0,, 你的问题提得早些 \\N{\\fs12}You had a question first here?\r\nDialogue: 0,0:24:25.68,0:24:27.51,yin,,0,0,0,, 好 你讲 \\N{\\fs12}Okay, question?\r\nDialogue: 0,0:24:40.29,0:24:43.24,yin,,0,0,0,, 你可以跟进我讲的 我不大理解你的问题 \\N{\\fs12}Well, follow up with me, I don’t understand the question.\r\nDialogue: 0,0:24:43.24,0:24:45.77,yin,,0,0,0,, 如果有其它初始化器 我猜 \\N{\\fs12}If you have other initializers, I guess the,\r\nDialogue: 0,0:24:45.77,0:24:50.51,yin,,0,0,0,, 你的问题是我怎样禁用另一个初始化器吗 \\N{\\fs12}your question is how do I disable another initializer?\r\nDialogue: 0,0:24:57.30,0:24:59.72,yin,,0,0,0,, 对 哦 我知道你是什么意思了 \\N{\\fs12}Right. Oh, I see what you mean.\r\nDialogue: 0,0:24:59.72,0:25:03.12,yin,,0,0,0,, 问题是 我能否有另一个初始化器 \\N{\\fs12}Yeah, you, okay, so the question is could I have another\r\nDialogue: 0,0:25:03.12,0:25:05.24,yin,,0,0,0,, 指定初始化器 不是公共的 \\N{\\fs12}initializer, designating initializer not be public\r\nDialogue: 0,0:25:05.24,0:25:07.62,yin,,0,0,0,, 而是私有的 再让事物调用它 \\N{\\fs12}or something be private and have things call from it?\r\nDialogue: 0,0:25:07.62,0:25:09.31,yin,,0,0,0,, 当然 你可以那样做 \\N{\\fs12}Yeah, you absolutely could do that,\r\nDialogue: 0,0:25:09.31,0:25:12.27,yin,,0,0,0,, 只是 如果你让指定初始化器不是公共的 \\N{\\fs12}although if you make your designating initializer not public,\r\nDialogue: 0,0:25:12.27,0:25:13.89,yin,,0,0,0,, 那么子类就不知道它 \\N{\\fs12}then subclasses don’t know about it\r\nDialogue: 0,0:25:13.89,0:25:16.21,yin,,0,0,0,, 因为 Objective-C 中没有 protected\\N{\\fs12}because there’s no protected in objective-C,\r\nDialogue: 0,0:25:16.21,0:25:18.69,yin,,0,0,0,, 所以任何子类需要的东西都要设为公共的 \\N{\\fs12}so anything subclassers need has to be made public\r\nDialogue: 0,0:25:18.69,0:25:19.82,yin,,0,0,0,, 来让它们看到它 \\N{\\fs12}for them to see it,\r\nDialogue: 0,0:25:19.82,0:25:22.15,yin,,0,0,0,, 它仍在那里 仍然能够创建它的子类 \\N{\\fs12}it’s still there, they can still subclass it,\r\nDialogue: 0,0:25:22.16,0:25:23.88,yin,,0,0,0,, 但要子类知道它 \\N{\\fs12}but, you know, to document it you want it,\r\nDialogue: 0,0:25:23.88,0:25:26.19,yin,,0,0,0,, 你需要把它放到公共 API 中 \\N{\\fs12}you have to put it in your public API.\r\nDialogue: 0,0:25:26.19,0:25:29.13,yin,,0,0,0,, 对 整个初始化器问题在 Objective-C 中 \\N{\\fs12}So. Yeah, the whole thing with initializers in objective-C is less\r\nDialogue: 0,0:25:29.13,0:25:32.09,yin,,0,0,0,, 并没有很好地得到语言的支持 \\N{\\fs12}than nicely supported by the language.\r\nDialogue: 0,0:25:32.09,0:25:33.51,yin,,0,0,0,, 请讲 \\N{\\fs12}Question?\r\nDialogue: 0,0:25:39.36,0:25:42.65,yin,,0,0,0,, 问题是 这里是否可以 \\N{\\fs12}Yeah, so the question is would it make sense here to,\r\nDialogue: 0,0:25:42.65,0:25:47.11,yin,,0,0,0,, 实现 init 在这里 \\N{\\fs12}for me to implement an init here, right?\r\nDialogue: 0,0:25:47.11,0:25:48.49,yin,,0,0,0,, 来做点什么 \\N{\\fs12}To do something.\r\nDialogue: 0,0:25:48.49,0:25:52.10,yin,,0,0,0,, 也许重写 init 也是可以的 \\N{\\fs12}And actually it might well make sense to override an init,\r\nDialogue: 0,0:25:52.10,0:25:53.51,yin,,0,0,0,, 你知道怎么做吗 \\N{\\fs12}and you know what you would do?\r\nDialogue: 0,0:25:53.51,0:25:55.16,yin,,0,0,0,, 返回 nil\\N{\\fs12}Return nil.\r\nDialogue: 0,0:25:55.17,0:25:58.46,yin,,0,0,0,, 因为如果你使用 [CardMatchingGame alloc] init\\N{\\fs12}Because if you do card matching game alloc init,\r\nDialogue: 0,0:25:58.46,0:26:00.15,yin,,0,0,0,, 它没有适当初始化 \\N{\\fs12}it’s not properly initialized\r\nDialogue: 0,0:26:00.15,0:26:04.69,yin,,0,0,0,, 而且纸牌数或牌堆没有默认值 所以返回 nil\\N{\\fs12}and there’s no default for the number of cards or the deck, so return nil.\r\nDialogue: 0,0:26:04.69,0:26:07.07,yin,,0,0,0,, 对 答案是肯定的 你可以 \\N{\\fs12}So, yeah, so the answer is yeah you could.\r\nDialogue: 0,0:26:07.07,0:26:09.43,yin,,0,0,0,, 好 回到我们的指定初始化器 \\N{\\fs12}Alright, so just back to our designating initializer,\r\nDialogue: 0,0:26:09.43,0:26:12.30,yin,,0,0,0,, 我们需要调用 super 的指定初始化器 \\N{\\fs12}we need to call our supers designating initializer,\r\nDialogue: 0,0:26:12.30,0:26:14.71,yin,,0,0,0,, 对于 NSObject 这是 init\\N{\\fs12}which for NSObject is an init.\r\nDialogue: 0,0:26:14.71,0:26:15.67,yin,,0,0,0,, 没有参数 \\N{\\fs12}No arguments.\r\nDialogue: 0,0:26:15.67,0:26:18.89,yin,,0,0,0,, 然后我们可以说 if (self)\\N{\\fs12}Then we just say if self,\r\nDialogue: 0,0:26:18.90,0:26:21.72,yin,,0,0,0,, 这时我们可以初始化我们自己 \\N{\\fs12}then we can initialize ourselves\r\nDialogue: 0,0:26:21.72,0:26:23.36,yin,,0,0,0,, 然后返回 self\\N{\\fs12}and then we’re going to return self.\r\nDialogue: 0,0:26:23.36,0:26:28.26,yin,,0,0,0,, 如果这里任何情况出现错误 我们将把 self 设为 nil\\N{\\fs12}And if anything goes wrong in here, we will set self equal to nil.\r\nDialogue: 0,0:26:28.26,0:26:30.22,yin,,0,0,0,, 从这里跳出来 \\N{\\fs12}Okay, and break out of this thing.\r\nDialogue: 0,0:26:30.22,0:26:33.23,yin,,0,0,0,, 实际上 你们会看到 这里确实会出错 \\N{\\fs12}And, in fact, something is going to go in wrong in here, as you will see.\r\nDialogue: 0,0:26:33.23,0:26:37.76,yin,,0,0,0,, 我们需要做什么来初始化这里的东西呢 \\N{\\fs12}So, what do we need to do to initialize our thing here?\r\nDialogue: 0,0:26:37.76,0:26:42.98,yin,,0,0,0,, 我们需要从牌堆中抽出这么多张牌 \\N{\\fs12}Well, we need to pull this many cards out of this deck\r\nDialogue: 0,0:26:42.98,0:26:45.97,yin,,0,0,0,, 将它放入我们的内部数据结构中 \\N{\\fs12}and put it in our internal data structure here.\r\nDialogue: 0,0:26:45.97,0:26:48.05,yin,,0,0,0,, 怎么做到呢 \\N{\\fs12}Alright? So how do we do that?\r\nDialogue: 0,0:26:48.05,0:26:56.21,yin,,0,0,0,, 这样做 for (int i = 0; i < count; i++)\\N{\\fs12}How about for int i equals 0, i is less than count, i plus, plus,\r\nDialogue: 0,0:26:56.21,0:26:59.18,yin,,0,0,0,, 这能让我遍历这么多个事物 \\N{\\fs12}so that’s just me going through this many of these things.\r\nDialogue: 0,0:26:59.18,0:27:02.51,yin,,0,0,0,, 下面是 Card *card =\\N{\\fs12}I’m going to say card star card equals\r\nDialogue: 0,0:27:02.51,0:27:05.57,yin,,0,0,0,,[deck drawRandomCard]\\N{\\fs12}deck, draw random card,\r\nDialogue: 0,0:27:05.57,0:27:07.39,yin,,0,0,0,, 这是从牌堆随机抽一张牌 \\N{\\fs12}so I’m drawing a random card of the deck,\r\nDialogue: 0,0:27:07.41,0:27:15.14,yin,,0,0,0,, 然后我要说 self.cards[i] = card\\N{\\fs12}and then I’m just going to say self dot cards, sub i, equals card.\r\nDialogue: 0,0:27:15.14,0:27:19.49,yin,,0,0,0,, 我有这个可变数组 它将总是非 nil\\N{\\fs12}So I’ve got this MutableArray, it’s always going to be non-nil.\r\nDialogue: 0,0:27:19.49,0:27:21.73,yin,,0,0,0,, 这完全没问题 \\N{\\fs12}So this is perfectly fine.\r\nDialogue: 0,0:27:21.73,0:27:23.80,yin,,0,0,0,, 不过这里有一个问题 \\N{\\fs12}There’s one problem here though.\r\nDialogue: 0,0:27:23.80,0:27:26.44,yin,,0,0,0,, 如果牌用完了会怎样 \\N{\\fs12}What if we run out of cards?\r\nDialogue: 0,0:27:26.44,0:27:29.20,yin,,0,0,0,, 如果传递一副扑克牌到这里 \\N{\\fs12}What if you pass a playing card deck here\r\nDialogue: 0,0:27:29.20,0:27:32.69,yin,,0,0,0,, 然后你说要 100 张牌用于游戏 \\N{\\fs12}and you say 100 cards for your game.\r\nDialogue: 0,0:27:32.69,0:27:35.52,yin,,0,0,0,, 这最终会返回 nil\\N{\\fs12}This is going to eventually return nil.\r\nDialogue: 0,0:27:35.52,0:27:36.83,yin,,0,0,0,, 牌不够 \\N{\\fs12}Okay, and run out of cards.\r\nDialogue: 0,0:27:36.83,0:27:40.58,yin,,0,0,0,, 所以这里我们要检验说 if (card)\\N{\\fs12}So we should check here and say if card,\r\nDialogue: 0,0:27:40.58,0:27:43.60,yin,,0,0,0,, 然后再做我们一般要做的事 \\N{\\fs12}then we’ll do what we normally do,\r\nDialogue: 0,0:27:43.60,0:27:46.30,yin,,0,0,0,, 否则 self = nil\\N{\\fs12}otherwise, self equals nil,\r\nDialogue: 0,0:27:46.30,0:27:50.10,yin,,0,0,0,, 并从 for 循环中跳出 \\N{\\fs12}break out of that for loop because we’re dead.\r\nDialogue: 0,0:27:51.17,0:27:52.51,yin,,0,0,0,, 有问题 \\N{\\fs12}Question?\r\nDialogue: 0,0:28:00.44,0:28:05.62,yin,,0,0,0,, 问题是 cards 中还没有任何东西时 我在这一行代码中 \\N{\\fs12}So the question is how can I access cards here to set it, in this line of\r\nDialogue: 0,0:28:05.62,0:28:07.99,yin,,0,0,0,, 是怎样访问 cards 来设置它的 \\N{\\fs12}code, when I haven’t put anything in the cards?\r\nDialogue: 0,0:28:07.99,0:28:12.80,yin,,0,0,0,,cards 最开始时是 nil 然后当我调用 getter 时 \\N{\\fs12}Well, cards starts out as nil, and then when I call the getter,\r\nDialogue: 0,0:28:12.80,0:28:16.22,yin,,0,0,0,, 这里 self.cards 是 getter 这会初始化它 \\N{\\fs12}self dot cards right here is the getter, it’s going to initialize it\r\nDialogue: 0,0:28:16.22,0:28:19.08,yin,,0,0,0,, 得到空数组 但数组可变 \\N{\\fs12}to an empty array, but it’s mutable.\r\nDialogue: 0,0:28:19.08,0:28:23.90,yin,,0,0,0,, 所以我可以在这里添加对象 哦 抱歉 \\N{\\fs12}So I can add objects here, Actually, oh I’m sorry.\r\nDialogue: 0,0:28:23.90,0:28:26.39,yin,,0,0,0,, 这里你是对的 不过这也没问题 \\N{\\fs12}You’re right about that, yeah, well, this is fine too,\r\nDialogue: 0,0:28:26.39,0:28:29.91,yin,,0,0,0,, 也许更好的做法是 self.cards\\N{\\fs12}but maybe a better way to do this is to say self dot cards\r\nDialogue: 0,0:28:29.91,0:28:33.17,yin,,0,0,0,,addObject:card 这样更清楚一些 \\N{\\fs12}add object card, because that’s a little clearer.\r\nDialogue: 0,0:28:33.17,0:28:35.92,yin,,0,0,0,, 也许你是对的 我的做法可能无法工作 \\N{\\fs12}In fact, you might be right, that wouldn’t have worked.\r\nDialogue: 0,0:28:35.92,0:28:40.47,yin,,0,0,0,, 这是更好的做法 将纸牌加到牌堆中 \\N{\\fs12}So, this is a better way to do it, we just add cards to the deck.\r\nDialogue: 0,0:28:40.47,0:28:41.79,yin,,0,0,0,, 好了吗 \\N{\\fs12}Make sense?\r\nDialogue: 0,0:28:41.79,0:28:44.58,yin,,0,0,0,, 抱歉 之前我的那个不怎么好 \\N{\\fs12}Sorry about that, I had a little different one.\r\nDialogue: 0,0:28:44.58,0:28:47.26,yin,,0,0,0,, 实际上 我不知道之前那个能否工作 \\N{\\fs12}And actually I’m not sure if that would work,\r\nDialogue: 0,0:28:47.26,0:28:49.80,yin,,0,0,0,, 我来想想 你说的是插入对象 \\N{\\fs12}let me think about that, so you’re saying insert object,\r\nDialogue: 0,0:28:49.80,0:28:51.44,yin,,0,0,0,, 这可能也能工作 \\N{\\fs12}yeah, that, actually that probably would work too.\r\nDialogue: 0,0:28:51.44,0:28:54.24,yin,,0,0,0,, 因为你做的是在某下标处插入对象 \\N{\\fs12}Because you’d be doing insert object at index, it wouldn’t be,\r\nDialogue: 0,0:28:54.24,0:28:56.92,yin,,0,0,0,, 这会是在数组最后 这也许也能行 \\N{\\fs12}you know, it would be just at the end of the array, that would probably work too.\r\nDialogue: 0,0:28:56.92,0:28:58.22,yin,,0,0,0,, 两种方式都行 \\N{\\fs12}So you could do it either way.\r\nDialogue: 0,0:28:58.22,0:29:01.62,yin,,0,0,0,, 因为 self.cards[i] 这里的下标 i\\N{\\fs12}Because self dot cards sub i, that sub i thing,\r\nDialogue: 0,0:29:01.62,0:29:03.96,yin,,0,0,0,, 调用的是一个方法 insertObject\\N{\\fs12}it’s really just calling a method, insert object\r\nDialogue: 0,0:29:03.96,0:29:06.30,yin,,0,0,0,,atIndex 在特定下标处插入 \\N{\\fs12}at substring index, that’s what the method is calling.\r\nDialogue: 0,0:29:06.30,0:29:09.30,yin,,0,0,0,, 你可以参考说明文档 看这里调用的方法名称 \\N{\\fs12}You can look at the documentation to see the name the method is calling there,\r\nDialogue: 0,0:29:09.30,0:29:13.27,yin,,0,0,0,, 如果是在数组最后的下标处插入对象 我想这能行 \\N{\\fs12}but if you insert object at index and it’s at the end of the array, I believe that’ll work.\r\nDialogue: 0,0:29:13.27,0:29:16.64,yin,,0,0,0,, 但如果是在下标 500 处 这也许就行不通了 \\N{\\fs12}But if you do it at 500, that’s not going to work.\r\nDialogue: 0,0:29:16.64,0:29:19.58,yin,,0,0,0,, 因为数组只能逐渐增长 我这么认为 \\N{\\fs12}Because it can only grow the array as you go, I believe.\r\nDialogue: 0,0:29:19.58,0:29:20.70,yin,,0,0,0,, 请讲 \\N{\\fs12}Question?\r\nDialogue: 0,0:29:23.17,0:29:25.25,yin,,0,0,0,, 问题是 能否将不同类型的对象 \\N{\\fs12}So the question is can I put different kinds of objects\r\nDialogue: 0,0:29:25.25,0:29:27.53,yin,,0,0,0,, 加到相同数组中 答案是当然可以 \\N{\\fs12}in the same array and the answer is absolutely.\r\nDialogue: 0,0:29:27.53,0:29:30.38,yin,,0,0,0,, 我们有时确实也会这样做 \\N{\\fs12}You can and we do, occasionally, and we’ll talk\r\nDialogue: 0,0:29:30.38,0:29:32.49,yin,,0,0,0,, 周三我会讲到如何处理这个 \\N{\\fs12}about on Wednesday how you deal with that.\r\nDialogue: 0,0:29:32.49,0:29:34.41,yin,,0,0,0,, 考虑该如何处理 \\N{\\fs12}Right? How, how we manage the fact\r\nDialogue: 0,0:29:34.41,0:29:35.98,yin,,0,0,0,, 不同类型的对象在这里 \\N{\\fs12}that we have different kinds of objects in there,\r\nDialogue: 0,0:29:35.98,0:29:38.39,yin,,0,0,0,, 你讲得没错 这完全合法 \\N{\\fs12}but yes, absolutely, perfectly legal.\r\nDialogue: 0,0:29:39.73,0:29:41.16,yin,,0,0,0,, 好 这是这个 \\N{\\fs12}Alright. So there’s that.\r\nDialogue: 0,0:29:41.16,0:29:45.85,yin,,0,0,0,, 我说过 我们还可以在最开始这里说 \\N{\\fs12}And, again, as I said, we could probably say at the beginning here,\r\nDialogue: 0,0:29:45.86,0:29:47.45,yin,,0,0,0,,if (self)\\N{\\fs12}if self,\r\nDialogue: 0,0:29:47.45,0:29:51.67,yin,,0,0,0,, 我们还可以有 if count <2\\N{\\fs12}we could also have an if count is less than two, right?\r\nDialogue: 0,0:29:51.67,0:29:55.51,yin,,0,0,0,, 这时返回 nil 我们也可以检验这个 \\N{\\fs12}Then return nil, we could do that, check that, as well.\r\nDialogue: 0,0:29:56.97,0:29:59.20,yin,,0,0,0,, 好 我们再来看一些别的方法 \\N{\\fs12}Okay, let’s do some of our other methods here.\r\nDialogue: 0,0:29:59.20,0:30:01.05,yin,,0,0,0,, 来看 chooseCardAtIndex\\N{\\fs12}How about choose card at index.\r\nDialogue: 0,0:30:01.05,0:30:03.41,yin,,0,0,0,, 我们先来看 cardAtIndex 吧 \\N{\\fs12}Actually let’s do card at index.\r\nDialogue: 0,0:30:03.41,0:30:05.23,yin,,0,0,0,, 因为 cardAtIndex 超级简单 \\N{\\fs12}Because card at index is super easy.\r\nDialogue: 0,0:30:05.23,0:30:08.81,yin,,0,0,0,, 这里是 Card * 注意当我键入时 \\N{\\fs12}Right? This is card star, and notice if I start to type here,\r\nDialogue: 0,0:30:08.81,0:30:10.96,yin,,0,0,0,, 它知道这是 cardAtIndex\\N{\\fs12}it knows that its card index\r\nDialogue: 0,0:30:10.97,0:30:14.26,yin,,0,0,0,, 它会自动补全 点 Tab 键就行了 \\N{\\fs12}so it’s going complete that, I press tab to get there,\r\nDialogue: 0,0:30:14.26,0:30:18.10,yin,,0,0,0,, 这个只是返回 self.cards[index]\\N{\\fs12}and this one it just returns self dot cards sub index.\r\nDialogue: 0,0:30:18.10,0:30:21.09,yin,,0,0,0,, 但是 你知道 这是一个公共方法 \\N{\\fs12}But, you know, this is a public method.\r\nDialogue: 0,0:30:21.09,0:30:24.19,yin,,0,0,0,, 如果有人传递了糟糕的 index 怎么办 \\N{\\fs12}What happens if someone passes a bad index there?\r\nDialogue: 0,0:30:24.19,0:30:26.71,yin,,0,0,0,, 例如大于 count 的 index\\N{\\fs12}An index that’s greater than the count.\r\nDialogue: 0,0:30:26.71,0:30:29.15,yin,,0,0,0,, 我们这里会崩溃掉吗 \\N{\\fs12}Are we just going to go ahead and crash here?\r\nDialogue: 0,0:30:29.15,0:30:33.56,yin,,0,0,0,, 有些人认为这很好 因为能够帮我们找 bug\\N{\\fs12}One could argue that might be good, because we’ll help find the bug.\r\nDialogue: 0,0:30:33.56,0:30:36.15,yin,,0,0,0,, 显然 这里有某种 assertion 会更好 \\N{\\fs12}Certainly some kind of assertion in here would be good,\r\nDialogue: 0,0:30:36.15,0:30:37.65,yin,,0,0,0,, 我以后会讲到这个 \\N{\\fs12}we’ll talk about that later,\r\nDialogue: 0,0:30:37.65,0:30:43.14,yin,,0,0,0,, 不过这里我将加一些保护 也就是 \\N{\\fs12}but I’m actually just going to protect myself against it by saying if self,\r\nDialogue: 0,0:30:43.14,0:30:48.19,yin,,0,0,0,, 如果这个 index 小于 self.cards count\\N{\\fs12}if this index is less than self dot cards count,\r\nDialogue: 0,0:30:48.19,0:30:50.04,yin,,0,0,0,, 我就返回 \\N{\\fs12}then I’ll return.\r\nDialogue: 0,0:30:50.04,0:30:53.02,yin,,0,0,0,, 否则… 噢 \\N{\\fs12}Otherwise, oops,\r\nDialogue: 0,0:30:53.04,0:30:57.72,yin,,0,0,0,,if… 我还是用传统的? 方式吧 \\N{\\fs12}if, actually we’ll do it this way, use the old question mark.\r\nDialogue: 0,0:30:57.72,0:31:00.78,yin,,0,0,0,, 有些人曾问过这个 \\N{\\fs12}Some people were asking about this.\r\nDialogue: 0,0:31:00.78,0:31:02.93,yin,,0,0,0,, 返回 问号 nil\\N{\\fs12}Return question mark nil,\r\nDialogue: 0,0:31:02.93,0:31:06.12,yin,,0,0,0,, 大家都知道这种问号冒号 C 语言做法吗 \\N{\\fs12}everyone know this question mark colon c thing,\r\nDialogue: 0,0:31:06.12,0:31:10.33,yin,,0,0,0,, 这完全是非对象的 C 语言做法 对吧 \\N{\\fs12}this is totally a c thing, nonobjective c thing, alright?\r\nDialogue: 0,0:31:10.33,0:31:11.95,yin,,0,0,0,, 就像 if then 一样 \\N{\\fs12}Just like an if then.\r\nDialogue: 0,0:31:11.95,0:31:12.94,yin,,0,0,0,, 有问题 \\N{\\fs12}Yeah, question?\r\nDialogue: 0,0:31:12.94,0:31:17.51,yin,,0,0,0,, 学生：[声音不清] 带有这些方法的数组访问 \\N{\\fs12}> So [inaudible], how does array access with these methods\r\nDialogue: 0,0:31:17.51,0:31:21.30,yin,,0,0,0,, 如何让可变数组在没有保护下工作 \\N{\\fs12}for the MutableArray to work without that index, if you, or without the guard,\r\nDialogue: 0,0:31:21.30,0:31:24.01,yin,,0,0,0,, 要是传递一个大的下标 它不会崩溃吗 \\N{\\fs12}if you pass the large index, would it necessarily crash or would?\r\nDialogue: 0,0:31:24.01,0:31:25.75,yin,,0,0,0,, 老师：好 问题是 \\N{\\fs12}> Yeah. So the question is,\r\nDialogue: 0,0:31:25.75,0:31:29.37,yin,,0,0,0,, 如果这里传递太大的下标 是否会崩溃 \\N{\\fs12}what if I pass too large an index here, would this crash?\r\nDialogue: 0,0:31:29.37,0:31:31.89,yin,,0,0,0,, 它会 而且异常将是数组下标越界 \\N{\\fs12}And it would, and what would happen is it would crash\r\nDialogue: 0,0:31:31.89,0:31:34.37,yin,,0,0,0,, 它会 而且异常将是数组下标越界 \\N{\\fs12}with the exception array index out of bounds.\r\nDialogue: 0,0:31:35.96,0:31:37.48,yin,,0,0,0,, 不 不 它会崩溃 \\N{\\fs12}No, no, it would crash, it,\r\nDialogue: 0,0:31:37.48,0:31:39.72,yin,,0,0,0,, 它会引发数组下标越界异常 \\N{\\fs12}raise an exception, array index out of bounds.\r\nDialogue: 0,0:31:39.72,0:31:41.91,yin,,0,0,0,,NSArray 类会引发这一异常 \\N{\\fs12}NSArray class would raise that exception,\r\nDialogue: 0,0:31:41.91,0:31:44.53,yin,,0,0,0,, 我们会谈到异常引发机制的 \\N{\\fs12}and we’ll talk about raising exceptions.\r\nDialogue: 0,0:31:44.53,0:31:47.85,yin,,0,0,0,, 现在 直到周五考虑调试之前 \\N{\\fs12}For now, until you go to this debugging thing, maybe on Friday,\r\nDialogue: 0,0:31:47.87,0:31:51.98,yin,,0,0,0,, 你将只会看到异常出现在控制台中 \\N{\\fs12}for now, you’re just going to see exceptions like that happen on your console,\r\nDialogue: 0,0:31:51.98,0:31:55.29,yin,,0,0,0,, 它甚至不会停在异常发生的地方 这很不幸 \\N{\\fs12}it’s not even going to stop where the exception happened, which is unfortunate,\r\nDialogue: 0,0:31:55.29,0:31:58.39,yin,,0,0,0,, 不过讲调试时 我会讲到如何让它停止 \\N{\\fs12}but that debugging session, we’ll talk about how to make it stop there,\r\nDialogue: 0,0:31:58.39,0:32:01.18,yin,,0,0,0,, 不过这就是会发生的情况 会引发异常 \\N{\\fs12}but that’s what’s going to happen, it’s going to raise an exception.\r\nDialogue: 0,0:32:01.18,0:32:04.23,yin,,0,0,0,, 这是 cardAtIndex 非常非常简单 \\N{\\fs12}So that’s card at index, really, really easy.\r\nDialogue: 0,0:32:04.23,0:32:07.82,yin,,0,0,0,, 下面再看另一个 即 chooseCardAtIndex\\N{\\fs12}And now let’s talk about this other one, choose card at index.\r\nDialogue: 0,0:32:07.82,0:32:10.19,yin,,0,0,0,, 这是我们逻辑的核心 \\N{\\fs12}This is really the heart of our logic.\r\nDialogue: 0,0:32:10.19,0:32:11.87,yin,,0,0,0,, 因为这里是选牌的地方 \\N{\\fs12}Because here’s where you’re choosing the cards,\r\nDialogue: 0,0:32:11.87,0:32:15.14,yin,,0,0,0,, 这是匹配和得分实际发生的地方 \\N{\\fs12}here’s where the matching actually has to happen, in the scoring.\r\nDialogue: 0,0:32:15.14,0:32:19.02,yin,,0,0,0,, 所以我们的整个逻辑都将发生在这个方法中 \\N{\\fs12}So this is basically our entire logic is going to be in this method.\r\nDialogue: 0,0:32:19.02,0:32:20.67,yin,,0,0,0,, 这里需要什么呢 \\N{\\fs12}So what do we need here?\r\nDialogue: 0,0:32:20.67,0:32:22.36,yin,,0,0,0,, 玩家会选一张牌 \\N{\\fs12}Well, they’re choosing a card,\r\nDialogue: 0,0:32:22.36,0:32:24.62,yin,,0,0,0,, 让我们获得玩家所选的牌 \\N{\\fs12}so let’s get the card they chose, and I’m going\r\nDialogue: 0,0:32:24.62,0:32:30.70,yin,,0,0,0,, 我将调用 self cardAtIndex 来获得这张牌 \\N{\\fs12}to call self card at index, to get that card.\r\nDialogue: 0,0:32:30.70,0:32:36.08,yin,,0,0,0,, 这样我就有了玩家所选的这张牌 \\N{\\fs12}Okay, so now I have the card that they, they’re choosing here.\r\nDialogue: 0,0:32:36.08,0:32:40.50,yin,,0,0,0,, 如果玩家所选的牌已经同另一张牌相匹配 \\N{\\fs12}Now, if a card that they chose has already been matched against another card,\r\nDialogue: 0,0:32:40.50,0:32:41.91,yin,,0,0,0,, 这里就什么都不用做 \\N{\\fs12}then I’m going to do nothing here.\r\nDialogue: 0,0:32:41.91,0:32:45.45,yin,,0,0,0,, 当玩家去选已经匹配过的牌时 我将忽略玩家的行为 \\N{\\fs12}I’m going to ignore when you try to choose a card that’s already been matched,\r\nDialogue: 0,0:32:45.45,0:32:47.22,yin,,0,0,0,, 当玩家去选已经匹配过的牌时 我将忽略玩家的行为 \\N{\\fs12}successfully matched with another card,\r\nDialogue: 0,0:32:47.22,0:32:49.81,yin,,0,0,0,, 这里我要的是 \\N{\\fs12}so I’m just going to say here,\r\nDialogue: 0,0:32:49.82,0:32:55.74,yin,,0,0,0,,if (card.isMatched)\\N{\\fs12}if card is matched,\r\nDialogue: 0,0:32:55.74,0:32:59.85,yin,,0,0,0,, 我要说的应该是 if (!card.isMatched)\\N{\\fs12}and actually I’ll just say if not card matched,\r\nDialogue: 0,0:32:59.85,0:33:02.53,yin,,0,0,0,, 我们会做点什么 否则我们什么都不做 \\N{\\fs12}we’ll do something, otherwise we’ll just do nothing.\r\nDialogue: 0,0:33:02.53,0:33:07.62,yin,,0,0,0,, 只在你选的牌没有已经匹配过时 \\N{\\fs12}So I’m only going to match these cards if, or only going\r\nDialogue: 0,0:33:07.62,0:33:12.88,yin,,0,0,0,, 我们才会尝试去匹配两张你选的牌 \\N{\\fs12}to try and match two chosen cards if the card you just chose is not already matched.\r\nDialogue: 0,0:33:12.88,0:33:15.31,yin,,0,0,0,, 大家都明白了为什么要这样做吗 \\N{\\fs12}Does that make sense? Does everyone see why we do that?\r\nDialogue: 0,0:33:15.31,0:33:18.13,yin,,0,0,0,, 已经匹配过的 就不能再同别的牌匹配了 \\N{\\fs12}It’s already matched, you can’t match it against another one.\r\nDialogue: 0,0:33:18.13,0:33:22.63,yin,,0,0,0,, 然后的问题是 如果纸牌已经被选 \\N{\\fs12}So now the question is if the card is already chosen,\r\nDialogue: 0,0:33:22.63,0:33:24.64,yin,,0,0,0,, 那我将怎么做呢 \\N{\\fs12}then what am I going to do?\r\nDialogue: 0,0:33:24.64,0:33:27.76,yin,,0,0,0,, 这时我将把纸牌翻回去 取消选择 \\N{\\fs12}Then I’m actually going to flip the card back over, un-choose it,\r\nDialogue: 0,0:33:27.76,0:33:33.51,yin,,0,0,0,, 所以这里我说 card.chosen = NO\\N{\\fs12}so I’m going to say card dot is, dot chosen, rather, equals no.\r\nDialogue: 0,0:33:33.51,0:33:35.95,yin,,0,0,0,, 如果选择了已经选过的牌 \\N{\\fs12}So if you’d pick the card that’s already chosen\r\nDialogue: 0,0:33:35.95,0:33:38.87,yin,,0,0,0,, 两次选择 等于取消选择 \\N{\\fs12}and you choose it again, it’s going to un-choose it.\r\nDialogue: 0,0:33:38.87,0:33:40.16,yin,,0,0,0,, 这是一种开关 \\N{\\fs12}So it’s kind of a toggle.\r\nDialogue: 0,0:33:40.16,0:33:42.67,yin,,0,0,0,, 选牌是在选择和未选择之间来回切换 \\N{\\fs12}Choosing a card is kind of a toggle thing, on and off.\r\nDialogue: 0,0:33:42.67,0:33:44.95,yin,,0,0,0,, 注意我们有 getter isChosen\\N{\\fs12}Notice that we have the getter is chosen,\r\nDialogue: 0,0:33:44.95,0:33:46.72,yin,,0,0,0,, 记得吧 我们在头文件中改名过 \\N{\\fs12}remember we renamed it in our header file,\r\nDialogue: 0,0:33:46.72,0:33:48.46,yin,,0,0,0,, 通过 getter = isChosen\\N{\\fs12}with that getter equals is chosen,\r\nDialogue: 0,0:33:48.46,0:33:52.13,yin,,0,0,0,, 但 setter 不用 isChosen\\N{\\fs12}but the setter, okay, we don’t use the is chosen.\r\nDialogue: 0,0:33:52.13,0:33:56.00,yin,,0,0,0,,setter 仍然是 chosen chosen 是属性名 \\N{\\fs12}The setter is still chosen. Chosen is the name of the property.\r\nDialogue: 0,0:33:56.00,0:33:57.78,yin,,0,0,0,, 大家都记得吗 \\N{\\fs12}Everyone remember that?\r\nDialogue: 0,0:33:57.78,0:34:00.59,yin,,0,0,0,, 来自 Card 你们需要键入这个 所以请记住 \\N{\\fs12}From card, hopefully, you had to type it in so remember it.\r\nDialogue: 0,0:34:00.59,0:34:03.02,yin,,0,0,0,, 否则 我们到这里 \\N{\\fs12}So otherwise we’re in here\r\nDialogue: 0,0:34:03.02,0:34:05.60,yin,,0,0,0,, 这种情况下 我们选择了一张新纸牌 \\N{\\fs12}and in this case, we’re choosing a new card and we need\r\nDialogue: 0,0:34:05.60,0:34:09.43,yin,,0,0,0,, 我们需要将它同其它纸牌进行匹配 \\N{\\fs12}to match it against other card.\r\nDialogue: 0,0:34:09.43,0:34:12.67,yin,,0,0,0,, 这里写 另一张牌 \\N{\\fs12}Let’s say another card.\r\nDialogue: 0,0:34:12.67,0:34:15.85,yin,,0,0,0,, 我们的匹配游戏只匹配两张牌 \\N{\\fs12}Now our matching game only matches two cards.\r\nDialogue: 0,0:34:15.85,0:34:19.46,yin,,0,0,0,, 你们的作业中 需要扩展到匹配三张牌 \\N{\\fs12}In your homework, you have to extend this game to match it to three cards.\r\nDialogue: 0,0:34:19.46,0:34:21.31,yin,,0,0,0,, 这是你们作业的一部分 \\N{\\fs12}That’s going to be part of your homework assignment,\r\nDialogue: 0,0:34:21.31,0:34:23.47,yin,,0,0,0,, 但这里 我们只匹配另一张牌 \\N{\\fs12}but here we’re only going to match one other card.\r\nDialogue: 0,0:34:23.47,0:34:28.78,yin,,0,0,0,, 所以 这里我只需要检查纸牌数组中的所有其它牌 \\N{\\fs12}So all I need to do here is look through all the other cards in my cards array up here,\r\nDialogue: 0,0:34:28.78,0:34:30.48,yin,,0,0,0,, 在这个内部数据结构中 \\N{\\fs12}alright, this is my internal data structure.\r\nDialogue: 0,0:34:30.48,0:34:34.14,yin,,0,0,0,, 我只需要检查所有这些 看看 \\N{\\fs12}I just need to look through them all and find, and go and see\r\nDialogue: 0,0:34:34.14,0:34:38.74,yin,,0,0,0,, 有没有另一张牌被选了 但没有匹配的 \\N{\\fs12}if there’s another card that is chosen and not matched.\r\nDialogue: 0,0:34:38.74,0:34:42.38,yin,,0,0,0,, 如果有 我将把它同刚选择的这张匹配起来 \\N{\\fs12}And if it is, I’m going to try to match it against this card that was just chosen.\r\nDialogue: 0,0:34:42.38,0:34:44.69,yin,,0,0,0,, 我将搜索所有的牌 \\N{\\fs12}So to search, I’m just going to go through my cards,\r\nDialogue: 0,0:34:44.69,0:34:48.84,yin,,0,0,0,,for (Card *otherCard in self.cards)\\N{\\fs12}for card other card, in self dot cards.\r\nDialogue: 0,0:34:48.84,0:34:50.36,yin,,0,0,0,, 遍历所有其它牌 \\N{\\fs12}And we go through all the other cards,\r\nDialogue: 0,0:34:50.36,0:34:59.01,yin,,0,0,0,, 如果能找到另一张牌 已经被选 而且没被匹配 \\N{\\fs12}and if I can find an other card that is chosen and is not matched,\r\nDialogue: 0,0:34:59.01,0:35:00.78,yin,,0,0,0,, 那就中了 \\N{\\fs12}then bingo!\r\nDialogue: 0,0:35:00.78,0:35:02.45,yin,,0,0,0,, 我找到了另一张牌匹配上 \\N{\\fs12}I found another card to try and match.\r\nDialogue: 0,0:35:02.45,0:35:04.62,yin,,0,0,0,, 这里只能有另外一张 \\N{\\fs12}Now, there can only be one other one,\r\nDialogue: 0,0:35:04.62,0:35:06.78,yin,,0,0,0,, 因为我总是只考虑两张牌的匹配 \\N{\\fs12}because I only do two card matches and I’m always looking\r\nDialogue: 0,0:35:06.78,0:35:09.05,yin,,0,0,0,, 我只检查第二张牌 如果不匹配 \\N{\\fs12}for that second match, so, if it doesn’t match,\r\nDialogue: 0,0:35:09.05,0:35:11.18,yin,,0,0,0,, 我将把它翻回去 取消选择它 \\N{\\fs12}I’m going to flip that, un-choose that other one anyway.\r\nDialogue: 0,0:35:11.18,0:35:12.92,yin,,0,0,0,, 这里我准备好了 \\N{\\fs12}So, I’m ready to go here,\r\nDialogue: 0,0:35:12.92,0:35:16.05,yin,,0,0,0,, 这里只用找到另外一张能进行匹配的牌 \\N{\\fs12}I basically found the only other possible card that can match.\r\nDialogue: 0,0:35:16.05,0:35:19.21,yin,,0,0,0,, 这里如果你要做三张或 n 张牌的匹配 \\N{\\fs12}Now, again, when you do a three card match or an n-card match,\r\nDialogue: 0,0:35:19.21,0:35:22.83,yin,,0,0,0,, 作业中考虑 n 张牌可能会是一个好主意 \\N{\\fs12}if you so choose in your homework, which might be a good idea,\r\nDialogue: 0,0:35:22.83,0:35:24.54,yin,,0,0,0,, 你会找到多张牌 \\N{\\fs12}you might find a number of cards here.\r\nDialogue: 0,0:35:24.54,0:35:26.92,yin,,0,0,0,, 你可能需要用数组这些来收集 \\N{\\fs12}You might have to collect them somehow in array or something\r\nDialogue: 0,0:35:26.92,0:35:29.57,yin,,0,0,0,, 这样你就能将它们进行匹配 但这里 \\N{\\fs12}so you can match them against each other, but here,\r\nDialogue: 0,0:35:29.57,0:35:31.62,yin,,0,0,0,, 我不需要担心这些 \\N{\\fs12}I don’t have to worry about that.\r\nDialogue: 0,0:35:31.62,0:35:34.71,yin,,0,0,0,, 找到了另外这张已经选择的牌 我们来进行匹配 \\N{\\fs12}So I found this other card that’s also chosen, let’s match them.\r\nDialogue: 0,0:35:34.71,0:35:37.75,yin,,0,0,0,, 通过代码 matchScore =\\N{\\fs12}And I’m going to do that by saying match score equals\r\nDialogue: 0,0:35:37.75,0:35:43.53,yin,,0,0,0,, 上面这里玩家所选的牌 card\\N{\\fs12}the card that we chose up here, right? This is the one that the user is choosing.\r\nDialogue: 0,0:35:43.53,0:35:48.01,yin,,0,0,0,,match: 记得吧 这是 Card 中匹配两张牌的方法 \\N{\\fs12}Match colon, remember that’s our method in card that matches two cards.\r\nDialogue: 0,0:35:48.01,0:35:51.31,yin,,0,0,0,, 它的参数是一个数组 \\N{\\fs12}It takes an array though, an array,\r\nDialogue: 0,0:35:51.31,0:35:56.41,yin,,0,0,0,, 我将现场创建一个数组 将另一张牌放入其中 \\N{\\fs12}so I’m going to have make an array on the fly and put the other card in it.\r\nDialogue: 0,0:35:56.41,0:35:59.43,yin,,0,0,0,, 大家都明白这行代码吗 \\N{\\fs12}Everyone understand this line of code?\r\nDialogue: 0,0:35:59.43,0:36:05.76,yin,,0,0,0,, 我在用 Card 中 match 方法将这张牌同这张牌进行匹配 \\N{\\fs12}I’m matching this card against this card using the match method in card.\r\nDialogue: 0,0:36:05.76,0:36:08.76,yin,,0,0,0,, 但我需要现场创建这样一个数组 \\N{\\fs12}But I had to create this little array on the fly\r\nDialogue: 0,0:36:08.76,0:36:12.41,yin,,0,0,0,, 因为 match 实际能够匹配多张牌 这很好 \\N{\\fs12}because match is actually capable of matching multiple cards, which is good\r\nDialogue: 0,0:36:12.41,0:36:14.32,yin,,0,0,0,, 因为你们的作业中需要这个 \\N{\\fs12}because your homework’s going to require that.\r\nDialogue: 0,0:36:14.32,0:36:17.12,yin,,0,0,0,, 但这里我只用考虑一个 所以这里 \\N{\\fs12}But here I’m only doing one, so I just create this little,\r\nDialogue: 0,0:36:17.12,0:36:21.05,yin,,0,0,0,, 只需要一个蓝色 @[] 来创建数组 \\N{\\fs12}blue at sign square brackets thing to create an array.\r\nDialogue: 0,0:36:21.05,0:36:22.76,yin,,0,0,0,, 这里有了这个 match\\N{\\fs12}So now I’ve got this match.\r\nDialogue: 0,0:36:22.76,0:36:26.58,yin,,0,0,0,, 我们定义过 match 的语义 \\N{\\fs12}Now, we’ve defined match, kind of the semantics of match,\r\nDialogue: 0,0:36:26.58,0:36:30.71,yin,,0,0,0,, 如果返回的是非 0 那就有了某种匹配 \\N{\\fs12}are that if it returns non-zero, then there was a match of some sort.\r\nDialogue: 0,0:36:30.71,0:36:33.22,yin,,0,0,0,, 如果返回 0 就没有匹配上 \\N{\\fs12}If it returns zero, no match.\r\nDialogue: 0,0:36:33.22,0:36:35.78,yin,,0,0,0,, 这就是 match: 的意义 \\N{\\fs12}That’s what match colon means.\r\nDialogue: 0,0:36:35.78,0:36:40.20,yin,,0,0,0,, 这就是我们对模型语义的定义 \\N{\\fs12}Okay, that’s what we just defined it that way in the semantics of our model.\r\nDialogue: 0,0:36:40.20,0:36:42.88,yin,,0,0,0,, 也许在 Card.h 中应该加一小段注释 \\N{\\fs12}Probably we should have put a comment in our card dot h\r\nDialogue: 0,0:36:42.88,0:36:45.59,yin,,0,0,0,, 说 match: 如果没有匹配返回 0\\N{\\fs12}that says match colon, return zero if no match,\r\nDialogue: 0,0:36:45.59,0:36:48.08,yin,,0,0,0,, 否则考虑匹配有多好 \\N{\\fs12}otherwise, how good a match it is basically.\r\nDialogue: 0,0:36:48.08,0:36:52.16,yin,,0,0,0,, 如果匹配得很好 match 会返回高分 \\N{\\fs12}So match should be returning high scores if it’s a really good match\r\nDialogue: 0,0:36:52.16,0:36:54.62,yin,,0,0,0,, 如果匹配不好 则会返回低分 \\N{\\fs12}and a lower score if it’s not so good a match.\r\nDialogue: 0,0:36:54.62,0:36:57.50,yin,,0,0,0,, 这就是它的语义 \\N{\\fs12}You know, that’s kind of the semantics of it.\r\nDialogue: 0,0:36:57.50,0:37:03.18,yin,,0,0,0,, 匹配上或没匹配上应该怎样呢 \\N{\\fs12}Alright, so, what if it is a match or it’s not a match.\r\nDialogue: 0,0:37:03.18,0:37:06.10,yin,,0,0,0,, 这两种情况我们都需要处理 \\N{\\fs12}We have to deal with both of those cases.\r\nDialogue: 0,0:37:06.10,0:37:11.57,yin,,0,0,0,, 在匹配上的情况下 我们将给自己分数 \\N{\\fs12}Alright, so in the case that it is a match, then let’s give ourselves that score.\r\nDialogue: 0,0:37:14.15,0:37:18.14,yin,,0,0,0,, 而且两张牌都匹配上了 我们将它们标记为已匹配 \\N{\\fs12}And, both these cards matched, so let’s mark them both as matched,\r\nDialogue: 0,0:37:18.14,0:37:21.50,yin,,0,0,0,, 所以这里说 card.matched = YES\\N{\\fs12}so we’re going to say card dot matched equals yes,\r\nDialogue: 0,0:37:21.50,0:37:25.68,yin,,0,0,0,, 而且另一张牌 otherCard.matched = YES\\N{\\fs12}and the other card dot matched equals yes.\r\nDialogue: 0,0:37:25.68,0:37:28.13,yin,,0,0,0,, 它们匹配上了 \\N{\\fs12}Alright? So they’re matched,\r\nDialogue: 0,0:37:28.13,0:37:30.10,yin,,0,0,0,, 它们使命完成 我们得到一些分 \\N{\\fs12}they’re out of the game, we got some points.\r\nDialogue: 0,0:37:30.10,0:37:31.75,yin,,0,0,0,, 如果没匹配上呢 \\N{\\fs12}Now what if they don’t match, well I told you\r\nDialogue: 0,0:37:31.75,0:37:36.42,yin,,0,0,0,, 我说过 这时我会将选择的另一张牌取消选择 \\N{\\fs12}if they don’t match, I’m going to turn that other chosen card, I’m going to un-choose it,\r\nDialogue: 0,0:37:36.42,0:37:41.38,yin,,0,0,0,, 所以这里有 otherCard.chosen = NO\\N{\\fs12}basically, so I’m going to say other card dot chosen equals no.\r\nDialogue: 0,0:37:41.38,0:37:47.61,yin,,0,0,0,, 而且 我还想因此罚一些分 \\N{\\fs12}And also, I think I’m going to impose a penalty for doing this.\r\nDialogue: 0,0:37:47.61,0:37:52.25,yin,,0,0,0,, 我将从 score 中减一些分 这叫作错匹配罚分 \\N{\\fs12}I’m going to subtract something from the score, I’m going to call it my mismatched penalty\r\nDialogue: 0,0:37:52.25,0:37:54.57,yin,,0,0,0,, 我将它设置为一个常量 \\N{\\fs12}here and I can make a constant.\r\nDialogue: 0,0:37:54.57,0:37:57.18,yin,,0,0,0,, 我来简单讲一下常量 \\N{\\fs12}Now, let’s talk a little bit about constants.\r\nDialogue: 0,0:37:57.18,0:37:58.48,yin,,0,0,0,, 要知道 这是 C\\N{\\fs12}You know, this is c. Okay?\r\nDialogue: 0,0:37:58.48,0:38:00.75,yin,,0,0,0,, 你可以按照 C 的方法来处理常量 \\N{\\fs12}So you’re going to make these constants however you want.\r\nDialogue: 0,0:38:00.75,0:38:03.72,yin,,0,0,0,, 一种做法是用 #define\\N{\\fs12}One way to do it is to say pound sign define, right?\r\nDialogue: 0,0:38:03.72,0:38:07.95,yin,,0,0,0,, 我可以说 #define MISMATCH_PENALTY\\N{\\fs12}So I could say pound sign define, mismatched penalty.\r\nDialogue: 0,0:38:09.31,0:38:12.38,yin,,0,0,0,, 我们可以将 MISMATCH_PENALTY 设为 2\\N{\\fs12}And we can make the mismatched penalty be, you know,\r\nDialogue: 0,0:38:12.38,0:38:16.25,yin,,0,0,0,, 我们可以将 MISMATCH_PENALTY 设为 2\\N{\\fs12}the mismatched penalty, what did I decide, I think something like two,\r\nDialogue: 0,0:38:16.25,0:38:19.02,yin,,0,0,0,, 如果错匹配 我将罚掉 2 分 \\N{\\fs12}so I’m going to take away two points if you mismatch,\r\nDialogue: 0,0:38:19.02,0:38:21.48,yin,,0,0,0,, 这是一种做法 \\N{\\fs12}so that’s one way to do it.\r\nDialogue: 0,0:38:21.48,0:38:24.81,yin,,0,0,0,, 另一种处理常量的方式是用 const\\N{\\fs12}Another way to do constants is const,\r\nDialogue: 0,0:38:24.81,0:38:26.45,yin,,0,0,0,, 这里可以是 static const\\N{\\fs12}okay, its static const even.\r\nDialogue: 0,0:38:26.45,0:38:33.29,yin,,0,0,0,,static const int MISMATCH_PENALTY = 2\\N{\\fs12}Static const int mismatched penalty, if equals two.\r\nDialogue: 0,0:38:34.37,0:38:36.61,yin,,0,0,0,, 这是另一种方式 \\N{\\fs12}So that’s another way to do it.\r\nDialogue: 0,0:38:36.61,0:38:38.48,yin,,0,0,0,, 你可以随喜好选择 \\N{\\fs12}This is kind of as you prefer.\r\nDialogue: 0,0:38:38.48,0:38:41.71,yin,,0,0,0,,static const 的好处在于它们具有类型 \\N{\\fs12}The nice thing about these static const’s is they’re typed.\r\nDialogue: 0,0:38:41.71,0:38:45.65,yin,,0,0,0,,#define 没有类型 只是替换 \\N{\\fs12}Whereas a pound sign define is not typed, it’s just substituting.\r\nDialogue: 0,0:38:45.65,0:38:49.39,yin,,0,0,0,, 而这里有类型 这在调试器中更好 \\N{\\fs12}But here you’ve got to type in and you’ll be able to see this in the debugger better.\r\nDialogue: 0,0:38:49.39,0:38:51.10,yin,,0,0,0,, 因为它有类型 \\N{\\fs12}Because it’s typed.\r\nDialogue: 0,0:38:51.10,0:38:52.84,yin,,0,0,0,, 不过你们可以根据喜好来 \\N{\\fs12}But it’s really kind of your own thing,\r\nDialogue: 0,0:38:52.84,0:38:55.23,yin,,0,0,0,, 我只想说 不管你选择用哪种 \\N{\\fs12}I would just say be consistent about what you choose\r\nDialogue: 0,0:38:55.23,0:39:00.23,yin,,0,0,0,,#define 也好 static const 也好 请保持一致 \\N{\\fs12}to pound sign define versus what you decide to make a static const.\r\nDialogue: 0,0:39:00.23,0:39:02.51,yin,,0,0,0,, 用哪种取决于你 \\N{\\fs12}Totally up to you.\r\nDialogue: 0,0:39:03.62,0:39:07.65,yin,,0,0,0,, 另外我还要做一件事 如果你匹配上 \\N{\\fs12}You know, the other thing I’m going to do here is if you match, I actually,\r\nDialogue: 0,0:39:07.65,0:39:10.92,yin,,0,0,0,, 毕竟这里错匹配会罚 2 分 \\N{\\fs12}since I’m basically charging you two points if you mismatch,\r\nDialogue: 0,0:39:10.92,0:39:14.27,yin,,0,0,0,, 如果你匹配上 我会给你很多分 \\N{\\fs12}if you match I want to give you a lot of points,\r\nDialogue: 0,0:39:14.27,0:39:18.22,yin,,0,0,0,, 所以我要给你一个匹配红利 \\N{\\fs12}so I’m actually going to give you a match bonus.\r\nDialogue: 0,0:39:18.22,0:39:20.59,yin,,0,0,0,,MATCH_BONUS\\N{\\fs12}Match bonus.\r\nDialogue: 0,0:39:20.61,0:39:23.92,yin,,0,0,0,, 这将是另外一个常量 \\N{\\fs12}And this is going to be another constant here.\r\nDialogue: 0,0:39:23.92,0:39:27.97,yin,,0,0,0,, 放在这里 复制粘贴这个 \\N{\\fs12}Put this up here, actually let’s copy and paste this over\r\nDialogue: 0,0:39:27.98,0:39:29.47,yin,,0,0,0,, 把这个贴过来 \\N{\\fs12}this, paste,\r\nDialogue: 0,0:39:29.48,0:39:32.27,yin,,0,0,0,, 我将给你匹配分数的四倍 \\N{\\fs12}and I’m going to give you four times whatever your matching is\r\nDialogue: 0,0:39:32.27,0:39:33.84,yin,,0,0,0,, 因为这里有罚分 \\N{\\fs12}because I’m giving you this penalty so I want\r\nDialogue: 0,0:39:33.84,0:39:36.04,yin,,0,0,0,, 所以匹配上了我要多给点分你 \\N{\\fs12}to give you a bonus if you actually match.\r\nDialogue: 0,0:39:36.04,0:39:38.32,yin,,0,0,0,, 不管匹配得分是多少 不管匹配有多少 \\N{\\fs12}So whatever the match score is, however good a match it is,\r\nDialogue: 0,0:39:38.32,0:39:41.98,yin,,0,0,0,, 这里得到的分数都会乘以 4\\N{\\fs12}you’re going to get four times as many points if you match.\r\nDialogue: 0,0:39:41.98,0:39:45.46,yin,,0,0,0,, 这些东西你们可以自己去倒腾 \\N{\\fs12}And these are things that you would want to tweak\r\nDialogue: 0,0:39:45.46,0:39:49.22,yin,,0,0,0,, 也许在你们的作业中 你们想要 \\N{\\fs12}or maybe, like, possibly in your homework, you might even want\r\nDialogue: 0,0:39:49.22,0:39:52.96,yin,,0,0,0,, 把这些红利和罚分设置为公共 API\\N{\\fs12}to make these be public API to set these bonuses and penalties.\r\nDialogue: 0,0:39:52.96,0:39:54.88,yin,,0,0,0,, 让它们可以被设置 \\N{\\fs12}Maybe that’s something that wants to be settable,\r\nDialogue: 0,0:39:54.88,0:39:59.14,yin,,0,0,0,, 为了简便起见 这里我们把它们设为常量 \\N{\\fs12}but we’re going to make them constants for expediency in our game.\r\nDialogue: 0,0:39:59.14,0:40:03.00,yin,,0,0,0,, 另外一点是 如果我们找到了这个匹配 \\N{\\fs12}The other thing we can do here is if we find this match,\r\nDialogue: 0,0:40:03.00,0:40:07.39,yin,,0,0,0,, 我们就可以从这个 for 循环中跳出来 \\N{\\fs12}right here, we can break out of this for.\r\nDialogue: 0,0:40:07.39,0:40:10.35,yin,,0,0,0,, 这是因为这里只需要匹配两张牌 \\N{\\fs12}And that’s because we’re a two card matching game,\r\nDialogue: 0,0:40:10.35,0:40:13.58,yin,,0,0,0,, 一旦找到匹配的 这就搞定了 \\N{\\fs12}once we found a match, we’re, we’re done.\r\nDialogue: 0,0:40:13.58,0:40:16.81,yin,,0,0,0,, 我们找到另一张已选牌 处理掉它 \\N{\\fs12}We found another chosen card, we processed it,\r\nDialogue: 0,0:40:16.81,0:40:19.40,yin,,0,0,0,, 我们不需要再找更多匹配的牌 \\N{\\fs12}we don’t need to keep looking for more matching cards.\r\nDialogue: 0,0:40:19.40,0:40:21.62,yin,,0,0,0,, 作业中 当要匹配的数量多于 2 时 \\N{\\fs12}Again, if you have, matching more than two\r\nDialogue: 0,0:40:21.62,0:40:25.96,yin,,0,0,0,, 你要将这些牌收集起来 这里就不能跳出 \\N{\\fs12}and you’re collecting cards, you may not be breaking out of this loop down here.\r\nDialogue: 0,0:40:25.96,0:40:30.70,yin,,0,0,0,, 这里我还想做一件事 也就是 \\N{\\fs12}The other thing I wanted to do here is\r\nDialogue: 0,0:40:30.70,0:40:35.90,yin,,0,0,0,, 如果你选择了一张牌 并让它正面朝上 \\N{\\fs12}if you are choosing the card and flipping it face up,\r\nDialogue: 0,0:40:35.90,0:40:39.27,yin,,0,0,0,, 我要让它消耗一些东西 \\N{\\fs12}I want to make it cost something.\r\nDialogue: 0,0:40:39.27,0:40:44.12,yin,,0,0,0,, 这里我要设置一些选择成本 \\N{\\fs12}So I’m actually going to give, make a cost to choose,\r\nDialogue: 0,0:40:44.12,0:40:46.49,yin,,0,0,0,, 这里设为 1 分 \\N{\\fs12}and I’m going to make it be one point.\r\nDialogue: 0,0:40:46.49,0:40:50.70,yin,,0,0,0,, 这是因为我不想让你 \\N{\\fs12}Okay, that’s because I don’t want you to be able to just,\r\nDialogue: 0,0:40:50.70,0:40:53.73,yin,,0,0,0,, 没有成本地来回来回翻牌 \\N{\\fs12}you know, flip the card over, flip it back down, flip the card over, flip it back down,\r\nDialogue: 0,0:40:53.73,0:40:57.02,yin,,0,0,0,, 最终记住所有牌 再翻过来让它们都匹配上 \\N{\\fs12}you’d eventually memorize all the cards and then flip them up and get all your matches.\r\nDialogue: 0,0:40:57.02,0:40:58.66,yin,,0,0,0,, 这会有一些花销 \\N{\\fs12}So it costs you a little bit.\r\nDialogue: 0,0:40:58.66,0:41:02.68,yin,,0,0,0,, 忘记牌的话 你需要重新翻开 这会花掉一些分 \\N{\\fs12}If you forget a card and you flip it again, it’s going to cost you just a little bit.\r\nDialogue: 0,0:41:02.68,0:41:05.36,yin,,0,0,0,, 没有错误匹配扣分多 但还是会扣一些分 \\N{\\fs12}Not as bad as mismatching, but it’s going to cost you a little.\r\nDialogue: 0,0:41:05.36,0:41:06.14,yin,,0,0,0,, 有问题 \\N{\\fs12}Question?\r\nDialogue: 0,0:41:10.49,0:41:12.09,yin,,0,0,0,, 对 你是对的 \\N{\\fs12}Oh yeah, you’re right.\r\nDialogue: 0,0:41:12.09,0:41:15.27,yin,,0,0,0,, 很好 我还得依赖你们提醒我哪里有错 \\N{\\fs12}Good call. See now I rely on all of you to make sure I don’t make mistakes\r\nDialogue: 0,0:41:15.27,0:41:16.24,yin,,0,0,0,, 没错 \\N{\\fs12}like that, so yeah, absolutely.\r\nDialogue: 0,0:41:16.24,0:41:17.92,yin,,0,0,0,, 这个 break 需要在这个 if 内 \\N{\\fs12}This break needs to be inside this if\r\nDialogue: 0,0:41:17.92,0:41:22.37,yin,,0,0,0,, 因为当我们找到另一张牌时 我们会跳出这个 for\\N{\\fs12}because we only break out of this for when we find another card.\r\nDialogue: 0,0:41:22.37,0:41:23.96,yin,,0,0,0,, 提得很好 \\N{\\fs12}Good, good call.\r\nDialogue: 0,0:41:24.72,0:41:29.78,yin,,0,0,0,, 最后当然是 我想要把这张牌标记为已选 \\N{\\fs12}The last thing, of course, is I want to mark this card as chosen.\r\nDialogue: 0,0:41:29.78,0:41:33.20,yin,,0,0,0,, 抱歉这里用的是大写 \\N{\\fs12}And sorry for the caps there.\r\nDialogue: 0,0:41:33.20,0:41:37.41,yin,,0,0,0,, 这张牌 噢 不是 isChosen 而是 chosen\\N{\\fs12}This card, woops, not is chosen, chosen,\r\nDialogue: 0,0:41:37.41,0:41:40.68,yin,,0,0,0,, 在做了所有这些之后 这张牌是已选的 \\N{\\fs12}this card is chosen after we’ve done all of this thing.\r\nDialogue: 0,0:41:40.68,0:41:44.71,yin,,0,0,0,, 无论如何它都被选了 它是新的已选牌 \\N{\\fs12}In any case, it’s going to be chosen, it’s going to be the new chosen card.\r\nDialogue: 0,0:41:44.71,0:41:49.51,yin,,0,0,0,, 它也可能已经被匹配 但它至少是已选的 \\N{\\fs12}It might also be matched, but it’s also chosen.\r\nDialogue: 0,0:41:49.51,0:41:51.79,yin,,0,0,0,, 这就完了 \\N{\\fs12}So, that’s it.\r\nDialogue: 0,0:41:51.79,0:41:54.89,yin,,0,0,0,, 这就是纸牌匹配游戏的整个逻辑 \\N{\\fs12}That’s the entire logic of my card matching game.\r\nDialogue: 0,0:41:54.89,0:41:58.14,yin,,0,0,0,, 很简单 有点过度简化了 \\N{\\fs12}It’s pretty simple, it’s kind of in a way ultra-simplified.\r\nDialogue: 0,0:41:58.14,0:42:01.30,yin,,0,0,0,, 你们可以想象复杂很多的情况 \\N{\\fs12}You can imagine much more complicated things, but,\r\nDialogue: 0,0:42:01.30,0:42:04.22,yin,,0,0,0,, 不过这里我是现场编程 \\N{\\fs12}you know, I’m doing this on the fly here and we only have,\r\nDialogue: 0,0:42:04.22,0:42:07.40,yin,,0,0,0,, 要知道 一堂课只有 1 小时 15 分钟左右 \\N{\\fs12}you know, an hour and 15 for, for lecture, so,\r\nDialogue: 0,0:42:07.40,0:42:09.36,yin,,0,0,0,, 我故意弄得简单一些 \\N{\\fs12}I’ve kept it kind of intentionally simple,\r\nDialogue: 0,0:42:09.36,0:42:13.70,yin,,0,0,0,, 不过我主要想让你们理解的是 这里没有 UI\\N{\\fs12}but the main point I want you to understand from this logic is it has no UI in it.\r\nDialogue: 0,0:42:13.70,0:42:16.87,yin,,0,0,0,, 这里只是处理纸牌 设置它们 \\N{\\fs12}Right? It’s purely just dealing with the cards and setting them\r\nDialogue: 0,0:42:16.87,0:42:19.00,yin,,0,0,0,, 是否被匹配 是否被选 \\N{\\fs12}to be matched or not, whether they’re chosen or not,\r\nDialogue: 0,0:42:19.00,0:42:22.55,yin,,0,0,0,, 取决于 match: 方法的使用 它也是我们模型的一部分 \\N{\\fs12}depending on using the match colon method, which is also part of our model.\r\nDialogue: 0,0:42:22.55,0:42:24.30,yin,,0,0,0,, 这里没有 UI\\N{\\fs12}There’s no UI here.\r\nDialogue: 0,0:42:24.30,0:42:29.25,yin,,0,0,0,, 将这些逻辑传达给 UI 的是控制器 \\N{\\fs12}It’s up to our controller to take this logic and turn it into UI.\r\nDialogue: 0,0:42:29.90,0:42:32.73,yin,,0,0,0,, 我们再来看看这个 \\N{\\fs12}So let’s take a look at that.\r\nDialogue: 0,0:42:32.73,0:42:38.35,yin,,0,0,0,, 回到我们的串连图板 腾出一些空间 \\N{\\fs12}I’m going to go back to our storyboard here and make more space.\r\nDialogue: 0,0:42:38.35,0:42:40.68,yin,,0,0,0,, 把这个移过来点 \\N{\\fs12}Move this over a little.\r\nDialogue: 0,0:42:40.68,0:42:42.59,yin,,0,0,0,, 留出更多空间 \\N{\\fs12}Give me more space.\r\nDialogue: 0,0:42:42.59,0:42:45.06,yin,,0,0,0,, 这是我们的控制器 \\N{\\fs12}Okay. So, here’s our controller, right?\r\nDialogue: 0,0:42:45.06,0:42:47.64,yin,,0,0,0,, 之前我们写出了这个简单控制器 \\N{\\fs12}Our simple controller just as we had left it off,\r\nDialogue: 0,0:42:47.64,0:42:51.63,yin,,0,0,0,, 我要把逻辑用到这个之中 \\N{\\fs12}and I need to use this logic in this thing.\r\nDialogue: 0,0:42:51.63,0:42:53.67,yin,,0,0,0,, 首先我要做的是 \\N{\\fs12}So the first thing I’m going to do is\r\nDialogue: 0,0:42:53.68,0:42:57.88,yin,,0,0,0,, 创建一个属性来容纳我的 CardMatchingGame\\N{\\fs12}create a property to hold my card matching game.\r\nDialogue: 0,0:42:59.76,0:43:03.65,yin,,0,0,0,, 有些人可能会把这叫作 model\\N{\\fs12}Now, one could argue, some people would call this model,\r\nDialogue: 0,0:43:03.65,0:43:05.64,yin,,0,0,0,, 我不大喜欢这样 \\N{\\fs12}I don’t like that so much,\r\nDialogue: 0,0:43:05.64,0:43:08.74,yin,,0,0,0,, 因为 model 有时会扩展到多个属性 \\N{\\fs12}because sometimes a model will expand multiple properties\r\nDialogue: 0,0:43:08.74,0:43:11.71,yin,,0,0,0,, 也有人会叫它 gameModel\\N{\\fs12}or they might call it game model.\r\nDialogue: 0,0:43:11.71,0:43:13.82,yin,,0,0,0,, 这不算太糟 我不反对这样 \\N{\\fs12}That’s not so bad. I’m okay with that.\r\nDialogue: 0,0:43:13.82,0:43:17.08,yin,,0,0,0,, 我喜欢 game 我认为这样在代码中读起来更好 \\N{\\fs12}I like game, I think it reads a little nicer in the code, but,\r\nDialogue: 0,0:43:17.08,0:43:19.88,yin,,0,0,0,, 不过这是一种个人偏好问题 \\N{\\fs12}it’s kind of a matter of personal preference,\r\nDialogue: 0,0:43:19.88,0:43:24.88,yin,,0,0,0,, 无论如何 我需要导入我的 CardMatchingGame 头文件 \\N{\\fs12}but in any case, I need to import my card matching game header file here,\r\nDialogue: 0,0:43:24.88,0:43:27.64,yin,,0,0,0,, 来让这个正常运行 \\N{\\fs12}to make this work,\r\nDialogue: 0,0:43:27.64,0:43:30.93,yin,,0,0,0,, 我将惰性实例化它 \\N{\\fs12}and I’m going to lazily instantiate it.\r\nDialogue: 0,0:43:33.25,0:43:35.66,yin,,0,0,0,, 如果 game 为 nil\\N{\\fs12}I’m just going to say if the game is nil,\r\nDialogue: 0,0:43:35.66,0:43:39.23,yin,,0,0,0,, 也就是说 我们的对象新初始化 \\N{\\fs12}in other words, just our object is freshly initialized,\r\nDialogue: 0,0:43:39.23,0:43:41.84,yin,,0,0,0,, 那么我会让_game =\\N{\\fs12}then I’m going to say game equals\r\nDialogue: 0,0:43:41.84,0:43:47.64,yin,,0,0,0,,[[CardMatchingGame alloc] init…\\N{\\fs12}card matching game alloc, woops, game alloc, and then init,\r\nDialogue: 0,0:43:47.64,0:43:50.67,yin,,0,0,0,, 这里有两个 init 一个继承自 NSObject\\N{\\fs12}okay there’s two inits there, the one inherited from NSObject\r\nDialogue: 0,0:43:50.67,0:43:53.14,yin,,0,0,0,, 我们知道它会返回 nil 所以我不想要这个 \\N{\\fs12}which we know is going to return nil so I don’t want that one,\r\nDialogue: 0,0:43:53.14,0:43:54.92,yin,,0,0,0,, 另一个是 initWithCardCount\\N{\\fs12}and init with card count.\r\nDialogue: 0,0:43:54.92,0:43:59.24,yin,,0,0,0,, 我将使用这个 按下 Tab 这个游戏中有多少牌 \\N{\\fs12}So I’m going to do that one, tab over here, how many cards are in this game?\r\nDialogue: 0,0:43:59.24,0:44:00.23,yin,,0,0,0,, 有 12 张 \\N{\\fs12}Well there’s 12.\r\nDialogue: 0,0:44:00.23,0:44:02.12,yin,,0,0,0,, 所以这里应该键入 12 吗 \\N{\\fs12}So I should type 12 here right?\r\nDialogue: 0,0:44:03.03,0:44:03.94,yin,,0,0,0,, 不对 \\N{\\fs12}Okay, no.\r\nDialogue: 0,0:44:03.94,0:44:07.49,yin,,0,0,0,, 这就像在作业中使用 102 一样 \\N{\\fs12}That’s like putting a 102 in your homework solution, right?\r\nDialogue: 0,0:44:07.49,0:44:09.50,yin,,0,0,0,, 以后我们可能增加牌数 \\N{\\fs12}We might add more cards someday,\r\nDialogue: 0,0:44:09.50,0:44:12.93,yin,,0,0,0,, 这里绝对不要写 12 这里我暂时写 0\\N{\\fs12}we absolutely do not want 12 here, so I’m going to put 0 here for now,\r\nDialogue: 0,0:44:12.93,0:44:16.17,yin,,0,0,0,, 我到时会给你们展示 如何弄清这个值是什么 \\N{\\fs12}and we’ll, I’ll show you how we’re going to figure out what this number is.\r\nDialogue: 0,0:44:16.17,0:44:17.88,yin,,0,0,0,,usingDeck\\N{\\fs12}And using deck,\r\nDialogue: 0,0:44:17.88,0:44:20.40,yin,,0,0,0,, 幸运的是 这里我有 self createDeck\\N{\\fs12}luckily I have self-create deck here,\r\nDialogue: 0,0:44:20.40,0:44:22.01,yin,,0,0,0,, 所以我这样做 \\N{\\fs12}that’s why I did that that way.\r\nDialogue: 0,0:44:22.01,0:44:25.33,yin,,0,0,0,, 这会创建我的牌堆 \\N{\\fs12}That’s going to create my, my deck.\r\nDialogue: 0,0:44:25.33,0:44:31.02,yin,,0,0,0,, 然后我们返回_game 这很好地得到了惰性初始化 \\N{\\fs12}Then we’ll return underbar game and it’s nice and lazily initialized.\r\nDialogue: 0,0:44:32.43,0:44:35.20,yin,,0,0,0,, 我们再来讨论一下这个 0\\N{\\fs12}Alright, so let’s talk about this zero right there.\r\nDialogue: 0,0:44:35.20,0:44:37.36,yin,,0,0,0,, 我们怎么知道这里有多少牌 \\N{\\fs12}How are we going to find out how many cards there are?\r\nDialogue: 0,0:44:37.36,0:44:43.32,yin,,0,0,0,, 实际上 它有可能创建一个 outlet 到 UI 中的多个事物 \\N{\\fs12}Well it turns out it’s possible to create an outlet to multiple things in your UI.\r\nDialogue: 0,0:44:43.32,0:44:45.51,yin,,0,0,0,, 记得吧 这里我们有这个 outlet\\N{\\fs12}Remember that we have this outlet right here\r\nDialogue: 0,0:44:45.51,0:44:46.52,yin,,0,0,0,,flipsLable\\N{\\fs12}flips label,\r\nDialogue: 0,0:44:46.52,0:44:52.26,yin,,0,0,0,, 这是到下面这个 flipCount 的 outlet\\N{\\fs12}which was an outlet that went to this little flip count thing, that we had down here.\r\nDialogue: 0,0:44:52.26,0:44:54.15,yin,,0,0,0,, 它是一个单 outlet\\N{\\fs12}It was a single outlet,\r\nDialogue: 0,0:44:54.16,0:44:56.86,yin,,0,0,0,, 我们其实可以删掉这个单 outlet\\N{\\fs12}which by the way, we can delete this single outlet.\r\nDialogue: 0,0:44:56.86,0:45:00.45,yin,,0,0,0,, 但它只到一个对象 这个 UILabel 我们删掉这个 \\N{\\fs12}But it went to one object, the UI label, so let’s get rid of that,\r\nDialogue: 0,0:45:00.45,0:45:02.33,yin,,0,0,0,, 我们不再需要 flipCount\\N{\\fs12}and we don’t need flip count either,\r\nDialogue: 0,0:45:02.33,0:45:06.17,yin,,0,0,0,, 我们也不再需要 deck 很多东西现在都可以删了 \\N{\\fs12}we actually don’t need deck either, there’s lots of stuff we can get rid of now.\r\nDialogue: 0,0:45:06.17,0:45:11.25,yin,,0,0,0,, 我们将重新写这整个 删掉 setFlipCount\\N{\\fs12}Alright, so we’re going to redo this whole thing, well, we’ll get rid of the setFlipCount.\r\nDialogue: 0,0:45:11.25,0:45:13.67,yin,,0,0,0,, 这个等下我们会删掉 \\N{\\fs12}We’ll get rid of that in a second.\r\nDialogue: 0,0:45:13.67,0:45:16.76,yin,,0,0,0,, 可以看到 现在游戏变得简单了很多 \\N{\\fs12}You can see our games gotten significantly simpler now\r\nDialogue: 0,0:45:16.76,0:45:20.03,yin,,0,0,0,, 模型接管了这里的很多东西 \\N{\\fs12}that the model’s taking care of a lot of our stuff here\r\nDialogue: 0,0:45:20.03,0:45:22.33,yin,,0,0,0,, 把这些都删除后 它会变得更简单 \\N{\\fs12}and it’s going to get even simpler when we delete all this.\r\nDialogue: 0,0:45:22.33,0:45:25.92,yin,,0,0,0,, 无论如何 这是单 outlet\\N{\\fs12}But anyway, that was a single outlet.\r\nDialogue: 0,0:45:25.92,0:45:28.33,yin,,0,0,0,, 我们可以让 outlet 到多个事物 \\N{\\fs12}We can actually create an outlet to multiple things,\r\nDialogue: 0,0:45:28.33,0:45:31.65,yin,,0,0,0,, 你们应该能够想到 这一 outlet 将是数组 \\N{\\fs12}and as you might imagine, that outlet will be an array.\r\nDialogue: 0,0:45:31.65,0:45:33.37,yin,,0,0,0,, 如何做到呢 \\N{\\fs12}So how we do that?\r\nDialogue: 0,0:45:33.37,0:45:34.28,yin,,0,0,0,, 很简单 \\N{\\fs12}Very simple.\r\nDialogue: 0,0:45:34.28,0:45:37.57,yin,,0,0,0,, 方法和原来一样 我按住 Control 键 \\N{\\fs12}Exact same way, I’m holding down the control key.\r\nDialogue: 0,0:45:37.57,0:45:41.54,yin,,0,0,0,, 选这张牌 按住 Control 并拖动到接口 \\N{\\fs12}Pick the card here, I’m going to hold down control and drag into my interface,\r\nDialogue: 0,0:45:41.54,0:45:46.84,yin,,0,0,0,, 和之前创建 outlet 的方式一样 然后松手 \\N{\\fs12}just like I do with any other outlet I’m trying to create, and when I let go,\r\nDialogue: 0,0:45:46.84,0:45:49.41,yin,,0,0,0,, 可以看到上面这里写有连接 \\N{\\fs12}you can see that at the top here where it says connection,\r\nDialogue: 0,0:45:49.41,0:45:53.02,yin,,0,0,0,, 这里实际有选项可以创建 outlet collection\\N{\\fs12}there’s actually the choice of making an outlet collection.\r\nDialogue: 0,0:45:53.02,0:45:55.11,yin,,0,0,0,, 这是一个数组 \\N{\\fs12}So that’s an array of things.\r\nDialogue: 0,0:45:55.11,0:45:59.34,yin,,0,0,0,, 这里还可以选 action 声明到这里 \\N{\\fs12}We can also make an action messenger, we’d be declaring it here.\r\nDialogue: 0,0:45:59.34,0:46:01.76,yin,,0,0,0,, 或者到单个按钮的 outlet\\N{\\fs12}Or an outlet to a single button,\r\nDialogue: 0,0:46:01.77,0:46:03.65,yin,,0,0,0,, 但这里我要选 outlet collection\\N{\\fs12}but here I’m going to do outlet collection\r\nDialogue: 0,0:46:03.65,0:46:06.50,yin,,0,0,0,, 选 outlet collection 时 XCode\\N{\\fs12}When you do do outlet collection, XCode,\r\nDialogue: 0,0:46:06.51,0:46:08.97,yin,,0,0,0,, 不是 Objective-C 而是 XCode 希望知道 \\N{\\fs12}not Objective-C, but XCode wants to know,\r\nDialogue: 0,0:46:08.97,0:46:12.72,yin,,0,0,0,, 这里有怎样的对象 这完全是 XCode 想知道 \\N{\\fs12}what kind of objects are in there, that’s purely for XCode, there’s,\r\nDialogue: 0,0:46:12.72,0:46:16.21,yin,,0,0,0,, 我讲过 Objective-C 中没办法知道数组中是什么 \\N{\\fs12}I told you there’s no way to know what’s in an array in objective-C\r\nDialogue: 0,0:46:16.21,0:46:17.69,yin,,0,0,0,, 编译器无法知道这个 \\N{\\fs12}and the compiler can’t know that,\r\nDialogue: 0,0:46:17.69,0:46:19.20,yin,,0,0,0,, 这纯粹是为 XCode 准备的 \\N{\\fs12}so this is purely for XCode and you’re going\r\nDialogue: 0,0:46:19.20,0:46:21.91,yin,,0,0,0,, 等下你们就能看到 XCode 是如何记住这个的 \\N{\\fs12}to see how XCode remembers this answer in a second,\r\nDialogue: 0,0:46:21.91,0:46:24.32,yin,,0,0,0,, 这里是它的名称 我将其起名为 cardButtons(纸牌按钮)\\N{\\fs12}and here’s the name, I’m going to call it card buttons,\r\nDialogue: 0,0:46:24.32,0:46:28.30,yin,,0,0,0,, 这就是这些 这些是容纳所有纸牌的按钮 \\N{\\fs12}that’s what these are, these are buttons that are holding all the cards.\r\nDialogue: 0,0:46:28.30,0:46:31.80,yin,,0,0,0,, 注意 这里没有问我是强是弱 \\N{\\fs12}Notice it’s not asking me strong or weak here.\r\nDialogue: 0,0:46:31.80,0:46:35.02,yin,,0,0,0,, 这是因为这一属性必须是强的 \\N{\\fs12}That’s because this property has to be strong.\r\nDialogue: 0,0:46:35.02,0:46:36.67,yin,,0,0,0,, 它必须是强的 \\N{\\fs12}And it has to be strong\r\nDialogue: 0,0:46:36.67,0:46:41.65,yin,,0,0,0,, 因为视图虽然有一个强指针单独指向所有这些牌 \\N{\\fs12}because while the view has a strong pointer to all these cards individually,\r\nDialogue: 0,0:46:41.65,0:46:45.86,yin,,0,0,0,, 但视图没有一个强指针指向这一数组 \\N{\\fs12}the view does not have a strong pointer to this array.\r\nDialogue: 0,0:46:45.86,0:46:48.73,yin,,0,0,0,, 如果我们不将其设为强 \\N{\\fs12}And if we did not make this strong,\r\nDialogue: 0,0:46:48.73,0:46:51.33,yin,,0,0,0,, 那么这就会被持续设为 0\\N{\\fs12}than this would be constantly being set to zero\r\nDialogue: 0,0:46:51.33,0:46:54.15,yin,,0,0,0,, 因为没人拥有强指针指向它 \\N{\\fs12}because no one would have a strong pointer to it.\r\nDialogue: 0,0:46:54.15,0:46:56.63,yin,,0,0,0,, 所以这里需要是强的 \\N{\\fs12}So, that’s why this has to be strong,\r\nDialogue: 0,0:46:56.63,0:46:58.76,yin,,0,0,0,, 因为它是数组 而不是一个按钮 \\N{\\fs12}because it’s an array, it’s not a button.\r\nDialogue: 0,0:46:58.76,0:47:03.86,yin,,0,0,0,, 这一小段代码 会完全被编译器忽略 \\N{\\fs12}Now, this little stuff right here, compiler completely ignores this,\r\nDialogue: 0,0:47:03.86,0:47:06.08,yin,,0,0,0,, 它同 IBAction 很像 \\N{\\fs12}it’s very much like IB action,\r\nDialogue: 0,0:47:06.08,0:47:09.70,yin,,0,0,0,, 不过是 XCode 加到这里的一些东西 \\N{\\fs12}it’s just some stuff that XCode puts in there\r\nDialogue: 0,0:47:09.70,0:47:14.47,yin,,0,0,0,, 让它自身知道这一特定属性是 outlet collection\\N{\\fs12}so that it knows that this particular property right here is an outlet collection,\r\nDialogue: 0,0:47:14.47,0:47:16.36,yin,,0,0,0,, 当我把鼠标悬停在这上面时 \\N{\\fs12}and you can see if I mouse over this\r\nDialogue: 0,0:47:16.36,0:47:19.18,yin,,0,0,0,, 它会显示我放在这里的这个按钮 \\N{\\fs12}it shows me the one button that I put in here.\r\nDialogue: 0,0:47:19.18,0:47:22.46,yin,,0,0,0,, 我倒想告诉你们 我们可以选择所有这些 \\N{\\fs12}Now, I’d love to tell you we can just select all of these\r\nDialogue: 0,0:47:22.46,0:47:25.48,yin,,0,0,0,, 并 Control 拖动 但这是不行的 \\N{\\fs12}and control drag, but you can’t.\r\nDialogue: 0,0:47:25.48,0:47:28.91,yin,,0,0,0,, 我一直希望有这种功能 但设计者从来就没提供过 \\N{\\fs12}I’ve been asking for that feature for years, but they never give it to me.\r\nDialogue: 0,0:47:28.91,0:47:32.54,yin,,0,0,0,, 所以 我们需要一个个拖动 \\N{\\fs12}So, I have to drag these one-by-one,\r\nDialogue: 0,0:47:32.54,0:47:34.53,yin,,0,0,0,, 有些不幸 但至少 你知道 \\N{\\fs12}it’s kind of unfortunate, but at least, you know,\r\nDialogue: 0,0:47:34.53,0:47:36.70,yin,,0,0,0,, 我将它拖到已经存在的这个上 \\N{\\fs12}I drag it to the thing that’s already existing, and you notice\r\nDialogue: 0,0:47:36.70,0:47:40.95,yin,,0,0,0,, 我靠近时 它会高亮显示合适的位置 \\N{\\fs12}as I get close, it highlights the thing that is appropriate and, again,\r\nDialogue: 0,0:47:40.95,0:47:45.02,yin,,0,0,0,, 因为它知道这是按钮的 outlet collection\\N{\\fs12}it knows that because it knows this an outlet collection of buttons,\r\nDialogue: 0,0:47:45.02,0:47:47.87,yin,,0,0,0,, 所以这条属性会高亮显示 \\N{\\fs12}so that’s why I can highlight this property.\r\nDialogue: 0,0:47:47.87,0:47:50.26,yin,,0,0,0,, 我将把它们都集中到这里 \\N{\\fs12}So I’m going to collect all of them here,\r\nDialogue: 0,0:47:50.26,0:47:52.41,yin,,0,0,0,, 这样做时 有些容易犯错 \\N{\\fs12}and when you do this, you know, it’s somewhat error prone,\r\nDialogue: 0,0:47:52.41,0:47:55.21,yin,,0,0,0,, 你可能会漏掉 所有最好是到这里来检验下 \\N{\\fs12}you might miss, so it’s nice to go back here and check,\r\nDialogue: 0,0:47:55.21,0:47:58.22,yin,,0,0,0,, 你会看到所有 12 个按钮在这里 \\N{\\fs12}and you can see all 12 buttons in here.\r\nDialogue: 0,0:47:58.22,0:47:59.42,yin,,0,0,0,, 有问题 \\N{\\fs12}Question?\r\nDialogue: 0,0:48:00.71,0:48:03.19,yin,,0,0,0,, 问得很好 问题是 顺序要不要紧 \\N{\\fs12}Okay. Great question! The question is does the order matter?\r\nDialogue: 0,0:48:03.19,0:48:04.56,yin,,0,0,0,, 顺序有没什么作用 \\N{\\fs12}Or is the order determined?\r\nDialogue: 0,0:48:04.56,0:48:06.31,yin,,0,0,0,, 答案是没有 \\N{\\fs12}And the answer is no.\r\nDialogue: 0,0:48:06.31,0:48:09.67,yin,,0,0,0,, 这里对象的顺序对你完全是未知的 \\N{\\fs12}This order, the order of the object here is completely unknown to you,\r\nDialogue: 0,0:48:09.67,0:48:11.22,yin,,0,0,0,, 你不能依赖于它 \\N{\\fs12}and you cannot depend on it.\r\nDialogue: 0,0:48:11.22,0:48:14.69,yin,,0,0,0,, 如果你需要顺序 你需要用不同方式来做 \\N{\\fs12}If you need the order, you’re going to have to do this a different way.\r\nDialogue: 0,0:48:14.69,0:48:18.21,yin,,0,0,0,,outlet collection 中顺序是未知的 \\N{\\fs12}Outlet collections are fundamentally, the order is not known.\r\nDialogue: 0,0:48:18.21,0:48:21.31,yin,,0,0,0,, 所以不管我按什么顺序 Control 拖动它们 \\N{\\fs12}So no matter what order I control drag them,\r\nDialogue: 0,0:48:21.31,0:48:23.57,yin,,0,0,0,, 这都不是数组中的顺序 \\N{\\fs12}that’s not going to be the order in the array.\r\nDialogue: 0,0:48:23.57,0:48:25.93,yin,,0,0,0,, 苹果这样决定是很好的 \\N{\\fs12}Which was a good decision by Apple, it seems like oh,\r\nDialogue: 0,0:48:25.93,0:48:29.58,yin,,0,0,0,, 也许你觉得这很好 但要放很多东西到这里 \\N{\\fs12}it’d be cool, but it’d be just too hard for them to, to throw a lot of things in here,\r\nDialogue: 0,0:48:29.58,0:48:31.82,yin,,0,0,0,, 要显示太难 而且你会被弄糊涂 \\N{\\fs12}it’d be too hard to show and you could get confused,\r\nDialogue: 0,0:48:31.82,0:48:34.10,yin,,0,0,0,, 所以你需要使用别的机制 \\N{\\fs12}so, you need to use something, a different mechanism, and you’re going\r\nDialogue: 0,0:48:34.10,0:48:37.80,yin,,0,0,0,, 我们后面的课上 会讲很多能够做到这个的机制 \\N{\\fs12}to learn many mechanisms later in this class that you could do this with.\r\nDialogue: 0,0:48:37.80,0:48:39.85,yin,,0,0,0,, 这里只是一个很简单的做法 \\N{\\fs12}This is just a pretty simple one right here.\r\nDialogue: 0,0:48:39.85,0:48:42.34,yin,,0,0,0,, 对少量东西奏效 \\N{\\fs12}For a fairly small numbers of things.\r\nDialogue: 0,0:48:42.34,0:48:45.65,yin,,0,0,0,, 无论如何 我们得到了到这些事物的连接 \\N{\\fs12}So anyway, we got this connection to these things.\r\nDialogue: 0,0:48:45.65,0:48:47.99,yin,,0,0,0,, 现在 我们可以进行纸牌计数 \\N{\\fs12}So now we can do card count.\r\nDialogue: 0,0:48:47.99,0:48:52.67,yin,,0,0,0,, 我们知道纸牌数量 我们可以说 self.cardButtons\\N{\\fs12}We know the number of cards, we can just say self dot card buttons,\r\nDialogue: 0,0:48:52.67,0:48:56.74,yin,,0,0,0,, 也就是这个属性 count\\N{\\fs12}that’s this property right here. Count.\r\nDialogue: 0,0:48:59.17,0:49:02.71,yin,,0,0,0,, 这就是这一数组中按钮的数量 \\N{\\fs12}So this is the number of buttons that’s in this array.\r\nDialogue: 0,0:49:02.73,0:49:06.09,yin,,0,0,0,, 这很好 对我们而言很不错 \\N{\\fs12}So that was good. That worked out well for us.\r\nDialogue: 0,0:49:06.09,0:49:10.19,yin,,0,0,0,, 有了这个很好的按钮数组之后 我们还可以更新它们 \\N{\\fs12}Now we also have a nice array of these buttons so that we can update them\r\nDialogue: 0,0:49:10.19,0:49:13.01,yin,,0,0,0,, 配合模型中发生的情况 \\N{\\fs12}with what’s happening in the model.\r\nDialogue: 0,0:49:13.01,0:49:15.69,yin,,0,0,0,, 首先 让我们来讨论触摸一张牌时 该怎么做 \\N{\\fs12}So, first though, let’s talk about touching a card,\r\nDialogue: 0,0:49:15.69,0:49:17.90,yin,,0,0,0,, 首先 让我们来讨论触摸一张牌时 该怎么做 \\N{\\fs12}when you touch on a card, what are we going to do,\r\nDialogue: 0,0:49:17.90,0:49:21.92,yin,,0,0,0,, 显然不是这一堆垃圾 删掉这些 \\N{\\fs12}well we don’t want to do any of this junk. So we’re just going to rid of all of that.\r\nDialogue: 0,0:49:21.92,0:49:24.67,yin,,0,0,0,, 因为我们要让模型来处理 \\N{\\fs12}Because we’re going to let the model handle it.\r\nDialogue: 0,0:49:24.67,0:49:28.78,yin,,0,0,0,, 要让模型来处理 我们需要做的是 \\N{\\fs12}So all we need to do to let the model handle this is\r\nDialogue: 0,0:49:28.78,0:49:33.06,yin,,0,0,0,, 获得这一按钮所关联的纸牌 \\N{\\fs12}to get the card that this button is associated with,\r\nDialogue: 0,0:49:33.06,0:49:35.46,yin,,0,0,0,, 因为这些按钮仍然在发送这个 \\N{\\fs12}because these buttons are all still sending this,\r\nDialogue: 0,0:49:35.46,0:49:38.61,yin,,0,0,0,, 看这个 12 个都在发送这个动作 \\N{\\fs12}if you look at this, see all 12 of them are sending this action\r\nDialogue: 0,0:49:38.61,0:49:42.19,yin,,0,0,0,, 而发送器仍然是你实际触摸的按钮 \\N{\\fs12}and the sender is still the actual button you touched on,\r\nDialogue: 0,0:49:42.19,0:49:43.85,yin,,0,0,0,, 不是数组 而是实际按钮 \\N{\\fs12}not the array, but the actual button,\r\nDialogue: 0,0:49:43.85,0:49:46.83,yin,,0,0,0,, 因为这是这里的目标动作事物 \\N{\\fs12}because this is the target action thing right here.\r\nDialogue: 0,0:49:46.83,0:49:50.79,yin,,0,0,0,, 我们仍然能够弄清 是谁发送的 实际上 \\N{\\fs12}So, we can still find out who sending it and, in fact,\r\nDialogue: 0,0:49:50.79,0:49:54.18,yin,,0,0,0,, 我们甚至还可以找到它在这个数组中的下标 \\N{\\fs12}we can even find out it’s index in this array\r\nDialogue: 0,0:49:54.18,0:49:57.32,yin,,0,0,0,, 通过如下代码 cardIndex =\\N{\\fs12}by saying card index equals\r\nDialogue: 0,0:49:57.32,0:50:02.49,yin,,0,0,0,,[self.cardButtons indextOfObject:sender]\\N{\\fs12}self dot card buttons, index of object, sender.\r\nDialogue: 0,0:50:02.49,0:50:03.80,yin,,0,0,0,, 这将告诉我们 \\N{\\fs12}So this is going to tell us\r\nDialogue: 0,0:50:03.80,0:50:09.33,yin,,0,0,0,, 这一发送按钮处在数组中什么地方 \\N{\\fs12}where this sending button is in this array.\r\nDialogue: 0,0:50:10.76,0:50:13.92,yin,,0,0,0,, 这样我们就知道了它是数组中哪张牌 \\N{\\fs12}So now that we know which card it is in the array,\r\nDialogue: 0,0:50:13.92,0:50:18.91,yin,,0,0,0,, 我们可以让游戏 选择那一下标处的纸牌 \\N{\\fs12}we can just tell our game please choose the card at that index.\r\nDialogue: 0,0:50:22.04,0:50:25.17,yin,,0,0,0,, 我们会告诉我们的模型 嘿 选那张牌 \\N{\\fs12}And we’re just going to tell our model, hey, choose that card.\r\nDialogue: 0,0:50:25.17,0:50:26.96,yin,,0,0,0,, 有一点要注意 \\N{\\fs12}Now, one thing here though is\r\nDialogue: 0,0:50:26.96,0:50:30.02,yin,,0,0,0,, 选那张牌可能改变游戏状态 \\N{\\fs12}choosing that card might change the state of the game.\r\nDialogue: 0,0:50:30.02,0:50:33.18,yin,,0,0,0,, 这会导致分数变化 或纸牌匹配 \\N{\\fs12}It might cause some points or match some cards,\r\nDialogue: 0,0:50:33.18,0:50:34.67,yin,,0,0,0,, 很多东西会变 \\N{\\fs12}a lot of things can change,\r\nDialogue: 0,0:50:34.67,0:50:37.98,yin,,0,0,0,, 所以这里需要 updateUI 来更新 UI\\N{\\fs12}so we’re going to put a little update UI here.\r\nDialogue: 0,0:50:37.98,0:50:40.05,yin,,0,0,0,, 这个 updateUI 方法 \\N{\\fs12}And this update UI method, which we’re going to have\r\nDialogue: 0,0:50:40.05,0:50:44.12,yin,,0,0,0,, 等下我们会写 它会让 UI 同模型同步 \\N{\\fs12}to write has got to keep our UI in sync with the model.\r\nDialogue: 0,0:50:44.12,0:50:47.17,yin,,0,0,0,, 记得吧 这是控制器的首要任务之一 \\N{\\fs12}And remember that’s one of the primary things a controller does,\r\nDialogue: 0,0:50:47.17,0:50:51.08,yin,,0,0,0,, 它会同步模型和 UI\\N{\\fs12}it syncs up the model with the UI.\r\nDialogue: 0,0:50:51.78,0:50:54.93,yin,,0,0,0,, 这里我们来加一小段代码 \\N{\\fs12}So let’s go ahead and put a little thing here.\r\nDialogue: 0,0:50:54.93,0:50:56.87,yin,,0,0,0,,updateUI\\N{\\fs12}Update UI.\r\nDialogue: 0,0:50:56.87,0:51:00.05,yin,,0,0,0,, 更新 UI 时我们需要做什么呢 \\N{\\fs12}So what do we need to do when we’re updating this UI?\r\nDialogue: 0,0:51:00.05,0:51:04.43,yin,,0,0,0,, 其实很简单 我们将遍历所有纸牌按钮 \\N{\\fs12}It’s actually pretty simple, we’re just going to go through all the card buttons.\r\nDialogue: 0,0:51:04.43,0:51:09.80,yin,,0,0,0,, 获得那个纸牌按钮 同时在模型中观察相应纸牌 \\N{\\fs12}Get that card button, simultaneously look into the model for that card,\r\nDialogue: 0,0:51:09.80,0:51:13.91,yin,,0,0,0,, 确保纸牌按钮展示出它所应该展示的纸牌内容 \\N{\\fs12}and make sure the card button is showing what should be on that card.\r\nDialogue: 0,0:51:13.91,0:51:19.28,yin,,0,0,0,, 所以这里需要 for (UIButton *cardButton\\N{\\fs12}So, let’s go for UI button, card button,\r\nDialogue: 0,0:51:19.28,0:51:22.02,yin,,0,0,0,, 属于我们的 cardButtons 中 )\\N{\\fs12}in our card buttons.\r\nDialogue: 0,0:51:22.02,0:51:24.50,yin,,0,0,0,, 这里是遍历所有这些按钮 \\N{\\fs12}So we’re iterating through all these buttons.\r\nDialogue: 0,0:51:24.50,0:51:27.77,yin,,0,0,0,,carbButton 是迭代变量 \\N{\\fs12}Card button is going to be the variable.\r\nDialogue: 0,0:51:27.77,0:51:31.80,yin,,0,0,0,, 让我们获取 cardIndex 还是一样 \\N{\\fs12}Let’s go ahead and get that card index, again, for the same thing,\r\nDialogue: 0,0:51:31.80,0:51:35.29,yin,,0,0,0,,self.cardButtons indexOfObject\\N{\\fs12}self dot card buttons, index of object,\r\nDialogue: 0,0:51:35.29,0:51:38.55,yin,,0,0,0,,carbButton 是我们的迭代变量 \\N{\\fs12}the card button that is our iteration variable\r\nDialogue: 0,0:51:38.55,0:51:40.58,yin,,0,0,0,, 这些东西明白了吗 \\N{\\fs12}and we’re cool with what we’re doing there.\r\nDialogue: 0,0:51:40.58,0:51:43.37,yin,,0,0,0,, 我们弄清了这是哪张牌 \\N{\\fs12}Alright? So we’re just figuring out which card it is.\r\nDialogue: 0,0:51:43.37,0:51:49.04,yin,,0,0,0,, 然后我们要让模型给我们那一下标处的牌 \\N{\\fs12}Then we’re going to ask our model, give us the card at that index,\r\nDialogue: 0,0:51:49.04,0:51:51.20,yin,,0,0,0,, 使用 cardAtIndex\\N{\\fs12}using card at index.\r\nDialogue: 0,0:51:54.45,0:51:58.65,yin,,0,0,0,, 现在我们就有了纸牌按钮和纸牌 很棒 \\N{\\fs12}So now we have the card button and the card, awesome.\r\nDialogue: 0,0:51:58.65,0:52:03.61,yin,,0,0,0,, 下面我们来确保纸牌按钮反映了纸牌上的情况 \\N{\\fs12}Now we can make sure the card button reflects the card that goes along with it.\r\nDialogue: 0,0:52:03.61,0:52:06.41,yin,,0,0,0,, 我们需要在按钮上设置什么 \\N{\\fs12}So, what do we need to set on the button?\r\nDialogue: 0,0:52:06.41,0:52:10.50,yin,,0,0,0,, 我们需要设置纸牌按钮的标题 \\N{\\fs12}Well, let’s see, we have to set the card buttons title.\r\nDialogue: 0,0:52:10.50,0:52:12.39,yin,,0,0,0,, 这里是 setTitle:\\N{\\fs12}So set title\r\nDialogue: 0,0:52:12.39,0:52:18.04,yin,,0,0,0,,forState:UIControlStateNormal\\N{\\fs12}for state UI control state, control state normal.\r\nDialogue: 0,0:52:19.52,0:52:22.70,yin,,0,0,0,, 我们还需要设置背景图像 \\N{\\fs12}And we have to set the background image.\r\nDialogue: 0,0:52:23.16,0:52:26.72,yin,,0,0,0,, 取决于这里是斯坦福 logo 还是空白背景 \\N{\\fs12}Depending on whether it’s the Stanford logo or the blank background.\r\nDialogue: 0,0:52:29.80,0:52:33.70,yin,,0,0,0,, 而且 如果纸牌已被匹配 \\N{\\fs12}Also, if the card is matched,\r\nDialogue: 0,0:52:33.70,0:52:35.73,yin,,0,0,0,, 我将禁用按钮 \\N{\\fs12}I’m going to disable the button.\r\nDialogue: 0,0:52:35.73,0:52:37.73,yin,,0,0,0,, 因为纸牌已经被匹配 \\N{\\fs12}Because you’ve already matched this card,\r\nDialogue: 0,0:52:37.73,0:52:39.98,yin,,0,0,0,, 你不能再点它 我将禁用它 \\N{\\fs12}you can’t click on it anyway, so I’m going to disable it\r\nDialogue: 0,0:52:39.98,0:52:41.92,yin,,0,0,0,, 因为禁用的按钮会略显不同 \\N{\\fs12}because a disabled button looks a little different\r\nDialogue: 0,0:52:41.92,0:52:44.39,yin,,0,0,0,, 而我希望已匹配的按钮有所不同 \\N{\\fs12}and I want buttons that are matched to look different.\r\nDialogue: 0,0:52:44.39,0:52:45.02,yin,,0,0,0,, 请讲 \\N{\\fs12}Yeah?\r\nDialogue: 0,0:52:50.97,0:52:51.84,yin,,0,0,0,, 确实 \\N{\\fs12}It does.\r\nDialogue: 0,0:52:51.84,0:52:54.76,yin,,0,0,0,, 问题是 这样的快速枚举 \\N{\\fs12}So the question is does a fast enumeration like this,\r\nDialogue: 0,0:52:54.76,0:52:56.57,yin,,0,0,0,, 使用这种 for in 结构 \\N{\\fs12}when you do this for in thing,\r\nDialogue: 0,0:52:56.57,0:52:59.69,yin,,0,0,0,, 是从 0 到 N 吗 答案是肯定的 \\N{\\fs12}does that go from the zero to the N and the answer, it does.\r\nDialogue: 0,0:52:59.69,0:53:01.93,yin,,0,0,0,, 确实是按顺序来的 \\N{\\fs12}It does go in order.\r\nDialogue: 0,0:53:01.93,0:53:05.69,yin,,0,0,0,, 你可以 问题是 这不是必需的吧 \\N{\\fs12}You could. So the question is do you, do you not need this,\r\nDialogue: 0,0:53:05.69,0:53:07.68,yin,,0,0,0,, 你可以用别的迭代变量 \\N{\\fs12}you could just have another iteration variable\r\nDialogue: 0,0:53:07.68,0:53:10.44,yin,,0,0,0,, 或者你也可以使用迭代变量 i\\N{\\fs12}or you could use an iteration variable here,\r\nDialogue: 0,0:53:10.44,0:53:12.22,yin,,0,0,0,, 如 for i = 0 to 长度 \\N{\\fs12}like for i equals 0 to the length?\r\nDialogue: 0,0:53:12.22,0:53:13.54,yin,,0,0,0,, 你可以 \\N{\\fs12}You could.\r\nDialogue: 0,0:53:13.55,0:53:17.39,yin,,0,0,0,, 我不喜欢用那种 0 到具体长度 \\N{\\fs12}I don’t like to depend on that going from 0 to whatever,\r\nDialogue: 0,0:53:17.39,0:53:20.54,yin,,0,0,0,, 所以我使用这个 这是风格问题 \\N{\\fs12}so that’s why I used this here. It’s a matter of style.\r\nDialogue: 0,0:53:20.54,0:53:21.65,yin,,0,0,0,, 完全是风格问题 \\N{\\fs12}Totally a matter of style.\r\nDialogue: 0,0:53:21.65,0:53:23.01,yin,,0,0,0,, 而且这样更清晰一些 \\N{\\fs12}This is also kind of a little clearer,\r\nDialogue: 0,0:53:23.01,0:53:25.33,yin,,0,0,0,, 因为这里我说 我想要 \\N{\\fs12}because here I’m saying I want the card that goes with,\r\nDialogue: 0,0:53:25.33,0:53:28.32,yin,,0,0,0,, 这里的所有纸牌按钮 \\N{\\fs12}you know, the card button that goes with this thing.\r\nDialogue: 0,0:53:28.32,0:53:31.11,yin,,0,0,0,, 最后我要说的是 \\N{\\fs12}So, so the last thing I’m going to say is\r\nDialogue: 0,0:53:31.11,0:53:38.22,yin,,0,0,0,,cardButton.enabled = !card.isMatched\\N{\\fs12}the card button enabled equals the card, not card is matched.\r\nDialogue: 0,0:53:40.31,0:53:43.98,yin,,0,0,0,, 只有纸牌没有被匹配时 按钮才启用 \\N{\\fs12}So, the card, the button will only be enabled if the card is not matched.\r\nDialogue: 0,0:53:45.12,0:53:49.04,yin,,0,0,0,, 当然 我还有这两个东西没有提供 \\N{\\fs12}Okay, now of course I have these two things, which I haven’t provided, right?\r\nDialogue: 0,0:53:49.04,0:53:52.54,yin,,0,0,0,, 我们还没有这些参数 \\N{\\fs12}I’ve just left them, we don’t have that argument.\r\nDialogue: 0,0:53:52.54,0:53:54.32,yin,,0,0,0,, 实际上对于这两者 \\N{\\fs12}And actually for both of those,\r\nDialogue: 0,0:53:54.32,0:53:59.21,yin,,0,0,0,, 我都将创建别的辅助方法 \\N{\\fs12}I’m going to create little other methods here, helper methods.\r\nDialogue: 0,0:53:59.21,0:54:01.27,yin,,0,0,0,, 对于标题 \\N{\\fs12}So, I’m going, for the title,\r\nDialogue: 0,0:54:01.27,0:54:04.15,yin,,0,0,0,, 我将创建一个辅助方法叫 titleForCard\\N{\\fs12}I’m going to have a helper method called title for card.\r\nDialogue: 0,0:54:04.98,0:54:06.98,yin,,0,0,0,, 它使用 card 作为参数 \\N{\\fs12}It’s going to take a card as the argument.\r\nDialogue: 0,0:54:07.50,0:54:10.32,yin,,0,0,0,, 而且它会返回 card 的标题 \\N{\\fs12}And it’s going to return the title of that card,\r\nDialogue: 0,0:54:10.32,0:54:12.90,yin,,0,0,0,, 背景我将使用 (UIImage *)\\N{\\fs12}and for the background I’m going to have UI image,\r\nDialogue: 0,0:54:12.91,0:54:16.33,yin,,0,0,0,,backgroundImageForCard\\N{\\fs12}background image for card.\r\nDialogue: 0,0:54:18.36,0:54:22.01,yin,,0,0,0,, 但愿随着课程推进 你们能理解我们的命名惯例 \\N{\\fs12}Hopefully as we’ll go along you’ll start to see the naming conventions that we use.\r\nDialogue: 0,0:54:22.01,0:54:26.94,yin,,0,0,0,, 我们通常会把冒号前名称的最后这部分 \\N{\\fs12}We often try to have this last part of a name of a method before a colon\r\nDialogue: 0,0:54:26.94,0:54:29.19,yin,,0,0,0,, 用来表示我们要的东西 \\N{\\fs12}indicate what we’re looking for.\r\nDialogue: 0,0:54:29.19,0:54:32.38,yin,,0,0,0,, 这里我们要的是一张牌 \\N{\\fs12}So here we’re looking for a card, so we try to make a thing.\r\nDialogue: 0,0:54:32.38,0:54:35.89,yin,,0,0,0,, 再看这个 按钮 对吧 这是一个按钮 \\N{\\fs12}Look at this one, button, right? This is a button.\r\nDialogue: 0,0:54:35.89,0:54:38.68,yin,,0,0,0,, 这里我们是在告诉代码的读者 \\N{\\fs12}So we try to make these arguments\r\nDialogue: 0,0:54:38.68,0:54:42.15,yin,,0,0,0,, 我们想要放到这里的是什么参数 \\N{\\fs12}guide the reader towards what we’re asking for there.\r\nDialogue: 0,0:54:42.15,0:54:44.46,yin,,0,0,0,, 对此 我们也不必太过拘泥 \\N{\\fs12}We don’t want to get too overwrought about it,\r\nDialogue: 0,0:54:44.46,0:54:47.43,yin,,0,0,0,, 不过总的命名惯例就是这样 \\N{\\fs12}but it’s a general naming convention there.\r\nDialogue: 0,0:54:47.43,0:54:49.55,yin,,0,0,0,, 一张给定纸牌的标题是什么 \\N{\\fs12}So, what is the title of a given card?\r\nDialogue: 0,0:54:49.55,0:54:51.97,yin,,0,0,0,, 我有一张牌 它的标题是什么 \\N{\\fs12}So I have the card, what’s its title?\r\nDialogue: 0,0:54:51.97,0:54:55.03,yin,,0,0,0,, 如果纸牌已被选择 \\N{\\fs12}Well, if the card is chosen,\r\nDialogue: 0,0:54:55.03,0:54:58.22,yin,,0,0,0,, 那么我将返回纸牌的内容 \\N{\\fs12}then I’m going to return the contents of the card.\r\nDialogue: 0,0:54:58.22,0:55:01.11,yin,,0,0,0,, 否则 我会返回空字符串或 nil\\N{\\fs12}If it’s not, I’m going to return empty string or nil,\r\nDialogue: 0,0:55:01.11,0:55:04.66,yin,,0,0,0,, 所以这里写 return card.isChosen\\N{\\fs12}so I’m just going to say return card dot is chosen,\r\nDialogue: 0,0:55:04.66,0:55:07.44,yin,,0,0,0,,? card.contents\\N{\\fs12}question mark, car dot contents,\r\nDialogue: 0,0:55:07.44,0:55:08.46,yin,,0,0,0,, 否则 \\N{\\fs12}otherwise,\r\nDialogue: 0,0:55:08.46,0:55:11.15,yin,,0,0,0,, 空字符串或 nil 这里都行 \\N{\\fs12}empty string let’s say or nil, either one in this case.\r\nDialogue: 0,0:55:11.15,0:55:12.77,yin,,0,0,0,, 背景图像怎么办呢 \\N{\\fs12}And how about the background image?\r\nDialogue: 0,0:55:12.77,0:55:16.22,yin,,0,0,0,, 这个很酷 这里我说 返回 UIImage\\N{\\fs12}This is kind of a cool one, I’m going to say return UI image,\r\nDialogue: 0,0:55:16.22,0:55:22.20,yin,,0,0,0,, 图像名为 card.isChosen\\N{\\fs12}image name is card dot is chosen,\r\nDialogue: 0,0:55:22.20,0:55:26.61,yin,,0,0,0,, 如果纸牌被选 那么我想要正面 \\N{\\fs12}so if the card is chosen, then I want the card front,\r\nDialogue: 0,0:55:26.61,0:55:28.61,yin,,0,0,0,, 否则我想要反面 \\N{\\fs12}otherwise the card back,\r\nDialogue: 0,0:55:28.61,0:55:34.07,yin,,0,0,0,, 你肯定会觉得 我很钟爱这种?: 语法 \\N{\\fs12}now you probably think I’m just in love with this question mark colon syntax,\r\nDialogue: 0,0:55:34.07,0:55:36.14,yin,,0,0,0,, 我确实喜欢 它很简洁 \\N{\\fs12}which I do like it a lot, it’s kind of clean.\r\nDialogue: 0,0:55:36.14,0:55:37.85,yin,,0,0,0,, 反正你们是懂的 对吧 \\N{\\fs12}But anyway, you understand what I’m doing here, right?\r\nDialogue: 0,0:55:37.85,0:55:40.78,yin,,0,0,0,, 我在名称这里 \\N{\\fs12}I’m actually having the name in here\r\nDialogue: 0,0:55:40.78,0:55:42.98,yin,,0,0,0,, 嵌套了?: 结构 \\N{\\fs12}with the question mark colon nested inside,\r\nDialogue: 0,0:55:42.98,0:55:45.92,yin,,0,0,0,, 这样来获得图像 \\N{\\fs12}[inaudible] to get the, the image.\r\nDialogue: 0,0:55:47.57,0:55:50.05,yin,,0,0,0,, 下面 我就可以将其用到这里了 \\N{\\fs12}So now, I can use that here.\r\nDialogue: 0,0:55:50.05,0:55:51.27,yin,,0,0,0,, 首先是标题 \\N{\\fs12}Let’s do the title first.\r\nDialogue: 0,0:55:51.27,0:55:54.94,yin,,0,0,0,, 这里我写 self titleForCard:card\\N{\\fs12}I’m just going to self, title for card, the card,\r\nDialogue: 0,0:55:54.94,0:55:56.64,yin,,0,0,0,, 然后这里我写 \\N{\\fs12}and then here I’m going to say\r\nDialogue: 0,0:55:56.64,0:55:59.42,yin,,0,0,0,,self backgroundImageForCard:card\\N{\\fs12}self background image for card, card,\r\nDialogue: 0,0:55:59.42,0:56:04.76,yin,,0,0,0,, 这两处我都加个回车 这样更清晰一些 \\N{\\fs12}and both of these I’m going to hit return just to make this a little easier to see.\r\nDialogue: 0,0:56:04.76,0:56:08.06,yin,,0,0,0,, 这基本就算完了 \\N{\\fs12}So, that’s pretty much it.\r\nDialogue: 0,0:56:08.06,0:56:11.98,yin,,0,0,0,, 我将 UI 同模型匹配了起来 \\N{\\fs12}I’ve matched up my UI with my model,\r\nDialogue: 0,0:56:11.98,0:56:16.25,yin,,0,0,0,, 触摸 UI 时 我让模型知道去选一张牌 \\N{\\fs12}when I touch in the UI I let my model know to choose a card\r\nDialogue: 0,0:56:16.26,0:56:19.18,yin,,0,0,0,, 我们基本上搞定了 \\N{\\fs12}and we’re pretty much good to go.\r\nDialogue: 0,0:56:19.18,0:56:23.23,yin,,0,0,0,, 我想我要做的都做了 分数我等下再处理 \\N{\\fs12}I think that’s all I had to show, yeah, we’ll, we’ll do the score in a second here.\r\nDialogue: 0,0:56:23.23,0:56:26.19,yin,,0,0,0,, 分数确实需要 但这之前 \\N{\\fs12}We need to score, but before we do the score, let’s go ahead\r\nDialogue: 0,0:56:26.19,0:56:29.27,yin,,0,0,0,, 我们先来运行这个 确保它能工作 \\N{\\fs12}and run this and make sure that it’s working.\r\nDialogue: 0,0:56:29.27,0:56:33.87,yin,,0,0,0,, 我点它 得到的应该是随机纸牌 \\N{\\fs12}Okay, so when I click, hopefully I get a random card,\r\nDialogue: 0,0:56:33.87,0:56:37.18,yin,,0,0,0,, 再点它 应该得到相同的牌 \\N{\\fs12}and when I click again, hopefully it continues to be the same card.\r\nDialogue: 0,0:56:37.18,0:56:39.81,yin,,0,0,0,, 如果总得到随机纸牌 那就糟了 \\N{\\fs12}It’d be bad if that was constantly getting random card,\r\nDialogue: 0,0:56:39.81,0:56:42.18,yin,,0,0,0,, 但我们删掉了那部分代码 肯定不会是那样 \\N{\\fs12}but we know that we got rid of that code so it’s not going to do that.\r\nDialogue: 0,0:56:42.18,0:56:43.62,yin,,0,0,0,, 这里是 K\\N{\\fs12}So there’s a king,\r\nDialogue: 0,0:56:43.63,0:56:44.77,yin,,0,0,0,, 然后是 5\\N{\\fs12}five,\r\nDialogue: 0,0:56:44.77,0:56:46.64,yin,,0,0,0,,2 我们得到了两个梅花 \\N{\\fs12}two, okay, now we got two clubs right here.\r\nDialogue: 0,0:56:46.64,0:56:49.32,yin,,0,0,0,, 我可以这样做 哦 不能匹配 \\N{\\fs12}So I could do that, oh, didn’t match.\r\nDialogue: 0,0:56:49.32,0:56:51.92,yin,,0,0,0,, 为什么不能匹配上呢 \\N{\\fs12}So why don’t these match?\r\nDialogue: 0,0:56:51.92,0:56:53.21,yin,,0,0,0,, 它们应该匹配上 \\N{\\fs12}They should match.\r\nDialogue: 0,0:56:53.21,0:56:55.98,yin,,0,0,0,, 原因有人能够告诉我吗 请讲 \\N{\\fs12}And the answer, anyone want to tell me? Yeah?\r\nDialogue: 0,0:56:57.40,0:56:58.49,yin,,0,0,0,, 正是 \\N{\\fs12}Absolutely.\r\nDialogue: 0,0:56:58.49,0:57:01.90,yin,,0,0,0,, 我们唯一的匹配函数 是这个很糟糕的 match 函数 \\N{\\fs12}The only match function we have is this really bad match function,\r\nDialogue: 0,0:57:01.90,0:57:03.41,yin,,0,0,0,, 我们来看看 \\N{\\fs12}let’s go look at it.\r\nDialogue: 0,0:57:03.41,0:57:07.93,yin,,0,0,0,, 它在 Card 中 整个应用中就这唯一一个匹配函数 \\N{\\fs12}It’s right here in card, okay, this is the only match function\r\nDialogue: 0,0:57:07.93,0:57:10.04,yin,,0,0,0,, 它在 Card 中 整个应用中就这唯一一个匹配函数 \\N{\\fs12}that exists in our entire application\r\nDialogue: 0,0:57:10.04,0:57:13.37,yin,,0,0,0,, 它说 只有两张牌完全相等时才匹配 \\N{\\fs12}and it only says it’s a match if both cards are identical,\r\nDialogue: 0,0:57:13.37,0:57:15.88,yin,,0,0,0,, 这在我们的情况中永远无法成立 \\N{\\fs12}well that’s never going to be true in our thing,\r\nDialogue: 0,0:57:15.88,0:57:19.50,yin,,0,0,0,, 因为我们的牌堆中是 52 张不同的牌 \\N{\\fs12}because we have a deck of 52 cards, every single one is different.\r\nDialogue: 0,0:57:19.50,0:57:22.31,yin,,0,0,0,, 这将永远无法匹配上 怎么解决呢 \\N{\\fs12}So it’s never going to match. So how do we deal with this?\r\nDialogue: 0,0:57:22.31,0:57:27.45,yin,,0,0,0,, 我们需要告诉 PlayingCard 如何更好地匹配 \\N{\\fs12}Well we need to teach playing card how to be a better matcher.\r\nDialogue: 0,0:57:27.45,0:57:32.00,yin,,0,0,0,, 因为 Card 对 match 的这种实现根本不够 \\N{\\fs12}Because cards implementation of match is simply not sufficient.\r\nDialogue: 0,0:57:32.00,0:57:34.52,yin,,0,0,0,, 所以我们需要重写这个 \\N{\\fs12}So what we’re going to do is we’re going to override this,\r\nDialogue: 0,0:57:34.52,0:57:35.94,yin,,0,0,0,, 我们使用面向对象编程 \\N{\\fs12}we use object-oriented programming,\r\nDialogue: 0,0:57:35.94,0:57:38.36,yin,,0,0,0,, 我们在这里就是做这个 我将重写它 \\N{\\fs12}that’s what we’re here for, so we’re going to override it.\r\nDialogue: 0,0:57:38.36,0:57:40.50,yin,,0,0,0,, 我们来到 PlayingCard 这是 PlayingCard\\N{\\fs12}Let’s go to playing card, here’s playing card.\r\nDialogue: 0,0:57:40.50,0:57:45.90,yin,,0,0,0,, 注意到 PlayingCard 没有在公共 API 中声明 match\\N{\\fs12}Now, notice the playing card doesn’t declare match in its public API.\r\nDialogue: 0,0:57:45.92,0:57:48.18,yin,,0,0,0,, 它是从 Card 中继承得到的 \\N{\\fs12}It inherits it from card\r\nDialogue: 0,0:57:48.18,0:57:51.53,yin,,0,0,0,, 我不打算重新声明它 因为我只需要实现它 \\N{\\fs12}and I’m not going to redeclare it just because I’m going to implement it.\r\nDialogue: 0,0:57:51.53,0:57:56.97,yin,,0,0,0,, 我将到这里重新实现 match\\N{\\fs12}So I am going to go here and I’m going to re-implement match.\r\nDialogue: 0,0:57:56.97,0:58:00.02,yin,,0,0,0,, 它知道 match 是我继承的方法 \\N{\\fs12}It knows that match is method I inherit,\r\nDialogue: 0,0:58:00.02,0:58:02.30,yin,,0,0,0,, 因此 这里它能够自动补全 \\N{\\fs12}that’s why it was able to escape, complete it like that.\r\nDialogue: 0,0:58:02.30,0:58:05.07,yin,,0,0,0,, 但我不打算把它放入我的公共 API\\N{\\fs12}But I’m not going to put it in my public API\r\nDialogue: 0,0:58:05.07,0:58:06.63,yin,,0,0,0,, 这就是我们的一般做法 \\N{\\fs12}and that’s generally the way we do it.\r\nDialogue: 0,0:58:06.63,0:58:09.61,yin,,0,0,0,, 一般而言 如果你继承了一个公共方法 \\N{\\fs12}Generally, if you inherit a method and you, a public method,\r\nDialogue: 0,0:58:09.61,0:58:12.17,yin,,0,0,0,, 你重写它 你就不需要再把它放入你的头文件了 \\N{\\fs12}and you override it, you don’t have to put it in your header again.\r\nDialogue: 0,0:58:12.17,0:58:14.82,yin,,0,0,0,, 有些人的风格希望把它放到那里 \\N{\\fs12}Some stylistically would say, yes, put it in there,\r\nDialogue: 0,0:58:14.82,0:58:17.09,yin,,0,0,0,, 这样别人就知道你在重写它 \\N{\\fs12}so that someone knows that you override it.\r\nDialogue: 0,0:58:17.09,0:58:19.42,yin,,0,0,0,, 但大多数面向对象的人会说 \\N{\\fs12}But most object-oriented people would say\r\nDialogue: 0,0:58:19.42,0:58:21.89,yin,,0,0,0,, 你不需要知道你重写了它 \\N{\\fs12}you shouldn’t have to know that you override it.\r\nDialogue: 0,0:58:21.89,0:58:23.64,yin,,0,0,0,, 这是面向对象编程 \\N{\\fs12}Alright? This is object-oriented programming.\r\nDialogue: 0,0:58:23.64,0:58:24.97,yin,,0,0,0,, 你无需知道这个 \\N{\\fs12}You should not have to know that.\r\nDialogue: 0,0:58:24.97,0:58:29.08,yin,,0,0,0,, 你重写了 match 只是实现细节 \\N{\\fs12}That, that’s implementation detail that you happen to override match here.\r\nDialogue: 0,0:58:29.08,0:58:32.49,yin,,0,0,0,, 我是不将 match 写到 PlayingCard 中的支持者 \\N{\\fs12}So, I’m a fan of the not putting match in playing card,\r\nDialogue: 0,0:58:32.49,0:58:34.57,yin,,0,0,0,, 它已经在 PlayingCard 公共 API 中了 \\N{\\fs12}it’s already in playing cards public API\r\nDialogue: 0,0:58:34.57,0:58:36.62,yin,,0,0,0,, 因为这会继承自 Card\\N{\\fs12}because it inherits it from card.\r\nDialogue: 0,0:58:36.62,0:58:38.51,yin,,0,0,0,,match 中我们怎么做呢 \\N{\\fs12}Alright, so what are we going to do in match?\r\nDialogue: 0,0:58:38.51,0:58:40.32,yin,,0,0,0,, 我这里随便弄一个 \\N{\\fs12}Well, I’m going to have a really dumb match.\r\nDialogue: 0,0:58:40.32,0:58:42.09,yin,,0,0,0,, 你们在作业中需要设计个更好的 \\N{\\fs12}You’re going to need a better one for your homework.\r\nDialogue: 0,0:58:42.09,0:58:44.95,yin,,0,0,0,, 我这个笨拙的 match 将只匹配一张牌 \\N{\\fs12}My dumb match only can match one other cards.\r\nDialogue: 0,0:58:44.95,0:58:47.04,yin,,0,0,0,, 所以这里首先我要说的是 \\N{\\fs12}So and the first thing I’m going to say here,\r\nDialogue: 0,0:58:47.04,0:58:51.77,yin,,0,0,0,,int score = 0 以及 return score\\N{\\fs12}let’s go ahead and do int score equals zero and return score.\r\nDialogue: 0,0:58:51.77,0:58:53.93,yin,,0,0,0,, 然后我要说的第一件事是 \\N{\\fs12}The first thing I’m going to say is\r\nDialogue: 0,0:58:53.93,0:58:59.12,yin,,0,0,0,,if ([otherCards count] == 1)\\N{\\fs12}if other cards count [pause] equals one.\r\nDialogue: 0,0:58:59.12,0:59:02.09,yin,,0,0,0,, 我将只匹配一张牌 \\N{\\fs12}So I’m only going to match one other card.\r\nDialogue: 0,0:59:02.09,0:59:04.66,yin,,0,0,0,, 有两张牌 则没有匹配 \\N{\\fs12}If there’s two cards in there, no match.\r\nDialogue: 0,0:59:04.66,0:59:06.42,yin,,0,0,0,, 对我而言 太多了 \\N{\\fs12}Too, too much for me.\r\nDialogue: 0,0:59:06.42,0:59:09.07,yin,,0,0,0,, 所以我只处理这一张牌 \\N{\\fs12}So I’m just going to say this one thing.\r\nDialogue: 0,0:59:09.07,0:59:12.04,yin,,0,0,0,, 但我需要这另外一张牌 如何获得呢 \\N{\\fs12}Now, I need that other card though, how do I get the other card?\r\nDialogue: 0,0:59:12.04,0:59:14.17,yin,,0,0,0,, 我要说的是 \\N{\\fs12}I’m going to say card star other, in fact,\r\nDialogue: 0,0:59:14.17,0:59:20.27,yin,,0,0,0,,PlayingCard *otherCard =\\N{\\fs12}I’m going to say playing card star other card equals,\r\nDialogue: 0,0:59:20.27,0:59:22.39,yin,,0,0,0,, 这里我可以做很多事 \\N{\\fs12}and I could do a lot of things here.\r\nDialogue: 0,0:59:22.39,0:59:25.08,yin,,0,0,0,, 我可以说 otherCards[0]\\N{\\fs12}I could say other cards sub zero,\r\nDialogue: 0,0:59:25.09,0:59:28.44,yin,,0,0,0,, 但这里 我想使用一个我希望你们知道的方法 \\N{\\fs12}but I’m actually going to use a method here I want you to know\r\nDialogue: 0,0:59:28.44,0:59:31.29,yin,,0,0,0,, 叫作 firstObject\\N{\\fs12}called first object.\r\nDialogue: 0,0:59:31.29,0:59:34.84,yin,,0,0,0,,otherCards firstObject\\N{\\fs12}Other cards, first object.\r\nDialogue: 0,0:59:34.84,0:59:38.53,yin,,0,0,0,,firstObject 返回数组的第一个对象 \\N{\\fs12}Okay, first object returns the first object in an array.\r\nDialogue: 0,0:59:38.53,0:59:41.72,yin,,0,0,0,, 如果数组为空 它会返回 nil\\N{\\fs12}If the array is empty, it returns nil.\r\nDialogue: 0,0:59:41.72,0:59:44.81,yin,,0,0,0,, 这不同于 otherCards[0]\\N{\\fs12}That’s different than saying other cards sub zero.\r\nDialogue: 0,0:59:44.81,0:59:47.66,yin,,0,0,0,,otherCards[0] 在数组为空时会崩溃 \\N{\\fs12}Because if that array is empty, that will crash.\r\nDialogue: 0,0:59:47.66,0:59:49.16,yin,,0,0,0,, 导致数组下标越界错误 \\N{\\fs12}That will say array index out of bounds.\r\nDialogue: 0,0:59:49.16,0:59:50.16,yin,,0,0,0,, 明白这种差别吗 \\N{\\fs12}You see the difference?\r\nDialogue: 0,0:59:50.16,0:59:52.34,yin,,0,0,0,,firstObject 还有 lastObject\\N{\\fs12}First object, there’s also a last object,\r\nDialogue: 0,0:59:52.34,0:59:57.45,yin,,0,0,0,, 它们有这种避免数组下标越界的额外功效 \\N{\\fs12}they just have this magic piece to them that they don’t do array index out of bounds.\r\nDialogue: 0,0:59:57.45,0:59:59.79,yin,,0,0,0,,firstObject 会返回第一个对象或 nil\\N{\\fs12}But otherwise they return the first object or nil\r\nDialogue: 0,0:59:59.79,1:00:01.36,yin,,0,0,0,, 如果没有对象的话 \\N{\\fs12}if there are no objects in there.\r\nDialogue: 0,1:00:01.36,1:00:02.66,yin,,0,0,0,, 我想让你们知道这个 \\N{\\fs12}I just want you to know that.\r\nDialogue: 0,1:00:02.66,1:00:04.35,yin,,0,0,0,, 这里其实并不需要这样 \\N{\\fs12}I don’t actually need that here,\r\nDialogue: 0,1:00:04.35,1:00:06.83,yin,,0,0,0,, 因为我知道数组中有一个对象 \\N{\\fs12}because I know there’s one object in that array.\r\nDialogue: 0,1:00:06.83,1:00:09.70,yin,,0,0,0,, 所以这里并不必要 我可以说 otherCards[0]\\N{\\fs12}So this is not really necessary, I could say other card subzero,\r\nDialogue: 0,1:00:09.70,1:00:11.44,yin,,0,0,0,, 这里没有问题 我只是 \\N{\\fs12}I’d be okay here, but I’m just trying\r\nDialogue: 0,1:00:11.44,1:00:14.05,yin,,0,0,0,, 希望教给你们 firstObject 方法 仅此而已 \\N{\\fs12}to teach you the method first object, that’s all.\r\nDialogue: 0,1:00:14.05,1:00:15.80,yin,,0,0,0,, 这就得到了另一张牌 \\N{\\fs12}So I got this other card.\r\nDialogue: 0,1:00:15.80,1:00:18.96,yin,,0,0,0,, 我们来匹配它 好的匹配是怎样的呢 \\N{\\fs12}So let’s go ahead and match it, what’s a good match here?\r\nDialogue: 0,1:00:18.96,1:00:22.77,yin,,0,0,0,, 如果花色匹配上 我会给一点分数 \\N{\\fs12}Well, if the suits match, I’ll give a little bit of points,\r\nDialogue: 0,1:00:22.77,1:00:25.13,yin,,0,0,0,, 如果大小匹配上 我会给更多分数 \\N{\\fs12}but if the ranks match, I’m going to give a lot of points,\r\nDialogue: 0,1:00:25.13,1:00:26.66,yin,,0,0,0,, 这里我说 \\N{\\fs12}so, let’s say\r\nDialogue: 0,1:00:26.66,1:00:35.74,yin,,0,0,0,,if ([self.suit isEqualToString:otherCard.suit])\\N{\\fs12}if my self dot suit is equal to string the other card’s suit.\r\nDialogue: 0,1:00:35.74,1:00:38.24,yin,,0,0,0,, 这是花色匹配的情况 例如都是梅花 \\N{\\fs12}So the suits match, they’re both clubs.\r\nDialogue: 0,1:00:38.24,1:00:41.90,yin,,0,0,0,, 这时我将把分数 score 设为 1\\N{\\fs12}Then I’m going to say the score equals one.\r\nDialogue: 0,1:00:41.90,1:00:46.30,yin,,0,0,0,, 这里可以用 else 因为这里假设所有牌都不同 \\N{\\fs12}But, and we can say else or not, because we’re going to assume the cards are all different.\r\nDialogue: 0,1:00:46.30,1:00:50.06,yin,,0,0,0,, 如果牌一样 只得到花色匹配的分数 \\N{\\fs12}So if the cards are the same, then you’re only going to get a suit match,\r\nDialogue: 0,1:00:50.07,1:00:52.10,yin,,0,0,0,, 就会显得很荒谬 \\N{\\fs12}which doesn’t really make sense,\r\nDialogue: 0,1:00:52.10,1:00:54.84,yin,,0,0,0,, 但这里没问题 再有 if ([self.rank])\\N{\\fs12}but let’s say if self dot rank,\r\nDialogue: 0,1:00:54.84,1:00:56.58,yin,,0,0,0,, 噢 这里不需要发送消息 \\N{\\fs12}oops, we don’t need to send a message there\r\nDialogue: 0,1:00:56.58,1:01:00.38,yin,,0,0,0,,if (self.rank == otherCards.rank)\\N{\\fs12}if self dot rank equals the other cards rank,\r\nDialogue: 0,1:01:00.38,1:01:02.43,yin,,0,0,0,, 那我们就给 4 分 \\N{\\fs12}then let’s give four points.\r\nDialogue: 0,1:01:02.43,1:01:04.72,yin,,0,0,0,, 为什么是 4 分对 1 分呢 \\N{\\fs12}Now why do I give four versus one?\r\nDialogue: 0,1:01:04.72,1:01:06.79,yin,,0,0,0,, 想想这里的数学 \\N{\\fs12}Well, think of the math, right?\r\nDialogue: 0,1:01:06.79,1:01:09.81,yin,,0,0,0,, 你手里有一张梅花 牌堆里还有多少张梅花 \\N{\\fs12}If you have a club in your hand, how many other cards are there\r\nDialogue: 0,1:01:09.81,1:01:12.14,yin,,0,0,0,, 你手里有一张梅花 牌堆里还有多少张梅花 \\N{\\fs12}in a full deck that will match a club?\r\nDialogue: 0,1:01:12.14,1:01:17.26,yin,,0,0,0,,12 张 如果我有一张 K 还有多少 K\\N{\\fs12}12. If I have a king, how many other kings are there?\r\nDialogue: 0,1:01:17.26,1:01:18.38,yin,,0,0,0,,3 张 \\N{\\fs12}Three. Okay?\r\nDialogue: 0,1:01:18.38,1:01:23.32,yin,,0,0,0,,12:3 所以一整副牌中 匹配花色要容易四倍 \\N{\\fs12}So 12 versus 3, it’s four times easier to match that club, assuming you have a full deck.\r\nDialogue: 0,1:01:23.32,1:01:25.22,yin,,0,0,0,, 这里我只是随机选的数字 \\N{\\fs12}I’m just picking numbers kind of at random here.\r\nDialogue: 0,1:01:25.22,1:01:28.21,yin,,0,0,0,, 对于这里的评分 这并不糟糕 \\N{\\fs12}It’s, it’s not a bad choice for the scoring here,\r\nDialogue: 0,1:01:28.21,1:01:31.00,yin,,0,0,0,, 不过多数时候相对分值不能搞错 \\N{\\fs12}but most times trying to get these relative scoring right.\r\nDialogue: 0,1:01:31.00,1:01:32.01,yin,,0,0,0,, 有问题 \\N{\\fs12}Question?\r\nDialogue: 0,1:01:33.51,1:01:36.54,yin,,0,0,0,, 问题是 这里我是不是使用了固定数字 正是 \\N{\\fs12}Yeah, so the question is am I using magic numbering and absolutely.\r\nDialogue: 0,1:01:36.54,1:01:40.12,yin,,0,0,0,, 在我们的简单实现中 整个评分系统都是用的固定数字 \\N{\\fs12}And you probably, you know, this whole thing\r\nDialogue: 0,1:01:40.12,1:01:44.03,yin,,0,0,0,, 在我们的简单实现中 整个评分系统都是用的固定数字 \\N{\\fs12}of the scoring here is somewhat magic numbers in our simple implementation,\r\nDialogue: 0,1:01:44.03,1:01:46.94,yin,,0,0,0,, 你也许…\\N{\\fs12}you probably, although,\r\nDialogue: 0,1:01:46.94,1:01:49.98,yin,,0,0,0,, 这里并不一定要是固定数字 \\N{\\fs12}this, okay, this is not necessarily a magic number.\r\nDialogue: 0,1:01:49.98,1:01:55.38,yin,,0,0,0,, 如果你定义最简单的匹配得分为 1\\N{\\fs12}If you define match to say make the easiest match verse, verse, equal one,\r\nDialogue: 0,1:01:55.38,1:01:57.56,yin,,0,0,0,, 然后让更复杂的匹配 \\N{\\fs12}and then make any more difficult matches\r\nDialogue: 0,1:01:57.56,1:02:00.79,yin,,0,0,0,, 是它的乘数倍 例如像这样更难的情况 \\N{\\fs12}to be multiplicatively, you know, more difficult like this,\r\nDialogue: 0,1:02:00.79,1:02:01.99,yin,,0,0,0,, 那么这就是对的 \\N{\\fs12}then this is actually right,\r\nDialogue: 0,1:02:01.99,1:02:05.16,yin,,0,0,0,, 因为这个 4 对于扑克牌是基本的 \\N{\\fs12}because that four is fundamental to a playing card,\r\nDialogue: 0,1:02:05.16,1:02:09.49,yin,,0,0,0,, 这对于扑克牌的大小和花色是很基本的 \\N{\\fs12}it’s fundamental to how a playing card ranks and suits work, alright?\r\nDialogue: 0,1:02:09.49,1:02:11.30,yin,,0,0,0,, 只要你定义的匹配 \\N{\\fs12}So, assuming you define this match\r\nDialogue: 0,1:02:11.31,1:02:13.70,yin,,0,0,0,, 只匹配相同牌堆中的其它扑克牌 \\N{\\fs12}only match against other playing cards in this same deck,\r\nDialogue: 0,1:02:13.70,1:02:16.83,yin,,0,0,0,, 这个 4 是固定的 但它对于这个类是固定的 \\N{\\fs12}that four is magic, but it’s magic to this class.\r\nDialogue: 0,1:02:16.83,1:02:18.54,yin,,0,0,0,, 没错 你可以使用 #define\\N{\\fs12}So, yeah, you could put a pound sign define,\r\nDialogue: 0,1:02:18.54,1:02:21.11,yin,,0,0,0,, 但这并没有减弱它的固定性质 \\N{\\fs12}but that doesn’t make it any less of a magic number.\r\nDialogue: 0,1:02:21.11,1:02:23.49,yin,,0,0,0,, 它是固定的 但你可以把它用到这里 \\N{\\fs12}So it is magic, but you could put it in there.\r\nDialogue: 0,1:02:23.49,1:02:25.32,yin,,0,0,0,, 明白我说的了吗 明白差别了吗 \\N{\\fs12}You see what I’m saying, see the difference between that\r\nDialogue: 0,1:02:25.32,1:02:27.32,yin,,0,0,0,, 这不同于控制器中的 102\\N{\\fs12}like 102 in your controller\r\nDialogue: 0,1:02:27.32,1:02:31.51,yin,,0,0,0,, 尝试把情况设置成通用的牌堆 这有些不同 \\N{\\fs12}which is trying to be maybe generic decks, that’s a little different.\r\nDialogue: 0,1:02:31.51,1:02:33.29,yin,,0,0,0,, 问得很好 \\N{\\fs12}Good question though.\r\nDialogue: 0,1:02:33.29,1:02:35.30,yin,,0,0,0,, 这样 我们有了更好的匹配 \\N{\\fs12}Alright, so now we have a better match.\r\nDialogue: 0,1:02:35.30,1:02:41.38,yin,,0,0,0,, 下面我们回到控制器中 \\N{\\fs12}So now if we go back to our controller, so let’s do that.\r\nDialogue: 0,1:02:41.38,1:02:43.06,yin,,0,0,0,, 回到这里的屏幕 \\N{\\fs12}Just back on screen right here.\r\nDialogue: 0,1:02:43.08,1:02:45.43,yin,,0,0,0,, 然后运行 \\N{\\fs12}And run.\r\nDialogue: 0,1:02:48.32,1:02:51.91,yin,,0,0,0,, 但愿这里我们能够找到匹配 \\N{\\fs12}Hopefully now, let’s see if we can find a match.\r\nDialogue: 0,1:02:51.91,1:02:54.03,yin,,0,0,0,, 好 这里有张梅花 \\N{\\fs12}Okay, so there’s a club,\r\nDialogue: 0,1:02:54.03,1:02:56.55,yin,,0,0,0,, 这里也有一张梅花 将它们匹配起来 \\N{\\fs12}and this is a club so let’s match them, ready?\r\nDialogue: 0,1:02:56.55,1:02:57.95,yin,,0,0,0,, 哦 确实能匹配上 \\N{\\fs12}Oh! It matched!\r\nDialogue: 0,1:02:57.95,1:02:59.88,yin,,0,0,0,, 而且禁用了这两个按钮 \\N{\\fs12}And it even disabled them.\r\nDialogue: 0,1:02:59.88,1:03:02.21,yin,,0,0,0,, 但我不知道我得到了多少分 \\N{\\fs12}But I have no idea how many points I got\r\nDialogue: 0,1:03:02.21,1:03:04.06,yin,,0,0,0,, 因为这里没有显示分数 \\N{\\fs12}because there’s no score on here,\r\nDialogue: 0,1:03:04.06,1:03:06.95,yin,,0,0,0,, 显然我们需要分数 下面把分数加进来 \\N{\\fs12}so, obviously, we need a score, so let’s put the score in.\r\nDialogue: 0,1:03:06.95,1:03:09.73,yin,,0,0,0,, 希望现在你们能够很容易地想象到 \\N{\\fs12}Hopefully by now you can imagine easily\r\nDialogue: 0,1:03:09.73,1:03:11.30,yin,,0,0,0,, 我们应该如何加入分数 \\N{\\fs12}how we would do the score,\r\nDialogue: 0,1:03:11.30,1:03:13.19,yin,,0,0,0,, 很简单 就像翻牌计数一样 \\N{\\fs12}simple, just like flips,\r\nDialogue: 0,1:03:13.19,1:03:14.70,yin,,0,0,0,, 我们使用这里的标签 \\N{\\fs12}we just grab a label here\r\nDialogue: 0,1:03:14.70,1:03:19.11,yin,,0,0,0,, 把它拖到这里 这里改成分数：0\\N{\\fs12}and then drop it down in here, I’m going to say score zero,\r\nDialogue: 0,1:03:19.11,1:03:23.01,yin,,0,0,0,, 因为这就是最开始我想要的分数情况 \\N{\\fs12}because that’s what I wanted, oops, that’s what I wanted to say when we start up.\r\nDialogue: 0,1:03:23.01,1:03:25.80,yin,,0,0,0,, 确实 你可以在开始时加载这些字符串 \\N{\\fs12}And yes, it’s possible you could load these strings up at start up,\r\nDialogue: 0,1:03:25.80,1:03:31.29,yin,,0,0,0,, 后面几讲中我会讲到代码中何时何地这样做 \\N{\\fs12}we’ll talk about when and where to do that in your code in the next couple lectures.\r\nDialogue: 0,1:03:31.29,1:03:34.93,yin,,0,0,0,, 有了这个分数后 我显然需要能够同它通信 \\N{\\fs12}So I have this score, I obviously need to be able to talk to it,\r\nDialogue: 0,1:03:34.93,1:03:39.38,yin,,0,0,0,, 于是我 Control 拖动到接口创建一个 outlet\\N{\\fs12}so I control drag up here into my interface to create an outlet.\r\nDialogue: 0,1:03:39.38,1:03:41.11,yin,,0,0,0,, 松手 这个应该是 outlet\\N{\\fs12}I let go, this one wants to be an outlet,\r\nDialogue: 0,1:03:41.11,1:03:43.26,yin,,0,0,0,, 不是 outlet collection 而是 outlet\\N{\\fs12}not an outlet collection, but an outlet.\r\nDialogue: 0,1:03:43.26,1:03:46.65,yin,,0,0,0,, 我将它称作 scoreLabel(分数标签)\\N{\\fs12}I’m going to call it score label.\r\nDialogue: 0,1:03:46.65,1:03:47.78,yin,,0,0,0,, 它可以是弱的 \\N{\\fs12}It can be weak\r\nDialogue: 0,1:03:47.79,1:03:51.68,yin,,0,0,0,, 因为我们知道视图会指向它 它是 UILabel\\N{\\fs12}because we know that the view is going to point it, it is the UI label.\r\nDialogue: 0,1:03:51.68,1:03:53.33,yin,,0,0,0,, 这里有了它的 outlet\\N{\\fs12}There’s an outlet for it.\r\nDialogue: 0,1:03:53.33,1:03:56.12,yin,,0,0,0,, 我将在 updateUI 中更新它 \\N{\\fs12}I’m just going to update it in update UI.\r\nDialogue: 0,1:03:56.12,1:03:57.21,yin,,0,0,0,, 所以这里我说 \\N{\\fs12}So I’m going to say\r\nDialogue: 0,1:03:57.21,1:04:00.71,yin,,0,0,0,,self.scoreLabel = [NSString\\N{\\fs12}self dot score label equals NSString,\r\nDialogue: 0,1:04:00.71,1:04:04.93,yin,,0,0,0,,stringWithFormat:@”Score:%d”…\\N{\\fs12}string with format, we’ll say score colon percent d,\r\nDialogue: 0,1:04:04.93,1:04:07.36,yin,,0,0,0,, 分数从哪里得到 \\N{\\fs12}and where do we get the score?\r\nDialogue: 0,1:04:09.91,1:04:13.45,yin,,0,0,0,, 有人知道分数从哪里得到吗 \\N{\\fs12}Anyone know where we get the score?\r\nDialogue: 0,1:04:13.45,1:04:14.64,yin,,0,0,0,, 从 game 正是 \\N{\\fs12}From the game, exactly!\r\nDialogue: 0,1:04:14.64,1:04:17.55,yin,,0,0,0,, 从我们的模型 self.game.score\\N{\\fs12}From our model, self dot game dot score.\r\nDialogue: 0,1:04:19.23,1:04:22.60,yin,,0,0,0,, 下面我来展示一下 确保大家理解了 \\N{\\fs12}Now I’m going to go show that just to make sure everyone understands that.\r\nDialogue: 0,1:04:22.60,1:04:24.67,yin,,0,0,0,, 这是我的 CardMatchingGame\\N{\\fs12}Here’s my card matching game,\r\nDialogue: 0,1:04:24.67,1:04:30.71,yin,,0,0,0,, 记得吧 在它的公共 API 中有 score\\N{\\fs12}remember that in its public API, it has the score.\r\nDialogue: 0,1:04:30.71,1:04:34.47,yin,,0,0,0,, 选择时 我们会计分 \\N{\\fs12}And we’re keeping the score when we’re choosing.\r\nDialogue: 0,1:04:34.47,1:04:37.27,yin,,0,0,0,, 大家都明白了吗 \\N{\\fs12}Everybody cool with that?\r\nDialogue: 0,1:04:37.27,1:04:38.69,yin,,0,0,0,, 这就是了 \\N{\\fs12}So that’s it.\r\nDialogue: 0,1:04:38.69,1:04:42.14,yin,,0,0,0,, 更新分数要做的事我们都做了 \\N{\\fs12}That’s all we need to do here, to update the score.\r\nDialogue: 0,1:04:42.14,1:04:46.27,yin,,0,0,0,, 一般我们… 噢 这里需要 scoreLabel.text\\N{\\fs12}Normally we have, oops, this needs score label dot text.\r\nDialogue: 0,1:04:46.27,1:04:51.29,yin,,0,0,0,, 抱歉 我们需要 UILabel 类的 text 属性 \\N{\\fs12}Sorry. Alright, we need the text property of the UI label class\r\nDialogue: 0,1:04:51.29,1:04:53.54,yin,,0,0,0,, 我们会调用它的 setter 设置 text\\N{\\fs12}and we’re calling it setter here, set text,\r\nDialogue: 0,1:04:53.54,1:04:56.38,yin,,0,0,0,, 这就是这里发生的情况 设置分数 \\N{\\fs12}this is basically what’s happening here and setting the score.\r\nDialogue: 0,1:04:57.14,1:04:58.90,yin,,0,0,0,, 我还要做一件事 \\N{\\fs12}One other thing I’m going to do just\r\nDialogue: 0,1:04:58.90,1:05:03.49,yin,,0,0,0,, 也就是防止分数太大 把这个拉宽一些 然后运行 \\N{\\fs12}in case the score is really big, so make that wide, and run.\r\nDialogue: 0,1:05:03.49,1:05:06.73,yin,,0,0,0,, 我们以后会讲到 文本框如何 \\N{\\fs12}And we’ll talk about, by the way, text fields that get larger\r\nDialogue: 0,1:05:06.73,1:05:09.60,yin,,0,0,0,, 随你输入的文本而增大 \\N{\\fs12}when you put text in them and stuff like that,\r\nDialogue: 0,1:05:09.60,1:05:11.93,yin,,0,0,0,,iOS 中有处理这个的方式 \\N{\\fs12}there’s a way to handle that in iOS, as well,\r\nDialogue: 0,1:05:11.93,1:05:15.36,yin,,0,0,0,, 不过我们一次讲不了那么多内容 \\N{\\fs12}we’re not, we can’t talk about it, everything all at once though.\r\nDialogue: 0,1:05:15.36,1:05:16.39,yin,,0,0,0,, 这里我们看看 \\N{\\fs12}Alright, so let’s see here.\r\nDialogue: 0,1:05:16.39,1:05:17.07,yin,,0,0,0,,-1\\N{\\fs12}Minus one.\r\nDialogue: 0,1:05:17.07,1:05:18.48,yin,,0,0,0,, 为什么获得 -1 分 \\N{\\fs12}Why did I get minus one?\r\nDialogue: 0,1:05:18.48,1:05:20.34,yin,,0,0,0,, 因为翻牌是有成本的 \\N{\\fs12}Because I have a cost to flip.\r\nDialogue: 0,1:05:20.34,1:05:23.84,yin,,0,0,0,, 每次翻牌都有代价 \\N{\\fs12}So every time I flip a card, I got to pay, alright?\r\nDialogue: 0,1:05:23.84,1:05:26.96,yin,,0,0,0,, 这是黑桃 这也是黑桃 对吧 \\N{\\fs12}Now here’s a spade and here’s a spade, alright?\r\nDialogue: 0,1:05:26.96,1:05:29.12,yin,,0,0,0,, 我点这个之后 分数会是多少 \\N{\\fs12}So what’s going to be my score after I click this?\r\nDialogue: 0,1:05:29.12,1:05:32.17,yin,,0,0,0,, 点这个还是会花掉 1 分 \\N{\\fs12}Well, clicking this still going to cost me one, so that’s going\r\nDialogue: 0,1:05:32.17,1:05:35.49,yin,,0,0,0,, 这会让我的分数减少为 -6\\N{\\fs12}to make my score go down to minus six, but I’m going\r\nDialogue: 0,1:05:35.49,1:05:39.37,yin,,0,0,0,, 但匹配正确后我能得到 1 分乘以 4 分的红利 \\N{\\fs12}to get one point for matching times my match bonus of four,\r\nDialogue: 0,1:05:39.38,1:05:40.88,yin,,0,0,0,, 也就是 4 分 \\N{\\fs12}is four more points.\r\nDialogue: 0,1:05:40.88,1:05:43.04,yin,,0,0,0,, 所以我的分数应该是 -2\\N{\\fs12}So my score should be minus two.\r\nDialogue: 0,1:05:43.04,1:05:45.28,yin,,0,0,0,, 对吧 确实也是 \\N{\\fs12}Alright? And it is!\r\nDialogue: 0,1:05:45.28,1:05:48.71,yin,,0,0,0,, 很好 看看能否找到匹配的大小 \\N{\\fs12}Woohoo. Okay, and let’s see if we can find ranks that match.\r\nDialogue: 0,1:05:50.99,1:05:53.21,yin,,0,0,0,, 哦 这里有个 6 这里也有个 6\\N{\\fs12}Oh, there’s a six and here’s a six.\r\nDialogue: 0,1:05:53.21,1:05:56.39,yin,,0,0,0,, 我将让这两个匹配上 分数会变成多少 \\N{\\fs12}Okay, so I’m going to make these two match, so what’s this going to be?\r\nDialogue: 0,1:05:56.39,1:05:58.74,yin,,0,0,0,, 现在是 -9 点这个以后 \\N{\\fs12}Alright, so we’re at minus 9 now, when I click this one,\r\nDialogue: 0,1:05:58.74,1:06:01.37,yin,,0,0,0,, 分数降到 -10 但它们会匹配上 \\N{\\fs12}we’re going to be at minus 10, but they’re going to match.\r\nDialogue: 0,1:06:01.37,1:06:02.26,yin,,0,0,0,, 我将得到 4 分 \\N{\\fs12}I’m going to get four points\r\nDialogue: 0,1:06:02.26,1:06:05.79,yin,,0,0,0,, 乘以 4 分的红利 总共得 16 分 \\N{\\fs12}for the match times my match bonus of four is 16 points.\r\nDialogue: 0,1:06:05.79,1:06:07.56,yin,,0,0,0,, 因此分数将变成 +6\\N{\\fs12}So I’m going to be at plus 6.\r\nDialogue: 0,1:06:07.56,1:06:09.09,yin,,0,0,0,, 大家都同意吗 \\N{\\fs12}Everyone agree with that?\r\nDialogue: 0,1:06:09.93,1:06:12.82,yin,,0,0,0,, 没问题 分数为 +6\\N{\\fs12}And there we are, score plus six.\r\nDialogue: 0,1:06:14.00,1:06:15.72,yin,,0,0,0,, 这就完了 \\N{\\fs12}Alright, so that’s it.\r\nDialogue: 0,1:06:15.72,1:06:20.48,yin,,0,0,0,, 今天我要讲的就这些 最后还有一些幻灯片 \\N{\\fs12}That’s as much as I’m going to do and I’m, we got some slides here at the end,\r\nDialogue: 0,1:06:20.48,1:06:22.94,yin,,0,0,0,, 不过 demo 就这些了 \\N{\\fs12}but that’s it on the demo here.\r\nDialogue: 0,1:06:22.94,1:06:26.42,yin,,0,0,0,, 你们的作业是匹配两张或三张牌 \\N{\\fs12}And your assignment is going to be to make it\r\nDialogue: 0,1:06:26.42,1:06:28.53,yin,,0,0,0,, 你们的作业是匹配两张或三张牌 \\N{\\fs12}so you can match two cards or three cards,\r\nDialogue: 0,1:06:28.53,1:06:31.82,yin,,0,0,0,, 你可以在 UI 中加一个开关 \\N{\\fs12}you can have a little switch or some sort of UI\r\nDialogue: 0,1:06:31.82,1:06:35.23,yin,,0,0,0,, 在两张或三张牌的匹配之间切换 \\N{\\fs12}to choose between whether you’re matching two cards or three cards,\r\nDialogue: 0,1:06:35.23,1:06:39.54,yin,,0,0,0,, 这需要模型中改变一些逻辑 \\N{\\fs12}and so that’s going to require some change to your logic in your model.\r\nDialogue: 0,1:06:39.54,1:06:42.60,yin,,0,0,0,, 也需要更多一点的 UI\\N{\\fs12}It’s going to require a little bit of UI and it’s going\r\nDialogue: 0,1:06:42.60,1:06:46.40,yin,,0,0,0,, 还需要你的控制器将两者衔接起来 \\N{\\fs12}to require your controller to do a little bit of glue in between that.\r\nDialogue: 0,1:06:46.40,1:06:52.10,yin,,0,0,0,, 你还需要在这里加一个标签 描述这里发生了什么 \\N{\\fs12}You’re also going to be asked to add another label in here that says what’s going on.\r\nDialogue: 0,1:06:52.10,1:06:55.69,yin,,0,0,0,, 但我点这里时 它要告诉我 你选了红桃 7\\N{\\fs12}So when I click this, it should say you chose the seven of hearts.\r\nDialogue: 0,1:06:55.69,1:06:57.97,yin,,0,0,0,, 当我选这个时 它要告诉我 \\N{\\fs12}When I choose this, it should say\r\nDialogue: 0,1:06:57.97,1:07:02.72,yin,,0,0,0,, 红心 7 和梅花 2 无法匹配上 -2 诸如此类 \\N{\\fs12}seven hearts and two of clubs did not match, minus 2, or something like that.\r\nDialogue: 0,1:07:04.02,1:07:07.89,yin,,0,0,0,, 如果选了两张确实匹配的牌 \\N{\\fs12}So, if you pick two things that do match,\r\nDialogue: 0,1:07:07.89,1:07:09.98,yin,,0,0,0,, 例如 \\N{\\fs12}like,\r\nDialogue: 0,1:07:09.99,1:07:11.47,yin,,0,0,0,, 这两张红心 \\N{\\fs12}those two hearts,\r\nDialogue: 0,1:07:11.47,1:07:14.94,yin,,0,0,0,, 它应该说 红心 4 和红心 7 匹配 得多少分 \\N{\\fs12}it should say four of hearts, seven of hearts match for whatever points.\r\nDialogue: 0,1:07:14.94,1:07:15.29,yin,,0,0,0,, 有问题 \\N{\\fs12}Question?\r\nDialogue: 0,1:07:18.74,1:07:20.22,yin,,0,0,0,, 如何在设备上测试它 \\N{\\fs12}How would you test it on a device?\r\nDialogue: 0,1:07:20.22,1:07:23.24,yin,,0,0,0,, 我们在设备上运行一下试试 问得很好 \\N{\\fs12}Okay, let’s run this on a device actually. Great question.\r\nDialogue: 0,1:07:23.24,1:07:26.91,yin,,0,0,0,, 这里我连了一个设备 你可以看到 \\N{\\fs12}So I have a device attached over here, which you can see,\r\nDialogue: 0,1:07:26.91,1:07:30.11,yin,,0,0,0,, 它要求我更新 我们这里不会照做 \\N{\\fs12}and it’s asking me to update, which we’re not going to do right now,\r\nDialogue: 0,1:07:30.11,1:07:34.32,yin,,0,0,0,, 在 XCode 上面 你会看到一些 \\N{\\fs12}and if you look up at the top of XCode, you’ll see that there’s a\r\nDialogue: 0,1:07:34.32,1:07:37.02,yin,,0,0,0,, 不同的模拟器可供运行 \\N{\\fs12}bunch of different simulators you can run on\r\nDialogue: 0,1:07:37.02,1:07:39.74,yin,,0,0,0,, 你还可以在连接的设备上运行 \\N{\\fs12}and you can also run on a device if you have it attached,\r\nDialogue: 0,1:07:39.74,1:07:43.88,yin,,0,0,0,, 下周五我们或许将有一节课 \\N{\\fs12}and we’re going to have a Friday section probably next week,\r\nDialogue: 0,1:07:43.88,1:07:46.43,yin,,0,0,0,, 或下下周 我们会为你展示 \\N{\\fs12}or maybe the week after, where we’re going to show you how\r\nDialogue: 0,1:07:46.43,1:07:50.02,yin,,0,0,0,, 如何注册你的设备 并将所有这些设置好 \\N{\\fs12}to register your device if you don’t know how to do that and get this all set up.\r\nDialogue: 0,1:07:50.02,1:07:52.94,yin,,0,0,0,, 这可以说是一个预览 我将在 iPad 上运行 \\N{\\fs12}So this is a bit of a preview, but I’m going to actually run this on the iPad.\r\nDialogue: 0,1:07:52.94,1:07:58.78,yin,,0,0,0,, 我将选择 iPad 点击运行 它就会在 iPad 上运行了 \\N{\\fs12}So I just pick iPad, and hit Run, and it runs on the iPad.\r\nDialogue: 0,1:07:58.78,1:08:01.98,yin,,0,0,0,, 我以后会为大多数 demo 这样做 \\N{\\fs12}And I’m going to start doing this for most of the demos,\r\nDialogue: 0,1:08:01.98,1:08:05.98,yin,,0,0,0,, 在设备上运行 而不是在模拟器上 \\N{\\fs12}is running it on a device instead of running it in the simulator.\r\nDialogue: 0,1:08:05.98,1:08:09.39,yin,,0,0,0,, 这更好一些 因为屏幕更大 \\N{\\fs12}It’s a little nicer because the screens a bit, little bigger\r\nDialogue: 0,1:08:09.39,1:08:12.93,yin,,0,0,0,, 如这里所示 这是在我的 iPad 上 \\N{\\fs12}as you can see, and so here it is on my iPad here.\r\nDialogue: 0,1:08:12.93,1:08:16.59,yin,,0,0,0,, 我可以轻击它 噢 死机了 \\N{\\fs12}And so I can tap and oop, it crashes.\r\nDialogue: 0,1:08:16.59,1:08:18.33,yin,,0,0,0,, 这不是很好 \\N{\\fs12}Oh, well, that’s not good.\r\nDialogue: 0,1:08:18.33,1:08:21.26,yin,,0,0,0,, 我做错了什么 \\N{\\fs12}What did I do wrong here?\r\nDialogue: 0,1:08:21.26,1:08:23.52,yin,,0,0,0,, 我不知道哪里出了问题 \\N{\\fs12}Well, I don’t know what I did wrong, but I messed it\r\nDialogue: 0,1:08:23.52,1:08:26.13,yin,,0,0,0,, 反正过程中我搞砸了 很抱歉 \\N{\\fs12}up when I preset this up so I’m sorry about that,\r\nDialogue: 0,1:08:26.13,1:08:27.42,yin,,0,0,0,, 我会展示这个的 \\N{\\fs12}but I will show you that,\r\nDialogue: 0,1:08:27.42,1:08:32.74,yin,,0,0,0,, 下周三开始 我将在设备上运行所有这些东西 \\N{\\fs12}I’ll start running all my demos hopefully on a device starting with next Wednesday’s thing\r\nDialogue: 0,1:08:32.74,1:08:36.41,yin,,0,0,0,, 但愿到时候不会出现这样的错误 很抱歉 \\N{\\fs12}and hopefully I won’t make this mistake, sorry about that.\r\nDialogue: 0,1:08:36.41,1:08:38.34,yin,,0,0,0,, 无论如何 今天就到这里 \\N{\\fs12}Anyway, okay, so that’s it.\r\nDialogue: 0,1:08:38.34,1:08:39.72,yin,,0,0,0,, 还有问题吗 \\N{\\fs12}Any other questions about it?\r\nDialogue: 0,1:08:39.72,1:08:44.00,yin,,0,0,0,, 更多内容 请访问我校官网 stanford.edu\\N{\\fs12}For more, please visit us at Stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/4. Foundation and Attributed Strings.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.1.2\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\nLast Style Storage: Default\r\nAegisub Scroll Position: 0\r\nAegisub Active Line: 2\r\nAegisub Video Zoom Percent: 1.000000\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:04.88,0:00:07.66,yin,,0,0,0,, 斯坦福大学 \\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:11.56,0:00:21.13,yin,,0,0,0,, 欢迎来到 2013/14 学年秋季 CS193P 课程第四讲 \\N{\\fs12}Welcome to lecture 4, then, of CS 193P for fall of academic year 2013/14.\r\nDialogue: 0,0:00:21.13,0:00:24.10,yin,,0,0,0,, 今天的内容几乎都将是幻灯片 \\N{\\fs12}Today I’m going to do pretty much all slides.\r\nDialogue: 0,0:00:24.10,0:00:28.31,yin,,0,0,0,, 还有一点时间我们会简要看一个 demo\\N{\\fs12}I do have one brief time when we’ll stop and do a little demo.\r\nDialogue: 0,0:00:28.31,0:00:31.25,yin,,0,0,0,, 然后下一讲开始 \\N{\\fs12}And then at the beginning of next lecture,\r\nDialogue: 0,0:00:31.25,0:00:34.40,yin,,0,0,0,, 我会讲一个 demo 基本上演示了 \\N{\\fs12}I’ll be doing a demo that pretty much demonstrates the vast\r\nDialogue: 0,0:00:34.40,0:00:37.20,yin,,0,0,0,, 这一讲在幻灯中讲的大多数内容 \\N{\\fs12}majority of what I talk about in the slides today.\r\nDialogue: 0,0:00:37.20,0:00:39.29,yin,,0,0,0,, 这将是这门课一贯的做法 \\N{\\fs12}And remember, that’s kind of how it’s always going to go:\r\nDialogue: 0,0:00:39.29,0:00:42.96,yin,,0,0,0,, 我先讲一些幻灯片 然后用 demo 进行演示 \\N{\\fs12}I’ll show it to you in slides, we’ll talk about it, then I’ll demo it to you.\r\nDialogue: 0,0:00:42.96,0:00:46.24,yin,,0,0,0,, 因为看到 demo 比听老师一个劲在那讲 \\N{\\fs12}Because when you see a demo, it all makes a lot more sense than if someone’s just talking\r\nDialogue: 0,0:00:46.24,0:00:48.98,yin,,0,0,0,,API 相关的抽象概念要容易理解得多 \\N{\\fs12}in an abstract conceptually about an API.\r\nDialogue: 0,0:00:48.98,0:00:51.53,yin,,0,0,0,, 然后作业通常是要你们做这个 \\N{\\fs12}And then your homework is usually going to ask you to do this.\r\nDialogue: 0,0:00:51.53,0:00:54.53,yin,,0,0,0,, 你们需要在课上注意我都讲了什么 \\N{\\fs12}So it’s, you know, you get a lot out of paying attention\r\nDialogue: 0,0:00:54.53,0:00:56.70,yin,,0,0,0,, 因为这会为你们做作业提供很多提示 \\N{\\fs12}in the lectures because I’m pretty much going to give you hints\r\nDialogue: 0,0:00:56.70,0:00:59.90,yin,,0,0,0,, 因为这会为你们做作业提供很多提示 \\N{\\fs12}and basically tell you a lot of how to do the homework –\r\nDialogue: 0,0:00:59.90,0:01:01.85,yin,,0,0,0,, 至少在 iOS 这方面 \\N{\\fs12}at least from the iOS side of it.\r\nDialogue: 0,0:01:01.85,0:01:06.26,yin,,0,0,0,, 我还要求你们在意思考和设计这方面 \\N{\\fs12}I’m still going to ask you to do the thinking side of it, the designing side of it.\r\nDialogue: 0,0:01:06.26,0:01:08.70,yin,,0,0,0,, 今天我们将首先谈到 \\N{\\fs12}So today we’re going to start off by talking\r\nDialogue: 0,0:01:08.70,0:01:11.39,yin,,0,0,0,,Objective-C 方面的各种知识 \\N{\\fs12}about a little bit more miscellaneous Objective-C.\r\nDialogue: 0,0:01:11.39,0:01:13.90,yin,,0,0,0,, 然后我会讲到 Foundation 框架 \\N{\\fs12}And then I’m going to go into talking about Foundation,\r\nDialogue: 0,0:01:13.90,0:01:17.19,yin,,0,0,0,, 也就是其中具有数组 字典等内容的框架 \\N{\\fs12}which is this framework that has arrays, and dictionaries, and all that in it.\r\nDialogue: 0,0:01:17.19,0:01:20.74,yin,,0,0,0,, 最后我们会离开 Foundation 这一主题 \\N{\\fs12}And we’ll start to transition out of Foundation at the end\r\nDialogue: 0,0:01:20.74,0:01:23.89,yin,,0,0,0,, 并开始讨论字体 颜色等内容 \\N{\\fs12}of that and start talking about things like fonts and colors,\r\nDialogue: 0,0:01:23.89,0:01:25.35,yin,,0,0,0,, 这些显然不属于 Foundation\\N{\\fs12}which are obviously not in Foundation\r\nDialogue: 0,0:01:25.35,0:01:28.59,yin,,0,0,0,, 因为 Foundation 不是基于 UI 的 \\N{\\fs12}because Foundation is really not a UI-based thing;\r\nDialogue: 0,0:01:28.59,0:01:32.80,yin,,0,0,0,, 它是用于构建模型 控制器 视图的 \\N{\\fs12}it’s for building both your model, and your controller, and your view.\r\nDialogue: 0,0:01:32.80,0:01:36.36,yin,,0,0,0,, 但它是用户界面层之下的一层 \\N{\\fs12}But it’s, you know, a layer below the user interface layer.\r\nDialogue: 0,0:01:36.36,0:01:38.09,yin,,0,0,0,, 我们开始进入主题 \\N{\\fs12}So let’s dive right in.\r\nDialogue: 0,0:01:38.09,0:01:39.88,yin,,0,0,0,, 我们先来看创建对象 \\N{\\fs12}Let’s talk about creating objects.\r\nDialogue: 0,0:01:39.88,0:01:42.42,yin,,0,0,0,, 希望这些东西是显而易见的 \\N{\\fs12}A few of these things are pretty obvious I hope, but I just want\r\nDialogue: 0,0:01:42.42,0:01:45.53,yin,,0,0,0,, 这里我只是想把它们放到幻灯片中正式提一下 \\N{\\fs12}to put them on slides so that you have them in writing here.\r\nDialogue: 0,0:01:45.53,0:01:48.25,yin,,0,0,0,, 大多数时候 当我们在堆中创建对象时 \\N{\\fs12}You know that most of the time when we create objects in the heap,\r\nDialogue: 0,0:01:48.25,0:01:50.63,yin,,0,0,0,, 我们用的是 alloc init 对吧 \\N{\\fs12}we do it with this alloc init business, right?\r\nDialogue: 0,0:01:50.63,0:01:54.56,yin,,0,0,0,, 有时 init 是 [NSMutableArray alloc] init 中的 init\\N{\\fs12}So sometimes the init is just init like NSMutableArray alloc init,\r\nDialogue: 0,0:01:54.56,0:01:58.36,yin,,0,0,0,, 有时 它更复杂 例如 CardMatchingGame 中的 init\\N{\\fs12}and sometimes it’s more complicated init like we had with our card matching game –\r\nDialogue: 0,0:01:58.36,0:02:00.16,yin,,0,0,0,,initWithCardCount usingDeck\\N{\\fs12}init with card count using deck –\r\nDialogue: 0,0:02:00.16,0:02:01.61,yin,,0,0,0,, 你们需要熟悉这些 \\N{\\fs12}so that you’re used to that.\r\nDialogue: 0,0:02:01.61,0:02:03.94,yin,,0,0,0,, 你们还见过这种在堆中创建对象的方式 \\N{\\fs12}And you’ve also seen us create objects in the heap\r\nDialogue: 0,0:02:03.94,0:02:06.59,yin,,0,0,0,, 使用类方法 例如 stringWithFormat\\N{\\fs12}using class methods like string with format.\r\nDialogue: 0,0:02:06.59,0:02:08.41,yin,,0,0,0,, 记得吧 我们用过 NSString stringWithFormat\\N{\\fs12}Remember, we did NSString, string with format.\r\nDialogue: 0,0:02:08.41,0:02:09.63,yin,,0,0,0,, 这是一个类方法 \\N{\\fs12}And that’s a class method, right?\r\nDialogue: 0,0:02:09.63,0:02:13.44,yin,,0,0,0,, 因为它是开方括号 类名 然后类方法 \\N{\\fs12}Because it’s open square bracket, name of a class, and then class method.\r\nDialogue: 0,0:02:13.44,0:02:17.68,yin,,0,0,0,, 这是两种你们见过的创建对象的不同方式 \\N{\\fs12}So it gets kind of two different ways you’ve seen already to create objects.\r\nDialogue: 0,0:02:17.68,0:02:19.93,yin,,0,0,0,, 有时 对于一些方法 \\N{\\fs12}Sometimes for some methods,\r\nDialogue: 0,0:02:19.93,0:02:23.21,yin,,0,0,0,, 同时有 init 和类方法 \\N{\\fs12}there’s both an init and a class method.\r\nDialogue: 0,0:02:23.21,0:02:25.05,yin,,0,0,0,,stringWithFormat 就是一个例子 \\N{\\fs12}So string with format is an example\r\nDialogue: 0,0:02:25.05,0:02:27.21,yin,,0,0,0,, 这里有 alloc initWithFormat\\N{\\fs12}that there’s alloc init with format\r\nDialogue: 0,0:02:27.22,0:02:29.72,yin,,0,0,0,, 还有 NSString stringWithFormat\\N{\\fs12}and there’s NSString, string with format.\r\nDialogue: 0,0:02:29.72,0:02:32.32,yin,,0,0,0,, 它们的作用完全相同 \\N{\\fs12}They do exactly the same thing.\r\nDialogue: 0,0:02:32.32,0:02:35.50,yin,,0,0,0,, 两者都在这里 可以说是一些历史原因 \\N{\\fs12}Both of them are there for kind of historical reasons.\r\nDialogue: 0,0:02:35.50,0:02:38.77,yin,,0,0,0,, 在我们有这种自动引用计数之前 \\N{\\fs12}Back before we had this automatic reference counting –\r\nDialogue: 0,0:02:38.77,0:02:40.77,yin,,0,0,0,, 这种强弱之类的东西 \\N{\\fs12}you know, the strong and weak thing –\r\nDialogue: 0,0:02:40.77,0:02:46.06,yin,,0,0,0,, 你需要更加明确 何时引用事物 \\N{\\fs12}you had to be much more explicit about things when you were going to reference them,\r\nDialogue: 0,0:02:46.06,0:02:49.73,yin,,0,0,0,, 何时取消引用 何时将它们从堆中清除 等等 \\N{\\fs12}and when they got dereferenced, and when you cleared them out of the heap, and all that stuff.\r\nDialogue: 0,0:02:49.73,0:02:53.10,yin,,0,0,0,, 其中一种方式就是使用这些类方法 \\N{\\fs12}And one of the ways that was done was using these class methods\r\nDialogue: 0,0:02:53.10,0:02:57.87,yin,,0,0,0,, 来创建能够用特定方式释放的字符串 \\N{\\fs12}to create the string in a way that it would get released in certain ways.\r\nDialogue: 0,0:02:57.87,0:02:59.67,yin,,0,0,0,, 所有这些现在都不再重要 \\N{\\fs12}So all of that doesn’t matter anymore.\r\nDialogue: 0,0:02:59.67,0:03:02.17,yin,,0,0,0,, 这样我们就同时有了这两者 \\N{\\fs12}So now we’re kind of stuck with having both of these things.\r\nDialogue: 0,0:03:02.17,0:03:05.41,yin,,0,0,0,, 在我看来 苹果的 iOS 设计者们 \\N{\\fs12}It seems to me that iOS, the designers at Apple –\r\nDialogue: 0,0:03:05.41,0:03:07.12,yin,,0,0,0,, 顺便说下 我不为苹果工作 \\N{\\fs12}I don’t work at Apple, by the way.\r\nDialogue: 0,0:03:07.12,0:03:09.09,yin,,0,0,0,, 有人问过我 我不在苹果工作 \\N{\\fs12}Some people have asked me if I work at Apple; I don’t work at Apple.\r\nDialogue: 0,0:03:09.09,0:03:11.87,yin,,0,0,0,, 我和你们一样 是从外部去看 iOS 的 \\N{\\fs12}So I’m just seeing iOS from the outside just like you are.\r\nDialogue: 0,0:03:11.87,0:03:15.51,yin,,0,0,0,, 在我看来 iOS 的人越来越偏向于 alloc init\\N{\\fs12}It looks to me like iOS people are moving towards alloc init,\r\nDialogue: 0,0:03:15.51,0:03:19.77,yin,,0,0,0,, 逐渐从类方法偏离 \\N{\\fs12}okay, and kind of away from the class methods.\r\nDialogue: 0,0:03:19.77,0:03:22.58,yin,,0,0,0,, 不过在特定环境下 我仍然会看到类方法 \\N{\\fs12}Although I still see the class methods coming up in certain circumstances, too.\r\nDialogue: 0,0:03:22.58,0:03:24.55,yin,,0,0,0,, 这方面也许存在某种考虑 \\N{\\fs12}And there’s probably some reasoning behind it.\r\nDialogue: 0,0:03:24.55,0:03:28.95,yin,,0,0,0,, 我没看到过苹果官方说偏好哪一种 \\N{\\fs12}I haven’t seen it put in writing by Apple as to when they choose which,\r\nDialogue: 0,0:03:28.95,0:03:33.18,yin,,0,0,0,, 不过这门课的过程中 你们随便用哪种都是安全的 \\N{\\fs12}but you’re certainly safe in this class until they start marketing some of these things\r\nDialogue: 0,0:03:33.18,0:03:37.09,yin,,0,0,0,, 苹果应该不会在这么短的时间内决定废掉哪种 \\N{\\fs12}as deprecated, like, don’t use them anymore, to use either form.\r\nDialogue: 0,0:03:37.09,0:03:39.46,yin,,0,0,0,, 我多数时候更偏爱 alloc init\\N{\\fs12}I tend to try to go for the alloc inits most of the time,\r\nDialogue: 0,0:03:39.46,0:03:41.82,yin,,0,0,0,, 除非没有 alloc init 能实现我的目的 \\N{\\fs12}unless there isn’t an alloc init that does what I want;\r\nDialogue: 0,0:03:41.83,0:03:43.58,yin,,0,0,0,, 这时我就会用类方法 \\N{\\fs12}then I’ll use a class method.\r\nDialogue: 0,0:03:43.58,0:03:45.68,yin,,0,0,0,, 不过还有其它方式可以创建对象 \\N{\\fs12}But there’s other ways to create objects.\r\nDialogue: 0,0:03:45.68,0:03:50.48,yin,,0,0,0,, 你可以让另一个对象为你创建对象 \\N{\\fs12}You can create objects by asking another object to create an object for you.\r\nDialogue: 0,0:03:50.48,0:03:52.96,yin,,0,0,0,, 例如 stringByAppendingString\\N{\\fs12}So that’s like string by appending string.\r\nDialogue: 0,0:03:52.96,0:03:55.61,yin,,0,0,0,, 这不是字符串的类方法 这是实例方法 \\N{\\fs12}That’s not a class method in string; that’s an instance method.\r\nDialogue: 0,0:03:55.61,0:04:00.00,yin,,0,0,0,, 你将它发送给一个字符串 你将它给第二个字符串 \\N{\\fs12}You send it to another string, you give it a second string,\r\nDialogue: 0,0:04:00.00,0:04:03.39,yin,,0,0,0,, 它会为你创建一个新字符串 因为字符串是不可变的 \\N{\\fs12}and it will create a new string for you since strings are immutable.\r\nDialogue: 0,0:04:03.39,0:04:04.91,yin,,0,0,0,,NSString 是不可变的 \\N{\\fs12}NSString is immutable.\r\nDialogue: 0,0:04:04.91,0:04:06.40,yin,,0,0,0,, 它会创建一个新字符串 \\N{\\fs12}It creates a new string\r\nDialogue: 0,0:04:06.40,0:04:10.37,yin,,0,0,0,, 这是将参数中的字符串加到原字符串后面 \\N{\\fs12}that is the string you sent it to with the one you passed as an argument added on, right?\r\nDialogue: 0,0:04:10.37,0:04:13.01,yin,,0,0,0,, 这就为你创建了一个新对象 \\N{\\fs12}So there it’s creating a new object for you.\r\nDialogue: 0,0:04:13.01,0:04:16.55,yin,,0,0,0,, 一个很有趣的实例方法 \\N{\\fs12}And a very interesting instance method\r\nDialogue: 0,0:04:16.55,0:04:19.77,yin,,0,0,0,, 你可以让对象为你做的 \\N{\\fs12}that you can ask an object to do for you\r\nDialogue: 0,0:04:19.77,0:04:22.22,yin,,0,0,0,, 是 mutableCopy(可变复制)\\N{\\fs12}is mutable copy.\r\nDialogue: 0,0:04:22.22,0:04:25.59,yin,,0,0,0,,mutableCopy 会复制一个对象 但它是可变的 \\N{\\fs12}So mutable copy makes a copy of an object but it’s mutable.\r\nDialogue: 0,0:04:25.59,0:04:27.72,yin,,0,0,0,, 例如将 NSString 发送给 mutableCopy\\N{\\fs12}So if you had an NSString and you send it mutable copy,\r\nDialogue: 0,0:04:27.72,0:04:29.95,yin,,0,0,0,, 你会得到 NSMutableString\\N{\\fs12}you’ll get back an NSMutableString.\r\nDialogue: 0,0:04:29.95,0:04:32.66,yin,,0,0,0,, 或者将 NSArray 发送给 mutableCopy\\N{\\fs12}Or if you have an NSArray and you send it a mutable copy,\r\nDialogue: 0,0:04:32.66,0:04:34.64,yin,,0,0,0,, 你会得到一个 NSMutableArray\\N{\\fs12}you’ll get an NSMutableArray.\r\nDialogue: 0,0:04:34.64,0:04:39.38,yin,,0,0,0,, 这是创建对象的另一种方式 \\N{\\fs12}So that’s another way that that happens that you’re creating objects.\r\nDialogue: 0,0:04:39.38,0:04:43.43,yin,,0,0,0,, 当然 并非所有返回对象的方法都会创建一个对象 \\N{\\fs12}Of course, not all methods that return an object are creating an object\r\nDialogue: 0,0:04:43.44,0:04:46.40,yin,,0,0,0,, 例如 NSArray 中的 lastObject firstObject\\N{\\fs12}like we saw in NSArray — last object, and first object,\r\nDialogue: 0,0:04:46.40,0:04:47.42,yin,,0,0,0,, 以及 objectAtIndex\\N{\\fs12}and object at index.\r\nDialogue: 0,0:04:47.42,0:04:48.97,yin,,0,0,0,, 这些没有创建新对象 \\N{\\fs12}Those aren’t creating new objects;\r\nDialogue: 0,0:04:48.97,0:04:52.57,yin,,0,0,0,, 它们只是给你指针指向数组中的这些对象 \\N{\\fs12}they’re just giving you pointers to the objects that are in those array.\r\nDialogue: 0,0:04:52.57,0:04:55.49,yin,,0,0,0,, 这对你们而言应该很明显 \\N{\\fs12}That should be completely obvious to you\r\nDialogue: 0,0:04:55.49,0:04:59.02,yin,,0,0,0,, 不过我这里想明确一下 这些是指向对象的指针 \\N{\\fs12}but I just want to make it clear, you know, these are pointers to objects.\r\nDialogue: 0,0:04:59.02,0:05:01.36,yin,,0,0,0,, 你可以有多个指针 \\N{\\fs12}And you’re allowed to have multiple pointers.\r\nDialogue: 0,0:05:01.36,0:05:06.02,yin,,0,0,0,, 这里是普通的指针被来回传递 \\N{\\fs12}And this is normal pointers here being passed around.\r\nDialogue: 0,0:05:06.02,0:05:10.28,yin,,0,0,0,, 除非方法中有 copy 这个单词 \\N{\\fs12}So basically, unless a method has the word “copy”\r\nDialogue: 0,0:05:10.28,0:05:14.08,yin,,0,0,0,, 否则当方法返回给你一个已经存在的对象时 \\N{\\fs12}in it, then if it’s returning to you an object that exists somewhere else,\r\nDialogue: 0,0:05:14.08,0:05:16.32,yin,,0,0,0,, 它会返回指向那个对象的指针 \\N{\\fs12}it’s going to be returning a pointer to that object,\r\nDialogue: 0,0:05:16.32,0:05:18.17,yin,,0,0,0,, 除非方法中有 copy 这个词 \\N{\\fs12}okay, unless it has the word “copy” in it like\r\nDialogue: 0,0:05:18.17,0:05:21.02,yin,,0,0,0,, 例如 mutableCopy 或 copy\\N{\\fs12}”mutable copy” or “copy.”\r\nDialogue: 0,0:05:21.02,0:05:24.22,yin,,0,0,0,, 如果你要返回的对象并不存在 \\N{\\fs12}And if the object that you’re getting back doesn’t exist\r\nDialogue: 0,0:05:24.22,0:05:27.56,yin,,0,0,0,, 它就会为你创建新的对象 \\N{\\fs12}somewhere, then it’s going to make a new one for you.\r\nDialogue: 0,0:05:27.56,0:05:31.61,yin,,0,0,0,, 好 这是创建对象 非常简单 \\N{\\fs12}All right. That’s it on creating objects. Pretty straightforward there.\r\nDialogue: 0,0:05:31.61,0:05:33.42,yin,,0,0,0,,nil 我已经讲过了 \\N{\\fs12}Okay. Nil, I already talked about this,\r\nDialogue: 0,0:05:33.42,0:05:37.70,yin,,0,0,0,, 我们可以通过为 nil 的指针发送消息 \\N{\\fs12}that we can send messages through a pointer that is nil,\r\nDialogue: 0,0:05:37.70,0:05:39.89,yin,,0,0,0,, 也就是说该指针不指向任何东西 \\N{\\fs12}i.e. that pointer does not point to anything.\r\nDialogue: 0,0:05:39.89,0:05:41.93,yin,,0,0,0,, 没有代码会被执行 \\N{\\fs12}And no code gets executed.\r\nDialogue: 0,0:05:41.93,0:05:42.78,yin,,0,0,0,, 如果我写 \\N{\\fs12}So if I do this\r\nDialogue: 0,0:05:42.79,0:05:45.95,yin,,0,0,0,,int i = [obj methodWhichReturnsAnInt]\\N{\\fs12}init I equals obj method which returns an init,\r\nDialogue: 0,0:05:45.95,0:05:49.78,yin,,0,0,0,, 没有代码执行到 methodWhichReturnsAnInt\\N{\\fs12}no code gets executed to execute method which returns an init;\r\nDialogue: 0,0:05:49.79,0:05:50.81,yin,,0,0,0,, 但是 \\N{\\fs12}however,\r\nDialogue: 0,0:05:50.81,0:05:55.31,yin,,0,0,0,, 发送方括号这些的消息会返回 0\\N{\\fs12}that message sending square bracket thing will return zero.\r\nDialogue: 0,0:05:55.31,0:05:57.49,yin,,0,0,0,, 知道这个很重要 \\N{\\fs12}So that’s important to know.\r\nDialogue: 0,0:05:57.49,0:05:59.64,yin,,0,0,0,,0 也就是 nil\\N{\\fs12}And zero is also what nil is.\r\nDialogue: 0,0:05:59.64,0:06:02.43,yin,,0,0,0,, 如果你的方法返回一个对象 \\N{\\fs12}So if you had a method that returned an object and you sent\r\nDialogue: 0,0:06:02.43,0:06:06.43,yin,,0,0,0,, 你将那个消息发给 nil 返回的也会是 nil\\N{\\fs12}that message to nil, then you get back nil.\r\nDialogue: 0,0:06:06.43,0:06:09.26,yin,,0,0,0,, 这可以用来帮助我们达到一些目的 \\N{\\fs12}And we can use that, actually, to our advantage.\r\nDialogue: 0,0:06:09.26,0:06:15.00,yin,,0,0,0,, 例如周一我们需要随机抽取纸牌 我们用了 \\N{\\fs12}For example, in our thing we did on Monday, we did draw a random card, right?\r\nDialogue: 0,0:06:15.00,0:06:17.05,yin,,0,0,0,,self.deck drawRandomCard\\N{\\fs12}Self.deck draw random card.\r\nDialogue: 0,0:06:17.05,0:06:20.29,yin,,0,0,0,, 如果牌堆里牌用完了 这会返回 nil\\N{\\fs12}And that returned nil if the deck was out of cards.\r\nDialogue: 0,0:06:20.29,0:06:24.74,yin,,0,0,0,, 如果牌堆本身是 nil 这也会返回 nil\\N{\\fs12}If the deck itself had been nil, that also would return nil.\r\nDialogue: 0,0:06:24.74,0:06:27.27,yin,,0,0,0,, 这样我们就可以只写一个 if\\N{\\fs12}So we can write one if that deals with the fact\r\nDialogue: 0,0:06:27.27,0:06:29.30,yin,,0,0,0,, 来处理抽不到牌的情况 \\N{\\fs12}that we can’t get another card, whether it’s\r\nDialogue: 0,0:06:29.30,0:06:32.90,yin,,0,0,0,, 不管是因为牌堆空了 还是因为牌堆本就为 nil\\N{\\fs12}because the deck is empty or because there is no deck because the deck is nil.\r\nDialogue: 0,0:06:32.90,0:06:35.36,yin,,0,0,0,, 两种情况下 代码的执行都一样 \\N{\\fs12}Either way, the code’s going to look exactly the same.\r\nDialogue: 0,0:06:35.36,0:06:38.32,yin,,0,0,0,, 你们会习惯这个的 \\N{\\fs12}So you’ll get used to that.\r\nDialogue: 0,0:06:38.32,0:06:39.93,yin,,0,0,0,, 这显然同其它语言有所不同 \\N{\\fs12}It’s definitely different from other languages\r\nDialogue: 0,0:06:39.93,0:06:42.93,yin,,0,0,0,, 其它语言中 你显然不希望将消息发送给 nil\\N{\\fs12}where you’re protecting against sending messages to nil.\r\nDialogue: 0,0:06:42.93,0:06:44.33,yin,,0,0,0,, 但你们会习惯的 \\N{\\fs12}But you’ll get used to it.\r\nDialogue: 0,0:06:44.33,0:06:49.04,yin,,0,0,0,, 你们确实需要小心 消息发送返回类型是 struct 的情况 \\N{\\fs12}You do have to be careful. If the return type of a message send is a struct\r\nDialogue: 0,0:06:49.04,0:06:52.28,yin,,0,0,0,, 因为你无法得到所有成员都设为 0 的 struct\\N{\\fs12}because you don’t get back a struct with all its members set to zero;\r\nDialogue: 0,0:06:52.28,0:06:54.27,yin,,0,0,0,, 你得到的是一个未定义的 struct\\N{\\fs12}you get back an undefined struct.\r\nDialogue: 0,0:06:54.27,0:06:56.45,yin,,0,0,0,, 其中有什么是未定义的 \\N{\\fs12}What’s in there is undefined.\r\nDialogue: 0,0:06:56.45,0:06:59.29,yin,,0,0,0,,struct 在栈上返回给你 \\N{\\fs12}This struct is being returned to you on the stack.\r\nDialogue: 0,0:06:59.29,0:07:00.57,yin,,0,0,0,, 你可能得到栈垃圾 \\N{\\fs12}You might get stack garbage,\r\nDialogue: 0,0:07:00.57,0:07:02.52,yin,,0,0,0,, 你可能得到 0.struct 你无法知道 \\N{\\fs12}you might get zero.struct, you just don’t know.\r\nDialogue: 0,0:07:02.52,0:07:03.86,yin,,0,0,0,, 你不能依赖它 \\N{\\fs12}So you can’t rely on it.\r\nDialogue: 0,0:07:03.86,0:07:06.57,yin,,0,0,0,, 这里 代码中永远不要依赖这个 \\N{\\fs12}So here you should never rely on that in your code.\r\nDialogue: 0,0:07:06.57,0:07:08.63,yin,,0,0,0,, 如果你调用一个返回 struct 的方法 \\N{\\fs12}If you call a method, it returns a struct,\r\nDialogue: 0,0:07:08.63,0:07:11.57,yin,,0,0,0,, 你要检验 确保没有将它发送给 nil\\N{\\fs12}you got to check to make sure you’re not sending it to nil.\r\nDialogue: 0,0:07:13.77,0:07:15.68,yin,,0,0,0,, 好 动态绑定 \\N{\\fs12}All right. Dynamic binding.\r\nDialogue: 0,0:07:15.68,0:07:21.67,yin,,0,0,0,,Objective-C 对方法分派和调用的处理 \\N{\\fs12}So Objective-C handles the dispatching and calling of methods\r\nDialogue: 0,0:07:21.67,0:07:25.49,yin,,0,0,0,, 不同于你们大多数人所熟悉的语言 \\N{\\fs12}differently than languages that most of you are used to.\r\nDialogue: 0,0:07:25.49,0:07:27.41,yin,,0,0,0,, 它所做的是动态绑定 \\N{\\fs12}It does what’s called “dynamic binding.”\r\nDialogue: 0,0:07:27.41,0:07:32.33,yin,,0,0,0,, 通过这张幻灯片的讲解 你们会知道动态绑定是什么 \\N{\\fs12}And you’ll see what dynamic binding is as we go through this slide.\r\nDialogue: 0,0:07:32.33,0:07:36.39,yin,,0,0,0,,Objective-C 动态绑定很重要的一点在于 \\N{\\fs12}But the important thing to understand about dynamic binding and about Objective-C is\r\nDialogue: 0,0:07:36.40,0:07:41.99,yin,,0,0,0,,Objective-C 中有一个非常非常重要的类型叫 id\\N{\\fs12}that there’s a really, really important type in Objective-C called “ID,” okay?\r\nDialogue: 0,0:07:41.99,0:07:46.15,yin,,0,0,0,, 我们将它读作 I-D 而不是 id\\N{\\fs12}We call it “ID.” We don’t call it id by the way; ID we call it.\r\nDialogue: 0,0:07:46.15,0:07:49.88,yin,,0,0,0,, 代码中我会说 id myObject\\N{\\fs12}So here in that line of code I would say that’s ID my object.\r\nDialogue: 0,0:07:49.88,0:07:54.86,yin,,0,0,0,, 这里声明了一个指针 我的对象 类型为 id\\N{\\fs12}So I’m declaring a pointer, my object, which is a type ID.\r\nDialogue: 0,0:07:54.86,0:07:58.81,yin,,0,0,0,,id 是一个指针 \\N{\\fs12}So ID means pointer — ID is a pointer,\r\nDialogue: 0,0:07:58.81,0:08:00.23,yin,,0,0,0,, 所以不需要 id\\N{\\fs12}so we don’t use ID star;\r\nDialogue: 0,0:08:00.23,0:08:01.51,yin,,0,0,0,,id 就是指针 \\N{\\fs12}ID is a pointer –\r\nDialogue: 0,0:08:01.51,0:08:05.30,yin,,0,0,0,, 它是一个指针 指向类未知的对象 \\N{\\fs12}it means a pointer to an object where I don’t know its class.\r\nDialogue: 0,0:08:05.30,0:08:08.06,yin,,0,0,0,, 指向未知类型或未指定类型 \\N{\\fs12}Of unknown type or unspecified type.\r\nDialogue: 0,0:08:08.06,0:08:09.88,yin,,0,0,0,, 这是指向对象的指针 \\N{\\fs12}So it’s just a pointer to an object;\r\nDialogue: 0,0:08:09.88,0:08:13.00,yin,,0,0,0,, 我对对象则一无所知 \\N{\\fs12}I do not know anything about that object.\r\nDialogue: 0,0:08:13.00,0:08:16.97,yin,,0,0,0,, 实际上 Objective-C 中的所有指针都是 id\\N{\\fs12}Really, all pointers in Objective-C are IDs\r\nDialogue: 0,0:08:16.97,0:08:20.64,yin,,0,0,0,, 当你将消息发送给一个对象时 \\N{\\fs12}in that the decision about what code to execute\r\nDialogue: 0,0:08:20.64,0:08:23.44,yin,,0,0,0,, 关于执行什么代码的决定 \\N{\\fs12}when you send a message to an object is not determined\r\nDialogue: 0,0:08:23.44,0:08:26.23,yin,,0,0,0,, 直到运行时才会决定 \\N{\\fs12}until runtime when you send that message.\r\nDialogue: 0,0:08:26.23,0:08:28.21,yin,,0,0,0,, 当你发送一个消息时 \\N{\\fs12}When you send a message,\r\nDialogue: 0,0:08:28.21,0:08:30.61,yin,,0,0,0,, 一个函数会被调用 \\N{\\fs12}it’s essentially calling a function that’s looking\r\nDialogue: 0,0:08:30.61,0:08:35.07,yin,,0,0,0,, 查阅消息发送时 对应于所指向的那一特定类 \\N{\\fs12}up the right code to execute for that particular class\r\nDialogue: 0,0:08:35.07,0:08:37.50,yin,,0,0,0,, 所应执行的正确代码 \\N{\\fs12}that you’re pointing to at the time you send the message.\r\nDialogue: 0,0:08:37.50,0:08:41.09,yin,,0,0,0,, 这被叫作动态或迟绑定 \\N{\\fs12}That’s called dynamic or late binding.\r\nDialogue: 0,0:08:41.09,0:08:46.81,yin,,0,0,0,,Objective-C 中的所有消息发送都是这样做的 \\N{\\fs12}And all message sends — all of them in Objective-C — are done this way.\r\nDialogue: 0,0:08:46.81,0:08:49.38,yin,,0,0,0,, 这意味着什么呢 \\N{\\fs12}Now, what does this mean?\r\nDialogue: 0,0:08:50.39,0:08:54.31,yin,,0,0,0,, 这意味着… 先看这安全吗 \\N{\\fs12}It means that — well, is this safe, right?\r\nDialogue: 0,0:08:54.31,0:08:56.02,yin,,0,0,0,, 因为你肯定会担心 \\N{\\fs12}Because you’re worried, I’m sure,\r\nDialogue: 0,0:08:56.02,0:08:59.24,yin,,0,0,0,, 我将消息发送给一个对象 如果它不理解该怎么办 \\N{\\fs12}”What if I send a message to an object and it doesn’t understand it?”\r\nDialogue: 0,0:08:59.24,0:09:02.28,yin,,0,0,0,, 没有机制能够阻止你这样做 \\N{\\fs12}Okay. Well, nothing stops you from doing that.\r\nDialogue: 0,0:09:02.28,0:09:05.31,yin,,0,0,0,, 不仅如此 如果你这样做 程序就会崩溃 \\N{\\fs12}And not only that, if you do that, your program will crash.\r\nDialogue: 0,0:09:05.31,0:09:06.76,yin,,0,0,0,, 这会引发异常 \\N{\\fs12}It will raise an exception.\r\nDialogue: 0,0:09:06.76,0:09:08.80,yin,,0,0,0,, 除非捕获异常 否则程序会崩溃 \\N{\\fs12}Unless you catch the exception, it will crash.\r\nDialogue: 0,0:09:08.80,0:09:11.04,yin,,0,0,0,, 你心里可能会想 哇 \\N{\\fs12}And so you’re probably feeling like, “Wow.\r\nDialogue: 0,0:09:11.04,0:09:13.57,yin,,0,0,0,, 这些 Objective-C 程序肯定总在崩溃 \\N{\\fs12}These Objective-C programs must be crashing all the time\r\nDialogue: 0,0:09:13.57,0:09:16.36,yin,,0,0,0,, 因为一不小心就容易将消息发送给 \\N{\\fs12}because you accidentally send a message to an object;\r\nDialogue: 0,0:09:16.36,0:09:18.13,yin,,0,0,0,, 不理解消息的对象 \\N{\\fs12}it doesn’t understand that message.”\r\nDialogue: 0,0:09:18.13,0:09:19.76,yin,,0,0,0,, 但实际不是这样 \\N{\\fs12}But actually, it doesn’t happen.\r\nDialogue: 0,0:09:19.76,0:09:21.32,yin,,0,0,0,, 为什么没有发生呢 \\N{\\fs12}Okay. Why doesn’t that happen?\r\nDialogue: 0,0:09:21.32,0:09:22.45,yin,,0,0,0,, 原因有两点 \\N{\\fs12}And there’s really two reasons.\r\nDialogue: 0,0:09:22.45,0:09:25.15,yin,,0,0,0,, 一是我们经常使用静态类型化 \\N{\\fs12}One is we use static typing a lot.\r\nDialogue: 0,0:09:25.15,0:09:26.98,yin,,0,0,0,, 我们不经常使用 id\\N{\\fs12}We don’t use ID that much.\r\nDialogue: 0,0:09:26.98,0:09:29.02,yin,,0,0,0,, 我们使用 NSString * 这些 \\N{\\fs12}We use, like, NSString star.\r\nDialogue: 0,0:09:29.02,0:09:32.05,yin,,0,0,0,,NSString * 完全等同于使用 id\\N{\\fs12}Now, NSString star is exactly the same as using ID,\r\nDialogue: 0,0:09:32.05,0:09:36.47,yin,,0,0,0,, 只是编译器在编译你的代码时 \\N{\\fs12}except that the compiler, while it’s compiling your code,\r\nDialogue: 0,0:09:36.47,0:09:40.70,yin,,0,0,0,, 知道你至少是意图让该指针指向一个字符串 \\N{\\fs12}knows that you at least intend that that pointer points to a string.\r\nDialogue: 0,0:09:40.70,0:09:44.33,yin,,0,0,0,, 如果你尝试发送非字符串消息给该指针 它会抱怨 \\N{\\fs12}So if you tried to send a nonstring message to that pointer, it’s going to complain.\r\nDialogue: 0,0:09:44.33,0:09:46.02,yin,,0,0,0,, 它会给你警告 \\N{\\fs12}It’s going to, you know, give you warnings.\r\nDialogue: 0,0:09:46.02,0:09:50.45,yin,,0,0,0,, 所以在编译 Objective-C 程序时 你应确保没有警告 \\N{\\fs12}And so when you compile your Objective-C programs they should always have no warnings,\r\nDialogue: 0,0:09:50.45,0:09:53.72,yin,,0,0,0,, 这样你就能够确保没有这种问题了 \\N{\\fs12}and then you can be pretty sure that you’re not going to have this problem\r\nDialogue: 0,0:09:53.72,0:09:55.25,yin,,0,0,0,, 没有在运行时将消息 \\N{\\fs12}where you send a message to an object at runtime\r\nDialogue: 0,0:09:55.25,0:09:58.24,yin,,0,0,0,, 发送给一个不理解它的对象 从而导致崩溃 \\N{\\fs12}and it doesn’t understand it and it crashes.\r\nDialogue: 0,0:09:58.26,0:10:00.74,yin,,0,0,0,, 这是第一种方式 \\N{\\fs12}So that’s the number one way.\r\nDialogue: 0,0:10:00.74,0:10:02.93,yin,,0,0,0,, 我要讲的第二种方式是 \\N{\\fs12}And the second way I’m going to talk about\r\nDialogue: 0,0:10:02.93,0:10:05.80,yin,,0,0,0,, 很多时候 在运行时我们都会检验 \\N{\\fs12}is that a lot of times we will check at runtime.\r\nDialogue: 0,0:10:05.80,0:10:08.80,yin,,0,0,0,, 我们会看这个 id 指针 \\N{\\fs12}We’ll look at that ID pointer.\r\nDialogue: 0,0:10:08.80,0:10:12.28,yin,,0,0,0,, 在发送之前 我们会检验它是否能够正确作出反应 \\N{\\fs12}And we will check and see if it responds to something before we send it.\r\nDialogue: 0,0:10:13.45,0:10:15.35,yin,,0,0,0,, 你们知道静态类型化 \\N{\\fs12}So you know about static typing,\r\nDialogue: 0,0:10:15.36,0:10:18.11,yin,,0,0,0,, 也就是 NSString *s = @”x”\\N{\\fs12}that’s the NSString star S equals at sign X.\r\nDialogue: 0,0:10:18.11,0:10:20.26,yin,,0,0,0,, 这是非常安全 非常好的做法 \\N{\\fs12}This is really safe, really good,\r\nDialogue: 0,0:10:20.26,0:10:21.85,yin,,0,0,0,, 任何糟糕的事情都不会发生在这里 \\N{\\fs12}nothing bad’s going to happen here\r\nDialogue: 0,0:10:21.86,0:10:25.19,yin,,0,0,0,, 因为编译器在编译时很好地知道你想要什么 \\N{\\fs12}because the compiler at compile time has a pretty good idea what you intend\r\nDialogue: 0,0:10:25.19,0:10:26.64,yin,,0,0,0,, 如果不是 它会警告你 \\N{\\fs12}and it will warn you if not.\r\nDialogue: 0,0:10:26.64,0:10:33.48,yin,,0,0,0,, 但是 编译器没有绑定这时执行的代码 \\N{\\fs12}However, the compiler is not doing the binding between what codes executes at this time;\r\nDialogue: 0,0:10:33.49,0:10:35.96,yin,,0,0,0,, 它只是警告你 这是语法上的甜头 \\N{\\fs12}it’s just warning you. It’s syntactic sugar.\r\nDialogue: 0,0:10:35.96,0:10:38.82,yin,,0,0,0,, 这种语法 它能看到并警告你 \\N{\\fs12}It’s syntax that it can look at to warn you,\r\nDialogue: 0,0:10:38.82,0:10:41.06,yin,,0,0,0,, 但这里没有任何强制作用 \\N{\\fs12}but it’s not actually enforcing anything here.\r\nDialogue: 0,0:10:41.06,0:10:45.43,yin,,0,0,0,, 用 id obj =s 也完全合法 \\N{\\fs12}It’s perfectly legal to say ID obj equals S,\r\nDialogue: 0,0:10:45.43,0:10:47.45,yin,,0,0,0,,s 也就是之前的 s\\N{\\fs12}where S is the line before.\r\nDialogue: 0,0:10:47.45,0:10:49.66,yin,,0,0,0,, 这里就连警告都不会产生了 \\N{\\fs12}And that will not even generate a warning.\r\nDialogue: 0,0:10:49.66,0:10:52.47,yin,,0,0,0,, 因为 id obj 是指向任何对象的指针 \\N{\\fs12}Because ID obj is a pointer to any kind of object;\r\nDialogue: 0,0:10:52.47,0:10:54.52,yin,,0,0,0,,s 是指向任何对象的指针 \\N{\\fs12}S is a pointer to any kind of object.\r\nDialogue: 0,0:10:54.52,0:10:57.12,yin,,0,0,0,, 根据前一行 它是一个指向字符串的指针 \\N{\\fs12}It’s a pointer to a string, according to the previous line.\r\nDialogue: 0,0:10:57.12,0:11:00.56,yin,,0,0,0,, 但由于两者都是指向对象的指针 这完全合法 \\N{\\fs12}But since those are both pointers to objects, that’s perfectly legal.\r\nDialogue: 0,0:11:00.56,0:11:01.93,yin,,0,0,0,, 编译器不会警告你 \\N{\\fs12}Compiler will not warn you.\r\nDialogue: 0,0:11:01.93,0:11:04.58,yin,,0,0,0,, 这一行代码就有些危险了 \\N{\\fs12}This is a little bit of a dangerous line of code, right?\r\nDialogue: 0,0:11:04.58,0:11:08.80,yin,,0,0,0,, 因为之前 s 是类型化良好的变量 \\N{\\fs12}Because you just went from having S — this nice variable that’s typed\r\nDialogue: 0,0:11:08.80,0:11:11.37,yin,,0,0,0,, 如果你做了不正确的事 编译器会告诉你 \\N{\\fs12}and the compiler can warn you if you do the wrong thing –\r\nDialogue: 0,0:11:11.37,0:11:14.00,yin,,0,0,0,, 而 obj 是没有类型化的指针 \\N{\\fs12}to having an obj, which is this untyped pointer\r\nDialogue: 0,0:11:14.00,0:11:17.21,yin,,0,0,0,, 不管发送什么消息 编译器都不会警告你 \\N{\\fs12}where you can send any message you want and the compiler’s not going to warn you.\r\nDialogue: 0,0:11:17.21,0:11:21.93,yin,,0,0,0,, 你还可以这样 NSArray *a = obj\\N{\\fs12}You can also do this NSArray star A equals obj.\r\nDialogue: 0,0:11:21.93,0:11:26.48,yin,,0,0,0,, 这时你就让 NSArray 变量指向了一个字符串 \\N{\\fs12}Okay. Now you have NSArray variable that points to a string.\r\nDialogue: 0,0:11:26.48,0:11:29.77,yin,,0,0,0,, 这很可能会导致问题 \\N{\\fs12}Now, that’s extremely likely to cause a problem.\r\nDialogue: 0,0:11:29.77,0:11:31.39,yin,,0,0,0,, 这也是合法的 \\N{\\fs12}This is also legal\r\nDialogue: 0,0:11:31.39,0:11:34.58,yin,,0,0,0,, 因为 NSArray *a 是一个指向对象的指针 \\N{\\fs12}because NSArray star A is a pointer to an object;\r\nDialogue: 0,0:11:34.58,0:11:38.93,yin,,0,0,0,,obj 也是一个指向对象的指针 所以这样赋值是允许的 \\N{\\fs12}obj is a pointer to an object, so it allows this assignment.\r\nDialogue: 0,0:11:38.93,0:11:40.84,yin,,0,0,0,, 非常危险 而且明显错误 \\N{\\fs12}Very dangerous. Obviously wrong.\r\nDialogue: 0,0:11:40.84,0:11:42.86,yin,,0,0,0,, 这三行代码放到一起 显然是错误的 \\N{\\fs12}If these three lines of code are there, that’s clearly wrong.\r\nDialogue: 0,0:11:42.86,0:11:45.82,yin,,0,0,0,, 你不应当让 NSArray 指向 NSString\\N{\\fs12}You would not want to have an NSArray pointing to an NSString.\r\nDialogue: 0,0:11:45.82,0:11:49.04,yin,,0,0,0,,id 在这方面可能会非常危险 \\N{\\fs12}So ID can be dangerous in this way.\r\nDialogue: 0,0:11:49.04,0:11:54.11,yin,,0,0,0,, 实际上 我们在原来写的代码中也默默地做过这个 \\N{\\fs12}And in fact, in the code that we’ve written we already did this kind of silently.\r\nDialogue: 0,0:11:54.11,0:11:56.76,yin,,0,0,0,, 在 PlayingCard 的 match 中 \\N{\\fs12}Remember that in match, playing card’s match\r\nDialogue: 0,0:11:56.76,0:11:58.65,yin,,0,0,0,, 我们有一行代码是 \\N{\\fs12}we put a line in there that said, “Playing\r\nDialogue: 0,0:11:58.65,0:12:01.99,yin,,0,0,0,,PlayingCard *otherCard = [otherCards firstObject]\\N{\\fs12}card star other car equals other card’s first object.”\r\nDialogue: 0,0:12:01.99,0:12:02.90,yin,,0,0,0,, 记得这个吗 \\N{\\fs12}Remember that?\r\nDialogue: 0,0:12:02.90,0:12:06.82,yin,,0,0,0,,NSArray 中的 firstObject 方法返回一个 id\\N{\\fs12}Well, the method first object in an NSArray returns an ID.\r\nDialogue: 0,0:12:06.84,0:12:09.04,yin,,0,0,0,, 你可以去查说明文档 \\N{\\fs12}If you go look it up in the documentation,\r\nDialogue: 0,0:12:09.04,0:12:12.01,yin,,0,0,0,, 其返回类型 括号 id\\N{\\fs12}look at its return type — parenthesis ID.\r\nDialogue: 0,0:12:12.01,0:12:15.59,yin,,0,0,0,, 所以 我们将一个 PlayingCard 赋值给一个 id\\N{\\fs12}So we just assigned a playing card to an ID.\r\nDialogue: 0,0:12:15.59,0:12:18.92,yin,,0,0,0,, 所以 从数组中得到的对象最好是 PlayingCard\\N{\\fs12}So that object that came out of that array better be a playing card\r\nDialogue: 0,0:12:18.92,0:12:20.46,yin,,0,0,0,, 否则运行时就会崩溃 \\N{\\fs12}or we’re going to crash at runtime.\r\nDialogue: 0,0:12:20.47,0:12:22.29,yin,,0,0,0,, 这堂课晚些时候 \\N{\\fs12}And a little later in this lecture I’m going\r\nDialogue: 0,0:12:22.29,0:12:27.87,yin,,0,0,0,, 我会讲到 如何保护代码 确保这种情况下不会崩溃 \\N{\\fs12}to show you how we can protect our code to make sure that we don’t crash in this case.\r\nDialogue: 0,0:12:27.87,0:12:31.80,yin,,0,0,0,, 大家都明白为什么说这里有点危险了吗 \\N{\\fs12}Does everyone see why this is a little dangerous?\r\nDialogue: 0,0:12:32.87,0:12:35.09,yin,,0,0,0,, 这方面有问题吗 \\N{\\fs12}Questions about that?\r\nDialogue: 0,0:12:35.09,0:12:37.64,yin,,0,0,0,, 好 提醒一下 绝对不要用 id\\N{\\fs12}Okay. And a reminder: Never use ID star.\r\nDialogue: 0,0:12:37.64,0:12:39.87,yin,,0,0,0,,id * 没有意义 因为 id 就是指针 \\N{\\fs12}ID star makes no sense because ID is a pointer.\r\nDialogue: 0,0:12:39.87,0:12:41.94,yin,,0,0,0,,id * 将是指向指针的指针 \\N{\\fs12}So ID star would be a pointer to a pointer.\r\nDialogue: 0,0:12:41.94,0:12:44.58,yin,,0,0,0,, 我们在 Objective-C 中不会这样做 \\N{\\fs12}We don’t do that in Objective-C, okay,\r\nDialogue: 0,0:12:44.58,0:12:47.63,yin,,0,0,0,, 特别是指向 id 的指针 \\N{\\fs12}especially a pointer to an ID [inaudible].\r\nDialogue: 0,0:12:47.63,0:12:51.08,yin,,0,0,0,, 为了总结上述内容 我将展示这个小小的例子 \\N{\\fs12}All right. So to summarize all this I’m going to show you this example.\r\nDialogue: 0,0:12:51.08,0:12:53.44,yin,,0,0,0,, 我有两个类 一个 Vehicle(交通工具) 类 \\N{\\fs12}I’ve got two classes: I got a vehicle class,\r\nDialogue: 0,0:12:53.45,0:12:56.05,yin,,0,0,0,, 它有一个方法 move(运动) 交通工具可以运动 \\N{\\fs12}which has what method move — you can move the vehicle around –\r\nDialogue: 0,0:12:56.05,0:12:58.56,yin,,0,0,0,, 然后有 Ship(船) 类 它是一种交通工具 \\N{\\fs12}and I got a ship which is a vehicle,\r\nDialogue: 0,0:12:58.56,0:12:59.68,yin,,0,0,0,, 继承自 Vehicle\\N{\\fs12}inherits from vehicle,\r\nDialogue: 0,0:12:59.68,0:13:01.08,yin,,0,0,0,, 它只有一个方法 shoot(射击)\\N{\\fs12}and it’s only got one method, shoot.\r\nDialogue: 0,0:13:01.08,0:13:02.92,yin,,0,0,0,, 这条船可以射击别的船 \\N{\\fs12}So this ship can shoot other ships.\r\nDialogue: 0,0:13:02.92,0:13:05.13,yin,,0,0,0,, 它也能运动 因为它是交通工具 \\N{\\fs12}And they can also move because they’re vehicles.\r\nDialogue: 0,0:13:05.13,0:13:09.70,yin,,0,0,0,, 如果我声明一个局部变量 一条船 s\\N{\\fs12}So if I declare a local variable ship, ship S,\r\nDialogue: 0,0:13:09.70,0:13:12.96,yin,,0,0,0,, 类型是 Ship * 我用 alloc init 分配初始化一条船 \\N{\\fs12}which is a ship star, and I allocate init a ship,\r\nDialogue: 0,0:13:12.96,0:13:16.45,yin,,0,0,0,, 我可以说 s shoot 或 s move 都能行 \\N{\\fs12}I can say “S shoot” or “S move” — works fine, right?\r\nDialogue: 0,0:13:16.45,0:13:19.92,yin,,0,0,0,, 因为 Ship 实现了 shoot 继承了 move\\N{\\fs12}Because ships implement shoot and they inherit move.\r\nDialogue: 0,0:13:19.92,0:13:22.01,yin,,0,0,0,, 所以大家都相安无事 \\N{\\fs12}So everybody’s totally happy here.\r\nDialogue: 0,0:13:22.01,0:13:27.44,yin,,0,0,0,, 我还可以写 Vehicle *v = s 这完全合法 \\N{\\fs12}I can also do vehicle star V equals S. That’s perfectly legal\r\nDialogue: 0,0:13:27.44,0:13:31.03,yin,,0,0,0,, 因为 v 是一个交通工具 s 也是一个交通工具 \\N{\\fs12}because V is a vehicle and S is a vehicle\r\nDialogue: 0,0:13:31.03,0:13:33.73,yin,,0,0,0,, 因为它从船中继承了交通工具的性质 \\N{\\fs12}because it inherits its vehicle-ness from ship.\r\nDialogue: 0,0:13:33.73,0:13:36.60,yin,,0,0,0,, 这有点像 deck = [[PlayingCardDeck alloc] init]\\N{\\fs12}Okay. This is like deck equals playing card deck alloc init –\r\nDialogue: 0,0:13:36.60,0:13:39.72,yin,,0,0,0,, 这是程序运行中完全合法的对象 \\N{\\fs12}perfectly legal object to run in your programming, right?\r\nDialogue: 0,0:13:39.72,0:13:43.68,yin,,0,0,0,, 下面我们尝试说 v shoot\\N{\\fs12}Okay. But now let’s try to say V shoot.\r\nDialogue: 0,0:13:43.68,0:13:45.70,yin,,0,0,0,, 这里会发生什么 \\N{\\fs12}Now, what’s going to happen here?\r\nDialogue: 0,0:13:45.70,0:13:48.46,yin,,0,0,0,, 在编译时 你会得到警告 \\N{\\fs12}All right. At compile time you’re going to get a warning\r\nDialogue: 0,0:13:48.46,0:13:51.55,yin,,0,0,0,, 因为交通工具没有实现 shoot\\N{\\fs12}because vehicles do not implement shoot;\r\nDialogue: 0,0:13:51.56,0:13:53.82,yin,,0,0,0,, 船有 但交通工具没有 \\N{\\fs12}ships do but not vehicles.\r\nDialogue: 0,0:13:53.83,0:13:56.36,yin,,0,0,0,, 明白这里为什么会有警告了吗 \\N{\\fs12}So do you see why this is going to give you a warning?\r\nDialogue: 0,0:13:56.36,0:13:58.97,yin,,0,0,0,, 运行时呢 \\N{\\fs12}What about at runtime?\r\nDialogue: 0,0:13:58.97,0:14:01.13,yin,,0,0,0,, 这段代码不会崩溃 \\N{\\fs12}This code will not crash\r\nDialogue: 0,0:14:01.13,0:14:03.93,yin,,0,0,0,, 因为我们知道 v 实际上是一条船 \\N{\\fs12}because we know that V actually is a ship.\r\nDialogue: 0,0:14:03.93,0:14:06.33,yin,,0,0,0,, 所以这在运行时会运行得很好 \\N{\\fs12}So this will work fine at runtime.\r\nDialogue: 0,0:14:06.33,0:14:08.36,yin,,0,0,0,, 明白了吗 \\N{\\fs12}Okay? See that?\r\nDialogue: 0,0:14:08.36,0:14:14.56,yin,,0,0,0,, 这种情况下 编译时出现警告 到运行时运行得很好 \\N{\\fs12}So this is where you get a warning at compile time; runs fine at runtime.\r\nDialogue: 0,0:14:14.56,0:14:19.29,yin,,0,0,0,, 这种情况呢 我声明一个 obj\\N{\\fs12}Now, what about this case where I declare an obj, okay,\r\nDialogue: 0,0:14:19.29,0:14:21.14,yin,,0,0,0,, 它可以是任何东西 \\N{\\fs12}and it can be anything we want.\r\nDialogue: 0,0:14:21.14,0:14:25.99,yin,,0,0,0,, 设法对它 alloc init 然后写代码 obj shoot\\N{\\fs12}Alloc init it somehow and you say “obj shoot,” okay?\r\nDialogue: 0,0:14:25.99,0:14:27.80,yin,,0,0,0,, 不管 obj 是什么 \\N{\\fs12}No matter what obj is –\r\nDialogue: 0,0:14:27.80,0:14:29.67,yin,,0,0,0,, 我故意没有讲清楚 obj 是什么 \\N{\\fs12}and I intentionally didn’t tell you what obj\r\nDialogue: 0,0:14:29.67,0:14:31.35,yin,,0,0,0,, 因为不管 obj 是什么 \\N{\\fs12}is because it doesn’t matter what obj is.\r\nDialogue: 0,0:14:31.35,0:14:33.35,yin,,0,0,0,, 编译器在这里都不会警告你 \\N{\\fs12}The compiler is not going to warn you here.\r\nDialogue: 0,0:14:33.35,0:14:35.52,yin,,0,0,0,, 任何时候将消息发送给 obj\\N{\\fs12}Anytime you send a message to obj,\r\nDialogue: 0,0:14:35.52,0:14:39.22,yin,,0,0,0,, 只要消息存在 编译器都不会警告你 \\N{\\fs12}as long as that message exists somewhere, the compiler will not warn you.\r\nDialogue: 0,0:14:39.22,0:14:44.74,yin,,0,0,0,, 运行时 obj 不是船或其它能对 shoot 作出反应的对象 \\N{\\fs12}At runtime, if obj is not a ship or some other object that responds to shoot,\r\nDialogue: 0,0:14:44.74,0:14:46.48,yin,,0,0,0,, 程序就会崩溃 \\N{\\fs12}it will crash.\r\nDialogue: 0,0:14:46.48,0:14:47.19,yin,,0,0,0,, 有问题 \\N{\\fs12}Question?\r\nDialogue: 0,0:14:47.19,0:14:50.07,yin,,0,0,0,, 学生：id 在这方面很特殊吗 \\N{\\fs12}> Is ID special in that way?\r\nDialogue: 0,0:14:50.07,0:14:51.32,yin,,0,0,0,, 老师：哪方面 \\N{\\fs12}> In what way?\r\nDialogue: 0,0:14:51.32,0:14:55.52,yin,,0,0,0,, 学生：因为似乎在这种情况下 \\N{\\fs12}> Because it seems like it’s a similar case where\r\nDialogue: 0,0:14:55.52,0:15:00.70,yin,,0,0,0,, 不管你怎么对 obj 赋值 它是指向对象的指针 \\N{\\fs12}whatever you’ve assigned obj is a pointer to an object\r\nDialogue: 0,0:15:00.70,0:15:05.51,yin,,0,0,0,, 但它可能 也可能不具有这种方法 \\N{\\fs12}but it may or may not have this method.\r\nDialogue: 0,0:15:05.51,0:15:07.94,yin,,0,0,0,, 老师：问题是 id 在这方面很特殊吗 \\N{\\fs12}> Well, so the question is: Is ID special in that way?\r\nDialogue: 0,0:15:07.94,0:15:11.33,yin,,0,0,0,, 你是说 id 特殊在我可以发送任何消息给它 \\N{\\fs12}You mean is ID special in that I can send it any message I want\r\nDialogue: 0,0:15:11.33,0:15:12.83,yin,,0,0,0,, 而编译器不会警告我 \\N{\\fs12}and the compiler won’t warn me?\r\nDialogue: 0,0:15:12.83,0:15:15.09,yin,,0,0,0,, 对 这就是 id 的语义 \\N{\\fs12}Yes. Because that’s kind of the semantics of ID.\r\nDialogue: 0,0:15:15.09,0:15:18.07,yin,,0,0,0,,id 是一个指针 指向类未知的对象 \\N{\\fs12}ID means a pointer to some object I don’t know the class of.\r\nDialogue: 0,0:15:18.07,0:15:20.85,yin,,0,0,0,, 所以编译器没法给你警告 \\N{\\fs12}So there’s no way for the compiler to give you a warning.\r\nDialogue: 0,0:15:20.85,0:15:23.76,yin,,0,0,0,, 它只会假设 有人会对 shoot 作出反应 \\N{\\fs12}So it just assumes “Okay, somebody responds to shoot.\r\nDialogue: 0,0:15:23.76,0:15:26.46,yin,,0,0,0,, 也许是这个 我不会警告你 \\N{\\fs12}So it might be this one, so I’m not going to warn you.”\r\nDialogue: 0,0:15:26.46,0:15:28.49,yin,,0,0,0,, 确实 id 在这方面很特殊 \\N{\\fs12}So yeah, ID is special in that way, I guess.\r\nDialogue: 0,0:15:28.49,0:15:34.00,yin,,0,0,0,, 这就是我们不像这样单纯使用 id 的原因 \\N{\\fs12}That’s why we don’t want to use ID unadorned like this.\r\nDialogue: 0,0:15:34.00,0:15:37.24,yin,,0,0,0,, 如果我说 obj 某不存在的方法名 \\N{\\fs12}If I’d say obj some method name that doesn’t exist,\r\nDialogue: 0,0:15:37.24,0:15:38.92,yin,,0,0,0,, 它确实会警告我 \\N{\\fs12}then it will warn me.\r\nDialogue: 0,0:15:38.92,0:15:41.85,yin,,0,0,0,, 如果任何地方都找不到这个方法 \\N{\\fs12}So if it can’t find that method anywhere,\r\nDialogue: 0,0:15:41.85,0:15:44.89,yin,,0,0,0,, 编译器所知道的任何对象都没实现这种方法 \\N{\\fs12}no object that the compiler’s ever heard of implements that method,\r\nDialogue: 0,0:15:44.89,0:15:46.24,yin,,0,0,0,, 那它肯定会警告你 \\N{\\fs12}then it will at least warn you.\r\nDialogue: 0,0:15:46.24,0:15:49.04,yin,,0,0,0,, 因为这时你很有可能是敲错了 犯了语法错误 \\N{\\fs12}Because then it’s likely you had a syntax error. You mistyped it.\r\nDialogue: 0,0:15:49.04,0:15:51.56,yin,,0,0,0,, 这时编译器就会帮你 \\N{\\fs12}And so the compiler is going to help you there.\r\nDialogue: 0,0:15:53.24,0:15:56.50,yin,,0,0,0,, 假设我有一个 NSString *hello\\N{\\fs12}So let’s say I had an NSString star hello.\r\nDialogue: 0,0:15:56.50,0:15:58.94,yin,,0,0,0,, 我让它等于 @”hello”\\N{\\fs12}And I’m going to make it equal to at sign hello.\r\nDialogue: 0,0:15:58.94,0:16:00.72,yin,,0,0,0,, 如果我说 hello shoot\\N{\\fs12}If I say hello shoot,\r\nDialogue: 0,0:16:00.72,0:16:02.89,yin,,0,0,0,, 编译器显然会警告我说 \\N{\\fs12}the compiler’s obviously going to warn me and say,\r\nDialogue: 0,0:16:02.89,0:16:04.79,yin,,0,0,0,, 字符串不会对 shoot 作出反应 \\N{\\fs12}”Strings don’t respond to shoot.”\r\nDialogue: 0,0:16:04.79,0:16:07.96,yin,,0,0,0,, 而运行时 这会崩溃 \\N{\\fs12}And at runtime this would crash\r\nDialogue: 0,0:16:07.96,0:16:10.03,yin,,0,0,0,, 因为字符串不会对 shoot 作出反应 \\N{\\fs12}because, of course, strings don’t respond to shoot.\r\nDialogue: 0,0:16:10.03,0:16:14.35,yin,,0,0,0,, 这很好 我们就希望情况是这样 \\N{\\fs12}Okay, so this is all good. This is the way we want things.\r\nDialogue: 0,0:16:14.35,0:16:17.77,yin,,0,0,0,, 如果这样做呢 Ship *helloShip =\\N{\\fs12}What if I did this, ship star hello ship equals\r\nDialogue: 0,0:16:17.78,0:16:18.96,yin,,0,0,0,, 类型转换 \\N{\\fs12}cast –\r\nDialogue: 0,0:16:18.96,0:16:21.35,yin,,0,0,0,, 大家都知道类型转换吧 \\N{\\fs12}okay, everyone knows about casting, right,\r\nDialogue: 0,0:16:21.35,0:16:26.37,yin,,0,0,0,, 所有语言几乎都有类型转换 \\N{\\fs12}all languages have casting pretty much; well, most languages that you know –\r\nDialogue: 0,0:16:26.37,0:16:29.10,yin,,0,0,0,,(Ship *)hello\\N{\\fs12}parenthesis ship star hello.\r\nDialogue: 0,0:16:29.10,0:16:32.53,yin,,0,0,0,, 这完全是合法的 编译器也不会警告我 \\N{\\fs12}This is perfectly legal. And the compiler will not warn me.\r\nDialogue: 0,0:16:32.53,0:16:37.25,yin,,0,0,0,, 我这里是将字符串放到了 Ship * 指针中 \\N{\\fs12}So I’ve now taken a string and put it in a ship star pointer.\r\nDialogue: 0,0:16:37.25,0:16:40.74,yin,,0,0,0,, 这时编译器会认为 helloShip 是一条船 \\N{\\fs12}And the compiler now thinks that that hello ship is a ship.\r\nDialogue: 0,0:16:40.74,0:16:44.24,yin,,0,0,0,, 它只会在看到船没有的方法时才会抱怨 \\N{\\fs12}And so it’s only going to complain if you do things to it that don’t look like ship,\r\nDialogue: 0,0:16:44.24,0:16:48.36,yin,,0,0,0,, 虽然这里我们知道 这里是一个字符串 \\N{\\fs12}even though we know we know that that is a string.\r\nDialogue: 0,0:16:48.36,0:16:51.16,yin,,0,0,0,, 所以说 类型转换极度危险 \\N{\\fs12}Okay. So casting can be super dangerous,\r\nDialogue: 0,0:16:51.16,0:16:53.14,yin,,0,0,0,, 就像所有语言中一样 \\N{\\fs12}just like in any language casting can be dangerous.\r\nDialogue: 0,0:16:53.14,0:16:54.46,yin,,0,0,0,, 这里也很危险 \\N{\\fs12}It can be dangerous here.\r\nDialogue: 0,0:16:54.46,0:16:56.72,yin,,0,0,0,, 但我们有时会进行类型转换 \\N{\\fs12}But we do do cast sometimes.\r\nDialogue: 0,0:16:56.72,0:16:58.14,yin,,0,0,0,, 我们使用类型转换的时候 \\N{\\fs12}And the times we cast are the\r\nDialogue: 0,0:16:58.15,0:17:01.56,yin,,0,0,0,, 也就是我们使用 id 并加以保护的时候 \\N{\\fs12}same kind of times we use ID, which is protected times.\r\nDialogue: 0,0:17:01.56,0:17:05.15,yin,,0,0,0,, 下一张幻灯片中我会讲到这种保护 \\N{\\fs12}I’m going talk about that protection on the next slide.\r\nDialogue: 0,0:17:05.15,0:17:09.26,yin,,0,0,0,, 如果我们之后说 helloShip shoot\\N{\\fs12}So if we then said hello ship shoot, okay,\r\nDialogue: 0,0:17:09.26,0:17:12.79,yin,,0,0,0,, 这不会造成编译错误 \\N{\\fs12}that would not generate a compiling error\r\nDialogue: 0,0:17:12.79,0:17:14.96,yin,,0,0,0,, 因为 helloShip 是一个 Ship\\N{\\fs12}because hello ship is a ship star;\r\nDialogue: 0,0:17:14.96,0:17:16.63,yin,,0,0,0,, 但它在运行时会崩溃 \\N{\\fs12}however, it would crash at runtime\r\nDialogue: 0,0:17:16.63,0:17:19.27,yin,,0,0,0,, 因为字符串不会对 shoot 作出反应 \\N{\\fs12}because strings don’t respond to shoot.\r\nDialogue: 0,0:17:19.27,0:17:20.53,yin,,0,0,0,, 都明白了吗 \\N{\\fs12}Everybody cool?\r\nDialogue: 0,0:17:20.53,0:17:21.45,yin,,0,0,0,, 请讲 \\N{\\fs12}Yeah?\r\nDialogue: 0,0:17:24.85,0:17:30.04,yin,,0,0,0,, 类型转换什么都没做 只是把编译器糊弄了 \\N{\\fs12}Okay, the typecasting really doesn’t do anything; that is just tricking the compiler.\r\nDialogue: 0,0:17:30.04,0:17:33.70,yin,,0,0,0,, 它其实没有执行任何代码 \\N{\\fs12}That’s not even executing really any code per se.\r\nDialogue: 0,0:17:33.70,0:17:37.19,yin,,0,0,0,, 当你发送 shoot 时 它会尝试分派那个 shoot\\N{\\fs12}It’s when you send the shoot, it tries to dispatch that shoot\r\nDialogue: 0,0:17:37.19,0:17:39.64,yin,,0,0,0,, 到那个 helloShip 变量 \\N{\\fs12}to that variable, that hello ship variable.\r\nDialogue: 0,0:17:39.64,0:17:42.73,yin,,0,0,0,, 结果这玩意是字符串 于是崩溃掉 \\N{\\fs12}The thing turns out to be a string, and it crashes right there.\r\nDialogue: 0,0:17:44.57,0:17:48.70,yin,,0,0,0,, 你还可以这样做 (id)hello shoot\\N{\\fs12}You can also do this: ID hello shoot.\r\nDialogue: 0,0:17:48.70,0:17:51.29,yin,,0,0,0,,hello 是 NSString\\N{\\fs12}So hello is the NSString star,\r\nDialogue: 0,0:17:51.29,0:17:54.13,yin,,0,0,0,, 我将它转化为 id 并将它发送给 shoot\\N{\\fs12}and I casted it to ID and sent it shoot.\r\nDialogue: 0,0:17:54.13,0:17:56.29,yin,,0,0,0,, 这也会抑制所有警告信息 \\N{\\fs12}And that will suppress all warnings as well\r\nDialogue: 0,0:17:56.29,0:17:58.90,yin,,0,0,0,, 因为我将 shoot 发送给一个 id\\N{\\fs12}because now I’m sending shoot to an ID.\r\nDialogue: 0,0:17:58.90,0:18:01.51,yin,,0,0,0,, 我只是想说 一行之内就能类型转换 \\N{\\fs12}And I just want to show you here that you can cast it right in line;\r\nDialogue: 0,0:18:01.51,0:18:03.35,yin,,0,0,0,, 无需创建新变量 \\N{\\fs12}you don’t have to create another variable.\r\nDialogue: 0,0:18:03.35,0:18:06.01,yin,,0,0,0,, 在一行内进行类型转换 会骗过编译器 \\N{\\fs12}If you cast it right in line, you fake out the compiler.\r\nDialogue: 0,0:18:06.01,0:18:07.73,yin,,0,0,0,, 我们不希望骗过编译器 \\N{\\fs12}Now, we don’t want to be faking out the compiler.\r\nDialogue: 0,0:18:07.73,0:18:09.99,yin,,0,0,0,, 编译器是我们的朋友 它能帮我们找 bug\\N{\\fs12}Compiler is our friend. It helps us find bugs.\r\nDialogue: 0,0:18:09.99,0:18:12.35,yin,,0,0,0,, 但这些都能够做到 \\N{\\fs12}But this all can be done.\r\nDialogue: 0,0:18:12.35,0:18:14.79,yin,,0,0,0,, 这里讲这些东西 \\N{\\fs12}Mostly I put this up here to see the difference\r\nDialogue: 0,0:18:14.79,0:18:18.03,yin,,0,0,0,, 我只是想讲清楚什么时候编译器能捕捉到 \\N{\\fs12}between the compiler catching something and it crashing at runtime,\r\nDialogue: 0,0:18:18.03,0:18:21.22,yin,,0,0,0,, 以及什么时候会在运行时崩溃 \\N{\\fs12}okay, and when it does which.\r\nDialogue: 0,0:18:21.22,0:18:25.93,yin,,0,0,0,, 好 我们什么时候会用到这种危险得荒唐的 id 呢 \\N{\\fs12}All right. So when would we ever use this ridiculously dangerous thing of ID?\r\nDialogue: 0,0:18:25.93,0:18:28.54,yin,,0,0,0,, 之前其实有人问过 NSArray 中 \\N{\\fs12}Well, someone asked earlier, “Can I have an NSArray\r\nDialogue: 0,0:18:28.54,0:18:30.34,yin,,0,0,0,, 能否有不同种类的事物 \\N{\\fs12}that has different kinds of things in it –\r\nDialogue: 0,0:18:30.34,0:18:32.92,yin,,0,0,0,, 一些字符串 一些数字 一些别的 \\N{\\fs12}some strings, some numbers, something else?”\r\nDialogue: 0,0:18:32.92,0:18:33.70,yin,,0,0,0,, 当然可以 \\N{\\fs12}Absolutely you can.\r\nDialogue: 0,0:18:33.70,0:18:36.94,yin,,0,0,0,, 而且很多时候 你确实想要这样做 \\N{\\fs12}And there’s plenty of times when you absolutely want that.\r\nDialogue: 0,0:18:36.94,0:18:38.11,yin,,0,0,0,, 这是很好的 \\N{\\fs12}So it’s great for that.\r\nDialogue: 0,0:18:38.11,0:18:41.23,yin,,0,0,0,,Java 等其它语言 会让你告诉编译器 \\N{\\fs12}Now, other language like Java lets you actually tell the\r\nDialogue: 0,0:18:41.23,0:18:44.18,yin,,0,0,0,, 这个数组中有字符串 \\N{\\fs12}compiler that this array has strings in it\r\nDialogue: 0,0:18:44.18,0:18:46.27,yin,,0,0,0,, 让编译器在你取出对象时 \\N{\\fs12}so that the compiler, when you pull objects out,\r\nDialogue: 0,0:18:46.27,0:18:48.96,yin,,0,0,0,, 知道有什么类型 然后它来帮你 \\N{\\fs12}it knows what type they are and it can kind of help you out.\r\nDialogue: 0,0:18:48.96,0:18:50.06,yin,,0,0,0,,Objective-C 不是这样 \\N{\\fs12}Objective-C doesn’t have that.\r\nDialogue: 0,0:18:50.06,0:18:52.68,yin,,0,0,0,, 编译器不会帮你处理数组内容 \\N{\\fs12}So the compiler cannot help you with contents array.\r\nDialogue: 0,0:18:52.68,0:18:54.27,yin,,0,0,0,, 这是你的责任 \\N{\\fs12}So it’s kind of your responsibility.\r\nDialogue: 0,0:18:54.27,0:18:56.42,yin,,0,0,0,, 我会讲怎么处理这个的 \\N{\\fs12}I’m going to show you how we deal with that.\r\nDialogue: 0,0:18:56.42,0:18:58.67,yin,,0,0,0,, 第二点是 记得 MVC 的内容吗 \\N{\\fs12}The second one is — remember the MVC talk?\r\nDialogue: 0,0:18:58.67,0:19:03.57,yin,,0,0,0,, 我讲了这种盲的结构化通信 \\N{\\fs12}I talked about all this blind structured communication, right, this blind communication.\r\nDialogue: 0,0:19:03.57,0:19:05.41,yin,,0,0,0,, 要有这种盲通信 \\N{\\fs12}Well, to have blind communication you got\r\nDialogue: 0,0:19:05.41,0:19:08.74,yin,,0,0,0,, 你需要有指针指向类型未知的对象 \\N{\\fs12}to have pointers to objects of types you don’t know.\r\nDialogue: 0,0:19:08.74,0:19:12.75,yin,,0,0,0,, 视图要将目标动作这些发送给 \\N{\\fs12}There’s no way that the view can send the target action\r\nDialogue: 0,0:19:12.75,0:19:15.86,yin,,0,0,0,, 不知道是什么类的控制器 \\N{\\fs12}thing to the controller without knowing the class of the controller,\r\nDialogue: 0,0:19:15.87,0:19:18.05,yin,,0,0,0,, 视图就必须有某种指针 \\N{\\fs12}unless the view can have some kind of pointer\r\nDialogue: 0,0:19:18.05,0:19:20.60,yin,,0,0,0,, 指向它不知道类型的控制器 \\N{\\fs12}to a controller that it doesn’t know the type of.\r\nDialogue: 0,0:19:20.60,0:19:24.12,yin,,0,0,0,, 这是 id 的一大用途 \\N{\\fs12}And that’s big use of ID.\r\nDialogue: 0,0:19:24.12,0:19:27.41,yin,,0,0,0,, 但是 我们需要保护我们自己 \\N{\\fs12}However, we need to protect ourselves,\r\nDialogue: 0,0:19:27.41,0:19:30.04,yin,,0,0,0,,id 方面 我们有两大方法来保护自己 \\N{\\fs12}and there’s two big ways that we protect ourselves against IDs.\r\nDialogue: 0,0:19:30.04,0:19:31.33,yin,,0,0,0,, 一是内省 \\N{\\fs12}One is introspection,\r\nDialogue: 0,0:19:31.33,0:19:33.36,yin,,0,0,0,, 过几张幻灯片我就会讲到 \\N{\\fs12}which I’m going to talk about in the next few slides,\r\nDialogue: 0,0:19:33.37,0:19:37.89,yin,,0,0,0,, 也就是我们可以在运行时问一个 id 你是什么类的 \\N{\\fs12}which is we can ask an ID at runtime, “What class are you?”\r\nDialogue: 0,0:19:37.89,0:19:40.01,yin,,0,0,0,, 或你对什么方法作出反应 \\N{\\fs12}or “What methods do you respond to?”\r\nDialogue: 0,0:19:40.03,0:19:41.79,yin,,0,0,0,, 这是一种很棒的保护方式 \\N{\\fs12}So that’s a great way to protect ourselves.\r\nDialogue: 0,0:19:41.79,0:19:44.08,yin,,0,0,0,, 另一种方式叫作协议 \\N{\\fs12}And then another way is called “protocols.”\r\nDialogue: 0,0:19:44.08,0:19:49.03,yin,,0,0,0,, 协议是在 id 后使用尖括号来表示 \\N{\\fs12}And protocols is a way using little angle brackets after an ID to say,\r\nDialogue: 0,0:19:49.03,0:19:52.68,yin,,0,0,0,, 这是一个 id 一个指针 指向的对象我不知道类是什么 \\N{\\fs12}”This is an ID, a pointer to some class I don’t know what it is,\r\nDialogue: 0,0:19:52.68,0:19:55.16,yin,,0,0,0,, 但它要能对尖括号中定义的这一组方法作出反应 \\N{\\fs12}but it responds to this set of methods that I’m going to\r\nDialogue: 0,0:19:55.16,0:19:57.66,yin,,0,0,0,, 但它要能对尖括号中定义的这一组方法作出反应 \\N{\\fs12}define with this little angle bracket thing\r\nDialogue: 0,0:19:57.66,0:19:58.90,yin,,0,0,0,, 如 UIScrollViewDelegate\\N{\\fs12}like UI scroll view delegate.”\r\nDialogue: 0,0:19:58.90,0:20:01.76,yin,,0,0,0,, 这就是我们进行委托和数据源这些的方式 \\N{\\fs12}And that’s how we do the delegation and data source thing.\r\nDialogue: 0,0:20:01.76,0:20:05.33,yin,,0,0,0,, 今天我们不会过多讲到协议 因为这里不大需要 \\N{\\fs12}So we’re not going to talk about protocols today because you don’t quite need them.\r\nDialogue: 0,0:20:05.35,0:20:07.68,yin,,0,0,0,, 我们也许会在下周或下下周讲到它 \\N{\\fs12}We’ll probably talk about them next week or the week after.\r\nDialogue: 0,0:20:07.68,0:20:10.22,yin,,0,0,0,, 这是我们在 id 上保护自己的另一方式 \\N{\\fs12}But that’s another way we protect ourselves against ID\r\nDialogue: 0,0:20:10.22,0:20:13.76,yin,,0,0,0,,id 后跟尖括号实际上介于纯 id 和静态类型之间 \\N{\\fs12}by having like — an ID with the angle brackets is kind of in\r\nDialogue: 0,0:20:13.76,0:20:17.80,yin,,0,0,0,,id 后跟尖括号实际上介于纯 id 和静态类型化之间 \\N{\\fs12}between pure ID and static typing. It’s kind of in the middle, right?\r\nDialogue: 0,0:20:17.80,0:20:19.62,yin,,0,0,0,, 这里静态类型化的不是类型 \\N{\\fs12}Instead of static typing the type,\r\nDialogue: 0,0:20:19.62,0:20:22.91,yin,,0,0,0,, 而是事物能够对其作出反应的消息 \\N{\\fs12}we’re just static typing the messages that the thing can respond to.\r\nDialogue: 0,0:20:22.91,0:20:25.73,yin,,0,0,0,, 就安全而言 它可以说介于中间 \\N{\\fs12}So it’s kind of in the middle in terms of safety.\r\nDialogue: 0,0:20:26.70,0:20:29.30,yin,,0,0,0,, 好 我们再来讲内省 \\N{\\fs12}So let’s talk about introspection, though.\r\nDialogue: 0,0:20:29.30,0:20:33.90,yin,,0,0,0,,NSObject 中有一些内省方法 \\N{\\fs12}There’s a few introspection methods in NSObject.\r\nDialogue: 0,0:20:33.90,0:20:35.69,yin,,0,0,0,, 这里我要讲三个 \\N{\\fs12}I’m going to talk about three of them here.\r\nDialogue: 0,0:20:35.69,0:20:37.44,yin,,0,0,0,,isKindOfClass isMemberOfClass\\N{\\fs12}Is kind of class, is member of class,\r\nDialogue: 0,0:20:37.44,0:20:38.99,yin,,0,0,0,, 以及 respondsToSelector\\N{\\fs12}and responds to selector.\r\nDialogue: 0,0:20:38.99,0:20:41.14,yin,,0,0,0,,isKindOfClass 及 isMemberOfClass\\N{\\fs12}So is kind of class and is member of class\r\nDialogue: 0,0:20:41.14,0:20:42.90,yin,,0,0,0,, 让你能够问一个 NSObject\\N{\\fs12}lets you ask an NSObject\r\nDialogue: 0,0:20:42.90,0:20:45.16,yin,,0,0,0,, 或者任何继承自 NSObject 的对象 \\N{\\fs12}or anything that inherits from NSObject,\r\nDialogue: 0,0:20:45.16,0:20:47.07,yin,,0,0,0,, 你属于这一系列类吗 \\N{\\fs12}”Are you of this kind of class?\r\nDialogue: 0,0:20:47.07,0:20:48.83,yin,,0,0,0,, 或者 isMemberOfClass 是说 \\N{\\fs12}Or is member of class means,\r\nDialogue: 0,0:20:48.83,0:20:51.33,yin,,0,0,0,, 你实际是这个类吗 \\N{\\fs12}”Are you actually this class?”\r\nDialogue: 0,0:20:51.33,0:20:55.04,yin,,0,0,0,, 不是这个类及它的子类 而是只包含这个类 \\N{\\fs12}Not this class or something that inherits from it, but actually this actual class.\r\nDialogue: 0,0:20:55.04,0:21:00.46,yin,,0,0,0,,respondsToSelector 说的则是 id 指向的这一对象 \\N{\\fs12}And then response to selector says, “Does this object that this ID points to,\r\nDialogue: 0,0:21:00.46,0:21:03.77,yin,,0,0,0,, 是否对某一特定方法作出反应 \\N{\\fs12}does it respond to a certain method?”\r\nDialogue: 0,0:21:03.77,0:21:09.67,yin,,0,0,0,, 很不幸 这些方法的参数显得很不牢靠 \\N{\\fs12}So the arguments unfortunately to these methods are really kind of wonky.\r\nDialogue: 0,0:21:09.67,0:21:12.46,yin,,0,0,0,, 这些你们使用的时候照做即可 \\N{\\fs12}And just you’re going to have to take my word for it on these ones\r\nDialogue: 0,0:21:12.46,0:21:17.13,yin,,0,0,0,, 因为等下我要用来解释这个的句子里 \\N{\\fs12}because when I spit out the sentence in a second here that describes what the argument is,\r\nDialogue: 0,0:21:17.13,0:21:19.27,yin,,0,0,0,, 会使用四次 class(类) 这个词 \\N{\\fs12}I’m going to use the word “class” four times\r\nDialogue: 0,0:21:19.27,0:21:21.01,yin,,0,0,0,, 每次都表示不同事物 \\N{\\fs12}and it’s going to mean four different things.\r\nDialogue: 0,0:21:21.01,0:21:24.47,yin,,0,0,0,,isKindOfClass 的参数 \\N{\\fs12}So the argument is kind of class,\r\nDialogue: 0,0:21:24.47,0:21:30.13,yin,,0,0,0,, 是通过将类方法 class 发送到某一个类来得到 \\N{\\fs12}you get by sending the class method class to the class,\r\nDialogue: 0,0:21:30.13,0:21:32.62,yin,,0,0,0,, 这会给你一个大写 C 开头的 Class\\N{\\fs12}which will give you a capital C Class,\r\nDialogue: 0,0:21:32.62,0:21:36.17,yin,,0,0,0,, 这就是 isKindOfClass 的参数 \\N{\\fs12}which is the argument to the is kind of class method.\r\nDialogue: 0,0:21:37.51,0:21:39.54,yin,,0,0,0,, 这里有一个方法 class\\N{\\fs12}So there’s this method class.\r\nDialogue: 0,0:21:39.54,0:21:41.36,yin,,0,0,0,, 在这里 NSString class\\N{\\fs12}You see it there, NSString class.\r\nDialogue: 0,0:21:41.36,0:21:45.51,yin,,0,0,0,, 它是一个 NSString 的类方法 返回 Class\\N{\\fs12}It’s a class method on NSString returns a capital C Class.\r\nDialogue: 0,0:21:45.51,0:21:47.66,yin,,0,0,0,, 这是 isKindOfClass 的参数 \\N{\\fs12}And that’s the thing that’s the argument is kind of class.\r\nDialogue: 0,0:21:47.66,0:21:50.15,yin,,0,0,0,, 它总是这样的形式 [obj isKindOfClass:\\N{\\fs12}It's always of this form, obj is kind of class,\r\nDialogue: 0,0:21:50.15,0:21:54.30,yin,,0,0,0,,[你要考虑的类 class]]\\N{\\fs12}open spare bracket, the class you want, class, close square bracket, closed square bracket.\r\nDialogue: 0,0:21:54.30,0:21:56.95,yin,,0,0,0,, 它总是这样 照做就行了 \\N{\\fs12}So it always looks like this. So just do it.\r\nDialogue: 0,0:21:56.95,0:22:00.25,yin,,0,0,0,, 如果你不能理解句子中包含四个 class 的解释 \\N{\\fs12}If you didn’t understand my four-class sentence,\r\nDialogue: 0,0:22:00.25,0:22:03.38,yin,,0,0,0,, 别管它 照做就行了 \\N{\\fs12}just do it just like this.\r\nDialogue: 0,0:22:03.38,0:22:07.45,yin,,0,0,0,, 发现对象属于这一系列类后 就可以进行类型转换了 \\N{\\fs12}Once I see that an object kind of a class, then I might want to cast it.\r\nDialogue: 0,0:22:07.45,0:22:11.04,yin,,0,0,0,, 注意这里我将 obj 转换为 NSString * 类型 \\N{\\fs12}You see here I’m casting obj to be an NSString star there\r\nDialogue: 0,0:22:11.04,0:22:13.09,yin,,0,0,0,, 因为我知道这时 它是 NSString\\N{\\fs12}because I know at that point it’s an NSString star.\r\nDialogue: 0,0:22:13.09,0:22:15.12,yin,,0,0,0,, 所以这时愚弄编译器没有关系 \\N{\\fs12}So it’s okay to fool the compiler,\r\nDialogue: 0,0:22:15.12,0:22:19.52,yin,,0,0,0,, 或者说 我是通过这样在教编译器更多关于 obj 的知识 \\N{\\fs12}or really I’m teaching the compiler a little bit more about what obj is by doing that.\r\nDialogue: 0,0:22:19.52,0:22:20.75,yin,,0,0,0,, 并非真的愚弄它 \\N{\\fs12}Not really tricking it.\r\nDialogue: 0,0:22:20.77,0:22:23.26,yin,,0,0,0,, 这样做是完全安全的 因为我知道 obj\\N{\\fs12}And it’s perfectly safe to do that because I know that obj\r\nDialogue: 0,0:22:23.26,0:22:26.34,yin,,0,0,0,, 在运行时是这样的类 \\N{\\fs12}at runtime is that kind of class.\r\nDialogue: 0,0:22:26.34,0:22:28.90,yin,,0,0,0,, 这方面有问题吗 请讲 \\N{\\fs12}Questions about that? Yeah?\r\nDialogue: 0,0:22:31.71,0:22:36.35,yin,,0,0,0,, 问题是 实例方法 class 会怎样 我可以说 \\N{\\fs12}Okay, the question is: What does the instance method class — so I can say, you know,\r\nDialogue: 0,0:22:36.35,0:22:42.11,yin,,0,0,0,, 想象一个例子 例如我们用过的 deck\\N{\\fs12}trying to think of an example where we use that, like deck.\r\nDialogue: 0,0:22:42.11,0:22:45.34,yin,,0,0,0,, 我可以说 deck class\\N{\\fs12}I might say deck class, for example.\r\nDialogue: 0,0:22:45.34,0:22:50.77,yin,,0,0,0,, 这会返回同这里基本一样的东西 \\N{\\fs12}That returns essentially the same thing as here,\r\nDialogue: 0,0:22:50.77,0:22:53.18,yin,,0,0,0,, 你也许可以说 \\N{\\fs12}and you probably could say\r\nDialogue: 0,0:22:53.18,0:22:55.66,yin,,0,0,0,,isKindOfClass 开方括号 实例方法 class\\N{\\fs12}is kind of class open square bracket instance method class.\r\nDialogue: 0,0:22:55.66,0:22:58.91,yin,,0,0,0,, 但你的读者会对此非常不解 \\N{\\fs12}But your reader would pretty darn confused by that.\r\nDialogue: 0,0:22:58.91,0:23:03.33,yin,,0,0,0,, 这里有实例方法和类方法 我想都返回相同的东西 \\N{\\fs12}So there’s an instance method and a class method; probably both return the same thing,\r\nDialogue: 0,0:23:03.33,0:23:04.70,yin,,0,0,0,, 大写 C 的 Class\\N{\\fs12}capital C class, I believe.\r\nDialogue: 0,0:23:04.70,0:23:08.44,yin,,0,0,0,, 但我们这里不会这样做 不要在这里调用实例方法 \\N{\\fs12}But we would never do that here, so don’t put an instance call there,\r\nDialogue: 0,0:23:08.44,0:23:10.38,yin,,0,0,0,, 仅使用类方法 \\N{\\fs12}just the class method you want.\r\nDialogue: 0,0:23:10.38,0:23:12.35,yin,,0,0,0,, 问得很好 \\N{\\fs12}Good question.\r\nDialogue: 0,0:23:12.35,0:23:15.13,yin,,0,0,0,, 再来看方法的情况 \\N{\\fs12}All right. How about the selector one, the method one rather?\r\nDialogue: 0,0:23:15.13,0:23:19.18,yin,,0,0,0,, 这类函数对选择某事物作出反应时所使用的 \\N{\\fs12}Okay. So methods, when we use them in this response to select a thing,\r\nDialogue: 0,0:23:19.18,0:23:20.44,yin,,0,0,0,, 叫作 selector(选择器)\\N{\\fs12}we call them “selectors.”\r\nDialogue: 0,0:23:20.44,0:23:25.24,yin,,0,0,0,,selector 可以说是一个方法名的识别器 \\N{\\fs12}A selector is really kind of an identifier for a method name\r\nDialogue: 0,0:23:25.24,0:23:27.54,yin,,0,0,0,, 以方法 shoot 为例 \\N{\\fs12}because if you have the method shoot,\r\nDialogue: 0,0:23:27.54,0:23:31.52,yin,,0,0,0,, 不管你考虑哪种实现它的类 selector 都是一样的 \\N{\\fs12}it’s the same selector no matter what class you’re talking about implementing it in.\r\nDialogue: 0,0:23:31.52,0:23:34.99,yin,,0,0,0,, 哪怕它们之间没有继承关系 完全无关 \\N{\\fs12}Even if they don’t inherit from each other, they’re completely unrelated.\r\nDialogue: 0,0:23:35.01,0:23:36.96,yin,,0,0,0,, 例如一个 Gun(枪) 类拥有 shoot 方法 \\N{\\fs12}You might have a gun class that says shoot\r\nDialogue: 0,0:23:36.96,0:23:38.82,yin,,0,0,0,, 还有一个 Ship 类拥有 shoot 方法 \\N{\\fs12}and you might have a ship class that says shoot –\r\nDialogue: 0,0:23:38.82,0:23:40.46,yin,,0,0,0,,shoot 的 selector 是一样的 \\N{\\fs12}the selector shoot would be the same.\r\nDialogue: 0,0:23:40.46,0:23:42.12,yin,,0,0,0,, 获得 selector 的方式是 \\N{\\fs12}And we get that selector by saying\r\nDialogue: 0,0:23:42.12,0:23:46.52,yin,,0,0,0,, 用 @selector(方法名)\\N{\\fs12}at sign selector parenthesis, the name of the method.\r\nDialogue: 0,0:23:46.52,0:23:47.51,yin,,0,0,0,, 例如 shoot\\N{\\fs12}Shoot.\r\nDialogue: 0,0:23:47.51,0:23:50.82,yin,,0,0,0,, 如果方法有多个参数 我们只需将冒号加到这里 \\N{\\fs12}And if the method has multiple arguments, we just put the colons in there.\r\nDialogue: 0,0:23:50.82,0:23:53.86,yin,,0,0,0,, 例如 shootAt: 有一个参数 \\N{\\fs12}So shoot at colon has one argument\r\nDialogue: 0,0:23:53.86,0:23:56.70,yin,,0,0,0,, 或者 addCard: atTop:\\N{\\fs12}or add card colon at top colon.\r\nDialogue: 0,0:23:56.70,0:23:57.99,yin,,0,0,0,, 我们只需要写 \\N{\\fs12}We just say that,\r\nDialogue: 0,0:23:57.99,0:24:02.11,yin,,0,0,0,,@selector(addCard: atTop:)\\N{\\fs12}at sign selector, open parenthesis, add card colon, add top colon, close parenthesis.\r\nDialogue: 0,0:24:02.11,0:24:04.14,yin,,0,0,0,, 这会给我们 selector\\N{\\fs12}And that gives us the selector,\r\nDialogue: 0,0:24:04.14,0:24:06.47,yin,,0,0,0,, 然后我们说 respondsToSelector\\N{\\fs12}and we say responds to selector.\r\nDialogue: 0,0:24:06.49,0:24:07.45,yin,,0,0,0,, 这会告诉我们 \\N{\\fs12}And that will tell us whether the\r\nDialogue: 0,0:24:07.45,0:24:10.42,yin,,0,0,0,, 我们发送给 respondsToSelector 的对象 \\N{\\fs12}object that we’re sending responds to selector\r\nDialogue: 0,0:24:10.42,0:24:12.29,yin,,0,0,0,, 是否对此方法作出反应 \\N{\\fs12}to responds to that method.\r\nDialogue: 0,0:24:12.29,0:24:15.42,yin,,0,0,0,, 这些 selector 实际上是一种类型 \\N{\\fs12}Now, these selectors, there’s actually a type,\r\nDialogue: 0,0:24:15.42,0:24:18.42,yin,,0,0,0,, 这些 selector 在 Objective-C 中是一种 typedef\\N{\\fs12}kind of a type def in Objective-C for these selectors.\r\nDialogue: 0,0:24:18.42,0:24:21.16,yin,,0,0,0,, 全大写 SEL 同全大写 BOOL 一样 \\N{\\fs12}All caps SEL, kind of like all caps BOOL, right?\r\nDialogue: 0,0:24:21.16,0:24:23.55,yin,,0,0,0,, 这里加入了这种 typedef\\N{\\fs12}So this type def thing is added.\r\nDialogue: 0,0:24:23.55,0:24:29.46,yin,,0,0,0,, 你可以声明类型为 SEL 的变量 并将事物存储于其中 \\N{\\fs12}And you can declare variables that are of type SEL and store things in there.\r\nDialogue: 0,0:24:29.46,0:24:32.88,yin,,0,0,0,, 实际上还有 respondsToSelector 之外的其它方法 \\N{\\fs12}And there are actually other methods besides respond to selector\r\nDialogue: 0,0:24:32.88,0:24:34.63,yin,,0,0,0,, 将 selector 作为参数 \\N{\\fs12}that take a selector.\r\nDialogue: 0,0:24:34.63,0:24:38.12,yin,,0,0,0,, 例如 对象有 performSelector:\\N{\\fs12}For example, object has perform selector\r\nDialogue: 0,0:24:38.12,0:24:40.79,yin,,0,0,0,, 以及 performSelector:withObject:\\N{\\fs12}and perform selector with object.\r\nDialogue: 0,0:24:40.79,0:24:45.52,yin,,0,0,0,, 它们会将这一方法执行到另一个对象上 \\N{\\fs12}They will perform that method on another object.\r\nDialogue: 0,0:24:45.52,0:24:46.84,yin,,0,0,0,, 为什么要这样做呢 \\N{\\fs12}Now, why would you ever want to do this?\r\nDialogue: 0,0:24:46.84,0:24:49.17,yin,,0,0,0,, 因为你可能有一些参数化的东西 \\N{\\fs12}Well, you might have some parameterized thing\r\nDialogue: 0,0:24:49.17,0:24:51.44,yin,,0,0,0,, 你要处理三种不同方法中的一个 \\N{\\fs12}where you’re going to do one of three different methods,\r\nDialogue: 0,0:24:51.44,0:24:53.21,yin,,0,0,0,, 取决于用户的选择 \\N{\\fs12}depending on something the user chooses.\r\nDialogue: 0,0:24:53.21,0:24:54.93,yin,,0,0,0,, 你可以说 performSelector\\N{\\fs12}And you can say perform selector\r\nDialogue: 0,0:24:54.93,0:24:59.01,yin,,0,0,0,, 然后有三个 SEL 变量 对应每种方法 \\N{\\fs12}and then have three SEL variables, one for each method,\r\nDialogue: 0,0:24:59.01,0:25:01.72,yin,,0,0,0,, 将这作为 performSelector 的参数 \\N{\\fs12}and pass that as the argument you want to perform selector.\r\nDialogue: 0,0:25:01.72,0:25:03.54,yin,,0,0,0,,performSelector: withObject:\\N{\\fs12}Perform selector with object,\r\nDialogue: 0,0:25:03.54,0:25:05.55,yin,,0,0,0,, 这一方法有一个参数 \\N{\\fs12}that method would have one argument.\r\nDialogue: 0,0:25:05.55,0:25:08.17,yin,,0,0,0,,selector 名应该是某某冒号 \\N{\\fs12}So the selector name better be something colon\r\nDialogue: 0,0:25:08.17,0:25:09.43,yin,,0,0,0,, 因为它有一个参数 \\N{\\fs12}because it’s got one argument.\r\nDialogue: 0,0:25:09.43,0:25:11.34,yin,,0,0,0,, 而参数必须是一个对象 \\N{\\fs12}And the argument has to be an object.\r\nDialogue: 0,0:25:11.34,0:25:14.39,yin,,0,0,0,,coordinate 在这里是某种对象 \\N{\\fs12}So coordinate here would be some sort of object.\r\nDialogue: 0,0:25:14.39,0:25:16.14,yin,,0,0,0,, 这里有一点限制 \\N{\\fs12}So just a little limitation.\r\nDialogue: 0,0:25:16.14,0:25:19.29,yin,,0,0,0,, 方法要么没有参数 要么有一个对象作为参数 \\N{\\fs12}It can only have no arguments or have one argument that’s an object.\r\nDialogue: 0,0:25:19.29,0:25:23.06,yin,,0,0,0,, 你还可以让数组做如下很酷的事 \\N{\\fs12}You can also do cool things like ask an array\r\nDialogue: 0,0:25:23.06,0:25:28.04,yin,,0,0,0,, 让数组中所有对象执行这个 selector\\N{\\fs12}make all the objects in yourself perform this selector.\r\nDialogue: 0,0:25:28.04,0:25:29.61,yin,,0,0,0,, 这是一个很酷的方法 \\N{\\fs12}This is a very cool method.\r\nDialogue: 0,0:25:29.61,0:25:32.63,yin,,0,0,0,, 如果你能习惯在数组中使用这样的方法 \\N{\\fs12}And if you get used to using methods like this in Array,\r\nDialogue: 0,0:25:32.63,0:25:35.47,yin,,0,0,0,, 你的代码量会大幅减少 \\N{\\fs12}you’ll find your code will shrink down really small\r\nDialogue: 0,0:25:35.47,0:25:37.59,yin,,0,0,0,, 因为 for in 循环这些 \\N{\\fs12}because, you know, for ins and things\r\nDialogue: 0,0:25:37.59,0:25:40.38,yin,,0,0,0,, 会缩减为这样的一行代码 \\N{\\fs12}like that you have to really zoomed down to one-liners,\r\nDialogue: 0,0:25:40.38,0:25:42.22,yin,,0,0,0,,makeObjectsPerformSelector:\\N{\\fs12}make objects perform selector, okay,\r\nDialogue: 0,0:25:42.22,0:25:44.43,yin,,0,0,0,, 或 makeObjectsPerformSelector: withObject:\\N{\\fs12}or make object perform selector with object.\r\nDialogue: 0,0:25:44.43,0:25:46.67,yin,,0,0,0,, 这是 NSArray 的方法 \\N{\\fs12}So that’s an NSArray thing.\r\nDialogue: 0,0:25:46.67,0:25:49.29,yin,,0,0,0,, 显然 我们还用 selector 处理目标动作 \\N{\\fs12}And of course, we do target action with selectors.\r\nDialogue: 0,0:25:49.29,0:25:52.43,yin,,0,0,0,, 如果你想设置目标动作 \\N{\\fs12}The method, if you wanted to set up target action,\r\nDialogue: 0,0:25:52.43,0:25:55.12,yin,,0,0,0,, 不用 Control 拖动 而是在代码中设置 \\N{\\fs12}not doing control drag but actually setting up in code,\r\nDialogue: 0,0:25:55.12,0:25:58.91,yin,,0,0,0,, 方法在 UIControl 中 按钮就是继承自这里 \\N{\\fs12}is in UI control actually, which button inheritance from.\r\nDialogue: 0,0:25:58.91,0:26:01.28,yin,,0,0,0,,addTarget: action:\\N{\\fs12}Add target colon, action colon.\r\nDialogue: 0,0:26:01.28,0:26:02.58,yin,,0,0,0,, 还有其它一些参数 \\N{\\fs12}There’s some other arguments.\r\nDialogue: 0,0:26:02.58,0:26:05.02,yin,,0,0,0,, 不过 addTarget: 的参数是 id 类型 \\N{\\fs12}But you can see that add target takes an ID\r\nDialogue: 0,0:26:05.02,0:26:07.88,yin,,0,0,0,, 然后 action: 的参数是 selector\\N{\\fs12}and then it takes an action colon, takes a selector.\r\nDialogue: 0,0:26:07.88,0:26:10.60,yin,,0,0,0,, 它会说明 什么消息发送到什么对象 \\N{\\fs12}So it says what message to send to what object –\r\nDialogue: 0,0:26:10.60,0:26:13.38,yin,,0,0,0,, 什么是目标 什么是动作 \\N{\\fs12}what’s the target, what’s the action?\r\nDialogue: 0,0:26:13.38,0:26:16.27,yin,,0,0,0,, 大家都理解了吗 \\N{\\fs12}Everyone understand that?\r\nDialogue: 0,0:26:16.27,0:26:19.02,yin,,0,0,0,, 这是选择 \\N{\\fs12}Okay. So this selection stuff,\r\nDialogue: 0,0:26:19.02,0:26:21.66,yin,,0,0,0,,selector 非常强大 \\N{\\fs12}pretty selector stuff is pretty powerful.\r\nDialogue: 0,0:26:21.66,0:26:24.31,yin,,0,0,0,, 下面我们来看 match\\N{\\fs12}All right. So let’s take a look at how match –\r\nDialogue: 0,0:26:24.31,0:26:25.75,yin,,0,0,0,,PlayingCard 中的 match\\N{\\fs12}the playing card match –\r\nDialogue: 0,0:26:25.75,0:26:27.37,yin,,0,0,0,, 如何用内省来改善 \\N{\\fs12}might be improved with introspection.\r\nDialogue: 0,0:26:27.37,0:26:31.56,yin,,0,0,0,, 我将回到 Xcode\\N{\\fs12}I’m going to go here back to Xcode.\r\nDialogue: 0,0:26:34.32,0:26:38.32,yin,,0,0,0,, 打开之前我们编辑过的 Machismo\\N{\\fs12}And I’m just going to open back up Machismo where we left off here.\r\nDialogue: 0,0:26:45.91,0:26:49.45,yin,,0,0,0,, 然后在下面找到 PlayingCard\\N{\\fs12}Okay. And then let’s go down to playing card.\r\nDialogue: 0,0:26:49.45,0:26:51.58,yin,,0,0,0,, 这是 PlayingCard 这是 match\\N{\\fs12}So here’s playing card and here’s match.\r\nDialogue: 0,0:26:51.58,0:26:53.26,yin,,0,0,0,, 都记得 match 吧 \\N{\\fs12}Okay. So you all remember match.\r\nDialogue: 0,0:26:53.26,0:26:56.36,yin,,0,0,0,, 这一行代码有一点问题 \\N{\\fs12}And here’s the line of code that’s a little bit of trouble.\r\nDialogue: 0,0:26:56.36,0:27:00.58,yin,,0,0,0,, 因为这里第一个对象 它会返回一个 id\\N{\\fs12}Because this first object here, this returns an ID.\r\nDialogue: 0,0:27:00.58,0:27:06.65,yin,,0,0,0,, 所以我们可以这样做 id card = 这个 \\N{\\fs12}So what we could do here, for example, is we could say ID card equals this.\r\nDialogue: 0,0:27:09.14,0:27:11.84,yin,,0,0,0,, 我要让这里完全清晰 \\N{\\fs12}Just to be totally clear here.\r\nDialogue: 0,0:27:11.84,0:27:13.76,yin,,0,0,0,, 我得到了这个 card 然后我说 \\N{\\fs12}So we got this card. And then I can say\r\nDialogue: 0,0:27:13.77,0:27:19.32,yin,,0,0,0,,if ([card isKindOfClass:[PlayingCard class]])\\N{\\fs12}if card is kind of class, playing card class,\r\nDialogue: 0,0:27:19.32,0:27:22.33,yin,,0,0,0,, 那么 我将做所有这些 \\N{\\fs12}okay, then I’ll do all this.\r\nDialogue: 0,0:27:25.67,0:27:29.28,yin,,0,0,0,, 而且我要将另外这张牌设为 \\N{\\fs12}And I’m going to set the other card here to be\r\nDialogue: 0,0:27:29.28,0:27:32.51,yin,,0,0,0,,(PlayingCard *)card\\N{\\fs12}playing card, star card.\r\nDialogue: 0,0:27:32.51,0:27:34.91,yin,,0,0,0,, 这里是类型转换 \\N{\\fs12}So I’m going to cast it.\r\nDialogue: 0,0:27:34.91,0:27:37.86,yin,,0,0,0,, 这时编译器就知道了这个变量 \\N{\\fs12}So now the compiler knows about this variable.\r\nDialogue: 0,0:27:37.86,0:27:40.25,yin,,0,0,0,, 从这里开始 当我触摸另一张牌时 \\N{\\fs12}And from here on out, whenever I touch other card,\r\nDialogue: 0,0:27:40.25,0:27:41.96,yin,,0,0,0,, 它都会知道这张牌是 PlayingCard\\N{\\fs12}it knows it’s going to be a playing card.\r\nDialogue: 0,0:27:41.96,0:27:45.21,yin,,0,0,0,, 而这里 我在运行时检验 以保证它是 PlayingCard\\N{\\fs12}And here I’ve checked at runtime to make sure that it’s actually the playing card\r\nDialogue: 0,0:27:45.21,0:27:47.09,yin,,0,0,0,, 这样这里就永远不会崩溃 \\N{\\fs12}so that I’ll never crash here.\r\nDialogue: 0,0:27:47.09,0:27:50.30,yin,,0,0,0,, 如果你说 match:otherCards\\N{\\fs12}Now, if you say match colon other cards\r\nDialogue: 0,0:27:50.30,0:27:53.33,yin,,0,0,0,, 而 otherCards 不是 PlayingCard(扑克牌)\\N{\\fs12}and the other cards are like, some not playing cards,\r\nDialogue: 0,0:27:53.33,0:27:57.24,yin,,0,0,0,, 例如只是普通卡片 或是字符串 这不会有问题 \\N{\\fs12}they’re regular cards or they’re strings or something, then that’s okay.\r\nDialogue: 0,0:27:57.24,0:27:58.50,yin,,0,0,0,, 这个方法能够运行 \\N{\\fs12}This method’s going to work fine because it’s going\r\nDialogue: 0,0:27:58.50,0:28:00.65,yin,,0,0,0,, 因为它会返回 0 分数为 0 这是对的 \\N{\\fs12}to return zero, a score of zero, which is right\r\nDialogue: 0,0:28:00.65,0:28:04.19,yin,,0,0,0,, 因为扑克牌不能同字符串或普通卡片匹配上 \\N{\\fs12}because a playing card wouldn’t match a string or any other kind of card.\r\nDialogue: 0,0:28:05.58,0:28:06.74,yin,,0,0,0,, 能理解吗 \\N{\\fs12}Make sense?\r\nDialogue: 0,0:28:06.74,0:28:09.02,yin,,0,0,0,, 明白这里是如何使用内省的吗 \\N{\\fs12}See how we used introspection there?\r\nDialogue: 0,0:28:09.02,0:28:13.52,yin,,0,0,0,, 你们将会在下周的作业中用到内省 \\N{\\fs12}So you will have to use introspection most likely in your solution to next week’s homework –\r\nDialogue: 0,0:28:13.52,0:28:15.07,yin,,0,0,0,, 不是现在你们在做的这次 \\N{\\fs12}not the one you’re currently working on.\r\nDialogue: 0,0:28:15.07,0:28:18.03,yin,,0,0,0,, 顺便我需要说明一下 \\N{\\fs12}By the way, I should take time out to say I’d almost –\r\nDialogue: 0,0:28:18.03,0:28:20.46,yin,,0,0,0,, 我在课堂上讲的内容 \\N{\\fs12}if I ever show you something in a lecture\r\nDialogue: 0,0:28:20.46,0:28:25.37,yin,,0,0,0,, 在我布置以后 这几乎从不需要用在当周的作业中 \\N{\\fs12}after I’ve assigned something to you, you almost never need it in that week’s homework.\r\nDialogue: 0,0:28:25.37,0:28:27.98,yin,,0,0,0,, 否则我会另行通知你们 \\N{\\fs12}And I would tell you if that were the case.\r\nDialogue: 0,0:28:27.98,0:28:29.90,yin,,0,0,0,, 懂我说的吗 \\N{\\fs12}You know what I’m saying?\r\nDialogue: 0,0:28:29.90,0:28:32.04,yin,,0,0,0,, 例如 周一布置的作业 \\N{\\fs12}So, like, you’ve got an assignment on Monday;\r\nDialogue: 0,0:28:32.04,0:28:35.41,yin,,0,0,0,, 我不会今天讲一些东西 让你们用在周一的作业中 \\N{\\fs12}I wouldn’t be showing you things today that you needed for the assignment on Monday.\r\nDialogue: 0,0:28:35.41,0:28:39.76,yin,,0,0,0,, 布置作业时 这次作业所需的内容就已经都讲过了 \\N{\\fs12}I’ve already shown you everything you need by the time you get the assignment.\r\nDialogue: 0,0:28:39.76,0:28:40.54,yin,,0,0,0,, 有问题 \\N{\\fs12}Question?\r\nDialogue: 0,0:28:45.36,0:28:47.96,yin,,0,0,0,, 问题是 内省是不是只用于 \\N{\\fs12}Okay. So the question is: Is introspection only used\r\nDialogue: 0,0:28:47.96,0:28:50.16,yin,,0,0,0,, 从数组中选出项目这样的时候 \\N{\\fs12}like this when you’re pulling items out of Array?\r\nDialogue: 0,0:28:50.16,0:28:52.08,yin,,0,0,0,, 记得吧 两张幻灯片前我讲了 \\N{\\fs12}And remember, I told you a couple slides ago\r\nDialogue: 0,0:28:52.08,0:28:55.39,yin,,0,0,0,, 我们主要有两种时候用到内省 一是这个 \\N{\\fs12}there are two major times when we use introspection — one is this.\r\nDialogue: 0,0:28:55.39,0:28:59.38,yin,,0,0,0,, 二是所有 MVC 盲通信 \\N{\\fs12}Second one is all that MVC blind communication, right?\r\nDialogue: 0,0:28:59.38,0:29:03.67,yin,,0,0,0,, 目标动作 委托等等那些 \\N{\\fs12}Target action, and delegation, and all that stuff.\r\nDialogue: 0,0:29:03.67,0:29:06.06,yin,,0,0,0,, 这是这部分内容 \\N{\\fs12}So that’s that.\r\nDialogue: 0,0:29:06.06,0:29:08.03,yin,,0,0,0,, 下面转入 Foundation\\N{\\fs12}Now let’s move onto Foundation.\r\nDialogue: 0,0:29:08.03,0:29:10.62,yin,,0,0,0,, 这里我们要讨论 Foundation 框架 \\N{\\fs12}So we’re going to talk about a Foundation framework here.\r\nDialogue: 0,0:29:10.62,0:29:14.63,yin,,0,0,0,, 我将很快过一遍对象 数组 字典等等这些 \\N{\\fs12}I’m going to really go fast through object, Array, dictionary, things like that\r\nDialogue: 0,0:29:14.63,0:29:16.86,yin,,0,0,0,, 因为我们已经见过很多数组 \\N{\\fs12}because we’ve already seen a lot of Array.\r\nDialogue: 0,0:29:16.86,0:29:18.95,yin,,0,0,0,, 你们应该已经知道它是什么了 \\N{\\fs12}I think you pretty much got a good feel for what it is.\r\nDialogue: 0,0:29:18.95,0:29:20.87,yin,,0,0,0,, 所以我不会花太多时间讲 \\N{\\fs12}So I don’t want to waste the time talking about that.\r\nDialogue: 0,0:29:20.87,0:29:22.92,yin,,0,0,0,, 我们有很多新东西要讲 \\N{\\fs12}We got a lot more new stuff to talk about.\r\nDialogue: 0,0:29:22.92,0:29:25.58,yin,,0,0,0,, 你们知道 NSObject 是所有对象的基类 \\N{\\fs12}But you know that NSObject is the base class for all objects.\r\nDialogue: 0,0:29:25.58,0:29:28.40,yin,,0,0,0,, 它实现内省这些东西 \\N{\\fs12}It implements those introspection things.\r\nDialogue: 0,0:29:28.40,0:29:30.58,yin,,0,0,0,, 它还实现了这个很重要的方法 \\N{\\fs12}It also implements this very important method\r\nDialogue: 0,0:29:30.58,0:29:31.86,yin,,0,0,0,, 叫作 description(描述)\\N{\\fs12}called description.\r\nDialogue: 0,0:29:31.86,0:29:35.05,yin,,0,0,0,,description 会返回一个 NSString\\N{\\fs12}So description, it just returns an NSString.\r\nDialogue: 0,0:29:35.05,0:29:39.54,yin,,0,0,0,, 它返回的字符串用于描绘这个对象 \\N{\\fs12}And it’s supposed to return a string that describes this object.\r\nDialogue: 0,0:29:39.54,0:29:41.67,yin,,0,0,0,, 什么时候用这个呢 \\N{\\fs12}When do we ever use this?\r\nDialogue: 0,0:29:41.67,0:29:44.21,yin,,0,0,0,, 两个地方 一是 NSLog\\N{\\fs12}Two places. One, NS log.\r\nDialogue: 0,0:29:44.23,0:29:47.87,yin,,0,0,0,, 调试时 我们喜欢用 NSLog %@\\N{\\fs12}When we’re debugging, we like to NS log percent at sign.\r\nDialogue: 0,0:29:47.89,0:29:49.71,yin,,0,0,0,, 用 %@时 \\N{\\fs12}And when we do percent at sign,\r\nDialogue: 0,0:29:49.71,0:29:53.45,yin,,0,0,0,,description 会被发送给匹配对象 \\N{\\fs12}the matching objects get sent description, and that’s what gets sent out.\r\nDialogue: 0,0:29:53.45,0:29:58.99,yin,,0,0,0,,NSString 通过返回 self 来实现 description\\N{\\fs12}Now, NSString implements a description by returning self.\r\nDialogue: 0,0:29:58.99,0:30:02.42,yin,,0,0,0,,NSObject 对 description 的实现非常糟糕 \\N{\\fs12}NSObject implements description very badly.\r\nDialogue: 0,0:30:02.42,0:30:04.30,yin,,0,0,0,, 它会返回指针 \\N{\\fs12}It returns like the pointer,\r\nDialogue: 0,0:30:04.30,0:30:07.42,yin,,0,0,0,, 带有指针的字符串这之类 \\N{\\fs12}a string with the pointer in it or something.\r\nDialogue: 0,0:30:07.42,0:30:10.94,yin,,0,0,0,, 在你自己的类中实现时 description 会很有用 \\N{\\fs12}Description becomes valuable when you implement it in your own classes.\r\nDialogue: 0,0:30:10.94,0:30:14.53,yin,,0,0,0,, 例如在 PlayingCard 中 你可以实现 description\\N{\\fs12}So you could imagine implementing in playing card,\r\nDialogue: 0,0:30:14.53,0:30:16.63,yin,,0,0,0,, 甚至在 Card 中 你也可以实现 description\\N{\\fs12}or even in card you could implement description\r\nDialogue: 0,0:30:16.63,0:30:18.95,yin,,0,0,0,, 返回 self.contents\\N{\\fs12}that would return self.contents.\r\nDialogue: 0,0:30:18.95,0:30:22.12,yin,,0,0,0,, 然后在调试器中 你就能够…\\N{\\fs12}And then in the debugger there’s a way –\r\nDialogue: 0,0:30:22.12,0:30:24.44,yin,,0,0,0,, 周五的课上你们会看到 \\N{\\fs12}in which you’ll see this Friday’s section –\r\nDialogue: 0,0:30:24.44,0:30:26.53,yin,,0,0,0,, 你就能够在调试器中打印一个对象 \\N{\\fs12}there’s a way to print an object in the debugger.\r\nDialogue: 0,0:30:26.53,0:30:28.63,yin,,0,0,0,, 它会为你调用 description 并返回它 \\N{\\fs12}It will call description for you and return it.\r\nDialogue: 0,0:30:28.63,0:30:31.33,yin,,0,0,0,, 于是你就能看到纸牌的内容 这非常酷 \\N{\\fs12}So for card you’d see the contents. So that’s really cool.\r\nDialogue: 0,0:30:31.33,0:30:32.90,yin,,0,0,0,, 而字符串显示的是字符串 \\N{\\fs12}And the string shows you the string.\r\nDialogue: 0,0:30:32.90,0:30:35.13,yin,,0,0,0,, 数组和字典实现 description 时 \\N{\\fs12}Arrays and dictionaries implement description\r\nDialogue: 0,0:30:35.13,0:30:37.97,yin,,0,0,0,, 会打印出数组内容 \\N{\\fs12}to print out the contents of the array.\r\nDialogue: 0,0:30:37.97,0:30:42.04,yin,,0,0,0,, 所以说 description 是 NSObject 中很酷的函数 \\N{\\fs12}So description’s a really cool little function to know about in NSObject.\r\nDialogue: 0,0:30:42.04,0:30:46.77,yin,,0,0,0,,NSObject 还实现了这种复制框架 \\N{\\fs12}NSObject kind of implements this framework for copying,\r\nDialogue: 0,0:30:46.77,0:30:49.58,yin,,0,0,0,, 但它并没有实际实现 copy 和 mutableCopy\\N{\\fs12}but it doesn’t actually implement copy and mutable copy.\r\nDialogue: 0,0:30:49.58,0:30:51.78,yin,,0,0,0,, 查一下 NSObject 你就会知道 \\N{\\fs12}If you look in NSObject, you’ll see that\r\nDialogue: 0,0:30:51.78,0:30:55.38,yin,,0,0,0,, 这些方法在这里有一个协议 \\N{\\fs12}these methods are implemented there or there’s a protocol for them there.\r\nDialogue: 0,0:30:55.38,0:30:59.16,yin,,0,0,0,,copy 和 mutableCopy\\N{\\fs12}Copy and mutable copy are –\r\nDialogue: 0,0:30:59.16,0:31:01.82,yin,,0,0,0,, 它们的语义在不同类中有所不同 \\N{\\fs12}the semantics of them vary from class to class.\r\nDialogue: 0,0:31:01.82,0:31:04.64,yin,,0,0,0,, 其实现取决于类 \\N{\\fs12}So it’s up the class to implement it.\r\nDialogue: 0,0:31:04.64,0:31:07.33,yin,,0,0,0,, 不要被 NSObject 中的 copy 和 mutableCopy 糊弄到 \\N{\\fs12}Don’t be fooled by the fact that copy and mutable copy are in NSObject.\r\nDialogue: 0,0:31:07.33,0:31:10.04,yin,,0,0,0,, 不是将 copy 发送给任何对象就能复制的 \\N{\\fs12}You can’t just send copy to any object and it will copy it.\r\nDialogue: 0,0:31:10.04,0:31:13.14,yin,,0,0,0,, 但 NSArray NSDictionary 这些 \\N{\\fs12}But NSArray, for example, NSDictionary, these things,\r\nDialogue: 0,0:31:13.14,0:31:14.85,yin,,0,0,0,, 实现了 copy 和 mutableCopy\\N{\\fs12}they implement copy and mutable copy,\r\nDialogue: 0,0:31:14.85,0:31:16.55,yin,,0,0,0,, 它们做了正确的事情 \\N{\\fs12}and they do the right thing.\r\nDialogue: 0,0:31:16.55,0:31:19.73,yin,,0,0,0,, 关于 copy 有一点要注意 如果将 copy\\N{\\fs12}One thing to note about copy is if you send copy\r\nDialogue: 0,0:31:19.73,0:31:22.43,yin,,0,0,0,, 发送给一个可变对象 例如可变数组 \\N{\\fs12}to a mutable object like a mutable array,\r\nDialogue: 0,0:31:22.43,0:31:24.51,yin,,0,0,0,, 返回的将不是可变数组 \\N{\\fs12}you don’t get a mutable array back,\r\nDialogue: 0,0:31:24.51,0:31:26.09,yin,,0,0,0,, 虽然你是在 copy 可变数组 \\N{\\fs12}even though you just copied a mutable array.\r\nDialogue: 0,0:31:26.09,0:31:28.76,yin,,0,0,0,, 返回的却是不可变数组 \\N{\\fs12}You get an immutable array back.\r\nDialogue: 0,0:31:28.76,0:31:30.50,yin,,0,0,0,,copy 的语义是 \\N{\\fs12}The semantics copy are,\r\nDialogue: 0,0:31:30.50,0:31:35.06,yin,,0,0,0,, 如果可能 返回该对象的一个不可变副本 \\N{\\fs12}”Give me an immutable copy of this object back if possible.”\r\nDialogue: 0,0:31:35.06,0:31:37.47,yin,,0,0,0,,mutableCopy 的语义是 \\N{\\fs12}The semantics of mutable copy are,\r\nDialogue: 0,0:31:37.47,0:31:40.64,yin,,0,0,0,, 返回该对象的一个可变副本 \\N{\\fs12}”Give me a mutable copy of this thing.”\r\nDialogue: 0,0:31:40.64,0:31:43.21,yin,,0,0,0,, 不管接收可变或不可变复制的是什么 \\N{\\fs12}No matter whether the receiver is mutable or immutable,\r\nDialogue: 0,0:31:43.21,0:31:45.72,yin,,0,0,0,,mutableCopy 意味着返回可变副本 \\N{\\fs12}mutable copy means give me a mutable copy;\r\nDialogue: 0,0:31:45.72,0:31:48.19,yin,,0,0,0,,copy 意味着返回不可变副本 \\N{\\fs12}copy means give me an immutable copy.\r\nDialogue: 0,0:31:48.19,0:31:51.25,yin,,0,0,0,, 理解了吗 \\N{\\fs12}Understand that?\r\nDialogue: 0,0:31:51.25,0:31:54.82,yin,,0,0,0,, 重申一次 特定类实现这个 \\N{\\fs12}And again, certain classes implement this;\r\nDialogue: 0,0:31:54.82,0:31:56.78,yin,,0,0,0,,NSObject 则没有 \\N{\\fs12}NSObject really does not.\r\nDialogue: 0,0:31:56.78,0:32:00.17,yin,,0,0,0,, 如果你希望自己的对象可复制 你需要自己实现 \\N{\\fs12}You would have to implement it yourself if you wanted to have your objects be copyable,\r\nDialogue: 0,0:32:00.17,0:32:01.76,yin,,0,0,0,, 这非常罕见 \\N{\\fs12}which is pretty rare by the way.\r\nDialogue: 0,0:32:01.76,0:32:04.79,yin,,0,0,0,, 一般不需要这样做 \\N{\\fs12}Really not generally doing that.\r\nDialogue: 0,0:32:04.79,0:32:07.65,yin,,0,0,0,, 好 NSArray 是对象的有序集合 \\N{\\fs12}Okay. NSArray is an ordered collection of objects.\r\nDialogue: 0,0:32:07.65,0:32:08.93,yin,,0,0,0,, 它是不可变的 \\N{\\fs12}It’s immutable.\r\nDialogue: 0,0:32:08.93,0:32:11.04,yin,,0,0,0,,NSArray 一经创建 其中的对象就会一直保持不变 \\N{\\fs12}When you create an NSArray, whatever objects are in it\r\nDialogue: 0,0:32:11.04,0:32:13.40,yin,,0,0,0,,NSArray 一经创建 其中的对象就会一直保持不变 \\N{\\fs12}when you create it, those are the objects that will be in there for life.\r\nDialogue: 0,0:32:13.40,0:32:16.04,yin,,0,0,0,, 无法删除 也无法添加任何对象 \\N{\\fs12}You can’t remove any, you can’t add any.\r\nDialogue: 0,0:32:16.06,0:32:19.49,yin,,0,0,0,, 数组中所有对象在堆中都是强存储的 \\N{\\fs12}All objects in an array are held onto strongly in the heap.\r\nDialogue: 0,0:32:19.49,0:32:22.55,yin,,0,0,0,, 只要该数组本身处在堆中 \\N{\\fs12}So as long as that array itself is in the heap, okay,\r\nDialogue: 0,0:32:22.55,0:32:24.83,yin,,0,0,0,, 只要有强指针指向数组本身 \\N{\\fs12}as long as someone has a strong pointer to the array itself,\r\nDialogue: 0,0:32:24.83,0:32:27.91,yin,,0,0,0,, 数组中的所有对象也都会留在堆中 \\N{\\fs12}all the objects that are in the array will stay in the heap as well\r\nDialogue: 0,0:32:27.91,0:32:31.22,yin,,0,0,0,, 因为有强指针指向所有这些对象 \\N{\\fs12}because it has strong pointers to all of them.\r\nDialogue: 0,0:32:31.22,0:32:33.91,yin,,0,0,0,,NSArray 的创建 \\N{\\fs12}You usually create an NSArray\r\nDialogue: 0,0:32:33.91,0:32:38.55,yin,,0,0,0,, 有时会调用类方法 甚至调用 alloc init\\N{\\fs12}by sometimes calling a class method or even alloc init.\r\nDialogue: 0,0:32:38.55,0:32:43.24,yin,,0,0,0,, 但最普遍的情况下 我们会使用 @[]\\N{\\fs12}But usually most commonly we do that at sign square bracket thing,\r\nDialogue: 0,0:32:43.24,0:32:44.84,yin,,0,0,0,, 例如创建 rank 字符串时 \\N{\\fs12}like how we created rank strings.\r\nDialogue: 0,0:32:44.84,0:32:49.39,yin,,0,0,0,, 记得吧 PlayingCard 中的 rank 字符串 \\N{\\fs12}Remember rank strings in playing card,\r\nDialogue: 0,0:32:49.39,0:32:51.71,yin,,0,0,0,,@ 方括号 然后元素 \\N{\\fs12}at sign, square bracket, and the elements?\r\nDialogue: 0,0:32:51.71,0:32:53.23,yin,,0,0,0,, 这就是通常创建数组的方式 \\N{\\fs12}That’s usually how we create arrays.\r\nDialogue: 0,0:32:53.23,0:32:56.11,yin,,0,0,0,, 有时我们创建数组是通过要其它数组 \\N{\\fs12}Sometimes we’ll create arrays by asking other arrays\r\nDialogue: 0,0:32:56.11,0:32:58.72,yin,,0,0,0,, 在自身上加一个对象 然后返回新数组 \\N{\\fs12}to add an object to themselves and give us a new array\r\nDialogue: 0,0:32:58.72,0:33:00.14,yin,,0,0,0,, 因为这里不可变 \\N{\\fs12}since they can’t be mutated;\r\nDialogue: 0,0:33:00.14,0:33:01.64,yin,,0,0,0,, 所以必须生成新的并返回 \\N{\\fs12}they have to make a new one and give it back.\r\nDialogue: 0,0:33:01.64,0:33:02.69,yin,,0,0,0,, 这是另一种方式 \\N{\\fs12}So that’s another way.\r\nDialogue: 0,0:33:02.69,0:33:07.41,yin,,0,0,0,, 你们知道基本的 count objectAtIndex 等方法 \\N{\\fs12}And you know the basic, you know, get the count, object at index.\r\nDialogue: 0,0:33:07.41,0:33:09.87,yin,,0,0,0,, 数组中还有很多其它非常酷的方法 \\N{\\fs12}There’s a lot of other really cool methods in an array.\r\nDialogue: 0,0:33:09.87,0:33:12.33,yin,,0,0,0,, 这个类你们需要非常熟悉才行 \\N{\\fs12}You really should familiarize yourself with this class.\r\nDialogue: 0,0:33:12.33,0:33:14.04,yin,,0,0,0,, 这里有很多东西 \\N{\\fs12}Okay. It’s a lot of stuff.\r\nDialogue: 0,0:33:14.04,0:33:15.94,yin,,0,0,0,, 我讲过 makeObjectsPerform\\N{\\fs12}We talked about make objects perform.\r\nDialogue: 0,0:33:15.94,0:33:18.57,yin,,0,0,0,, 这里还有 sortedArrayUsingSelector\\N{\\fs12}There’s sorted array using selector.\r\nDialogue: 0,0:33:18.57,0:33:21.78,yin,,0,0,0,, 你可以给它一个 selector\\N{\\fs12}So you give it a selector that takes another –\r\nDialogue: 0,0:33:21.78,0:33:24.85,yin,,0,0,0,, 它被发送到数组中的每个对象 \\N{\\fs12}that basically gets sent to each object in the array\r\nDialogue: 0,0:33:24.85,0:33:26.92,yin,,0,0,0,, 并将数组中另一个对象作为参数 \\N{\\fs12}and takes one of the other objects in the array as an argument.\r\nDialogue: 0,0:33:26.92,0:33:29.53,yin,,0,0,0,, 你要确保这里的参数类型正确 \\N{\\fs12}So you got to make sure they have the right type of argument there.\r\nDialogue: 0,0:33:29.53,0:33:32.94,yin,,0,0,0,, 它会这样来创建一个排过序的数组 \\N{\\fs12}And it will just use that to create a sorted version of the array\r\nDialogue: 0,0:33:32.94,0:33:34.67,yin,,0,0,0,, 并返回这个排过序的新数组 \\N{\\fs12}and give you back a new array that’s sorted.\r\nDialogue: 0,0:33:34.67,0:33:37.68,yin,,0,0,0,, 只要你有一个 selector\\N{\\fs12}Okay. So one line of code as long as you have a selector\r\nDialogue: 0,0:33:37.68,0:33:40.46,yin,,0,0,0,, 针对一个方法 能够对比数组中的两个对象 \\N{\\fs12}for a method that can compare two objects that are in an array,\r\nDialogue: 0,0:33:40.46,0:33:41.91,yin,,0,0,0,, 你就能够排序 \\N{\\fs12}you can sort it.\r\nDialogue: 0,0:33:41.91,0:33:46.60,yin,,0,0,0,,NSArray 中的这些怪异内容你都需要知道 \\N{\\fs12}So you really should know about all these kind of whacky things in NSArray.\r\nDialogue: 0,0:33:46.60,0:33:49.41,yin,,0,0,0,,NSArray 无法被修改 \\N{\\fs12}Now, NSArray can’t be modified.\r\nDialogue: 0,0:33:49.41,0:33:52.42,yin,,0,0,0,, 这有时存在局限 \\N{\\fs12}Sometimes that’s a limitation,\r\nDialogue: 0,0:33:52.43,0:33:54.33,yin,,0,0,0,, 但可能没你们想的那么严重 \\N{\\fs12}not as often as you might think.\r\nDialogue: 0,0:33:54.33,0:33:56.31,yin,,0,0,0,, 当然 还有一种可变的数组 \\N{\\fs12}But there’s a mutable version of Array, of course,\r\nDialogue: 0,0:33:56.31,0:33:59.50,yin,,0,0,0,, 叫作 NSMutableArray 这个我们也用过 \\N{\\fs12}called NSMutableArray, which we’ve also used.\r\nDialogue: 0,0:33:59.50,0:34:03.27,yin,,0,0,0,, 我们通常使用 alloc init 来创建它 \\N{\\fs12}We usually create it using alloc init\r\nDialogue: 0,0:34:03.27,0:34:05.87,yin,,0,0,0,, 有时我们则会使用 arrayWithCapacity\\N{\\fs12}or sometimes we use Array with capacity.\r\nDialogue: 0,0:34:05.87,0:34:07.92,yin,,0,0,0,,arrayWithCapacity 中 \\N{\\fs12}Array with capacity is –\r\nDialogue: 0,0:34:07.92,0:34:10.70,yin,,0,0,0,, 容量参数只是性能提示 \\N{\\fs12}that capacity argument is just performance hint.\r\nDialogue: 0,0:34:10.70,0:34:14.03,yin,,0,0,0,, 它并没有说 数组最开始只能有那么多项目 \\N{\\fs12}It’s not saying that the array starts out with that many items;\r\nDialogue: 0,0:34:14.04,0:34:16.97,yin,,0,0,0,, 它只是说 我觉得这个数组中将有 100 个元素 \\N{\\fs12}it just means, “I think this array is going to have a hundred things in it.”\r\nDialogue: 0,0:34:16.97,0:34:20.15,yin,,0,0,0,, 创建 100 个元素的数组 这只是性能提示 \\N{\\fs12}So creating an array with a hundred — it’s a performance hint only.\r\nDialogue: 0,0:34:20.33,0:34:23.92,yin,,0,0,0,, 你们知道 NSMutableArray 继承了 NSArray 的一切 \\N{\\fs12}You know that NSMutableArray inherits everything from NSArray,\r\nDialogue: 0,0:34:23.92,0:34:26.01,yin,,0,0,0,, 当然 它还增加了 addObject:\\N{\\fs12}of course, and then it adds add object,\r\nDialogue: 0,0:34:26.01,0:34:27.29,yin,,0,0,0,,insertObject:\\N{\\fs12}insert object at,\r\nDialogue: 0,0:34:27.30,0:34:28.82,yin,,0,0,0,,removeObject: atIndex:\\N{\\fs12}remove object at index.\r\nDialogue: 0,0:34:28.82,0:34:31.76,yin,,0,0,0,, 你们还知道 可以使用方括号表示法 \\N{\\fs12}And you know that you can use the square brackets notation,\r\nDialogue: 0,0:34:31.76,0:34:34.94,yin,,0,0,0,, 例如 self.cards[index]\\N{\\fs12}right, like self.cards open square bracket, index,\r\nDialogue: 0,0:34:34.94,0:34:39.63,yin,,0,0,0,, 将事物放到数组中 或是从数组中删除 \\N{\\fs12}closed square brackets to both put things into an array and get things out of an array.\r\nDialogue: 0,0:34:39.63,0:34:43.28,yin,,0,0,0,, 使用这种表示法其实也就是调用 \\N{\\fs12}And using that notation is really just calling\r\nDialogue: 0,0:34:43.28,0:34:45.72,yin,,0,0,0,,objectAtSubscriptedIndex\\N{\\fs12}object at subscripted index\r\nDialogue: 0,0:34:45.72,0:34:47.94,yin,,0,0,0,, 以及 setObjectAtSubscriptedIndex\\N{\\fs12}and set object at subscripted index.\r\nDialogue: 0,0:34:47.94,0:34:50.27,yin,,0,0,0,, 这里不过是在调用这些方法 \\N{\\fs12}Okay. It’s just calling those methods; that’s all it’s doing.\r\nDialogue: 0,0:34:50.27,0:34:54.42,yin,,0,0,0,, 但使用方括号表示法让代码更清晰 \\N{\\fs12}But it looks really nice in your code to use those square brackets.\r\nDialogue: 0,0:34:54.42,0:34:59.21,yin,,0,0,0,, 枚举 我们知道如何使用 for in 结构 \\N{\\fs12}Enumeration, we saw how to do this for in business.\r\nDialogue: 0,0:34:59.21,0:35:01.78,yin,,0,0,0,, 不要忘记 控制变量 \\N{\\fs12}Don’t forget that that control variable\r\nDialogue: 0,0:35:01.78,0:35:04.59,yin,,0,0,0,, 例如 NSString *string in myArray\\N{\\fs12}like NSString star string in my array –\r\nDialogue: 0,0:35:04.59,0:35:06.09,yin,,0,0,0,, 这里有 NSString *string\\N{\\fs12}you see the NSString star string –\r\nDialogue: 0,0:35:06.09,0:35:08.44,yin,,0,0,0,, 这实际上是类型转换 \\N{\\fs12}that’s essentially your casting.\r\nDialogue: 0,0:35:08.44,0:35:11.56,yin,,0,0,0,, 你将该数组中取出的元素转化为 NSString\\N{\\fs12}You’re casting, whatever comes out of that array to be an NSString.\r\nDialogue: 0,0:35:11.56,0:35:15.41,yin,,0,0,0,, 你告诉编译器 我知道这个数组中都是字符串 \\N{\\fs12}You’re telling the compiler, “I know that what’s in that array is strings.”\r\nDialogue: 0,0:35:15.41,0:35:17.57,yin,,0,0,0,, 如果你不知道数组中都是什么 \\N{\\fs12}Now, if you don’t know what’s in there,\r\nDialogue: 0,0:35:17.57,0:35:19.28,yin,,0,0,0,, 或者如果是混合事物 \\N{\\fs12}you could say — or if it’s a mixed things –\r\nDialogue: 0,0:35:19.28,0:35:22.53,yin,,0,0,0,, 你可以说 for (id obj in myArray)\\N{\\fs12}you would say for ID obj in my array.\r\nDialogue: 0,0:35:22.53,0:35:24.64,yin,,0,0,0,, 这时 迭代变量将是 obj\\N{\\fs12}Then the iteration variable will be an obj\r\nDialogue: 0,0:35:24.65,0:35:27.00,yin,,0,0,0,, 你可能需要内省来弄清 \\N{\\fs12}and you’ll likely want to use introspection to find\r\nDialogue: 0,0:35:27.00,0:35:30.96,yin,,0,0,0,, 每次经过循环时 返回给你的东西是什么 \\N{\\fs12}out what the thing you got back is each time around the loop.\r\nDialogue: 0,0:35:30.96,0:35:33.33,yin,,0,0,0,, 能理解吗 \\N{\\fs12}Make sense?\r\nDialogue: 0,0:35:33.33,0:35:35.68,yin,,0,0,0,, 下一个 NSNumber\\N{\\fs12}Next NSNumber.\r\nDialogue: 0,0:35:35.68,0:35:40.40,yin,,0,0,0,,NSNumber 这个类被用于包含原始类型 \\N{\\fs12}NSNumber is a class that is used to wrap primitive types\r\nDialogue: 0,0:35:40.40,0:35:42.89,yin,,0,0,0,, 例如整型 浮点型 双精浮点型 布尔型等等 \\N{\\fs12}like integers, floats, doubles, Bools, things like that.\r\nDialogue: 0,0:35:42.89,0:35:44.28,yin,,0,0,0,, 为什么要把这些总起来呢 \\N{\\fs12}And why do you want to wrap them?\r\nDialogue: 0,0:35:44.28,0:35:47.73,yin,,0,0,0,, 通常是因为你想把它们放入数组或词典 \\N{\\fs12}Usually because you want to put them in Array or a dictionary.\r\nDialogue: 0,0:35:47.73,0:35:51.52,yin,,0,0,0,, 你不能将 int 放到数组中 你需要 NSNumber 对象 \\N{\\fs12}So you can’t put an int into an array; you need to have an NSNumber object.\r\nDialogue: 0,0:35:51.52,0:35:56.02,yin,,0,0,0,, 你可以用类方法创建它们 例如 numberWithInt\\N{\\fs12}You can create them with class methods like number with int –\r\nDialogue: 0,0:35:56.02,0:35:59.51,yin,,0,0,0,, 这是 NSNumber 方法中的一个类函数 \\N{\\fs12}that’s a class number in a class method NSNumber –\r\nDialogue: 0,0:35:59.52,0:36:02.60,yin,,0,0,0,, 你也可以使用 @()\\N{\\fs12}or you can use at sign parenthesis.\r\nDialogue: 0,0:36:02.60,0:36:05.40,yin,,0,0,0,, 我们已经看到过 @[] 用于数组 \\N{\\fs12}So we already saw at sign square bracket for arrays,\r\nDialogue: 0,0:36:05.40,0:36:07.33,yin,,0,0,0,, 这里还有 @()\\N{\\fs12}there’s also at sign parenthesis,\r\nDialogue: 0,0:36:07.33,0:36:10.84,yin,,0,0,0,, 甚至在创建数字时还可以用 @数字 \\N{\\fs12}or even just at sign number if you want to create a number.\r\nDialogue: 0,0:36:10.84,0:36:11.89,yin,,0,0,0,, 例如 @3\\N{\\fs12}So you could say at sign three.\r\nDialogue: 0,0:36:11.89,0:36:13.83,yin,,0,0,0,, 还可以有 @3.2\\N{\\fs12}You could also say at sign 3.2,\r\nDialogue: 0,0:36:13.83,0:36:16.84,yin,,0,0,0,, 这会创建一个 NSNumber 包含这一原始类型 \\N{\\fs12}and that would create an NSNumber that would contain that primitive type.\r\nDialogue: 0,0:36:16.84,0:36:19.69,yin,,0,0,0,, 如果使用括号 那么你就可以在括号中 \\N{\\fs12}If you put the parenthesis, then you could put things inside\r\nDialogue: 0,0:36:19.69,0:36:22.92,yin,,0,0,0,, 调用返回原始类型的方法 \\N{\\fs12}like calls to methods that return a primitive type,\r\nDialogue: 0,0:36:22.92,0:36:23.94,yin,,0,0,0,, 或枚举 \\N{\\fs12}or enums,\r\nDialogue: 0,0:36:23.94,0:36:25.22,yin,,0,0,0,, 或任意你想放到这里的东西 \\N{\\fs12}or anything you want in there –\r\nDialogue: 0,0:36:25.22,0:36:29.34,yin,,0,0,0,, 任意计算得到原始类型的表达式都能放到括号内 \\N{\\fs12}any expression that evaluates to a primitive type can be put inside of parenthesis.\r\nDialogue: 0,0:36:29.34,0:36:33.62,yin,,0,0,0,, 你可以说 @() 它会根据结果创建一个 NSNumber\\N{\\fs12}You say at sign parenthesis and it will create an NSNumber with the result.\r\nDialogue: 0,0:36:35.03,0:36:38.00,yin,,0,0,0,, 大家都理解了这种语法吗 \\N{\\fs12}Everybody understand that syntax?\r\nDialogue: 0,0:36:38.00,0:36:43.67,yin,,0,0,0,, 其它语言都有这种自动装箱 \\N{\\fs12}Okay. So other languages kind of have this autoboxing kind of stuff in there.\r\nDialogue: 0,0:36:43.67,0:36:47.33,yin,,0,0,0,,NSValue 我不打算讲太多 \\N{\\fs12}NSValue, I’m not going to talk too much about it.\r\nDialogue: 0,0:36:47.33,0:36:51.98,yin,,0,0,0,, 这是一种封装比原始类型更复杂类型的方式 \\N{\\fs12}It’s essentially a way to encapsulate more complicated types than primitive types,\r\nDialogue: 0,0:36:51.98,0:36:54.97,yin,,0,0,0,, 基本上也就是 C struct\\N{\\fs12}so structs basically, C structs.\r\nDialogue: 0,0:36:54.97,0:36:57.55,yin,,0,0,0,,NSValue 知道如何包装 \\N{\\fs12}And NSValue knows how to wrap up\r\nDialogue: 0,0:36:57.55,0:37:00.26,yin,,0,0,0,,iOS 中一些不同类型的 struct\\N{\\fs12}a few different kinds of structs that are in iOS.\r\nDialogue: 0,0:37:00.26,0:37:03.14,yin,,0,0,0,, 具体哪些你们可以参阅说明文档 \\N{\\fs12}And you can go look at the documentations to see which ones.\r\nDialogue: 0,0:37:03.14,0:37:06.38,yin,,0,0,0,, 这里我要简单提到的是一点是 \\N{\\fs12}One thing I’m going to give you a little tip right here, okay,\r\nDialogue: 0,0:37:06.38,0:37:12.19,yin,,0,0,0,, 有时将 struct 包装起来的好办法是将它转化为字符串 \\N{\\fs12}sometimes a good way to wrap up a struct is to turn it into a string.\r\nDialogue: 0,0:37:12.19,0:37:13.74,yin,,0,0,0,, 然后你可以把它作为字符串放入数组 \\N{\\fs12}Then you can put it in the array as a string.\r\nDialogue: 0,0:37:13.74,0:37:16.84,yin,,0,0,0,, 这很棒 可以在调试器中打印 可以很好地看到 \\N{\\fs12}It’s nice because you print it out in the debugger and you can see it really nicely.\r\nDialogue: 0,0:37:16.84,0:37:21.52,yin,,0,0,0,, 然后还有办法将字符串转换为 C struct\\N{\\fs12}And then there’s ways to turn things from strings back into C structs.\r\nDialogue: 0,0:37:21.52,0:37:26.83,yin,,0,0,0,,iOS 中有 C 函数能将大多数 struct 转化为字符串 \\N{\\fs12}So there are C functions in iOS that turn most of the structs in iOS into strings\r\nDialogue: 0,0:37:26.83,0:37:29.71,yin,,0,0,0,, 还有其它 C 函数将字符串转化回 struct\\N{\\fs12}and then other C functions that turn the strings back into the structs.\r\nDialogue: 0,0:37:29.71,0:37:34.30,yin,,0,0,0,,NSValue… 我认为多数时候你们可以用字符串 \\N{\\fs12}So NSValue — I think most of the time you can use strings.\r\nDialogue: 0,0:37:34.30,0:37:36.46,yin,,0,0,0,, 也许存储在 NSValue 中更高效 \\N{\\fs12}It’s probably more efficient to store something as an NSValue\r\nDialogue: 0,0:37:36.46,0:37:38.50,yin,,0,0,0,, 不过还是那句话 不要过度优化 \\N{\\fs12}but, again, don’t overoptimize.\r\nDialogue: 0,0:37:38.50,0:37:43.48,yin,,0,0,0,, 转化为字符串在使用时也很不错 \\N{\\fs12}Turning into a string is just as performant in the case you’re using it.\r\nDialogue: 0,0:37:43.48,0:37:47.46,yin,,0,0,0,, 这是因为它是一个字符串 很容易处理 \\N{\\fs12}It’s nice because it’s a string and it’s easy to look at.\r\nDialogue: 0,0:37:48.16,0:37:50.38,yin,,0,0,0,,NSData 是另一种 Foundation 类 \\N{\\fs12}NSData is another Foundation class,\r\nDialogue: 0,0:37:50.38,0:37:51.63,yin,,0,0,0,, 只是”二进制包”\\N{\\fs12}just a bag of bits.\r\nDialogue: 0,0:37:51.63,0:37:53.12,yin,,0,0,0,, 我们将使用 NSData\\N{\\fs12}And we’re going to be using NSDatas.\r\nDialogue: 0,0:37:53.12,0:37:54.56,yin,,0,0,0,, 以后讲到时我会进一步讲 \\N{\\fs12}We’ll talk about them more when we get to that.\r\nDialogue: 0,0:37:54.56,0:37:58.66,yin,,0,0,0,, 简单说来 NSData 不过是一些二进制数据 \\N{\\fs12}But it’s just basically a certain count of bytes, that’s what NSData is.\r\nDialogue: 0,0:37:59.05,0:38:01.75,yin,,0,0,0,,NSDate 是日期 \\N{\\fs12}NSDate is a date, right?\r\nDialogue: 0,0:38:01.75,0:38:03.26,yin,,0,0,0,, 它有一些内部表示 \\N{\\fs12}It has some internal representation.\r\nDialogue: 0,0:38:03.26,0:38:05.36,yin,,0,0,0,, 也许是 UNIX 表示 \\N{\\fs12}It’s probably the UNIX representation\r\nDialogue: 0,0:38:05.37,0:38:08.80,yin,,0,0,0,, 如 1970 年以来的秒数 诸如此类 \\N{\\fs12}like the number of seconds since 1970 or whatever it is.\r\nDialogue: 0,0:38:08.80,0:38:13.70,yin,,0,0,0,,NSDate 可以这样考虑 如果你要在 UI 中加入日期 \\N{\\fs12}One thing to think about with NSDates, if you’re going to put a date in your UI,\r\nDialogue: 0,0:38:13.70,0:38:16.40,yin,,0,0,0,, 你需要知道你在做什么 \\N{\\fs12}you got to know what you’re doing.\r\nDialogue: 0,0:38:16.40,0:38:18.01,yin,,0,0,0,, 为什么呢 \\N{\\fs12}Why is that?\r\nDialogue: 0,0:38:18.01,0:38:21.95,yin,,0,0,0,, 这是因为日期在世界范围内差异很大 \\N{\\fs12}That’s because dates vary dramatically all around the world.\r\nDialogue: 0,0:38:21.95,0:38:24.31,yin,,0,0,0,, 我讲的还不是在法国 \\N{\\fs12}And I’m not just talking about in French, you know,\r\nDialogue: 0,0:38:24.31,0:38:26.70,yin,,0,0,0,, 连月份名字都不同 要知道 \\N{\\fs12}the month names are different, but you know,\r\nDialogue: 0,0:38:26.70,0:38:30.35,yin,,0,0,0,, 甚至连月在前还是日在前 不同地方都会不同 \\N{\\fs12}the order of whether the month comes first or the date comes first varies.\r\nDialogue: 0,0:38:30.35,0:38:32.12,yin,,0,0,0,, 世界上有些地方 \\N{\\fs12}Some places on earth,\r\nDialogue: 0,0:38:32.12,0:38:35.38,yin,,0,0,0,, 使用的日历都跟我们不一样 \\N{\\fs12}some locales don’t even use the same calendar as we use.\r\nDialogue: 0,0:38:35.38,0:38:40.03,yin,,0,0,0,, 所以 iOS 中有大量基础设施来处理这个 \\N{\\fs12}So there is an enormous amount of infrastructure in iOS for dealing with this.\r\nDialogue: 0,0:38:40.03,0:38:41.76,yin,,0,0,0,, 有 NSCalendar 这样的类 \\N{\\fs12}Classes like NSCalendar,\r\nDialogue: 0,0:38:41.76,0:38:43.82,yin,,0,0,0,, 有日期格式化器等等 \\N{\\fs12}and date formatter, and things like that.\r\nDialogue: 0,0:38:43.82,0:38:47.89,yin,,0,0,0,, 如果你要在 UI 中使用日期 请务必熟悉所有这些 \\N{\\fs12}If you’re going to put in your UI, familiarize yourself with all of that.\r\nDialogue: 0,0:38:47.89,0:38:50.85,yin,,0,0,0,, 课堂上我显然没时间一一讲解 \\N{\\fs12}I don’t have time to go over it all in lecture unfortunately.\r\nDialogue: 0,0:38:50.85,0:38:53.11,yin,,0,0,0,, 但你需要知道 有些东西你需要知道 \\N{\\fs12}But you just need to know that there’s something you need to know.\r\nDialogue: 0,0:38:53.11,0:38:58.21,yin,,0,0,0,, 你不能在 UI 中仅仅说 NSDate description\\N{\\fs12}You can’t just say NSDate description and put it in the UI.\r\nDialogue: 0,0:38:58.21,0:39:01.30,yin,,0,0,0,, 日期比这要复杂很多 \\N{\\fs12}Dates are a little bit complicated.\r\nDialogue: 0,0:39:01.30,0:39:05.12,yin,,0,0,0,,NSSet 是对象的无序集合 \\N{\\fs12}There’s NSSet, which a set is an unordered collection of objects,\r\nDialogue: 0,0:39:05.12,0:39:06.51,yin,,0,0,0,, 对象都是唯一的 \\N{\\fs12}so the objects are unique.\r\nDialogue: 0,0:39:06.51,0:39:11.46,yin,,0,0,0,, 就算你把相同对象放进去两次 它也只会存在一次 \\N{\\fs12}So you put the same objects in there twice, it only goes in there once.\r\nDialogue: 0,0:39:11.46,0:39:14.61,yin,,0,0,0,,NSSet 就是一般意义上的集合 \\N{\\fs12}So sets are what you would think of in term of sets.\r\nDialogue: 0,0:39:14.61,0:39:18.54,yin,,0,0,0,, 然后还有有序集 介于 NSSet 和数组之间 \\N{\\fs12}And there’s actually an ordered set, which is like a cross between the set and an array.\r\nDialogue: 0,0:39:18.54,0:39:19.63,yin,,0,0,0,, 你们可以自己去查 \\N{\\fs12}And you can look those up.\r\nDialogue: 0,0:39:19.63,0:39:22.95,yin,,0,0,0,, 这些你们可能用不着 NSSet 你们可能会用到 \\N{\\fs12}You’re not going to need those probably — well, you might need set.\r\nDialogue: 0,0:39:22.95,0:39:25.15,yin,,0,0,0,,NSSet 很好 \\N{\\fs12}Set is nice because you can do things if you have –\r\nDialogue: 0,0:39:25.15,0:39:27.85,yin,,0,0,0,, 很便于告诉你集合中是否有什么 \\N{\\fs12}set is very good at telling you whether something’s in the set.\r\nDialogue: 0,0:39:27.85,0:39:31.29,yin,,0,0,0,, 而数组 如果数组中有一千个元素 \\N{\\fs12}Whereas an array, if you had an array of a thousand things,\r\nDialogue: 0,0:39:31.29,0:39:33.34,yin,,0,0,0,, 数组可能需要进行二分查找 \\N{\\fs12}the array might have to do some binary searching or –\r\nDialogue: 0,0:39:33.34,0:39:35.43,yin,,0,0,0,, 二分查找可能都不行 因为它不知道顺序 \\N{\\fs12}well, I guess it can’t even binary search because it doesn’t know the order.\r\nDialogue: 0,0:39:35.43,0:39:38.76,yin,,0,0,0,, 它会在这里面到处找 很难找到东西 \\N{\\fs12}So it’s got to look around in there. It’s hard for it to find things.\r\nDialogue: 0,0:39:38.76,0:39:42.24,yin,,0,0,0,, 但 NSSet 经过了 hash 处理 效率很高 \\N{\\fs12}But a set is probably hashed and high efficiency.\r\nDialogue: 0,0:39:42.24,0:39:44.33,yin,,0,0,0,, 就算集合中有一万个对象 \\N{\\fs12}It can tell you if you had a set of ten thousand objects\r\nDialogue: 0,0:39:44.33,0:39:46.18,yin,,0,0,0,, 你问它 这个对象在里面吗 \\N{\\fs12}and you ask it, “Is this object in there?”\r\nDialogue: 0,0:39:46.18,0:39:48.17,yin,,0,0,0,, 它会很高效地告诉你 \\N{\\fs12}it could probably tell you really efficiently.\r\nDialogue: 0,0:39:48.17,0:39:52.59,yin,,0,0,0,, 有时 NSSet 对比数组还是有些价值的 \\N{\\fs12}So there are some values sometimes sets versus Array.\r\nDialogue: 0,0:39:52.59,0:39:54.91,yin,,0,0,0,, 好 字典 \\N{\\fs12}Okay. Dictionary.\r\nDialogue: 0,0:39:54.91,0:39:59.03,yin,,0,0,0,, 这是第二重要的集合类 可能仅次于数组 \\N{\\fs12}This is the second most important collection class behind Array probably.\r\nDialogue: 0,0:39:59.03,0:40:03.66,yin,,0,0,0,, 它是键值对的不可变集合 \\N{\\fs12}It’s an immutable collection of key value pairs.\r\nDialogue: 0,0:40:03.66,0:40:04.83,yin,,0,0,0,, 类似 hash 表 \\N{\\fs12}It’s like a hash table.\r\nDialogue: 0,0:40:04.83,0:40:09.55,yin,,0,0,0,, 所有键和值都是强存储的 \\N{\\fs12}All the keys and values are held onto strongly.\r\nDialogue: 0,0:40:09.55,0:40:13.81,yin,,0,0,0,, 如果它们在那里作为键或值 那么它们就在堆中 \\N{\\fs12}So if they’re in there as a key or a value, then they’re in the heap.\r\nDialogue: 0,0:40:13.81,0:40:16.31,yin,,0,0,0,, 只要字典在堆中 它们就在 \\N{\\fs12}And they stay in there as long as the dictionary stays in the heap.\r\nDialogue: 0,0:40:16.31,0:40:19.16,yin,,0,0,0,, 键和值显然都是对象 \\N{\\fs12}The keys and values, obviously, are both objects.\r\nDialogue: 0,0:40:19.16,0:40:22.73,yin,,0,0,0,, 等下我会讲到键要怎样才能成为键 \\N{\\fs12}We’ll talk about what the key has to do to be a key in a second here.\r\nDialogue: 0,0:40:22.73,0:40:26.36,yin,,0,0,0,, 不可变 NSDictionary 的创建方法通常是 \\N{\\fs12}You usually create immutable NSDictionaries using another\r\nDialogue: 0,0:40:26.36,0:40:30.07,yin,,0,0,0,, 另一种 @语法 即 @花括号 \\N{\\fs12}at sign syntax called “at sign curly brace.”\r\nDialogue: 0,0:40:30.07,0:40:34.16,yin,,0,0,0,, 形如 @ 花括号 键: 值 逗号 \\N{\\fs12}Okay. So it’s at sign curly brace, key colon value, comma,\r\nDialogue: 0,0:40:34.16,0:40:37.85,yin,,0,0,0,, 键: 值 逗号 键: 值 反花括号 \\N{\\fs12}key colon value, comma, key colon value, end curly brace.\r\nDialogue: 0,0:40:37.85,0:40:39.90,yin,,0,0,0,, 这类似于数组的 @[]\\N{\\fs12}So this is kind of like the at sign square brackets\r\nDialogue: 0,0:40:39.90,0:40:42.32,yin,,0,0,0,, 以及 NSNumber 的 @()\\N{\\fs12}for arrays or the at sign parenthesis for NSNumbers.\r\nDialogue: 0,0:40:42.32,0:40:46.38,yin,,0,0,0,, 这是 @版本的 NSDictionary\\N{\\fs12}This is NSDictionary’s version of that.\r\nDialogue: 0,0:40:46.38,0:40:49.29,yin,,0,0,0,, 你可以在字典中查东西 \\N{\\fs12}You look up things inside a dictionary.\r\nDialogue: 0,0:40:49.29,0:40:51.61,yin,,0,0,0,, 显然你可以用 objectForKey\\N{\\fs12}You can obviously do object for key.\r\nDialogue: 0,0:40:51.61,0:40:54.42,yin,,0,0,0,, 这是通过键找值的很好方法 \\N{\\fs12}That’s a nice method for looking the value up by key.\r\nDialogue: 0,0:40:54.42,0:40:56.27,yin,,0,0,0,, 但你也可以使用方括号 \\N{\\fs12}But you can also use square brackets\r\nDialogue: 0,0:40:56.27,0:40:58.81,yin,,0,0,0,, 类似于在数组中查找 \\N{\\fs12}that looks kind of like looking up an array.\r\nDialogue: 0,0:40:58.81,0:41:01.57,yin,,0,0,0,, 例如幻灯片中的这个颜色字典 colors\\N{\\fs12}So if I had that colors dictionary that’s showing right there\r\nDialogue: 0,0:41:01.57,0:41:04.77,yin,,0,0,0,, 字符串有绿 蓝 红 \\N{\\fs12}and I had a string that was either green, or blue, or red,\r\nDialogue: 0,0:41:04.77,0:41:09.16,yin,,0,0,0,, 想要查找 我可以说 colors[colorString]\\N{\\fs12}and I wanted to look it up, I can just say colors, open square bracket, the color string.\r\nDialogue: 0,0:41:09.16,0:41:10.88,yin,,0,0,0,, 它会查找这个字符串 \\N{\\fs12}And it will look up that string.\r\nDialogue: 0,0:41:10.88,0:41:14.58,yin,,0,0,0,, 如果没有这样的键 它会返回 nil\\N{\\fs12}It would return nil if there’s no such key in there.\r\nDialogue: 0,0:41:14.58,0:41:18.03,yin,,0,0,0,, 如果存在 它会返回实际 UIColor 值 \\N{\\fs12}And it will return the value, the actual UI color.\r\nDialogue: 0,0:41:18.03,0:41:20.96,yin,,0,0,0,, 过几张幻灯片我会讲到 UIColor\\N{\\fs12}So we’re going to talk about UI colors in a couple slides.\r\nDialogue: 0,0:41:20.96,0:41:28.71,yin,,0,0,0,, 这也是访问事物的很酷语法 \\N{\\fs12}So this is also really cool UI — or syntax rather — for accessing stuff.\r\nDialogue: 0,0:41:28.71,0:41:31.06,yin,,0,0,0,, 这些 @方括号 @花括号 \\N{\\fs12}These at sign square brackets, at sign curly brace,\r\nDialogue: 0,0:41:31.06,0:41:35.42,yin,,0,0,0,,@圆括号 是 Objective-C 中的重大改进 \\N{\\fs12}at sign parenthesis — big improvement to Objective-C.\r\nDialogue: 0,0:41:35.42,0:41:38.58,yin,,0,0,0,, 当然 你也可以看其中有多少对象 \\N{\\fs12}Of course, you can see how many objects in there.\r\nDialogue: 0,0:41:38.58,0:41:40.52,yin,,0,0,0,, 你可以用 objectForKey 来得到它 \\N{\\fs12}You can do object for key to get it.\r\nDialogue: 0,0:41:40.52,0:41:43.71,yin,,0,0,0,, 键需要实现 hash 和 isEqual\\N{\\fs12}Key has to implement hash and is equal, right?\r\nDialogue: 0,0:41:43.71,0:41:45.18,yin,,0,0,0,, 这是一张 hash 表 \\N{\\fs12}It’s a hash table.\r\nDialogue: 0,0:41:45.18,0:41:48.37,yin,,0,0,0,, 你需要能够为键实现 hash 从而能够有效查找 \\N{\\fs12}You have to be able to hash the key so we can have an efficient lookup.\r\nDialogue: 0,0:41:48.37,0:41:50.62,yin,,0,0,0,, 但两个键可能 hash 到相同事物 \\N{\\fs12}But then two things might hash to the same thing,\r\nDialogue: 0,0:41:50.62,0:41:52.82,yin,,0,0,0,, 所以你需要 isEqual 来检验 \\N{\\fs12}so you have to have is equal determine whether\r\nDialogue: 0,0:41:52.82,0:41:56.18,yin,,0,0,0,,hash 到相同事物的两个对象是否相等 \\N{\\fs12}two objects that hash to the same thing are actually equal.\r\nDialogue: 0,0:41:56.18,0:42:00.37,yin,,0,0,0,,NSObject 对这个的实现很糟糕 \\N{\\fs12}NSObject implements this very poorly.\r\nDialogue: 0,0:42:00.37,0:42:06.14,yin,,0,0,0,, 千万别把一个通用对象 或你创建的某种对象的子类 \\N{\\fs12}So you would never use a generic object or some subclass of object that you’ve created.\r\nDialogue: 0,0:42:06.14,0:42:07.73,yin,,0,0,0,, 用作键 \\N{\\fs12}You would never use it as a key.\r\nDialogue: 0,0:42:07.75,0:42:10.64,yin,,0,0,0,, 你也许可以使用指针 hash\\N{\\fs12}You’re probably going to do pointer hashing.\r\nDialogue: 0,0:42:10.64,0:42:13.19,yin,,0,0,0,, 只在对象总是唯一时这才能行 \\N{\\fs12}So it would only do it if your objects are always unique.\r\nDialogue: 0,0:42:13.19,0:42:17.48,yin,,0,0,0,, 堆中两个相同对象不会具有不同指针 \\N{\\fs12}In the heap there’s never two objects that are the same that have different pointers.\r\nDialogue: 0,0:42:17.48,0:42:20.73,yin,,0,0,0,, 字符串在 NSDictionary 中是很好的键 \\N{\\fs12}Strings are excellent keys in NSDictionaries.\r\nDialogue: 0,0:42:20.73,0:42:26.14,yin,,0,0,0,, 我可以说 字典中的键 90% 的时候都是字符串 \\N{\\fs12}And so I would say strings are the key in a dictionary 90 percent of the time.\r\nDialogue: 0,0:42:26.14,0:42:27.41,yin,,0,0,0,, 它们很好 \\N{\\fs12}They’re very good.\r\nDialogue: 0,0:42:27.41,0:42:28.75,yin,,0,0,0,,hash 很好 \\N{\\fs12}They hash really well.\r\nDialogue: 0,0:42:28.75,0:42:32.97,yin,,0,0,0,, 它们很快 对 isEqual 很有利 等等 \\N{\\fs12}They’re very fast and do is equal, etc. Okay?\r\nDialogue: 0,0:42:32.97,0:42:35.37,yin,,0,0,0,, 当然 这是不可变的 \\N{\\fs12}Of course, immutable, again,\r\nDialogue: 0,0:42:35.37,0:42:38.22,yin,,0,0,0,, 有时我们希望将事物加到字典中 \\N{\\fs12}we’d like to sometimes add things to our dictionaries.\r\nDialogue: 0,0:42:38.22,0:42:40.63,yin,,0,0,0,, 所以我们有可变版本的 NSMutableDictionary\\N{\\fs12}So we have a mutable version, NSMutable dictionary.\r\nDialogue: 0,0:42:40.63,0:42:42.45,yin,,0,0,0,, 通常用 alloc init 创建 \\N{\\fs12}Usually create it with alloc init.\r\nDialogue: 0,0:42:42.47,0:42:44.15,yin,,0,0,0,, 字典有的它都有 \\N{\\fs12}It has all the things of a dictionary,\r\nDialogue: 0,0:42:44.15,0:42:46.06,yin,,0,0,0,, 此外 它还有 setObject: forKey:\\N{\\fs12}plus it has set object for key –\r\nDialogue: 0,0:42:46.06,0:42:48.09,yin,,0,0,0,, 来添加一个键值对 \\N{\\fs12}that adds a key value pair –\r\nDialogue: 0,0:42:48.09,0:42:52.40,yin,,0,0,0,, 你还可以删掉对象 从另一个字典中加入条目 等等 \\N{\\fs12}and you can remove objects, add entries from another dictionary, etc., etc.\r\nDialogue: 0,0:42:52.40,0:42:54.77,yin,,0,0,0,, 循环遍历字典是这样的 \\N{\\fs12}Looping through a dictionary looks like this.\r\nDialogue: 0,0:42:54.77,0:42:57.58,yin,,0,0,0,, 使用 for id key in 字典 \\N{\\fs12}You do for ID key in the dictionary.\r\nDialogue: 0,0:42:57.58,0:43:02.80,yin,,0,0,0,, 对字典使用 for in 结构 都是遍历键 \\N{\\fs12}So basically when you do for in on a dictionary, you’re looping through the keys.\r\nDialogue: 0,0:43:02.80,0:43:04.69,yin,,0,0,0,, 当然 循环中间就简单了 \\N{\\fs12}Now, of course, inside it’s really easy.\r\nDialogue: 0,0:43:04.69,0:43:07.15,yin,,0,0,0,, 你只需要 value 等于 objectForKey\\N{\\fs12}You just say, “Value equals object for key,”\r\nDialogue: 0,0:43:07.15,0:43:10.60,yin,,0,0,0,, 或者也可以使用方括号表示法来获得值 \\N{\\fs12}or even use the square brackets notation to get the value.\r\nDialogue: 0,0:43:10.60,0:43:12.95,yin,,0,0,0,, 这也就循环遍历了值 \\N{\\fs12}So you’re kind of looping through the values, too,\r\nDialogue: 0,0:43:12.95,0:43:15.30,yin,,0,0,0,, 只要你的 hash 非常有效 \\N{\\fs12}as long as your hashing is efficient,\r\nDialogue: 0,0:43:15.30,0:43:17.79,yin,,0,0,0,, 如果是字符串确实也会很有效 \\N{\\fs12}which it is if they’re strings. This is [inaudible].\r\nDialogue: 0,0:43:17.81,0:43:20.86,yin,,0,0,0,, 你还可以让字典 \\N{\\fs12}It is possible to ask a dictionary,\r\nDialogue: 0,0:43:20.86,0:43:23.64,yin,,0,0,0,, 将所有值作为数组给你 \\N{\\fs12}”Give me all your values as an array”?\r\nDialogue: 0,0:43:23.64,0:43:26.42,yin,,0,0,0,, 然后你可以在数组中使用 for in 循环 \\N{\\fs12}And then you could for in through that array.\r\nDialogue: 0,0:43:26.42,0:43:28.66,yin,,0,0,0,, 那是否比这更有效 \\N{\\fs12}And whether that’s more efficient than doing this probably\r\nDialogue: 0,0:43:28.66,0:43:31.39,yin,,0,0,0,, 取决于字典的规模等等 别太担心这些 \\N{\\fs12}depends on the size of your dictionary, etc., etc. Don’t worry about it.\r\nDialogue: 0,0:43:31.39,0:43:32.66,yin,,0,0,0,, 这门课中这不要紧 \\N{\\fs12}It’s never going to be an issue in this class.\r\nDialogue: 0,0:43:32.66,0:43:36.12,yin,,0,0,0,, 我们的字典中不会有成千上万的对象 \\N{\\fs12}We’re not going to have dictionaries of thousands of objects.\r\nDialogue: 0,0:43:38.29,0:43:42.53,yin,,0,0,0,, 我要讲的下一点不是类 不是语法 \\N{\\fs12}Next thing I’m going to talk about is not a class, or syntax,\r\nDialogue: 0,0:43:42.53,0:43:46.17,yin,,0,0,0,, 而是一个短语 属性列表 \\N{\\fs12}or whatever; it’s a word, a phrase — property list.\r\nDialogue: 0,0:43:46.17,0:43:48.10,yin,,0,0,0,, 我将定义这个术语 \\N{\\fs12}And I’m just going to define this term.\r\nDialogue: 0,0:43:48.10,0:43:50.40,yin,,0,0,0,, 你们需要知道属性列表是什么意思 \\N{\\fs12}You need to know what this term means, property list.\r\nDialogue: 0,0:43:50.40,0:43:54.56,yin,,0,0,0,, 属性列表的意思是 集合的集合 \\N{\\fs12}A property list means a “collection of collections.”\r\nDialogue: 0,0:43:54.56,0:43:56.15,yin,,0,0,0,, 什么是集合 \\N{\\fs12}What’s a collection?\r\nDialogue: 0,0:43:56.15,0:43:58.43,yin,,0,0,0,, 也就是 NSArray 字典 甚至字符串 \\N{\\fs12}NSArray, dictionary, even string,\r\nDialogue: 0,0:43:58.43,0:43:59.67,yin,,0,0,0,,NSData NSNumber\\N{\\fs12}NSData, NSNumber –\r\nDialogue: 0,0:43:59.67,0:44:02.21,yin,,0,0,0,, 这些都是简单的集合 \\N{\\fs12}those are all simple collections if you want it think of them\r\nDialogue: 0,0:44:02.21,0:44:05.48,yin,,0,0,0,, 或者可以把它们看成集合的叶节点 \\N{\\fs12}that way or they’re the leaf nodes of collections.\r\nDialogue: 0,0:44:05.48,0:44:08.38,yin,,0,0,0,, 任意对象图 只要其中只有数组 \\N{\\fs12}So if you have any object graph that just has arrays\r\nDialogue: 0,0:44:08.38,0:44:11.14,yin,,0,0,0,, 字典 数字 字符串 日期和数据这些 \\N{\\fs12}and dictionaries, numbers, strings, dates, and datas,\r\nDialogue: 0,0:44:11.14,0:44:13.41,yin,,0,0,0,, 那它就是属性列表了 \\N{\\fs12}then it’s called a “property list.”\r\nDialogue: 0,0:44:13.41,0:44:17.38,yin,,0,0,0,, 例如一个字符串数组就是属性列表 \\N{\\fs12}So just for an example, if you had an array of strings, that’s a property list;\r\nDialogue: 0,0:44:17.38,0:44:19.65,yin,,0,0,0,, 数组的数组 \\N{\\fs12}an array of arrays,\r\nDialogue: 0,0:44:19.65,0:44:23.54,yin,,0,0,0,, 而这些数组包含属性列表 那它也是属性列表 \\N{\\fs12}and those arrays contain property lists, it’s the property list.\r\nDialogue: 0,0:44:23.54,0:44:24.93,yin,,0,0,0,, 任意的图 \\N{\\fs12}So any arbitrary graph.\r\nDialogue: 0,0:44:24.93,0:44:27.36,yin,,0,0,0,, 只要其中有这些对象 \\N{\\fs12}But as soon as you have any object in there\r\nDialogue: 0,0:44:27.36,0:44:30.78,yin,,0,0,0,, 而且对象属于这些东西或者它们的可变版本 \\N{\\fs12}that’s not one of these things or they’re mutable versions –\r\nDialogue: 0,0:44:30.78,0:44:32.51,yin,,0,0,0,, 可变的这些也是允许的 \\N{\\fs12}that’s allowed, too; so you can have\r\nDialogue: 0,0:44:32.51,0:44:35.10,yin,,0,0,0,, 例如 NSMutableString 或 NSMutableArray\\N{\\fs12}NSMutableStrings or NSMutableArrays in there –\r\nDialogue: 0,0:44:35.10,0:44:37.54,yin,,0,0,0,, 这就是属性列表了 \\N{\\fs12}then it’s a property list.\r\nDialogue: 0,0:44:37.54,0:44:40.69,yin,,0,0,0,, 字典是属性列表的条件是 它所有的键 \\N{\\fs12}A dictionary is only a property list if all of its keys\r\nDialogue: 0,0:44:40.69,0:44:43.74,yin,,0,0,0,, 及所有值都是属性列表 \\N{\\fs12}and all of its values are property lists.\r\nDialogue: 0,0:44:43.74,0:44:46.28,yin,,0,0,0,, 例如键是字符串 值是数组或其它属性列表的字典 \\N{\\fs12}So a dictionary that keys are strings,\r\nDialogue: 0,0:44:46.28,0:44:50.17,yin,,0,0,0,, 例如键是字符串 值是数组或其它属性列表的字典 \\N{\\fs12}and values are arrays, or other dictionaries of property lists,\r\nDialogue: 0,0:44:50.17,0:44:52.10,yin,,0,0,0,, 将也是属性列表 \\N{\\fs12}that would be a property list.\r\nDialogue: 0,0:44:52.10,0:44:54.31,yin,,0,0,0,, 为什么要定义这个说法呢 \\N{\\fs12}Why do we define this term?\r\nDialogue: 0,0:44:54.31,0:44:57.61,yin,,0,0,0,, 因为 iOS 中有一系列 API\\N{\\fs12}Because there’s a bunch of API throughout iOS that you’re going\r\nDialogue: 0,0:44:57.61,0:45:01.19,yin,,0,0,0,, 将属性列表作为参数 \\N{\\fs12}to see that takes a property list as the argument.\r\nDialogue: 0,0:45:01.19,0:45:03.99,yin,,0,0,0,, 但属性列表只是我们定义的一个短语 \\N{\\fs12}But property list is only a phrase we define,\r\nDialogue: 0,0:45:03.99,0:45:07.84,yin,,0,0,0,, 其类型可能用的是 id\\N{\\fs12}so it’s probably going to take an ID. It’s going to take an ID.\r\nDialogue: 0,0:45:07.84,0:45:09.97,yin,,0,0,0,, 也可能是 NSArray 或 NSDictionary\\N{\\fs12}It might take an NSArray or an NSDictionary,\r\nDialogue: 0,0:45:09.97,0:45:11.21,yin,,0,0,0,, 取决于 API\\N{\\fs12}depending on the API.\r\nDialogue: 0,0:45:11.21,0:45:15.10,yin,,0,0,0,, 不过在说明文档中 它说的基本上是 \\N{\\fs12}But it’s basically saying in its documentation,\r\nDialogue: 0,0:45:15.10,0:45:17.28,yin,,0,0,0,, 这个的参数是属性列表 \\N{\\fs12}”The argument to this is a property list.”\r\nDialogue: 0,0:45:17.28,0:45:20.40,yin,,0,0,0,, 如果是数组 那就是属性列表的数组 \\N{\\fs12}So even if it’s an array, it’s got to be an array of property lists.\r\nDialogue: 0,0:45:20.40,0:45:21.62,yin,,0,0,0,, 如果是字典 \\N{\\fs12}If it’s a dictionary, it’s got to be\r\nDialogue: 0,0:45:21.62,0:45:23.77,yin,,0,0,0,, 那就是键和值只有属性列表的字典 \\N{\\fs12}a dictionary that has only property lists with keys and values.\r\nDialogue: 0,0:45:23.77,0:45:27.84,yin,,0,0,0,, 如果是 id 它将是数组 字典 字符串或数字 \\N{\\fs12}If it’s an ID, it’s got to be an array, or a dictionary, or a string, or number.\r\nDialogue: 0,0:45:27.84,0:45:30.17,yin,,0,0,0,, 这必须是一个属性列表 \\N{\\fs12}You know what I mean? It’s got to be a property list.\r\nDialogue: 0,0:45:30.19,0:45:31.28,yin,,0,0,0,, 能理解吗 \\N{\\fs12}Make sense?\r\nDialogue: 0,0:45:31.30,0:45:35.89,yin,,0,0,0,, 实际上 我要讲一个只作用于属性列表的类 \\N{\\fs12}And in fact, I’m going to show you one class that only operates on property lists,\r\nDialogue: 0,0:45:35.90,0:45:37.83,yin,,0,0,0,, 也就是 NSUserDefaults\\N{\\fs12}which is NSUserDefaults.\r\nDialogue: 0,0:45:37.83,0:45:42.48,yin,,0,0,0,,NSUserDefaults 是一种共享字典 \\N{\\fs12}So NSUserDefaults is this one shared dictionary essentially\r\nDialogue: 0,0:45:42.48,0:45:48.22,yin,,0,0,0,, 这甚至在应用程序启动和退出时仍然持续存在 \\N{\\fs12}that persists, even across application launching. Exiting and launching.\r\nDialogue: 0,0:45:48.22,0:45:52.62,yin,,0,0,0,, 它就像是一个永久的 NSDictionary\\N{\\fs12}So it’s like a permanent NSDictionary kind of.\r\nDialogue: 0,0:45:52.62,0:45:55.60,yin,,0,0,0,,NSUserDefaults 数据库中存储的一切 \\N{\\fs12}Everything that’s stored in an NSUserDefault database\r\nDialogue: 0,0:45:55.60,0:45:57.35,yin,,0,0,0,, 都必须是一个属性列表 \\N{\\fs12}has to be a property list.\r\nDialogue: 0,0:45:57.35,0:46:01.01,yin,,0,0,0,, 不过它并非一个完全的数据库 \\N{\\fs12}So it’s not a full-on database, though.\r\nDialogue: 0,0:46:01.01,0:46:02.79,yin,,0,0,0,, 它很小 \\N{\\fs12}It’s pretty small.\r\nDialogue: 0,0:46:02.79,0:46:04.83,yin,,0,0,0,, 性能不是很好 \\N{\\fs12}It’s not really high performance.\r\nDialogue: 0,0:46:04.83,0:46:07.98,yin,,0,0,0,, 你只能将小东西存放到这里 \\N{\\fs12}So you only want to store small things in there.\r\nDialogue: 0,0:46:07.98,0:46:10.73,yin,,0,0,0,, 不要存放大型图片这样的东西 \\N{\\fs12}Okay. You don’t want to be storing huge images or anything\r\nDialogue: 0,0:46:10.73,0:46:13.90,yin,,0,0,0,, 将它们转化为 NSData 然后存储 \\N{\\fs12}like that, you know, turning them into NSDatas or something and storing them.\r\nDialogue: 0,0:46:13.90,0:46:14.90,yin,,0,0,0,, 不要这样做 \\N{\\fs12}You really don’t want to do that.\r\nDialogue: 0,0:46:14.90,0:46:19.78,yin,,0,0,0,, 小字符串 字符串数组 NSNumber\\N{\\fs12}Small strings, and arrays of strings, and NSNumbers,\r\nDialogue: 0,0:46:19.78,0:46:24.12,yin,,0,0,0,, 日期 这些东西是可以的 \\N{\\fs12}dates maybe — those kind of things is okay.\r\nDialogue: 0,0:46:24.12,0:46:25.62,yin,,0,0,0,, 其 API\\N{\\fs12}Its API.\r\nDialogue: 0,0:46:25.62,0:46:29.28,yin,,0,0,0,, 要访问它 你要调用 NSUserDefaults 的这个类方法 \\N{\\fs12}To access it, you call this class method on NSUserDefaults\r\nDialogue: 0,0:46:29.28,0:46:30.64,yin,,0,0,0,, 叫 standardUserDefaults\\N{\\fs12}called “standard user defaults.”\r\nDialogue: 0,0:46:30.64,0:46:34.36,yin,,0,0,0,, 这会给你整个应用中共享的一个实例 \\N{\\fs12}And that will give you an instance that is shared across your entire application.\r\nDialogue: 0,0:46:34.36,0:46:35.71,yin,,0,0,0,, 这是全局的 \\N{\\fs12}It’s like a global.\r\nDialogue: 0,0:46:35.71,0:46:38.17,yin,,0,0,0,, 这种东西只有一个 \\N{\\fs12}There’s only one of these things.\r\nDialogue: 0,0:46:38.17,0:46:42.77,yin,,0,0,0,, 你将消息发送给它 例如 setArray: forKey:\\N{\\fs12}And you send messages to it like this set array for key.\r\nDialogue: 0,0:46:42.77,0:46:45.65,yin,,0,0,0,, 还有 setDouble: forKey:\\N{\\fs12}There’s also set double for key,\r\nDialogue: 0,0:46:45.65,0:46:47.14,yin,,0,0,0,,setObject: forKey:\\N{\\fs12}set object for key.\r\nDialogue: 0,0:46:47.14,0:46:49.55,yin,,0,0,0,, 这一对象需要是属性列表 \\N{\\fs12}That object would have to be a property list.\r\nDialogue: 0,0:46:49.55,0:46:51.43,yin,,0,0,0,, 这就像是一个字典 \\N{\\fs12}So it’s kind of like a dictionary\r\nDialogue: 0,0:46:51.43,0:46:54.17,yin,,0,0,0,, 但它还有这些额外方法 如 setDouble: forKey:\\N{\\fs12}but it has these extra method like set double for key\r\nDialogue: 0,0:46:54.17,0:46:56.93,yin,,0,0,0,, 这样你就能够存储原始类型到这里 \\N{\\fs12}so that you can store primitive types in there\r\nDialogue: 0,0:46:56.93,0:46:59.11,yin,,0,0,0,, 无需先将它们转化为 NSNumber\\N{\\fs12}without having to turn them into NSNumbers first.\r\nDialogue: 0,0:46:59.11,0:47:01.82,yin,,0,0,0,, 这里可以说是得到类型检查 \\N{\\fs12}You know, it kind of gets the type checking of it\r\nDialogue: 0,0:47:01.82,0:47:03.89,yin,,0,0,0,, 而不只是 setObject: forKey:\\N{\\fs12}versus just set object for key where\r\nDialogue: 0,0:47:03.89,0:47:07.04,yin,,0,0,0,, 不知道类型是不是 double 等等 \\N{\\fs12}it doesn’t know whether that’s a double or not, etc.\r\nDialogue: 0,0:47:07.04,0:47:09.53,yin,,0,0,0,, 有的这种东西 因为现在我们有了自动装箱 \\N{\\fs12}And some of this — because now we have the autoboxing,\r\nDialogue: 0,0:47:09.53,0:47:11.74,yin,,0,0,0,, 你们知道 @括号这些东西 \\N{\\fs12}you know, the at sign parenthesis business –\r\nDialogue: 0,0:47:11.74,0:47:14.88,yin,,0,0,0,, 有的 API 我们不再那么需要 \\N{\\fs12}some of this API we don’t really need that much anymore.\r\nDialogue: 0,0:47:14.88,0:47:17.67,yin,,0,0,0,, 但它仍然在这里 请讲 \\N{\\fs12}But it’s all still in there. Yeah?\r\nDialogue: 0,0:47:24.13,0:47:26.38,yin,,0,0,0,, 问题是 属性列表这个概念 \\N{\\fs12}Yeah. So the question is: Does the property list idea have\r\nDialogue: 0,0:47:26.38,0:47:28.92,yin,,0,0,0,, 是否往下逐步应用到子内容 \\N{\\fs12}to cascade down through all of the sub things?\r\nDialogue: 0,0:47:28.92,0:47:30.30,yin,,0,0,0,, 答案是肯定的 \\N{\\fs12}And the answer is yes.\r\nDialogue: 0,0:47:30.30,0:47:32.21,yin,,0,0,0,, 要成为属性列表 \\N{\\fs12}A property list, for it to be a property list,\r\nDialogue: 0,0:47:32.21,0:47:35.99,yin,,0,0,0,, 整个对象图中的一切都需要是属性列表 \\N{\\fs12}everything in the entire object graph has to be a property list.\r\nDialogue: 0,0:47:35.99,0:47:37.17,yin,,0,0,0,, 一直往下 \\N{\\fs12}All the way down.\r\nDialogue: 0,0:47:37.17,0:47:39.09,yin,,0,0,0,, 没有例外 \\N{\\fs12}No exceptions.\r\nDialogue: 0,0:47:39.09,0:47:41.88,yin,,0,0,0,, 如果你要调用 setObject: forKey: 这些 \\N{\\fs12}And if you were to, for example, call set object for key\r\nDialogue: 0,0:47:41.88,0:47:46.38,yin,,0,0,0,, 你将它往下传递到一个叶节点 它是 Card\\N{\\fs12}and you passed it something that somewhere down a leaf node was a card, right,\r\nDialogue: 0,0:47:46.38,0:47:48.34,yin,,0,0,0,, 或某种非属性列表的东西 \\N{\\fs12}or some nonproperty list thing,\r\nDialogue: 0,0:47:48.34,0:47:51.15,yin,,0,0,0,, 这个方法会引发异常 说 \\N{\\fs12}this method would raise an exception and say,\r\nDialogue: 0,0:47:51.15,0:47:53.63,yin,,0,0,0,, 这不是属性列表 这是在运行时 \\N{\\fs12}”That’s not a property list,” okay, at runtime.\r\nDialogue: 0,0:47:53.63,0:47:55.87,yin,,0,0,0,, 这会让程序崩溃 \\N{\\fs12}So it would crash your program.\r\nDialogue: 0,0:47:57.19,0:47:58.91,yin,,0,0,0,, 还要记住一点 \\N{\\fs12}The other thing to remember, though,\r\nDialogue: 0,0:47:58.91,0:48:01.55,yin,,0,0,0,, 一旦得到这种 standardUserDefaults 实例 \\N{\\fs12}is once you’ve gotten this standard user default instance\r\nDialogue: 0,0:48:01.55,0:48:02.93,yin,,0,0,0,, 且你存储了你想存储的 \\N{\\fs12}and you’ve stored what you want,\r\nDialogue: 0,0:48:02.93,0:48:06.50,yin,,0,0,0,, 你需要调用这个 synchronize 方法来同步 \\N{\\fs12}you have to call this method synchronize on the instance.\r\nDialogue: 0,0:48:06.50,0:48:08.30,yin,,0,0,0,,[NSUserDefaults standardUserDefaults]\\N{\\fs12}So NSUserDefault, standard user default,\r\nDialogue: 0,0:48:08.30,0:48:09.14,yin,,0,0,0,,synchronize\\N{\\fs12}synchronize.\r\nDialogue: 0,0:48:09.14,0:48:11.45,yin,,0,0,0,, 这是让它永久的东西 \\N{\\fs12}That’s what makes it permanent.\r\nDialogue: 0,0:48:11.45,0:48:15.49,yin,,0,0,0,, 你写了一些东西 一些批处理 然后同步 \\N{\\fs12}So you write a few things, a little batch, and then synchronize.\r\nDialogue: 0,0:48:15.49,0:48:18.85,yin,,0,0,0,, 不要忘记同步 \\N{\\fs12}Don’t forget to synchronize.\r\nDialogue: 0,0:48:18.85,0:48:21.73,yin,,0,0,0,, 如果你要在这里设置一些东西 \\N{\\fs12}If you were to set some things in there\r\nDialogue: 0,0:48:21.73,0:48:25.66,yin,,0,0,0,,app 在同步之前崩溃 它不会得到同步化 \\N{\\fs12}and your app crashed before you did the synchronize, it would not get synced.\r\nDialogue: 0,0:48:25.66,0:48:29.56,yin,,0,0,0,,app 重启时 你存入那里的东西会消失 \\N{\\fs12}When your app launched again it would be gone, the stuff you put in there.\r\nDialogue: 0,0:48:31.80,0:48:37.43,yin,,0,0,0,,Foundation 的核心部分中 我要讲的最后一点是 \\N{\\fs12}The last thing really I’m going to talk about that’s kind of in the core part of Foundation\r\nDialogue: 0,0:48:37.43,0:48:40.06,yin,,0,0,0,,NSRange 也是一种 C struct\\N{\\fs12}is NSRange, which is just a C struct.\r\nDialogue: 0,0:48:40.06,0:48:42.31,yin,,0,0,0,, 顾名思义 它描述一个范围 \\N{\\fs12}It’s exactly what you think: It describes a range.\r\nDialogue: 0,0:48:42.31,0:48:45.84,yin,,0,0,0,, 这可以是字符串的范围 也可以是数组的范围 \\N{\\fs12}This might be a range in a string or it could be a range in an array.\r\nDialogue: 0,0:48:45.84,0:48:47.58,yin,,0,0,0,, 基本上是一个开始位置 \\N{\\fs12}It’s basically a starting location,\r\nDialogue: 0,0:48:47.58,0:48:49.47,yin,,0,0,0,, 也就是 NSUInteger location\\N{\\fs12}that’s the NSUInteger location\r\nDialogue: 0,0:48:49.47,0:48:50.46,yin,,0,0,0,, 还有长度 \\N{\\fs12}and a length –\r\nDialogue: 0,0:48:50.46,0:48:53.84,yin,,0,0,0,, 有多少字符 或数组中有多少项目 \\N{\\fs12}how many characters or how many items in the array?\r\nDialogue: 0,0:48:53.84,0:48:58.40,yin,,0,0,0,, 有一个重要的常数叫作 NSNotFound\\N{\\fs12}There’s an important constant called NSNotFound.\r\nDialogue: 0,0:48:58.40,0:49:03.41,yin,,0,0,0,,NSNotFound 是 range 中 location 值 \\N{\\fs12}NSNotFound is the value of location in a range\r\nDialogue: 0,0:49:03.41,0:49:06.42,yin,,0,0,0,, 没有被发现 或者无效 \\N{\\fs12}that was not found or that is otherwise invalid.\r\nDialogue: 0,0:49:06.42,0:49:10.15,yin,,0,0,0,, 例如 在一个字符串中搜索子字符串 \\N{\\fs12}Okay. So it’s, like, search for a substring in a string\r\nDialogue: 0,0:49:10.15,0:49:13.20,yin,,0,0,0,, 结果找不到 这就会返回一个 range\\N{\\fs12}and it couldn’t find it, you’re going to get a range back\r\nDialogue: 0,0:49:13.20,0:49:17.22,yin,,0,0,0,, 其位置将是 NSNotFound\\N{\\fs12}that the location is going to be NSNotFound.\r\nDialogue: 0,0:49:17.22,0:49:19.37,yin,,0,0,0,, 大家都理解吗 \\N{\\fs12}Everyone understand that?\r\nDialogue: 0,0:49:19.37,0:49:22.70,yin,,0,0,0,, 然后还有这个 NSRangePointer\\N{\\fs12}There’s also this thing, NSRangePointer.\r\nDialogue: 0,0:49:22.70,0:49:25.03,yin,,0,0,0,, 这其实是一个 NSRange\\N{\\fs12}That’s basically just an NSRange star.\r\nDialogue: 0,0:49:25.03,0:49:31.64,yin,,0,0,0,, 我讲过 iOS 中 我们不会将 struct 放到堆中 \\N{\\fs12}Okay. Now I told you in iOS we don’t really put structs in the heap and we don’t.\r\nDialogue: 0,0:49:31.64,0:49:35.97,yin,,0,0,0,, 这个 NSRangePointer 用于引用调用 range\\N{\\fs12}This NSRangePointer is for call by reference ranges.\r\nDialogue: 0,0:49:35.97,0:49:40.70,yin,,0,0,0,, 有些方法会将 NSRangePointer 作为参数 \\N{\\fs12}So some methods will take an NSRangePointer as an argument — one of its arguments –\r\nDialogue: 0,0:49:40.70,0:49:41.91,yin,,0,0,0,, 这里说的是 \\N{\\fs12}and what it’s saying there is,\r\nDialogue: 0,0:49:41.91,0:49:43.89,yin,,0,0,0,, 如果你将一个指向 range 的指针传递给我 \\N{\\fs12}”If you pass me a pointer to a range,\r\nDialogue: 0,0:49:43.89,0:49:46.10,yin,,0,0,0,, 我将使用一些信息填充它 \\N{\\fs12}I’ll fill it in with some information.”\r\nDialogue: 0,0:49:46.10,0:49:47.93,yin,,0,0,0,, 这里你几乎总是可以传递 null\\N{\\fs12}Almost always you can pass null there\r\nDialogue: 0,0:49:47.93,0:49:50.57,yin,,0,0,0,, 它不会填入任何信息 因为你没有指向一个 range\\N{\\fs12}and it won’t fill the information in because you won’t be pointing to a range.\r\nDialogue: 0,0:49:50.57,0:49:55.42,yin,,0,0,0,, 但这是用于引用 大家都理解引用调用吗 \\N{\\fs12}But it’s for reference. Everyone know what it means to call by reference?\r\nDialogue: 0,0:49:55.42,0:49:56.65,yin,,0,0,0,, 有问题 \\N{\\fs12}Question?\r\nDialogue: 0,0:49:58.59,0:50:01.73,yin,,0,0,0,, 学生：我只是好奇 为什么你用 unsigned\\N{\\fs12}> Just out of curiosity, why are you using unsigned\r\nDialogue: 0,0:50:01.73,0:50:05.51,yin,,0,0,0,, 或者说为什么苹果选择对 range 使用 unsigned\\N{\\fs12}or why did Apple choose to use unsigned on its range.\r\nDialogue: 0,0:50:05.51,0:50:09.89,yin,,0,0,0,, 看起来好像不能用负数来表示 range\\N{\\fs12}It seems like you can’t represent a range over negative numbers.\r\nDialogue: 0,0:50:09.89,0:50:12.57,yin,,0,0,0,, 老师：问题是 为什么苹果选择 \\N{\\fs12}> Yeah. So the question is: Why did Apple choose\r\nDialogue: 0,0:50:12.57,0:50:15.03,yin,,0,0,0,, 将 location 值预设为无符号整数 \\N{\\fs12}to make location be an unsigned integer?\r\nDialogue: 0,0:50:15.03,0:50:18.88,yin,,0,0,0,, 换句话说 为什么 range 只能是正的范围 \\N{\\fs12}In other words, why can the range only be a positive range?\r\nDialogue: 0,0:50:18.88,0:50:22.47,yin,,0,0,0,, 我想 主要原因可能在于 \\N{\\fs12}And I think the main reason they did that is, you know,\r\nDialogue: 0,0:50:22.47,0:50:24.82,yin,,0,0,0,, 他们是为自己的目的设计 NSRange 的 \\N{\\fs12}they designed NSRange for their own purposes,\r\nDialogue: 0,0:50:24.82,0:50:27.22,yin,,0,0,0,, 例如数组的范围 字符串的范围 \\N{\\fs12}like ranges in arrays, ranges in strings.\r\nDialogue: 0,0:50:27.22,0:50:28.96,yin,,0,0,0,, 他们不想像那样表示 \\N{\\fs12}They never want to represent that.\r\nDialogue: 0,0:50:28.96,0:50:34.24,yin,,0,0,0,, 而且我敢打赌 NSNotFound 要么是最大整数 \\N{\\fs12}And I will bet you dollars to doughnuts NSNotFound is either the maximum integer\r\nDialogue: 0,0:50:34.24,0:50:36.67,yin,,0,0,0,, 要么是负数 \\N{\\fs12}or it’s minus, you know, whatever, negative,\r\nDialogue: 0,0:50:36.67,0:50:38.07,yin,,0,0,0,, 这些有时是一样的 \\N{\\fs12}which sometimes are the same thing, right?\r\nDialogue: 0,0:50:38.07,0:50:39.76,yin,,0,0,0,, 计算机科学就是这样 \\N{\\fs12}If you know how computer science works,\r\nDialogue: 0,0:50:39.76,0:50:42.88,yin,,0,0,0,, 很多时候 所有二进制数倒过来 这就是 -1\\N{\\fs12}a lot of times it’s all the bits inverted, that’s minus one\r\nDialogue: 0,0:50:42.88,0:50:44.35,yin,,0,0,0,, 这也是范围的最后 \\N{\\fs12}that also would be at the end of the range.\r\nDialogue: 0,0:50:44.35,0:50:48.76,yin,,0,0,0,, 我想 这是因为他们不需要其它的 \\N{\\fs12}So I think it’s just because they didn’t need it for anything else and they wanted\r\nDialogue: 0,0:50:48.76,0:50:51.76,yin,,0,0,0,, 他们希望自己的 API 尽可能简洁明了 \\N{\\fs12}to make their API clearer possibly.\r\nDialogue: 0,0:50:51.76,0:50:52.54,yin,,0,0,0,, 我不知道 \\N{\\fs12}I don’t know.\r\nDialogue: 0,0:50:52.54,0:50:58.08,yin,,0,0,0,, 我从未在苹果干过 所以我不知道他们为什么那么做 \\N{\\fs12}I don’t work at Apple — never did — so I don’t really know why they did that.\r\nDialogue: 0,0:50:58.08,0:51:01.59,yin,,0,0,0,, 以上就是 Foundation 方面 我要讲的所有内容了 \\N{\\fs12}Okay. So that’s really kind of it for the Foundational stuff.\r\nDialogue: 0,0:51:01.59,0:51:03.73,yin,,0,0,0,, 我还会讲到 Foundation 中的一些类 \\N{\\fs12}I am going to talk about some more classes in Foundation.\r\nDialogue: 0,0:51:03.73,0:51:07.90,yin,,0,0,0,, 但首先 我先转换一下主题 讨论 UIKit 中的一些类 \\N{\\fs12}But first we’re going to take a little detour and talk about a couple classes in UIkit.\r\nDialogue: 0,0:51:07.90,0:51:10.89,yin,,0,0,0,, 也就是颜色和字体 \\N{\\fs12}And those are colors and fonts.\r\nDialogue: 0,0:51:10.89,0:51:15.49,yin,,0,0,0,,UIColor 是超级简单的类 表示颜色 \\N{\\fs12}All right. So UIColor, super simple class, represents a color.\r\nDialogue: 0,0:51:15.49,0:51:18.87,yin,,0,0,0,, 颜色可以用很多方式表示 \\N{\\fs12}The color can be represented in so many different ways,\r\nDialogue: 0,0:51:18.87,0:51:21.25,yin,,0,0,0,, 包括 RGB 即红绿蓝 \\N{\\fs12}RGB — red, green, blue, right?\r\nDialogue: 0,0:51:21.25,0:51:23.23,yin,,0,0,0,,HSB 即色调 饱和度 亮度 \\N{\\fs12}HSB, that’s hue, saturation, and brightness.\r\nDialogue: 0,0:51:23.23,0:51:24.91,yin,,0,0,0,, 它甚至可以是一个样式 \\N{\\fs12}It could even be a pattern.\r\nDialogue: 0,0:51:24.91,0:51:28.67,yin,,0,0,0,, 你可以让颜色是一个 UIImage 样式 \\N{\\fs12}Okay. So you can have a color that is a UI image pattern in there.\r\nDialogue: 0,0:51:28.67,0:51:31.36,yin,,0,0,0,, 当你用那个颜色绘图时 它会用那个样式 \\N{\\fs12}And when you draw with that color, it will draw with the pattern.\r\nDialogue: 0,0:51:31.36,0:51:35.57,yin,,0,0,0,, 颜色 超级强大 但 API 很简单明了 \\N{\\fs12}So color, super powerful but nice and simple API.\r\nDialogue: 0,0:51:35.57,0:51:38.44,yin,,0,0,0,, 颜色还可以有 alpha\\N{\\fs12}Colors can also have alpha.\r\nDialogue: 0,0:51:38.44,0:51:41.30,yin,,0,0,0,, 多少人不知道 alpha 是什么 \\N{\\fs12}Okay. How many people in here do not know what alpha is?\r\nDialogue: 0,0:51:41.30,0:51:42.81,yin,,0,0,0,, 没听过 alpha 这个词 \\N{\\fs12}Never heard the phrase “alpha”?\r\nDialogue: 0,0:51:42.81,0:51:44.08,yin,,0,0,0,, 大家都知道 alpha 是什么 \\N{\\fs12}So everybody knows what alpha is.\r\nDialogue: 0,0:51:44.08,0:51:45.30,yin,,0,0,0,, 它是第一个希腊字母 \\N{\\fs12}Okay. So that’s a first.\r\nDialogue: 0,0:51:45.30,0:51:49.03,yin,,0,0,0,,alpha 在计算机图形中表示透明度 \\N{\\fs12}So alpha, which in computer graphics is how transparent it\r\nDialogue: 0,0:51:49.03,0:51:53.12,yin,,0,0,0,,1 表示完全不透明 0 表示完全透明 \\N{\\fs12}is — one being fully opaque and zero being fully transparent.\r\nDialogue: 0,0:51:53.12,0:51:56.75,yin,,0,0,0,, 你可以创建部分透明的颜色 \\N{\\fs12}You can create colors that are partially transparent.\r\nDialogue: 0,0:51:56.75,0:52:00.58,yin,,0,0,0,, 用它们绘图时 你会看到它们是如何填充的 \\N{\\fs12}And then if you draw with them, you’ll be able to see behind where you filled in.\r\nDialogue: 0,0:52:00.58,0:52:02.73,yin,,0,0,0,, 颜色很酷 \\N{\\fs12}So colors are really cool.\r\nDialogue: 0,0:52:02.73,0:52:06.14,yin,,0,0,0,, 颜色有一些标准的 \\N{\\fs12}There’s a handful of kind of standard colors –\r\nDialogue: 0,0:52:06.14,0:52:09.04,yin,,0,0,0,, 绿色 红色 紫色 等等 \\N{\\fs12}the green color, red color, purple color, whatever.\r\nDialogue: 0,0:52:09.04,0:52:12.28,yin,,0,0,0,, 你可以在说明文档中找到这些 \\N{\\fs12}You can look in its documentation to find those.\r\nDialogue: 0,0:52:12.28,0:52:13.66,yin,,0,0,0,, 它们只不过是类方法 \\N{\\fs12}They’re just class method.\r\nDialogue: 0,0:52:13.66,0:52:16.43,yin,,0,0,0,, 然后还有一些方法 像 lightTextColor\\N{\\fs12}There’s also a few methods in there like the light text color,\r\nDialogue: 0,0:52:16.43,0:52:19.88,yin,,0,0,0,, 这是为浅色文本 禁用文本这些准备的灰色阴影 \\N{\\fs12}which is the shade of gray for light text, disabled text, or whatever.\r\nDialogue: 0,0:52:19.88,0:52:21.62,yin,,0,0,0,, 这些你们都可以看看 \\N{\\fs12}So you can look at all that.\r\nDialogue: 0,0:52:21.62,0:52:22.80,yin,,0,0,0,, 颜色很简单 \\N{\\fs12}So colors are simple.\r\nDialogue: 0,0:52:22.80,0:52:25.32,yin,,0,0,0,, 字体 没这么简单 \\N{\\fs12}Fonts, not so simple.\r\nDialogue: 0,0:52:25.32,0:52:32.00,yin,,0,0,0,,iOS7 中 将字体设置正确是非常重要的 \\N{\\fs12}Now, fonts in iOS 7 are incredibly important to get right.\r\nDialogue: 0,0:52:32.00,0:52:38.37,yin,,0,0,0,,iOS7 的 UI 设计 很大一部分都取决于字体选择 \\N{\\fs12}A huge percentage of good iOS 7 UI design is picking the right fronts,\r\nDialogue: 0,0:52:38.37,0:52:44.32,yin,,0,0,0,, 使用方式正确 以及屏幕排列美观 \\N{\\fs12}and using fonts in the right way, arranging fonts on screen in a nice way.\r\nDialogue: 0,0:52:44.32,0:52:45.13,yin,,0,0,0,, 超级重要 \\N{\\fs12}Super important.\r\nDialogue: 0,0:52:45.13,0:52:48.17,yin,,0,0,0,, 所以 iOS7 中有很多新支持 \\N{\\fs12}So there’s a lot of support in iOS 7 that’s new\r\nDialogue: 0,0:52:48.17,0:52:52.72,yin,,0,0,0,, 帮助我们更容易将字体设置正确 \\N{\\fs12}that is basically about making it easy to do the right thing with fonts.\r\nDialogue: 0,0:52:52.72,0:52:55.70,yin,,0,0,0,, 这里我列出了一些 iOS7 app 的例子 \\N{\\fs12}So I put up some examples of some iOS 7 apps here.\r\nDialogue: 0,0:52:55.70,0:52:59.69,yin,,0,0,0,, 可以看到所有这些例子中 字体具有怎样的重要作用 \\N{\\fs12}And you can see how front and center fonts are on all these things.\r\nDialogue: 0,0:52:59.69,0:53:04.25,yin,,0,0,0,, 如果字体很丑 例如没有用粗体 \\N{\\fs12}If you had ugly fonts here or you didn’t have bold,\r\nDialogue: 0,0:53:04.25,0:53:07.07,yin,,0,0,0,, 或者字体之间揉在一起 \\N{\\fs12}or you had, you know, fronts that were too smashed together\r\nDialogue: 0,0:53:07.07,0:53:10.13,yin,,0,0,0,, 或很难读 或颜色错误 \\N{\\fs12}or hard to read or the wrong color,\r\nDialogue: 0,0:53:10.13,0:53:16.01,yin,,0,0,0,, 这些 UI 将会很难辨识 \\N{\\fs12}these UIs would be, you know, impossible to decipher or very difficult to decipher here.\r\nDialogue: 0,0:53:16.01,0:53:22.02,yin,,0,0,0,, 所以 颜色 背景颜色 还有字体大小 \\N{\\fs12}So color, and background colors, and, you know, the size of fonts,\r\nDialogue: 0,0:53:22.02,0:53:26.57,yin,,0,0,0,, 所有这些在应用中都至关重要 \\N{\\fs12}and all these things are all critically important in all of these applications.\r\nDialogue: 0,0:53:26.57,0:53:30.54,yin,,0,0,0,, 我将简单讲一下如何处理这些 \\N{\\fs12}So we’re going to talk a little bit about how to deal\r\nDialogue: 0,0:53:30.54,0:53:34.84,yin,,0,0,0,, 以及 iOS7 中所有这些是如何做到的 \\N{\\fs12}with this and what’s in there for iOS 7 to make this happen.\r\nDialogue: 0,0:53:34.84,0:53:39.97,yin,,0,0,0,, 很不幸 我课上没有足够时间详细讲解所有这些 \\N{\\fs12}Unfortunately, I don’t have enough time in lecture in general to go through all of this.\r\nDialogue: 0,0:53:39.97,0:53:44.15,yin,,0,0,0,, 我们会在关于 UI 的课堂和演示中 \\N{\\fs12}I’ll kind of distribute little bits of wisdom about it as we go\r\nDialogue: 0,0:53:44.15,0:53:49.13,yin,,0,0,0,, 零星讲到其中一些内容 \\N{\\fs12}through various UIs in lecture, and demos, and things like that.\r\nDialogue: 0,0:53:49.13,0:53:51.65,yin,,0,0,0,, 今天我将大致介绍一下基础 \\N{\\fs12}What I’m going to try and give you today is just the basis\r\nDialogue: 0,0:53:51.65,0:53:55.05,yin,,0,0,0,, 告诉你们如何将文字呈现在屏幕上 \\N{\\fs12}for how we present text on screen.\r\nDialogue: 0,0:53:55.05,0:53:57.02,yin,,0,0,0,, 这方面有哪些基本内容 \\N{\\fs12}What the primitives are for that\r\nDialogue: 0,0:53:57.02,0:53:59.98,yin,,0,0,0,, 如何正确使用并保持一致 \\N{\\fs12}and how we do it in the right way so that we get consistency.\r\nDialogue: 0,0:53:59.98,0:54:01.62,yin,,0,0,0,, 注意 所有这些 app 中 \\N{\\fs12}See, the one thing about all these apps –\r\nDialogue: 0,0:54:01.62,0:54:06.25,yin,,0,0,0,, 都有粗体 以及可以点击的字体 \\N{\\fs12}do you see how the bold font, and the fonts you can click on,\r\nDialogue: 0,0:54:06.25,0:54:08.17,yin,,0,0,0,, 还有小的子标题字体 \\N{\\fs12}and the kind of little subheading fonts,\r\nDialogue: 0,0:54:08.17,0:54:13.30,yin,,0,0,0,, 它们都是相关的字体 相同种类 也许 也许不是 \\N{\\fs12}they’re all related fonts, same family — maybe, maybe not.\r\nDialogue: 0,0:54:13.30,0:54:14.67,yin,,0,0,0,, 但它们是相关的 \\N{\\fs12}But they’re related.\r\nDialogue: 0,0:54:14.67,0:54:16.30,yin,,0,0,0,, 大小相同 \\N{\\fs12}They’re the same sizes.\r\nDialogue: 0,0:54:16.30,0:54:19.44,yin,,0,0,0,, 看起来一样 因此所有 app 都有类似的外观 \\N{\\fs12}They look the same. So all the apps kind of have a similar look.\r\nDialogue: 0,0:54:19.44,0:54:21.90,yin,,0,0,0,, 因为它们的字体使用都很合适 \\N{\\fs12}That’s because they’re all using fonts properly.\r\nDialogue: 0,0:54:21.90,0:54:24.96,yin,,0,0,0,, 我来讲讲字体 \\N{\\fs12}So let’s talk about fonts.\r\nDialogue: 0,0:54:24.96,0:54:27.44,yin,,0,0,0,, 关于字体要了解的最重要一点是 \\N{\\fs12}The most important thing to understand about fonts is\r\nDialogue: 0,0:54:27.44,0:54:31.58,yin,,0,0,0,, 如果你在展示用户内容 也就是用户的信息 \\N{\\fs12}that if you’re displaying user content — okay, that the user’s information.\r\nDialogue: 0,0:54:31.58,0:54:34.73,yin,,0,0,0,, 在日历中 也就是预约 日期 \\N{\\fs12}So in the calendar that’s the appointments, and the days\r\nDialogue: 0,0:54:34.73,0:54:37.05,yin,,0,0,0,, 星期几 月份 所有这些 \\N{\\fs12}of the week, and the month, and all those things.\r\nDialogue: 0,0:54:37.05,0:54:41.81,yin,,0,0,0,, 在天气中 则是温度 城市名等等 \\N{\\fs12}In the weather it’s the temperature, and the name of the city, and things like that.\r\nDialogue: 0,0:54:41.81,0:54:46.73,yin,,0,0,0,, 在计时应用中 则是时钟所在城市 \\N{\\fs12}In the timer app it’s the city that the clock is in.\r\nDialogue: 0,0:54:46.73,0:54:48.32,yin,,0,0,0,, 如果是用户内容 \\N{\\fs12}So if it’s user content –\r\nDialogue: 0,0:54:48.32,0:54:51.84,yin,,0,0,0,, 也就是说 不是按钮上的文字 \\N{\\fs12}in other words, it’s not the text on a button.\r\nDialogue: 0,0:54:51.84,0:54:55.48,yin,,0,0,0,, 按钮上的文字便于用户点击 如编辑等等 \\N{\\fs12}It’s not a text on a button that user’s clicking like edit or something like that.\r\nDialogue: 0,0:54:55.48,0:54:58.54,yin,,0,0,0,, 那么你就需要使用首选字体 所谓的首选字体 \\N{\\fs12}Then you want to use a preferred font, what’s called a “preferred font.”\r\nDialogue: 0,0:54:58.54,0:55:01.01,yin,,0,0,0,, 所以你需要这种很重要的方法 \\N{\\fs12}And so you want this incredibly important method.\r\nDialogue: 0,0:55:01.01,0:55:03.64,yin,,0,0,0,,UIFont 中如果你只学一种方法 \\N{\\fs12}If you only learn one method in all of UI font,\r\nDialogue: 0,0:55:03.64,0:55:05.22,yin,,0,0,0,, 那肯定就是这种 iOS7 方法 \\N{\\fs12}it’s this iOS 7 method\r\nDialogue: 0,0:55:05.22,0:55:07.46,yin,,0,0,0,, 叫作 preferredFontForTextStyle\\N{\\fs12}called “preferred font for text style.”\r\nDialogue: 0,0:55:07.46,0:55:10.02,yin,,0,0,0,, 文本样式参数是一个字符串 \\N{\\fs12}The text style argument is a string.\r\nDialogue: 0,0:55:10.02,0:55:11.66,yin,,0,0,0,, 你将使用一个常数 \\N{\\fs12}You use a constant\r\nDialogue: 0,0:55:11.66,0:55:14.65,yin,,0,0,0,, 这可以在 UIFontDescriptor 中查到 \\N{\\fs12}that you’re going to look up in UI font descriptor, actually.\r\nDialogue: 0,0:55:14.65,0:55:18.29,yin,,0,0,0,, 查看 UIFont 四处点一下 你可以找到它 \\N{\\fs12}If you go through UI font, you can link click through and find it.\r\nDialogue: 0,0:55:18.29,0:55:20.15,yin,,0,0,0,, 这里有体样式 \\N{\\fs12}And so there’s the body style.\r\nDialogue: 0,0:55:20.15,0:55:24.56,yin,,0,0,0,, 这是体中的文字 体也就是显示的主要部分 \\N{\\fs12}So that’s text that’s in the body, the main part of what’s being displayed.\r\nDialogue: 0,0:55:24.56,0:55:26.75,yin,,0,0,0,, 例如在预约中 这将是…\\N{\\fs12}So like, in an appointment that would be –\r\nDialogue: 0,0:55:26.75,0:55:28.16,yin,,0,0,0,, 在日历中 \\N{\\fs12}like in a calendar item\r\nDialogue: 0,0:55:28.16,0:55:32.08,yin,,0,0,0,, 这将是关于某预约时实际将会发生什么的信息 \\N{\\fs12}that would be the actual information about what’s going to happen at that appointment.\r\nDialogue: 0,0:55:32.08,0:55:34.10,yin,,0,0,0,, 然后还有标题样式 \\N{\\fs12}And then there’s a headline style.\r\nDialogue: 0,0:55:34.10,0:55:36.15,yin,,0,0,0,, 这显然用于标题 \\N{\\fs12}So that would be, obviously, a header.\r\nDialogue: 0,0:55:36.15,0:55:40.37,yin,,0,0,0,, 还有脚注 解说文字 例如图像上的解说文字 等等 \\N{\\fs12}There’s footnotes, captions, like a caption on an image, things like that.\r\nDialogue: 0,0:55:40.37,0:55:43.44,yin,,0,0,0,, 这些样式总共有大概八个 \\N{\\fs12}There’s about, I think, eight or so of these.\r\nDialogue: 0,0:55:43.44,0:55:45.49,yin,,0,0,0,, 你们应该熟悉 \\N{\\fs12}And you should familiarize yourself\r\nDialogue: 0,0:55:45.49,0:55:49.07,yin,,0,0,0,, 什么语义环境下应该使用什么样式 \\N{\\fs12}with what circumstances semantically those things should be used in.\r\nDialogue: 0,0:55:49.07,0:55:53.06,yin,,0,0,0,, 你们在 app 中使用字体时 应该从这些里面选择 \\N{\\fs12}And then when you want a font in your app, you should be using one of these.\r\nDialogue: 0,0:55:53.06,0:55:55.43,yin,,0,0,0,, 用于用户内容 \\N{\\fs12}For user content.\r\nDialogue: 0,0:55:55.43,0:55:57.00,yin,,0,0,0,, 还有系统字体 \\N{\\fs12}There’s also system fonts.\r\nDialogue: 0,0:55:57.00,0:55:58.68,yin,,0,0,0,, 这些是按钮上的字体 \\N{\\fs12}These are what goes on buttons.\r\nDialogue: 0,0:55:58.68,0:56:02.60,yin,,0,0,0,, 不要在用户内容中使用系统字体 \\N{\\fs12}Don’t use the system fonts for user content.\r\nDialogue: 0,0:56:02.60,0:56:06.56,yin,,0,0,0,, 有时 在按钮上使用首选字体是可以的 \\N{\\fs12}Sometimes it’s okay to use a preferred font on a button.\r\nDialogue: 0,0:56:06.56,0:56:08.71,yin,,0,0,0,, 这取决于按钮的标题是否会变化 \\N{\\fs12}It depends on whether the title of the button might change,\r\nDialogue: 0,0:56:08.71,0:56:11.45,yin,,0,0,0,, 取决于用户内容 \\N{\\fs12}depending on user’s, you know, content.\r\nDialogue: 0,0:56:11.45,0:56:13.96,yin,,0,0,0,, 这是按钮上的用户内容 \\N{\\fs12}Basically it’s the user’s content on a button.\r\nDialogue: 0,0:56:13.96,0:56:15.09,yin,,0,0,0,, 这没问题 \\N{\\fs12}That would be okay.\r\nDialogue: 0,0:56:15.09,0:56:18.57,yin,,0,0,0,, 但一般不要对用户内容使用系统字体 \\N{\\fs12}But you generally wouldn’t want to use system fonts for user’s content.\r\nDialogue: 0,0:56:18.57,0:56:23.88,yin,,0,0,0,, 这是按钮上用的字体 你们知道 就是这样 \\N{\\fs12}So this is what’s on a button, what’s — you know, that kind of thing.\r\nDialogue: 0,0:56:26.28,0:56:28.14,yin,,0,0,0,,UIFontDescriptor\\N{\\fs12}UI font descriptor.\r\nDialogue: 0,0:56:28.14,0:56:31.46,yin,,0,0,0,, 我在发布的幻灯片中额外加了一些 \\N{\\fs12}I put some extra slides in what I posted\r\nDialogue: 0,0:56:31.46,0:56:34.03,yin,,0,0,0,, 关于 UIFontDescriptor 的内容 \\N{\\fs12}that talks more about UI font descriptor.\r\nDialogue: 0,0:56:34.03,0:56:35.98,yin,,0,0,0,, 这里我不打算细讲 \\N{\\fs12}I’m not going to go through them here.\r\nDialogue: 0,0:56:35.98,0:56:37.65,yin,,0,0,0,, 你们可以自己看一下 \\N{\\fs12}You can look through them, just kind of get a little bit\r\nDialogue: 0,0:56:37.65,0:56:39.68,yin,,0,0,0,, 从而对 UIFontDescriptor 有一定了解 \\N{\\fs12}of a hint for UI font descriptor.\r\nDialogue: 0,0:56:39.68,0:56:41.40,yin,,0,0,0,, 关于这个我就想说一点 \\N{\\fs12}But the bottom line is:\r\nDialogue: 0,0:56:41.40,0:56:46.66,yin,,0,0,0,, 字体不是计算机程序员设计的 而是艺术家设计的 \\N{\\fs12}Fonts are designed not by computer programmers but by artists.\r\nDialogue: 0,0:56:46.66,0:56:50.98,yin,,0,0,0,, 艺术家设计字体 也许设计已经有数百年历史了 \\N{\\fs12}Artists design fonts, and they’ve been designing them for hundreds of years.\r\nDialogue: 0,0:56:50.98,0:56:56.30,yin,,0,0,0,, 也许有几百年历史了 这是印刷出版刚兴起的时候 \\N{\\fs12}Yeah, probably couple hundred years since the ledgers, since presses were made.\r\nDialogue: 0,0:56:56.30,0:56:58.87,yin,,0,0,0,, 古腾堡是什么时候我不大确定 \\N{\\fs12}I don’t know when Gutenberg was exactly.\r\nDialogue: 0,0:56:58.87,0:57:00.51,yin,,0,0,0,, 这考了考我的历史 \\N{\\fs12}Testing my history here.\r\nDialogue: 0,0:57:00.51,0:57:02.19,yin,,0,0,0,, 但这些设计 \\N{\\fs12}But those were designed.\r\nDialogue: 0,0:57:02.19,0:57:06.94,yin,,0,0,0,, 是很久以前雕刻在铅块上使用的 \\N{\\fs12}You know, back then you actually etched on pieces of lead or whatever.\r\nDialogue: 0,0:57:06.94,0:57:12.13,yin,,0,0,0,, 而现在 设计是在 PhotoShop 或 Illustrator\\N{\\fs12}Now they’re designed in, you know, PhotoShop or Illustrator probably type, you know,\r\nDialogue: 0,0:57:12.13,0:57:14.63,yin,,0,0,0,, 或别的什么矢量图形设计工具上 \\N{\\fs12}vector graphics designing tools.\r\nDialogue: 0,0:57:14.63,0:57:17.01,yin,,0,0,0,, 这个的问题是 \\N{\\fs12}And the problem with that is\r\nDialogue: 0,0:57:17.01,0:57:20.24,yin,,0,0,0,, 它们并不一定满足我们计算机科学家所想要的 \\N{\\fs12}that they don’t fit what we computer scientists want,\r\nDialogue: 0,0:57:20.24,0:57:22.84,yin,,0,0,0,, 也就是 我们想要这种字体的粗体版本 \\N{\\fs12}which is we want the bold version of this font,\r\nDialogue: 0,0:57:22.84,0:57:26.24,yin,,0,0,0,, 我们想要斜体 我们想要细体 \\N{\\fs12}we want the italic version, we want the narrow version.\r\nDialogue: 0,0:57:26.24,0:57:30.92,yin,,0,0,0,, 除非字体设计者实际设计了粗体或斜体 \\N{\\fs12}Okay. Unless the font designer actually designs a bold font or an italic font\r\nDialogue: 0,0:57:30.92,0:57:34.15,yin,,0,0,0,, 一般而言我们没有这些 \\N{\\fs12}[inaudible], we don’t get it. We don’t get one of those.\r\nDialogue: 0,0:57:34.15,0:57:37.29,yin,,0,0,0,, 我们可以尝试将它拉粗一些 \\N{\\fs12}We could try and somehow scrunch it up to look more bold,\r\nDialogue: 0,0:57:37.29,0:57:40.03,yin,,0,0,0,, 但这通常看起来很糟糕 \\N{\\fs12}but that usually looks, like, bad.\r\nDialogue: 0,0:57:40.03,0:57:42.43,yin,,0,0,0,, 看起来不会好 \\N{\\fs12}That does not look good.\r\nDialogue: 0,0:57:42.43,0:57:44.79,yin,,0,0,0,,UIFontDescriptor 是 iOS7 中的新特性 \\N{\\fs12}So UI font descriptor’s new in iOS 7.\r\nDialogue: 0,0:57:44.79,0:57:51.94,yin,,0,0,0,, 它会尝试将类别施加在未分类化的字体上 \\N{\\fs12}It attempts to put categories on fonts that defy categorization.\r\nDialogue: 0,0:57:53.36,0:57:57.32,yin,,0,0,0,,UIFontDescriptor 在这方面有很多知识 \\N{\\fs12}So the UI font descriptor has a lot of knowledge in it\r\nDialogue: 0,0:57:57.32,0:58:00.83,yin,,0,0,0,, 关于某字体是否有黑体版本 \\N{\\fs12}about faces and is there a bold version of this,\r\nDialogue: 0,0:58:00.83,0:58:03.74,yin,,0,0,0,, 有没有细体 有没有斜体 \\N{\\fs12}is there a condensed version, is there an italic version?\r\nDialogue: 0,0:58:03.74,0:58:07.46,yin,,0,0,0,, 它会将此映射到我们计算机科学家希望处理的事物上 \\N{\\fs12}And so it maps that into something we, as computer scientists, want to do\r\nDialogue: 0,0:58:07.46,0:58:10.66,yin,,0,0,0,, 因为我们希望将黑体的事物显示在屏幕上 \\N{\\fs12}because we want to put something in bold on the screen.\r\nDialogue: 0,0:58:10.66,0:58:13.28,yin,,0,0,0,,UIFontDescriptor 就是这样了 \\N{\\fs12}So that’s what UI font descriptor is all about.\r\nDialogue: 0,0:58:13.28,0:58:17.35,yin,,0,0,0,, 哪怕大小 也通常设计到字体中 \\N{\\fs12}Even size, by the way, is designed into a font often.\r\nDialogue: 0,0:58:17.35,0:58:23.37,yin,,0,0,0,, 字体设计者对较大 S 的设计中 会有更多曲线 \\N{\\fs12}A designer of a font will design a larger S with a little more curve here and there\r\nDialogue: 0,0:58:23.37,0:58:26.04,yin,,0,0,0,, 而较小 S 则不是这样 \\N{\\fs12}than a smaller S. Okay?\r\nDialogue: 0,0:58:26.04,0:58:29.20,yin,,0,0,0,, 大小并不只是矢量图形的放大和缩小 \\N{\\fs12}Size is not just a matter of vector graphic zooming in and out –\r\nDialogue: 0,0:58:29.20,0:58:31.16,yin,,0,0,0,, 有时 它会取决于字体 \\N{\\fs12}sometimes, it depends on the font.\r\nDialogue: 0,0:58:31.16,0:58:35.69,yin,,0,0,0,, 你们可以看看幻灯片 看具体情况是怎样的 \\N{\\fs12}So anyway, look at that, at slides that are in there to try and figure that out.\r\nDialogue: 0,0:58:35.69,0:58:39.38,yin,,0,0,0,, 作业中没有任何内容涉及到 UIFontDescriptor\\N{\\fs12}There’s nothing you will have to do in your homeworks that is font descriptor.\r\nDialogue: 0,0:58:39.38,0:58:43.29,yin,,0,0,0,, 你们可能需要考虑字体 但 UIFontDescriptor 不需要 \\N{\\fs12}You might have to do fonts but not font descriptors, I don’t think.\r\nDialogue: 0,0:58:43.29,0:58:48.30,yin,,0,0,0,, 有兴趣的话 你们可以做一些更进阶的东西 \\N{\\fs12}You might want to if you want to do some advanced stuff.\r\nDialogue: 0,0:58:48.30,0:58:49.96,yin,,0,0,0,, 理解了这些 \\N{\\fs12}So understand, though, that,\r\nDialogue: 0,0:58:49.96,0:58:51.84,yin,,0,0,0,, 当你使用 UIFontDescriptor\\N{\\fs12}yeah, when you do a font descriptor and you\r\nDialogue: 0,0:58:51.85,0:58:54.41,yin,,0,0,0,, 要它给你字体相应的粗体 \\N{\\fs12}ask it for a bold version of a font,\r\nDialogue: 0,0:58:54.41,0:58:56.07,yin,,0,0,0,, 你可能得不到粗体 \\N{\\fs12}you might not get a bold version.\r\nDialogue: 0,0:58:56.07,0:58:58.27,yin,,0,0,0,, 你会得到它能给出的最接近的东西 \\N{\\fs12}You’ll get the best thing it can come up with,\r\nDialogue: 0,0:58:58.27,0:58:59.63,yin,,0,0,0,, 但也许看起来并非粗体 \\N{\\fs12}but it might not actually look bold,\r\nDialogue: 0,0:58:59.63,0:59:03.12,yin,,0,0,0,, 取决于是什么字体 它有没有相应的粗体 等等 \\N{\\fs12}depending on what font it is and whether it has a bold, etc.\r\nDialogue: 0,0:59:04.42,0:59:07.47,yin,,0,0,0,, 下面我们来谈 文本在屏幕上的效果 \\N{\\fs12}So now let’s talk about how text looks on screen.\r\nDialogue: 0,0:59:07.47,0:59:10.60,yin,,0,0,0,, 字体是文本屏幕效果的一个重要部分 \\N{\\fs12}Well, the font is a big part of how text looks on screen.\r\nDialogue: 0,0:59:10.60,0:59:12.23,yin,,0,0,0,, 取决于你选择什么字体 \\N{\\fs12}Depending on which font you pick, that’s going\r\nDialogue: 0,0:59:12.23,0:59:13.71,yin,,0,0,0,, 这会很大程度上决定效果 \\N{\\fs12}to determine a lot of what it looks like.\r\nDialogue: 0,0:59:13.71,0:59:15.11,yin,,0,0,0,, 但还有很多其它因素 \\N{\\fs12}But there’s a lot of other things\r\nDialogue: 0,0:59:15.11,0:59:17.08,yin,,0,0,0,, 会决定字体在屏幕上的效果 \\N{\\fs12}that determine what a font looks like on screen.\r\nDialogue: 0,0:59:17.08,0:59:20.43,yin,,0,0,0,, 例如 文本有没有下划线 \\N{\\fs12}For example, is the thing underlined?\r\nDialogue: 0,0:59:20.43,0:59:21.74,yin,,0,0,0,, 是不是空心字体 \\N{\\fs12}Is it outlined?\r\nDialogue: 0,0:59:21.74,0:59:27.36,yin,,0,0,0,, 字体的外边缘有多强的描边 \\N{\\fs12}How strongly stroked is the outer edge of the font?\r\nDialogue: 0,0:59:27.36,0:59:29.96,yin,,0,0,0,, 这些都独立于字体 \\N{\\fs12}Those things are all kind of independent of the font.\r\nDialogue: 0,0:59:29.96,0:59:32.51,yin,,0,0,0,, 这些可以应用到任何字体 \\N{\\fs12}You can apply these things to any font.\r\nDialogue: 0,0:59:32.51,0:59:35.68,yin,,0,0,0,, 所以 Foundation 中有一个新类你们会学到 \\N{\\fs12}So there’s a new class that you’re going to learn that’s in Foundation\r\nDialogue: 0,0:59:35.68,0:59:37.82,yin,,0,0,0,, 叫 NSAttributedString\\N{\\fs12}called NSAttributedString.\r\nDialogue: 0,0:59:37.82,0:59:40.32,yin,,0,0,0,,NSAttributedString 非常非常简单 \\N{\\fs12}And an NSAttributedString, very, very simple.\r\nDialogue: 0,0:59:40.32,0:59:44.16,yin,,0,0,0,, 它很像… 它不是 NSString 但它很像 NSString\\N{\\fs12}It’s like — it is not an NSString — but it’s like an NSString\r\nDialogue: 0,0:59:44.16,0:59:47.37,yin,,0,0,0,, 每个字符都有一个属性字典 \\N{\\fs12}where every character has a dictionary of attributes.\r\nDialogue: 0,0:59:47.37,0:59:52.74,yin,,0,0,0,, 这些属性诸如下划线 描边宽度 字体等等 \\N{\\fs12}And those attributes are like underlined, or stroke width, font, etc. Okay?\r\nDialogue: 0,0:59:52.74,0:59:57.45,yin,,0,0,0,, 我说它很像 NSString 是因为 它不是 NSString 的子类 \\N{\\fs12}Now, the reason I say it’s like NSString — it’s not a subclass of NSString.\r\nDialogue: 0,0:59:57.45,1:00:00.16,yin,,0,0,0,, 你不能将字符串消息发送给它 \\N{\\fs12}You cannot send it string messages.\r\nDialogue: 0,1:00:01.46,1:00:04.58,yin,,0,0,0,, 这是一个很重大的限制 \\N{\\fs12}So that seems like a significant restriction. And it is,\r\nDialogue: 0,1:00:04.58,1:00:07.39,yin,,0,0,0,, 等下我们会谈到如何处理它 \\N{\\fs12}and we’ll talk about how we’re going to deal with that in a second.\r\nDialogue: 0,1:00:07.39,1:00:10.99,yin,,0,0,0,, 设置属性可以仅仅通过调用…\\N{\\fs12}You set the attributes simply by calling –\r\nDialogue: 0,1:00:10.99,1:00:13.67,yin,,0,0,0,, 抱歉 这是 NSAttributedString\\N{\\fs12}sorry, this is NSAttributedString.\r\nDialogue: 0,1:00:13.67,1:00:16.51,yin,,0,0,0,, 它是不可变的 不可修改 \\N{\\fs12}It’s immutable — immutable — not modifiable.\r\nDialogue: 0,1:00:16.51,1:00:19.83,yin,,0,0,0,, 所以 NSAttributedString 的属性无法设置 \\N{\\fs12}So you cannot set the attributes of an NSAttributedString.\r\nDialogue: 0,1:00:19.83,1:00:22.46,yin,,0,0,0,, 还有可变的带属性字符串 等下我会讲到 \\N{\\fs12}There is a mutable attributed string; we’ll talk about that in a second.\r\nDialogue: 0,1:00:22.46,1:00:25.99,yin,,0,0,0,, 获得属性可以通过调用 attributesAtIndex:\\N{\\fs12}So you get the attributes by calling attributes at index.\r\nDialogue: 0,1:00:25.99,1:00:27.76,yin,,0,0,0,, 它会返回一个字典给你 \\N{\\fs12}And it will return you a dictionary\r\nDialogue: 0,1:00:27.76,1:00:30.29,yin,,0,0,0,, 包含这一下标处字符的所有属性 \\N{\\fs12}with all the attributes for the character at that index.\r\nDialogue: 0,1:00:30.29,1:00:31.88,yin,,0,0,0,, 而这个 NSRangePointer\\N{\\fs12}And that NSRangePointer,\r\nDialogue: 0,1:00:31.88,1:00:34.42,yin,,0,0,0,, 如果你传递一个指针给一个 range struct\\N{\\fs12}if you pass it a pointer to a range struct,\r\nDialogue: 0,1:00:34.42,1:00:40.11,yin,,0,0,0,, 它会用”多少字符具有完全相同的属性”来填充它 \\N{\\fs12}it will fill it in with “How many characters have the exact same attributes?”\r\nDialogue: 0,1:00:40.11,1:00:44.23,yin,,0,0,0,, 它这里是在明确你想要属性的位置 \\N{\\fs12}So it’s basically you specify the location that you want the attributes\r\nDialogue: 0,1:00:44.23,1:00:46.79,yin,,0,0,0,, 如果很多字符具有这种属性 \\N{\\fs12}and if a whole bunch of characters have those exact same attributes,\r\nDialogue: 0,1:00:46.79,1:00:49.42,yin,,0,0,0,, 它会返回这个范围 如果你要求的话 \\N{\\fs12}it will return that range if you ask it.\r\nDialogue: 0,1:00:49.44,1:00:52.23,yin,,0,0,0,, 能理解吗 这个范围是什么 \\N{\\fs12}Does that make sense, what that range is?\r\nDialogue: 0,1:00:52.23,1:00:54.82,yin,,0,0,0,, 它告诉你 多少字符具有 \\N{\\fs12}It’s basically just telling you how many characters have the\r\nDialogue: 0,1:00:54.82,1:00:57.98,yin,,0,0,0,, 你要询问的字符处的属性 \\N{\\fs12}attributes you asked for at that character.\r\nDialogue: 0,1:00:57.98,1:01:00.86,yin,,0,0,0,, 如果你不关心 你可以传递 null\\N{\\fs12}You can pass null if you don’t care and just want\r\nDialogue: 0,1:01:00.86,1:01:03.03,yin,,0,0,0,, 只想知道那个字符的属性 \\N{\\fs12}to know the attributes of that character.\r\nDialogue: 0,1:01:03.03,1:01:06.28,yin,,0,0,0,,NSAttributedString 不是字符串 \\N{\\fs12}So NSAttributedString is not a string.\r\nDialogue: 0,1:01:06.28,1:01:08.86,yin,,0,0,0,, 但我们希望做类似字符串的事情 \\N{\\fs12}But we want to do string-like things.\r\nDialogue: 0,1:01:08.86,1:01:13.11,yin,,0,0,0,, 我们希望搜索其它子字符串 做这类能对字符串做的事情 \\N{\\fs12}We want to search for other substrings and things like that, that we do on a string.\r\nDialogue: 0,1:01:13.11,1:01:15.86,yin,,0,0,0,, 所以 NSAttributedString 中有一个方法 \\N{\\fs12}So there’s a method in NSAttributedString –\r\nDialogue: 0,1:01:15.86,1:01:18.21,yin,,0,0,0,, 它很重要 叫作 string\\N{\\fs12}really important one — called “string.”\r\nDialogue: 0,1:01:18.21,1:01:22.56,yin,,0,0,0,, 这会返回一个 NSString 你可以进行搜索 \\N{\\fs12}And this will return an NSString that you can then search in\r\nDialogue: 0,1:01:22.56,1:01:25.31,yin,,0,0,0,, 做所有能对字符串做的事 \\N{\\fs12}or do all the string things you want.\r\nDialogue: 0,1:01:25.32,1:01:27.56,yin,,0,0,0,, 例如 如果你想搜索 \\N{\\fs12}For example, if we wanted to search,\r\nDialogue: 0,1:01:27.57,1:01:30.16,yin,,0,0,0,,NSString 中有个方法叫 rangeOfString\\N{\\fs12}there’s a method in NSString called “range of string,”\r\nDialogue: 0,1:01:30.16,1:01:32.16,yin,,0,0,0,, 它会返回一个 NSRange 告诉你 \\N{\\fs12}which returns an NSRange that tells you\r\nDialogue: 0,1:01:32.16,1:01:35.01,yin,,0,0,0,, 字符串中子字符串在哪 \\N{\\fs12}where a substring is in a string.\r\nDialogue: 0,1:01:35.01,1:01:37.50,yin,,0,0,0,, 我们可以说 我们有一个带属性字符串 \\N{\\fs12}And so we can just say we have an attributed string lying\r\nDialogue: 0,1:01:37.50,1:01:39.86,yin,,0,0,0,, 我们要找某个子字符串 \\N{\\fs12}around and we’re looking for some substring;\r\nDialogue: 0,1:01:39.86,1:01:40.60,yin,,0,0,0,, 我们可以说 \\N{\\fs12}we just say\r\nDialogue: 0,1:01:40.60,1:01:43.32,yin,,0,0,0,,[attributedString string] rangeOfString:substring\\N{\\fs12}attributed string string, range of string string,\r\nDialogue: 0,1:01:43.32,1:01:44.77,yin,,0,0,0,, 返回的将是范围 \\N{\\fs12}and we’ll get the range back.\r\nDialogue: 0,1:01:44.77,1:01:50.55,yin,,0,0,0,, 这个 string 方法保证能具有高性能 \\N{\\fs12}Now, that string method is guaranteed to be very high performance\r\nDialogue: 0,1:01:50.55,1:01:52.26,yin,,0,0,0,, 因为你会一直做这个 \\N{\\fs12}because you’re doing this all the time.\r\nDialogue: 0,1:01:52.26,1:01:55.51,yin,,0,0,0,, 你希望像字符串那样处理 NSAttributedString\\N{\\fs12}You want to look at the NSAttributedString like a string.\r\nDialogue: 0,1:01:55.51,1:01:56.77,yin,,0,0,0,, 它是高性能的 \\N{\\fs12}So it’s high performance.\r\nDialogue: 0,1:01:56.77,1:01:58.90,yin,,0,0,0,, 但是 它又是容易丢失的 \\N{\\fs12}However, it’s also volatile.\r\nDialogue: 0,1:01:58.90,1:02:01.94,yin,,0,0,0,, 结果 这个返回的指针可能指向 \\N{\\fs12}The bottom line is this thing is probably returning you a pointer\r\nDialogue: 0,1:02:01.94,1:02:04.79,yin,,0,0,0,, 那个 NSAttributedString 的内部数据结构 \\N{\\fs12}to that NSAttributedStrings’ internal data structure,\r\nDialogue: 0,1:02:04.79,1:02:06.66,yin,,0,0,0,, 或它的某一部分 这之类 \\N{\\fs12}or some parts of it, or something.\r\nDialogue: 0,1:02:06.66,1:02:08.18,yin,,0,0,0,, 你不知道具体是什么 \\N{\\fs12}You don’t really know what it is.\r\nDialogue: 0,1:02:08.18,1:02:11.34,yin,,0,0,0,, 你知道返回的是一个 NSString 但是…\\N{\\fs12}You know whatever it returns is an NSString. But\r\nDialogue: 0,1:02:11.34,1:02:16.40,yin,,0,0,0,, 如果你想保留这个 不仅用于你所调用的地方 \\N{\\fs12}so if you want to keep that thing around for more than just right there where you call it,\r\nDialogue: 0,1:02:16.40,1:02:17.85,yin,,0,0,0,, 你可以复制一份 \\N{\\fs12}make a copy of it.\r\nDialogue: 0,1:02:17.85,1:02:20.85,yin,,0,0,0,, 这样你就有了 NSString 的一个副本 可以存储下来 \\N{\\fs12}Then you have a copy of the NSString. You can hold onto it.\r\nDialogue: 0,1:02:20.85,1:02:22.36,yin,,0,0,0,, 你几乎从来不需要这样做 因为 \\N{\\fs12}You almost never need to do that because you’re almost\r\nDialogue: 0,1:02:22.36,1:02:25.79,yin,,0,0,0,, 你基本总会在此时此地处理字符串 \\N{\\fs12}always operating on the string right there in place like this –\r\nDialogue: 0,1:02:25.79,1:02:26.62,yin,,0,0,0,, 字符串的范围 \\N{\\fs12}a range of string.\r\nDialogue: 0,1:02:26.62,1:02:27.86,yin,,0,0,0,, 你尝试得到它 \\N{\\fs12}You’re just trying to get it.\r\nDialogue: 0,1:02:29.62,1:02:31.71,yin,,0,0,0,, 这是字符串 NSString 中很重要的属性 \\N{\\fs12}So that’s string. Very important property in NSString.\r\nDialogue: 0,1:02:31.71,1:02:33.37,yin,,0,0,0,, 还有一个可变版本 \\N{\\fs12}So there is a mutable one.\r\nDialogue: 0,1:02:33.37,1:02:41.17,yin,,0,0,0,, 可变版本继承自不可变的带属性字符串 \\N{\\fs12}And mutable one, it does inherit from the nonmutable attributed string.\r\nDialogue: 0,1:02:41.17,1:02:43.81,yin,,0,0,0,, 但它不是 NSString 或 NSMutableString\\N{\\fs12}But it’s not an NSString or an NSMutableString.\r\nDialogue: 0,1:02:43.81,1:02:46.14,yin,,0,0,0,, 它是一种 NSAttributedString\\N{\\fs12}It’s an NSAttributedString.\r\nDialogue: 0,1:02:46.14,1:02:49.65,yin,,0,0,0,, 它添加了增加属性和设置属性方法 \\N{\\fs12}And it adds these methods to add attributes and set attributes\r\nDialogue: 0,1:02:49.65,1:02:53.99,yin,,0,0,0,, 在带属性字符串中的各种范围内 \\N{\\fs12}at various ranges inside the attributed string.\r\nDialogue: 0,1:02:53.99,1:02:55.82,yin,,0,0,0,, 这很容易理解 \\N{\\fs12}Exactly what you would think.\r\nDialogue: 0,1:02:55.82,1:02:59.42,yin,,0,0,0,, 几张幻灯片以后 我会讲到这些字典中都有什么 \\N{\\fs12}And we’re going to talk about what’s in these dictionaries in a couple slides.\r\nDialogue: 0,1:02:59.42,1:03:05.34,yin,,0,0,0,, 如果想要修改可变带属性字符串中的字符该怎么做 \\N{\\fs12}Now, what if you want to modify the characters in a mutable attributed string?\r\nDialogue: 0,1:03:05.34,1:03:08.80,yin,,0,0,0,, 同带属性字符串一样 \\N{\\fs12}Exact same thing as the attributed string.\r\nDialogue: 0,1:03:08.80,1:03:12.69,yin,,0,0,0,, 当你考虑字符时 你可以调用 mutableString 方法 \\N{\\fs12}When you want to look at the characters, you call this method mutable string.\r\nDialogue: 0,1:03:12.69,1:03:14.74,yin,,0,0,0,, 它会返回一个 NSMutableString\\N{\\fs12}And it will return an NSMutableString.\r\nDialogue: 0,1:03:14.74,1:03:18.73,yin,,0,0,0,, 信不信由你 如果你修改这个可变字符串 \\N{\\fs12}And believe it or not, if you modify that mutable string\r\nDialogue: 0,1:03:18.73,1:03:24.30,yin,,0,0,0,, 回到可变带属性字符串 其属性会追踪你的变化 \\N{\\fs12}that you get back, the mutable attributed string, its attributes will track your changes.\r\nDialogue: 0,1:03:24.30,1:03:28.02,yin,,0,0,0,, 例如 如果你插入一些文本 新文本将获得 \\N{\\fs12}So like, if you insert some text, the new text will get the attributes\r\nDialogue: 0,1:03:28.02,1:03:30.74,yin,,0,0,0,, 插入处字符的属性 \\N{\\fs12}of the character right where you inserted it.\r\nDialogue: 0,1:03:30.74,1:03:34.04,yin,,0,0,0,, 如果你将字符从可变字符串中删除 \\N{\\fs12}If you delete characters out of that mutable string,\r\nDialogue: 0,1:03:34.04,1:03:38.34,yin,,0,0,0,, 那么在可变带属性字符串中 那些字符属性也会消失 \\N{\\fs12}then the mutable attributed string, those character attributes will just go away.\r\nDialogue: 0,1:03:38.34,1:03:39.40,yin,,0,0,0,, 明白吗 \\N{\\fs12}Make sense?\r\nDialogue: 0,1:03:39.40,1:03:41.30,yin,,0,0,0,, 这些类 \\N{\\fs12}So these classes –\r\nDialogue: 0,1:03:41.30,1:03:44.06,yin,,0,0,0,,NSMutableString 和 NSMutableAttributedString\\N{\\fs12}NSMutableString and NSMutableAttributedString –\r\nDialogue: 0,1:03:44.06,1:03:46.92,yin,,0,0,0,, 相互联系起来 关系就像 NSAttributedString\\N{\\fs12}are in bed with each other, just like NSAttributedString\r\nDialogue: 0,1:03:46.92,1:03:48.47,yin,,0,0,0,, 和 NSString 之间一样 \\N{\\fs12}and NSString are in bed with each other.\r\nDialogue: 0,1:03:48.47,1:03:51.23,yin,,0,0,0,, 我不知道苹果是怎么做到的 \\N{\\fs12}I don’t know how they did it at Apple,\r\nDialogue: 0,1:03:51.23,1:03:53.07,yin,,0,0,0,, 不过这很棒 因为 \\N{\\fs12}but it’s really nice because it makes it really easy\r\nDialogue: 0,1:03:53.07,1:03:59.71,yin,,0,0,0,, 字符和带属性字符串中的属性都很容易操作 \\N{\\fs12}to manipulate both the characters and the attributes in an attributed string.\r\nDialogue: 0,1:03:59.71,1:04:03.61,yin,,0,0,0,, 好 那这些属性字典中都有些什么属性呢 \\N{\\fs12}Okay. So what kind of attributes are in those attributes dictionaries?\r\nDialogue: 0,1:04:03.61,1:04:06.30,yin,,0,0,0,, 一个重要的是字体 \\N{\\fs12}One of the big ones is the font.\r\nDialogue: 0,1:04:06.30,1:04:08.72,yin,,0,0,0,, 这是一个字典 \\N{\\fs12}So this is a dictionary.\r\nDialogue: 0,1:04:08.72,1:04:11.89,yin,,0,0,0,, 字体的键是 NSFontAttributeName\\N{\\fs12}The key for the font is NSFontAttributeName.\r\nDialogue: 0,1:04:11.89,1:04:14.74,yin,,0,0,0,, 你们可以去查下这些键 \\N{\\fs12}And you can look up these keys by going and looking –\r\nDialogue: 0,1:04:14.74,1:04:20.04,yin,,0,0,0,,NSAttributedString 在说明文档中有一个链接 \\N{\\fs12}if you look up NSAttributedString in the documentation, there’s a link there,\r\nDialogue: 0,1:04:20.04,1:04:23.26,yin,,0,0,0,, 也就是 NSAttributedString 的 UIKit 增添部分 \\N{\\fs12}which is UIkit additions to NSAttributedString,\r\nDialogue: 0,1:04:23.26,1:04:25.65,yin,,0,0,0,, 我要讲的所有键都在这里有 \\N{\\fs12}and all the keys that I’m going to talk about are there.\r\nDialogue: 0,1:04:25.65,1:04:28.38,yin,,0,0,0,, 其中一个键就是 NSFontAttributeName\\N{\\fs12}And one of the keys is NSFontAttributeName.\r\nDialogue: 0,1:04:28.38,1:04:32.90,yin,,0,0,0,, 其值是 UIFont\\N{\\fs12}And the value of that is a UIFont.\r\nDialogue: 0,1:04:32.90,1:04:36.39,yin,,0,0,0,, 这就是获得特定样式首选字体的地方 \\N{\\fs12}So this is where you would get a preferred font of a certain style,\r\nDialogue: 0,1:04:36.40,1:04:38.40,yin,,0,0,0,, 例如这里是标题 \\N{\\fs12}like a headline, let’s say, in this case.\r\nDialogue: 0,1:04:39.60,1:04:43.15,yin,,0,0,0,, 如果我的字典中只有这个 \\N{\\fs12}So if I had a dictionary that just had this in there –\r\nDialogue: 0,1:04:43.15,1:04:45.88,yin,,0,0,0,, 没有别的 默认文本颜色是黑色 \\N{\\fs12}nothing else — the default text color is black.\r\nDialogue: 0,1:04:45.88,1:04:49.25,yin,,0,0,0,, 也许我的 A 会是这样的 \\N{\\fs12}Probably my letter A would like look that.\r\nDialogue: 0,1:04:49.25,1:04:53.58,yin,,0,0,0,, 如果我将这个键值对加到我的字典呢 \\N{\\fs12}What if I added this key value pair to my dictionary?\r\nDialogue: 0,1:04:53.58,1:04:55.60,yin,,0,0,0,,NSForegroundColorAttributeName :\\N{\\fs12}NS Foreground Color Attribute Name,\r\nDialogue: 0,1:04:55.60,1:04:57.45,yin,,0,0,0,,[UIColor blueColor]\\N{\\fs12}UIColor, blue color. So\r\nDialogue: 0,1:04:57.47,1:04:59.69,yin,,0,0,0,, 这里的键是 NSForegroundColorAttributeName\\N{\\fs12}here the key is this foreground color attribute name;\r\nDialogue: 0,1:04:59.69,1:05:01.38,yin,,0,0,0,, 值是 UIColor\\N{\\fs12}the value is a UIColor.\r\nDialogue: 0,1:05:01.38,1:05:03.00,yin,,0,0,0,, 这将它换成蓝色 \\N{\\fs12}So that changed it to blue.\r\nDialogue: 0,1:05:03.00,1:05:06.11,yin,,0,0,0,, 我还可以将它换成绿色 \\N{\\fs12}Okay. And I could change it to green if I wanted to.\r\nDialogue: 0,1:05:06.11,1:05:10.88,yin,,0,0,0,, 创建具有颜色文本的带属性字符串时要小心 \\N{\\fs12}Be a little bit careful when you create an attributed string that has colored text\r\nDialogue: 0,1:05:10.88,1:05:15.64,yin,,0,0,0,, 因为在 iOS7 中 文本颜色有时是一个指示器 \\N{\\fs12}because in iOS 7 the color of text sometimes is an indicator\r\nDialogue: 0,1:05:15.64,1:05:18.46,yin,,0,0,0,, 告诉终端用户他们能够触摸什么 \\N{\\fs12}to the end user what they can touch.\r\nDialogue: 0,1:05:18.46,1:05:26.56,yin,,0,0,0,,iOS 的 app 中有一个颜色主题 默认是蓝色 \\N{\\fs12}And so if — turns out apps in iOS kind of have a color theme. The default is blue.\r\nDialogue: 0,1:05:26.56,1:05:31.25,yin,,0,0,0,, 所以 Machismo 的按钮我们用的是蓝色 \\N{\\fs12}That’s why on Machismo buttons that we make will be blue.\r\nDialogue: 0,1:05:31.25,1:05:34.10,yin,,0,0,0,, 不过也可以是别的颜色 例如橙色 \\N{\\fs12}But they can be different colors like orange.\r\nDialogue: 0,1:05:34.10,1:05:36.50,yin,,0,0,0,, 这取决于你想要怎样的色彩 \\N{\\fs12}It depends on what tint you want your thing to be.\r\nDialogue: 0,1:05:36.50,1:05:41.98,yin,,0,0,0,, 这些颜色通常就是暗示能够触击 \\N{\\fs12}But whatever your color is of your app, that color you can usually tap on.\r\nDialogue: 0,1:05:41.98,1:05:47.19,yin,,0,0,0,, 这是按钮上文本的颜色 用于链接的文字的颜色 \\N{\\fs12}Okay. That’s the color of text on buttons, text at the top of the screen to navigate places.\r\nDialogue: 0,1:05:47.19,1:05:52.35,yin,,0,0,0,, 所以你要小心 不要将不能触击的文本设置为这种颜色 \\N{\\fs12}So be careful not to set anything else to be that color unless you can tap on it.\r\nDialogue: 0,1:05:52.35,1:05:54.79,yin,,0,0,0,, 颜色上你需要很小心 \\N{\\fs12}Be real careful with color.\r\nDialogue: 0,1:05:54.79,1:05:58.12,yin,,0,0,0,, 还有描边宽度属性 以及描边颜色 \\N{\\fs12}There’s also stroke width attribute and stroke color.\r\nDialogue: 0,1:05:58.12,1:06:02.23,yin,,0,0,0,, 宽度属性 注意这个 因为以后在作业中 \\N{\\fs12}The width attribute — and pay attention to this because you’ll need this probably\r\nDialogue: 0,1:06:02.23,1:06:06.33,yin,,0,0,0,, 你们可能会需要 这是一个 NSNumber\\N{\\fs12}for your homework — it’s an NSNumber.\r\nDialogue: 0,1:06:06.33,1:06:13.39,yin,,0,0,0,, 如果是负 NSNumber 那就意味着填充字形 \\N{\\fs12}If it’s a negative NSNumber, then that means fill glyph,\r\nDialogue: 0,1:06:13.39,1:06:16.52,yin,,0,0,0,, 这里也就是填充 A 并描边 \\N{\\fs12}you know, the A fill it, and stroke around the edge.\r\nDialogue: 0,1:06:16.52,1:06:19.86,yin,,0,0,0,, 如果是正数 那就意味着只描边 \\N{\\fs12}If it’s a positive number, it means just do the stroke around the edge\r\nDialogue: 0,1:06:19.86,1:06:22.31,yin,,0,0,0,, 而中间则是透明的 \\N{\\fs12}and the middle is transparent.\r\nDialogue: 0,1:06:23.67,1:06:25.71,yin,,0,0,0,, 看看还有什么 \\N{\\fs12}What else can we have?\r\nDialogue: 0,1:06:25.71,1:06:27.49,yin,,0,0,0,, 下划线样式属性名 \\N{\\fs12}Underline style attribute name.\r\nDialogue: 0,1:06:27.49,1:06:29.85,yin,,0,0,0,, 这是一个 NSNumber 它具有一个 enum\\N{\\fs12}So that’s an NSNumber that has an enum,\r\nDialogue: 0,1:06:29.85,1:06:32.61,yin,,0,0,0,, 有 NSUnderlineStyleSingle 或 Double\\N{\\fs12}one of NS style underline style single or double.\r\nDialogue: 0,1:06:32.61,1:06:35.16,yin,,0,0,0,, 还有 NSUnderlineStyleNone\\N{\\fs12}Or there’s also NS underline style none.\r\nDialogue: 0,1:06:35.16,1:06:36.75,yin,,0,0,0,, 表示没有下划线 \\N{\\fs12}That would be no underlining.\r\nDialogue: 0,1:06:36.75,1:06:38.80,yin,,0,0,0,, 然后还有背景颜色 \\N{\\fs12}There’s also background color.\r\nDialogue: 0,1:06:38.80,1:06:41.28,yin,,0,0,0,, 这里是想告诉你们 这是可以的 \\N{\\fs12}So here just to show you this is possible,\r\nDialogue: 0,1:06:41.28,1:06:46.52,yin,,0,0,0,, 我将这个字形的背景设为了透明黄色 \\N{\\fs12}I set the background of this glyph to be a transparent yellow.\r\nDialogue: 0,1:06:46.52,1:06:52.10,yin,,0,0,0,, 它是透明度为 30% 的黄色 \\N{\\fs12}It’s thirty percent visible, thirty percent towards opaque yellow.\r\nDialogue: 0,1:06:52.12,1:06:55.27,yin,,0,0,0,, 所以这里可以看到黑板的颜色 \\N{\\fs12}So you see how you can see the chalkboard shown through there?\r\nDialogue: 0,1:06:55.27,1:06:59.10,yin,,0,0,0,, 我不知道 iTunes U 视频中显得得如何 你们应该能够看得出 \\N{\\fs12}I don’t know if that will show up on iTunes U. But here hopefully you can see –\r\nDialogue: 0,1:06:59.10,1:07:02.54,yin,,0,0,0,, 我可以看到黄色背景后的东西 \\N{\\fs12}I can see through that yellow background.\r\nDialogue: 0,1:07:02.54,1:07:05.27,yin,,0,0,0,, 你们在作业中 也应该 \\N{\\fs12}In your homework, you might want to think\r\nDialogue: 0,1:07:05.27,1:07:07.66,yin,,0,0,0,, 尝试用一下透明色 \\N{\\fs12}about using transparent colors somewhere else.\r\nDialogue: 0,1:07:07.66,1:07:10.99,yin,,0,0,0,, 不是字符背景 而是填充颜色这些 \\N{\\fs12}Okay. Not the background of a character or maybe the fill color or something.\r\nDialogue: 0,1:07:10.99,1:07:12.19,yin,,0,0,0,, 不管怎样 \\N{\\fs12}Anyway, okay.\r\nDialogue: 0,1:07:12.19,1:07:14.29,yin,,0,0,0,, 透明色很好 \\N{\\fs12}So transparent color’s good.\r\nDialogue: 0,1:07:14.29,1:07:16.10,yin,,0,0,0,, 但愿你们都感受到了 \\N{\\fs12}Okay. So hopefully you’re all getting a feel, then,\r\nDialogue: 0,1:07:16.10,1:07:17.83,yin,,0,0,0,, 我们是如何构建这个字典的 \\N{\\fs12}for how we build this dictionary.\r\nDialogue: 0,1:07:17.83,1:07:20.93,yin,,0,0,0,, 我们只需要设置字符的属性 \\N{\\fs12}Okay. All we need to do is set the attributes of the characters\r\nDialogue: 0,1:07:20.93,1:07:25.60,yin,,0,0,0,, 设置为我们所希望设定的这一系列属性 \\N{\\fs12}that we want to have this particular set of attributes.\r\nDialogue: 0,1:07:25.60,1:07:27.93,yin,,0,0,0,, 我们在哪使用带属性字符串呢 \\N{\\fs12}So where do we use attributed strings?\r\nDialogue: 0,1:07:27.93,1:07:29.85,yin,,0,0,0,, 我可以创建一个带属性字符串 \\N{\\fs12}So I can create an attributed string.\r\nDialogue: 0,1:07:29.85,1:07:31.25,yin,,0,0,0,, 它有所有这些属性 \\N{\\fs12}It’s got all these attributes.\r\nDialogue: 0,1:07:31.25,1:07:32.67,yin,,0,0,0,, 在哪使用它呢 \\N{\\fs12}Okay. Where do I use it?\r\nDialogue: 0,1:07:32.67,1:07:34.70,yin,,0,0,0,, 我可以在按钮上使用它 \\N{\\fs12}Well, I can use it in a button.\r\nDialogue: 0,1:07:34.70,1:07:37.63,yin,,0,0,0,, 我可以设置按钮的标题为带属性字符串 \\N{\\fs12}Okay. I can set the title of a button to be an attributed string.\r\nDialogue: 0,1:07:37.63,1:07:40.75,yin,,0,0,0,, 这对你们的作业可能会有好处 \\N{\\fs12}That might be useful for your homework.\r\nDialogue: 0,1:07:40.75,1:07:44.17,yin,,0,0,0,, 我们可以创建一个具有带属性字符串的 UILabel\\N{\\fs12}We can create a UI label that has an attributed string.\r\nDialogue: 0,1:07:44.17,1:07:48.11,yin,,0,0,0,, 还有一个很重要的类 也许下次我会讲到 \\N{\\fs12}And a very important class, which I’m probably going to talk about next time,\r\nDialogue: 0,1:07:48.11,1:07:50.06,yin,,0,0,0,, 也就是 UITextView\\N{\\fs12}which is UITextView.\r\nDialogue: 0,1:07:50.06,1:07:52.24,yin,,0,0,0,,UITextView 类似于 UILabel\\N{\\fs12}UITextView is like a UILabel,\r\nDialogue: 0,1:07:52.24,1:07:57.17,yin,,0,0,0,, 但它可编辑 可选择 可滚动等等 \\N{\\fs12}but it’s editable, selectable, scrollable, etc. Okay?\r\nDialogue: 0,1:07:57.17,1:07:59.47,yin,,0,0,0,, 我们来看一下按钮 \\N{\\fs12}So let’s talk about button.\r\nDialogue: 0,1:07:59.47,1:08:02.84,yin,,0,0,0,, 实际上 我不打算详细讲按钮 \\N{\\fs12}Actually, I’m not going to talk about button,\r\nDialogue: 0,1:08:02.84,1:08:06.16,yin,,0,0,0,, 我只想说 它对你们的作业很重要 \\N{\\fs12}except for to say it’s important for your homework.\r\nDialogue: 0,1:08:06.16,1:08:10.65,yin,,0,0,0,, 它有一个方法 setAttributedTitle:\\N{\\fs12}It just has a method — set attributed title –\r\nDialogue: 0,1:08:10.65,1:08:12.78,yin,,0,0,0,, 就像 setTitle: forState: 一样 \\N{\\fs12}just like it has set title for a state,\r\nDialogue: 0,1:08:12.78,1:08:14.25,yin,,0,0,0,, 这里有 setAttributedTitle: forState:\\N{\\fs12}it has set attributed title for state.\r\nDialogue: 0,1:08:14.25,1:08:16.60,yin,,0,0,0,, 你会用到这个 \\N{\\fs12}And you’re going to want to use that.\r\nDialogue: 0,1:08:16.60,1:08:20.83,yin,,0,0,0,, 还有可能直接在屏幕上绘制字符串 \\N{\\fs12}It’s also possible to draw strings directly on screen.\r\nDialogue: 0,1:08:20.83,1:08:23.56,yin,,0,0,0,, 不过我们还没讨论到直接在屏幕上绘制 \\N{\\fs12}But we haven’t talked about drawing on screen directly yet.\r\nDialogue: 0,1:08:23.56,1:08:26.61,yin,,0,0,0,, 这部分内容我们将推迟到下周 \\N{\\fs12}So we’ll postpone until we talk about that next week.\r\nDialogue: 0,1:08:26.61,1:08:30.26,yin,,0,0,0,, 不过我们是能够直接在屏幕上绘制带属性字符串的 \\N{\\fs12}But we will be able to draw attributed strings on screens directly,\r\nDialogue: 0,1:08:30.26,1:08:35.24,yin,,0,0,0,, 就像我们能够直接在屏幕上绘制直线这些一样 \\N{\\fs12}just like we can draw lines and things like that directly on screen.\r\nDialogue: 0,1:08:35.24,1:08:38.00,yin,,0,0,0,,UILabel 有一个属性 \\N{\\fs12}UILabel has a property,\r\nDialogue: 0,1:08:38.00,1:08:39.79,yin,,0,0,0,, 它是一个 NSAttributedString 叫作 \\N{\\fs12}it’s an NSAttributedString called\r\nDialogue: 0,1:08:39.79,1:08:41.07,yin,,0,0,0,,attributedText\\N{\\fs12}”attributed text.”\r\nDialogue: 0,1:08:41.07,1:08:43.85,yin,,0,0,0,, 就像文本标签 这是一个 NSString\\N{\\fs12}It’s just like the text label, which is an NSString,\r\nDialogue: 0,1:08:43.85,1:08:45.59,yin,,0,0,0,, 我们已经使用过这个 \\N{\\fs12}which we’ve already used in this class,\r\nDialogue: 0,1:08:45.59,1:08:48.07,yin,,0,0,0,, 例如分数标签和翻牌计数标签 \\N{\\fs12}we like the score label and the flips label.\r\nDialogue: 0,1:08:48.07,1:08:49.40,yin,,0,0,0,, 我们设置了文本属性 \\N{\\fs12}We set the text property.\r\nDialogue: 0,1:08:49.40,1:08:51.36,yin,,0,0,0,, 这里有一个带属性的文本属性 \\N{\\fs12}So there’s an attributed text property.\r\nDialogue: 0,1:08:51.36,1:08:54.99,yin,,0,0,0,, 你通过 NSAttributedString 而非 NSString 设置属性 \\N{\\fs12}And you just set the property via an NSAttributedString instead of an NSString.\r\nDialogue: 0,1:08:54.99,1:08:55.83,yin,,0,0,0,, 就是这样了 \\N{\\fs12}And that’s it.\r\nDialogue: 0,1:08:55.83,1:08:58.07,yin,,0,0,0,, 很不幸 它是只读的 \\N{\\fs12}Unfortunately, it’s read-only.\r\nDialogue: 0,1:08:58.07,1:08:59.79,yin,,0,0,0,, 它是不可变的 \\N{\\fs12}Okay. It’s immutable.\r\nDialogue: 0,1:08:59.79,1:09:02.66,yin,,0,0,0,, 该属性不是 NSMutableAttributedString\\N{\\fs12}That property you see is not an NS Mutable Attributed String;\r\nDialogue: 0,1:09:02.66,1:09:04.13,yin,,0,0,0,, 它只是 NSAttributedString\\N{\\fs12}it’s an NSAttributedString.\r\nDialogue: 0,1:09:04.13,1:09:07.72,yin,,0,0,0,, 如果你希望改变 UILabel 上的带属性文本 \\N{\\fs12}So if you want to change the attributed text that’s on a UILabel,\r\nDialogue: 0,1:09:07.72,1:09:11.19,yin,,0,0,0,, 你需要获取标签 复制它得到一个可变副本 \\N{\\fs12}you have to get the label, make a mutable copy of it,\r\nDialogue: 0,1:09:11.19,1:09:14.19,yin,,0,0,0,, 按要求修改它 再将它放回去 \\N{\\fs12}modify it however you want, and put it back.\r\nDialogue: 0,1:09:14.19,1:09:16.50,yin,,0,0,0,, 如果你有一个已有标签 \\N{\\fs12}Okay. That’s if you have an existing label and you want\r\nDialogue: 0,1:09:16.50,1:09:19.62,yin,,0,0,0,, 你想把它变成蓝色 而非绿色 诸如此类 \\N{\\fs12}to make it be blue instead of green or something like that.\r\nDialogue: 0,1:09:19.62,1:09:22.46,yin,,0,0,0,, 你需要获取它 创建一个可变副本 \\N{\\fs12}You have to get it, create a mutable copy,\r\nDialogue: 0,1:09:22.46,1:09:25.58,yin,,0,0,0,, 修改属性 再将它放回去 \\N{\\fs12}modify the attributes, put it back.\r\nDialogue: 0,1:09:27.31,1:09:29.71,yin,,0,0,0,, 标签上 你不需要经常这样做 \\N{\\fs12}You don’t need to do this very often on labels.\r\nDialogue: 0,1:09:29.71,1:09:33.27,yin,,0,0,0,, 标签上不会经常出现带属性文本 \\N{\\fs12}Labels don’t really have attributed text on them that much.\r\nDialogue: 0,1:09:33.27,1:09:35.19,yin,,0,0,0,, 也许是设置颜色 \\N{\\fs12}Maybe to set the color.\r\nDialogue: 0,1:09:35.19,1:09:39.02,yin,,0,0,0,, 也许 如果有一些专门标签 \\N{\\fs12}Possibly if they’re specialty labels that are kind\r\nDialogue: 0,1:09:39.02,1:09:41.97,yin,,0,0,0,, 用于指定并非正常文本的东西 \\N{\\fs12}of specifying something that’s not just normal text.\r\nDialogue: 0,1:09:41.97,1:09:45.27,yin,,0,0,0,, 所以说 这对 UILabel 并不那么普遍 \\N{\\fs12}So it’s not that common to do UILabel.\r\nDialogue: 0,1:09:45.27,1:09:52.19,yin,,0,0,0,, 今天我要讲的也就这些了 \\N{\\fs12}So that’s all I’m going to cover for today, I think.\r\nDialogue: 0,1:09:52.19,1:09:53.79,yin,,0,0,0,, 周五有一堂讨论课 \\N{\\fs12}We do have a Friday section.\r\nDialogue: 0,1:09:53.79,1:09:58.81,yin,,0,0,0,, 时间在我讲课的时候得到了确认 \\N{\\fs12}The time is being confirmed to me probably as I speak right now.\r\nDialogue: 0,1:09:58.81,1:10:01.74,yin,,0,0,0,, 我会发布在 Piazza 上 \\N{\\fs12}I will post that for you on Piazza.\r\nDialogue: 0,1:10:01.74,1:10:02.77,yin,,0,0,0,, 时间是周五 \\N{\\fs12}It’s on Friday.\r\nDialogue: 0,1:10:02.77,1:10:07.88,yin,,0,0,0,, 我记得应该是周五 1 点在 102 室 \\N{\\fs12}I believe it’s going to be at 1:00 o’clock on Friday in 102. Okay, unit 102.\r\nDialogue: 0,1:10:07.88,1:10:10.93,yin,,0,0,0,, 不过不要以我为准 以 Piazza 为准 \\N{\\fs12}But don’t hold me to that yet. Look at Piazza.\r\nDialogue: 0,1:10:10.95,1:10:13.30,yin,,0,0,0,, 我们会谈到调试 \\N{\\fs12}We’re going to be talking about debugging.\r\nDialogue: 0,1:10:13.30,1:10:16.53,yin,,0,0,0,,iOS7 有一些新的调试内容 它们非常酷 \\N{\\fs12}There are some new debugging things for iOS 7 that are pretty cool.\r\nDialogue: 0,1:10:16.53,1:10:17.82,yin,,0,0,0,, 我们会讲到一些 \\N{\\fs12}We’ll get to a couple of them.\r\nDialogue: 0,1:10:17.82,1:10:20.42,yin,,0,0,0,, 我还将讲到 Xcode 的一些要诀和技巧 \\N{\\fs12}And we’re also going to talk about Xcode tips and tricks.\r\nDialogue: 0,1:10:20.42,1:10:23.43,yin,,0,0,0,,Command 键组合非常有价值 \\N{\\fs12}So command key combinations that are really valuable to have,\r\nDialogue: 0,1:10:23.43,1:10:27.31,yin,,0,0,0,, 如何设置偏好 让你的体验更好一些 \\N{\\fs12}how to set some preferences up to make your experience a little nicer.\r\nDialogue: 0,1:10:27.31,1:10:29.39,yin,,0,0,0,, 这些都是可选的 不要求大家一定到课 \\N{\\fs12}So it’s totally optional. You don’t need to go there.\r\nDialogue: 0,1:10:29.39,1:10:30.59,yin,,0,0,0,, 很多人很了解 Xcode\\N{\\fs12}A lot of you know Xcode.\r\nDialogue: 0,1:10:30.59,1:10:34.15,yin,,0,0,0,, 也很熟悉调试 至少在其它语言中 \\N{\\fs12}You’re probably used to debugging, at least in other languages.\r\nDialogue: 0,1:10:34.15,1:10:37.34,yin,,0,0,0,, 所以 就算没上 也不是世界末日 \\N{\\fs12}So, you know, if you miss it, it’s not going to be the end the world.\r\nDialogue: 0,1:10:37.34,1:10:39.20,yin,,0,0,0,, 不过这可能会有价值 \\N{\\fs12}But it might be valuable.\r\nDialogue: 0,1:10:39.20,1:10:41.81,yin,,0,0,0,, 下周一我将讲到 UITextView\\N{\\fs12}Next Monday I’m going to talk about UITextView\r\nDialogue: 0,1:10:41.82,1:10:47.75,yin,,0,0,0,, 它是 NSMutableAttributedString 的最重要使用者 \\N{\\fs12}since it’s the most important user of NS Mutable Attributed String.\r\nDialogue: 0,1:10:47.75,1:10:52.52,yin,,0,0,0,, 然后我将讲到来自 MVC 的电台 \\N{\\fs12}And then I’m also going to talk about the radio station from MVC.\r\nDialogue: 0,1:10:52.52,1:10:53.77,yin,,0,0,0,, 记得 MVC 模型吗 \\N{\\fs12}Remember that MVC model?\r\nDialogue: 0,1:10:53.77,1:10:58.37,yin,,0,0,0,, 我讲过 有时通信可以通过电台的广播来进行 \\N{\\fs12}I told you that sometimes communication happens by radio station, where you broadcast\r\nDialogue: 0,1:10:58.37,1:11:01.76,yin,,0,0,0,, 其它对象收听 我们会讲到这个 \\N{\\fs12}and some other objects tune in. We’re going to talk about doing that.\r\nDialogue: 0,1:11:01.76,1:11:04.57,yin,,0,0,0,, 然后我有一个大 demo 演示带属性字符串 \\N{\\fs12}And then I have a big demo that does attributed strings,\r\nDialogue: 0,1:11:04.57,1:11:07.10,yin,,0,0,0,, 文本视图等等所有这些 \\N{\\fs12}and text views, and all that stuff.\r\nDialogue: 0,1:11:07.10,1:11:10.18,yin,,0,0,0,, 然后我们将开始谈到视图控制器生命周期 \\N{\\fs12}And then we’re going to go start talking about the view controller lifecycle,\r\nDialogue: 0,1:11:10.19,1:11:12.48,yin,,0,0,0,, 也就是你的视图控制器 \\N{\\fs12}okay, which is your view controller.\r\nDialogue: 0,1:11:12.48,1:11:14.17,yin,,0,0,0,, 首先开始存在 \\N{\\fs12}It comes into existence.\r\nDialogue: 0,1:11:14.17,1:11:15.52,yin,,0,0,0,, 它会发生一些事情 \\N{\\fs12}Things happen to it.\r\nDialogue: 0,1:11:15.52,1:11:19.06,yin,,0,0,0,, 例如显示在屏幕上 从屏幕上消失 改变大小 等等 \\N{\\fs12}It appears on screen and goes off screen, changes size, things like that.\r\nDialogue: 0,1:11:19.06,1:11:20.04,yin,,0,0,0,, 然后它消失 \\N{\\fs12}And then it goes away.\r\nDialogue: 0,1:11:20.04,1:11:22.30,yin,,0,0,0,, 从屏幕消失 甚至完全消失 \\N{\\fs12}Okay. It goes off screen and maybe even disappears.\r\nDialogue: 0,1:11:22.30,1:11:26.10,yin,,0,0,0,, 这个发生的过程中 你会得到系统的通知 \\N{\\fs12}And as all that happens, you get notified by the system.\r\nDialogue: 0,1:11:26.10,1:11:28.80,yin,,0,0,0,, 你需要知道 什么时候获得通知 怎么做 \\N{\\fs12}And it’s important to know when you’re going to get notified and what to do\r\nDialogue: 0,1:11:28.80,1:11:30.96,yin,,0,0,0,, 这些通知在哪 \\N{\\fs12}where in terms of that notification.\r\nDialogue: 0,1:11:30.96,1:11:33.87,yin,,0,0,0,, 我们会在周一谈到这些 视图控制器生命周期 \\N{\\fs12}So we’ll be talking about that on Monday, view controller lifecycle.\r\nDialogue: 0,1:11:33.87,1:11:36.15,yin,,0,0,0,, 它对你们下次作业至关重要 \\N{\\fs12}Super important one for your next homework.\r\nDialogue: 0,1:11:36.15,1:11:38.92,yin,,0,0,0,, 你们下次作业也许是周一布置 也许是下周三布置 \\N{\\fs12}Your next homework might go out on Monday; might go out on next Wednesday.\r\nDialogue: 0,1:11:38.92,1:11:40.88,yin,,0,0,0,, 我们现在还不确定 \\N{\\fs12}I’m not quite sure yet.\r\nDialogue: 0,1:11:40.88,1:11:43.68,yin,,0,0,0,, 反正都是一周后交 \\N{\\fs12}But in case, it will be due a week later.\r\nDialogue: 0,1:11:43.68,1:11:44.65,yin,,0,0,0,, 就这些了 \\N{\\fs12}So that’s it.\r\nDialogue: 0,1:11:44.65,1:11:47.32,yin,,0,0,0,, 有问题的可以来提 \\N{\\fs12}And if you have any questions, I’ll be here.\r\nDialogue: 0,1:11:47.32,1:11:50.47,yin,,0,0,0,, 下次再见 \\N{\\fs12}And I’ll see you next time.\r\nDialogue: 0,1:11:50.47,1:11:54.35,yin,,0,0,0,, 更多内容 请访问我校官网 stanford.edu\\N{\\fs12}For more, please visit us at Stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/5. View Controller Lifecycle.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.1.2\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\nLast Style Storage: Default\r\nAegisub Video Zoom Percent: 1.000000\r\nAegisub Scroll Position: 0\r\nAegisub Active Line: 4\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin, 冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.04,0:00:07.01,yin,,0,0,0,, 斯坦福大学 \\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:11.28,0:00:16.91,yin,,0,0,0,, 欢迎来到 2013 至 2014 秋季学期 CS193P\\N{\\fs12}Okay. Well, welcome to CS193P fall of 2013/2014.\r\nDialogue: 0,0:00:17.29,0:00:20.59,yin,,0,0,0,, 今天我们会继续讲解 \\N{\\fs12}Today we’re going to continue our discussion\r\nDialogue: 0,0:00:20.60,0:00:22.45,yin,,0,0,0,, 属性化字符串的内容 \\N{\\fs12}of attributed string from last time\r\nDialogue: 0,0:00:22.63,0:00:24.40,yin,,0,0,0,, 还会介绍 UITextView\\N{\\fs12}and talk about UITextView,\r\nDialogue: 0,0:00:24.59,0:00:28.66,yin,,0,0,0,, 它基本上是一个可变属性化字符串查看器 \\N{\\fs12}which is basically a mutable attributed string viewer, okay?\r\nDialogue: 0,0:00:28.68,0:00:32.33,yin,,0,0,0,, 有点像 UILable 但是功能更强大 \\N{\\fs12}It’s kind of like a UILabel but much more powerful.\r\nDialogue: 0,0:00:32.81,0:00:34.09,yin,,0,0,0,, 我们会讲讲这部分内容 \\N{\\fs12}And we’ll talk about that.\r\nDialogue: 0,0:00:34.43,0:00:37.68,yin,,0,0,0,, 然后我们会介绍 iOS7 甚至整个 iOS 中 \\N{\\fs12}Then we’re going to talk about a very important kind of conceptual thing\r\nDialogue: 0,0:00:37.69,0:00:39.59,yin,,0,0,0,, 非常重要的一个概念 \\N{\\fs12}in iOS 7, or in iOS in general,\r\nDialogue: 0,0:00:39.59,0:00:41.66,yin,,0,0,0,, 也就是视图控制器生命周期 \\N{\\fs12}which is view controller lifecycle.\r\nDialogue: 0,0:00:41.67,0:00:45.13,yin,,0,0,0,, 指的是 MVC 中控制器的生命周期 \\N{\\fs12}So that’s just the lifecycle of the controller part of your MVC\r\nDialogue: 0,0:00:45.39,0:00:49.05,yin,,0,0,0,, 以及在其生命周期的各个阶段中 \\N{\\fs12}and how it gets notified at different times in its lifecycle\r\nDialogue: 0,0:00:49.06,0:00:50.20,yin,,0,0,0,, 如何得到事件进展的通知 \\N{\\fs12}about what’s going on.\r\nDialogue: 0,0:00:50.83,0:00:52.85,yin,,0,0,0,, 然后我们会讲解广播站机制 \\N{\\fs12}Then we’re going to talk about the radio station\r\nDialogue: 0,0:00:52.99,0:00:54.99,yin,,0,0,0,, 在讲 MVC 时我提到过 \\N{\\fs12}that I referred to in MVC.\r\nDialogue: 0,0:00:55.63,0:00:58.96,yin,,0,0,0,, 今天我们会从不太相同的角度进行讲解 \\N{\\fs12}We’re going to talk about it in a little different context that we see in MVC\r\nDialogue: 0,0:00:58.97,0:01:01.91,yin,,0,0,0,, 因为目前我只是想为大家介绍一下这部分内容 \\N{\\fs12}because I just want to introduce it to you now.\r\nDialogue: 0,0:01:02.12,0:01:06.91,yin,,0,0,0,, 而在今天的整个讲解过程中 \\N{\\fs12}And then throughout today’s thing –\r\nDialogue: 0,0:01:06.92,0:01:08.35,yin,,0,0,0,, 我会… 看这个幻灯片 \\N{\\fs12}so I’m going to be — slides here.\r\nDialogue: 0,0:01:08.35,0:01:09.70,yin,,0,0,0,, 在幻灯片讲解过程中 \\N{\\fs12}I’m going to be stopping every once and a while\r\nDialogue: 0,0:01:09.70,0:01:10.85,yin,,0,0,0,, 我会停下来做一些演示 \\N{\\fs12}and we’ll do a little demo.\r\nDialogue: 0,0:01:11.12,0:01:15.47,yin,,0,0,0,, 然后再继续讲解幻灯片内容 \\N{\\fs12}And then we will move back to the slides\r\nDialogue: 0,0:01:15.48,0:01:18.07,yin,,0,0,0,, 如此反复 直至讲完全部内容 \\N{\\fs12}and back and forth as we cover various topics.\r\nDialogue: 0,0:01:18.41,0:01:21.93,yin,,0,0,0,, 明白了吗 那我们先来讲 UITextView\\N{\\fs12}Okay? So let’s start with UITextView.\r\nDialogue: 0,0:01:22.40,0:01:26.40,yin,,0,0,0,, 和 UILabel 一样 它也能显示文本 但是功能更强大 \\N{\\fs12}Like UILabel in that it displays text but way more powerful\r\nDialogue: 0,0:01:26.40,0:01:29.07,yin,,0,0,0,, 因为它能显示多行文本 \\N{\\fs12}because the text is multiline.\r\nDialogue: 0,0:01:29.07,0:01:30.94,yin,,0,0,0,, 在 UILabel 中 如果想显示多行文本 \\N{\\fs12}UILabel, if you want it to be multiline,\r\nDialogue: 0,0:01:30.95,0:01:33.18,yin,,0,0,0,, 你需要提前声明有多少行 \\N{\\fs12}you kind of have to say how many lines it is in advance,\r\nDialogue: 0,0:01:33.19,0:01:36.27,yin,,0,0,0,, 而在 UITextView 中 想显示多少行都可以 \\N{\\fs12}whereas UITextView, as many lines as it needs.\r\nDialogue: 0,0:01:36.74,0:01:41.69,yin,,0,0,0,, 还可以滚动 可以编辑 也可以根据需要选中 \\N{\\fs12}It’s also scrollable, editable, or just selectable if you want.\r\nDialogue: 0,0:01:41.91,0:01:45.84,yin,,0,0,0,, 当然了 你还可以使用可变属性化字符串的各种设置 \\N{\\fs12}And of course, you get all the mutable attributed string\r\nDialogue: 0,0:01:45.88,0:01:48.53,yin,,0,0,0,, 比如颜色等等 \\N{\\fs12}setting of various things like colors and all that stuff.\r\nDialogue: 0,0:01:48.53,0:01:53.83,yin,,0,0,0,,UITextView 非常强大且容易使用 \\N{\\fs12}So UITextView, super powerful object but very easy to use.\r\nDialogue: 0,0:01:54.86,0:01:59.48,yin,,0,0,0,, 使用时要用到它的一个属性 叫做 textStorage\\N{\\fs12}The way you use it is that it has a property called textStorage,\r\nDialogue: 0,0:01:59.78,0:02:01.50,yin,,0,0,0,, 它是一个 NSTextStorage 类型 \\N{\\fs12}which is an NSTextStorage.\r\nDialogue: 0,0:02:01.50,0:02:05.29,yin,,0,0,0,,NSTextStorage 是 NSMutableAttributedString 的一个子类 \\N{\\fs12}NSTextStorage is a subclass of NSMutableAttributedString.\r\nDialogue: 0,0:02:05.72,0:02:07.18,yin,,0,0,0,, 你得到这个 textStorage 后 \\N{\\fs12}So you get this textStorage,\r\nDialogue: 0,0:02:07.18,0:02:08.96,yin,,0,0,0,, 就可以直接设置属性 \\N{\\fs12}and you can just start setting attributes\r\nDialogue: 0,0:02:08.98,0:02:11.82,yin,,0,0,0,, 或者如果它是可编辑的 用户会进行编辑 \\N{\\fs12}or if it’s editable, the user will start editing it\r\nDialogue: 0,0:02:11.82,0:02:14.11,yin,,0,0,0,, 属性会在这个可变字符串上显示出来 \\N{\\fs12}and the attributes will just show up on this mutable string.\r\nDialogue: 0,0:02:14.42,0:02:18.54,yin,,0,0,0,, 这是 iOS7 中新增的一个很棒的编程接口 \\N{\\fs12}It’s a super great programming interface new in iOS 7.\r\nDialogue: 0,0:02:18.64,0:02:21.78,yin,,0,0,0,, 它有一个可变属性化字符串 \\N{\\fs12}Okay. It’s having a mutable attributed string\r\nDialogue: 0,0:02:21.79,0:02:25.19,yin,,0,0,0,, 像这样由 UITextView 发布出来 \\N{\\fs12}be just vended like this by UITextView\r\nDialogue: 0,0:02:25.20,0:02:28.47,yin,,0,0,0,, 你或用户可以随时对其进行编辑 \\N{\\fs12}and editable on the fly by both the user and by you\r\nDialogue: 0,0:02:28.48,0:02:32.02,yin,,0,0,0,, 这是新功能 非常棒 非常好用 \\N{\\fs12}is all new and it’s really incredibly awesome and easy to use.\r\nDialogue: 0,0:02:33.26,0:02:36.31,yin,,0,0,0,,UITextView 有一些方法 \\N{\\fs12}There are some methods on UITextView like, you know,\r\nDialogue: 0,0:02:36.31,0:02:38.34,yin,,0,0,0,, 比如字体属性可以用来设置字体 \\N{\\fs12}property font where you can just set the font.\r\nDialogue: 0,0:02:39.05,0:02:41.68,yin,,0,0,0,, 但是大家要明白 当你设置字体时 \\N{\\fs12}Understand, though, that when you set the font,\r\nDialogue: 0,0:02:41.68,0:02:44.89,yin,,0,0,0,, 它会依次查看可变字符串中的每个字符 \\N{\\fs12}all it’s doing is going through every character in the mutable string\r\nDialogue: 0,0:02:44.89,0:02:47.24,yin,,0,0,0,, 然后将字体属性名称 \\N{\\fs12}and setting the font attribute name –\r\nDialogue: 0,0:02:47.24,0:02:49.91,yin,,0,0,0,, 设置为这个字体 \\N{\\fs12}font, you know, that thing — to this font.\r\nDialogue: 0,0:02:49.91,0:02:55.28,yin,,0,0,0,, 要记得加粗和斜体都是字体的属性 \\N{\\fs12}So remember that bold and italic are attributes of the font.\r\nDialogue: 0,0:02:55.60,0:02:57.30,yin,,0,0,0,, 大小其实也是 \\N{\\fs12}Okay? And so is the size, actually.\r\nDialogue: 0,0:02:57.59,0:03:00.07,yin,,0,0,0,, 所以如果你调用这个设置字体方法 \\N{\\fs12}So if you call this method set font –\r\nDialogue: 0,0:03:00.07,0:03:02.28,yin,,0,0,0,, 调用设置字体的 setter\\N{\\fs12}you know, call the set font setter there –\r\nDialogue: 0,0:03:02.56,0:03:04.91,yin,,0,0,0,, 所有加粗 斜体和大小的设置 \\N{\\fs12}it’s going to blast all of your bolds,\r\nDialogue: 0,0:03:04.91,0:03:07.24,yin,,0,0,0,, 就会无效了 \\N{\\fs12}and italics, and size, okay?\r\nDialogue: 0,0:03:07.24,0:03:08.98,yin,,0,0,0,, 所以使用时要小心 \\N{\\fs12}So you be a little careful of that.\r\nDialogue: 0,0:03:09.25,0:03:11.62,yin,,0,0,0,, 如果你想设置所有字符的字体 \\N{\\fs12}If you want to set the font, though, of every character\r\nDialogue: 0,0:03:11.62,0:03:13.22,yin,,0,0,0,, 且加粗斜体和大小不变 \\N{\\fs12}and have that stuff preserved,\r\nDialogue: 0,0:03:13.23,0:03:14.48,yin,,0,0,0,, 只要加个 for 循环 \\N{\\fs12}just do a little for loop,\r\nDialogue: 0,0:03:14.85,0:03:16.91,yin,,0,0,0,, 逐一查看可变字符串的全部属性 \\N{\\fs12}go through all the attributes in the mutable string,\r\nDialogue: 0,0:03:16.92,0:03:18.44,yin,,0,0,0,, 得到当前字体 \\N{\\fs12}get the font that’s already there.\r\nDialogue: 0,0:03:18.66,0:03:20.59,yin,,0,0,0,, 你可以用 UIFontDescriptor 的符号特征方法 \\N{\\fs12}You can grab the symbolic traits that are off of it\r\nDialogue: 0,0:03:20.60,0:03:23.65,yin,,0,0,0,, 获取它的符号特征 \\N{\\fs12}using the symbolic traits method in UIFontDescriptor\r\nDialogue: 0,0:03:24.20,0:03:26.01,yin,,0,0,0,, 然后新建一个字体 \\N{\\fs12}and then create a new font\r\nDialogue: 0,0:03:26.16,0:03:29.13,yin,,0,0,0,, 等于你想要设置的字体加上那些特征 \\N{\\fs12}that is the font you’re trying to set, plus those traits,\r\nDialogue: 0,0:03:29.37,0:03:31.13,yin,,0,0,0,, 然后再将最后结果设置为属性 \\N{\\fs12}and then set it back as the attribute.\r\nDialogue: 0,0:03:31.13,0:03:33.18,yin,,0,0,0,, 这是实现它需要用到的 for 循环 \\N{\\fs12}So a little for loop there to do that.\r\nDialogue: 0,0:03:33.18,0:03:36.03,yin,,0,0,0,, 但是我希望大家在用设置字体这类方法时要小心 \\N{\\fs12}But I just want you to be careful about methods like set font,\r\nDialogue: 0,0:03:36.04,0:03:37.90,yin,,0,0,0,, 这类方法在设置字体属性时 \\N{\\fs12}which are going to set the font attribute\r\nDialogue: 0,0:03:37.90,0:03:39.53,yin,,0,0,0,, 会改变全部字符的设置 \\N{\\fs12}of all the characters, okay?\r\nDialogue: 0,0:03:41.12,0:03:45.57,yin,,0,0,0,,UITextView 具有非常高级的文本布局机制 \\N{\\fs12}UITextView has incredibly advanced text layout mechanisms.\r\nDialogue: 0,0:03:45.57,0:03:50.28,yin,,0,0,0,, 比如 你可以指定文本所处容器 \\N{\\fs12}For example, you can specify the container that the text is going to be in\r\nDialogue: 0,0:03:50.28,0:03:52.49,yin,,0,0,0,, 甚至可以指定不可填充文本的限制区域 \\N{\\fs12}and it can even have exclusion zones.\r\nDialogue: 0,0:03:52.76,0:03:55.75,yin,,0,0,0,, 所以如果你在文字中间放置一张图片 \\N{\\fs12}So if you had an image that was dropped in the middle of your text\r\nDialogue: 0,0:03:55.78,0:03:57.79,yin,,0,0,0,, 想让文字环绕图片 \\N{\\fs12}and you wanted text to flow around it,\r\nDialogue: 0,0:03:57.79,0:04:02.40,yin,,0,0,0,, 即便这张图片的形状很奇怪 \\N{\\fs12}even if it’s funny-shaped thing — you know, image –\r\nDialogue: 0,0:04:02.41,0:04:03.40,yin,,0,0,0,, 你也可以实现文字环绕效果 \\N{\\fs12}you can flow around it.\r\nDialogue: 0,0:04:03.79,0:04:05.46,yin,,0,0,0,, 你只要… 非常简单 \\N{\\fs12}And you just — it’s so easy to do it.\r\nDialogue: 0,0:04:05.46,0:04:06.05,yin,,0,0,0,, 难以置信 \\N{\\fs12}unbelievably.\r\nDialogue: 0,0:04:06.06,0:04:07.45,yin,,0,0,0,, 你只要创建一条贝塞尔曲线 \\N{\\fs12}You just create a Bezier path\r\nDialogue: 0,0:04:07.46,0:04:09.79,yin,,0,0,0,, 包围住想要环绕的对象 \\N{\\fs12}that encompasses the thing you want it to flow around.\r\nDialogue: 0,0:04:09.79,0:04:11.64,yin,,0,0,0,, 你只要在 UITextView 的 textContainer 属性中 \\N{\\fs12}You just set that as an exclusion zone\r\nDialogue: 0,0:04:11.64,0:04:14.75,yin,,0,0,0,, 把它设为限制区域 \\N{\\fs12}in the textContainer property here of UITextView,\r\nDialogue: 0,0:04:14.90,0:04:15.92,yin,,0,0,0,, 就会自动进行环绕布局 \\N{\\fs12}and it will just flow around.\r\nDialogue: 0,0:04:15.92,0:04:19.67,yin,,0,0,0,, 我们这里不再讲这些高级应用了 \\N{\\fs12}So we’re not going to talk about that advanced stuff.\r\nDialogue: 0,0:04:19.68,0:04:22.95,yin,,0,0,0,, 这些都是 TextKit 中的内容 是 iOS7 的新增功能 \\N{\\fs12}It’s all part of TextKit, which is new for iOS 7.\r\nDialogue: 0,0:04:23.62,0:04:26.18,yin,,0,0,0,,layoutManager 负责布局各个字形 \\N{\\fs12}The layoutManager is the thing that lays out the glyphs.\r\nDialogue: 0,0:04:26.26,0:04:29.11,yin,,0,0,0,, 它得到全部字符和它们的属性 \\N{\\fs12}So it takes all the characters and all the attributes and stuff\r\nDialogue: 0,0:04:29.11,0:04:31.21,yin,,0,0,0,, 然后对各个字形逐一进行布局 \\N{\\fs12}and it laying out the glyphs one by one.\r\nDialogue: 0,0:04:31.44,0:04:33.25,yin,,0,0,0,, 有人不知道字形是什么吗 \\N{\\fs12}For those of you who don’t know what glyphs are,\r\nDialogue: 0,0:04:33.46,0:04:37.15,yin,,0,0,0,, 它们代表一个或一串字符 \\N{\\fs12}they’re kind of how you represent a character or a sequence of characters\r\nDialogue: 0,0:04:37.47,0:04:39.85,yin,,0,0,0,, 在屏幕上显示的样子 \\N{\\fs12}on screen with some things.\r\nDialogue: 0,0:04:39.85,0:04:41.29,yin,,0,0,0,, 所以 layoutManager 负责 \\N{\\fs12}So the layoutManager is the thing\r\nDialogue: 0,0:04:41.30,0:04:43.84,yin,,0,0,0,, 在文本容器中布局字形 \\N{\\fs12}that lays the glyphs out inside the text container.\r\nDialogue: 0,0:04:43.84,0:04:45.85,yin,,0,0,0,, 所以如果你对字体排印感兴趣 \\N{\\fs12}So if you’re interested in typography\r\nDialogue: 0,0:04:45.86,0:04:47.37,yin,,0,0,0,, 或者想在期末项目中 \\N{\\fs12}or you’re going to do a final project\r\nDialogue: 0,0:04:47.38,0:04:50.01,yin,,0,0,0,, 做关于文本布局的应用 \\N{\\fs12}that has a lot of text layout and stuff in it,\r\nDialogue: 0,0:04:50.24,0:04:51.91,yin,,0,0,0,, 就应该从这里入手 \\N{\\fs12}this is where you get started there.\r\nDialogue: 0,0:04:52.65,0:04:55.08,yin,,0,0,0,, 我们来演示一下 \\N{\\fs12}Okay? So let’s have a demo\r\nDialogue: 0,0:04:55.09,0:04:56.95,yin,,0,0,0,, 结合上节课讲过的 \\N{\\fs12}where we kind of combine all the things\r\nDialogue: 0,0:04:56.96,0:04:59.34,yin,,0,0,0,, 关于 UITextView 的全部内容 \\N{\\fs12}we saw in last lecture in this UITextView.\r\nDialogue: 0,0:04:59.98,0:05:02.82,yin,,0,0,0,, 我要叫这个演示 Attributor 属性 \\N{\\fs12}I’m going to call this demo “Attributor”\r\nDialogue: 0,0:05:02.85,0:05:06.80,yin,,0,0,0,, 因为我们要用到属性化字符串 \\N{\\fs12}because we’re going to be doing attributed strings here.\r\nDialogue: 0,0:05:07.36,0:05:08.70,yin,,0,0,0,, 它的样子呢 \\N{\\fs12}And it’s going to look like this.\r\nDialogue: 0,0:05:08.71,0:05:10.34,yin,,0,0,0,, 这是一个新应用 \\N{\\fs12}It’s going to be a totally new app,\r\nDialogue: 0,0:05:10.34,0:05:12.37,yin,,0,0,0,, 和 Matchismo 毫无关联 \\N{\\fs12}totally unrelated to Matchismo.\r\nDialogue: 0,0:05:12.37,0:05:14.21,yin,,0,0,0,, 我要新建一个项目 \\N{\\fs12}So I’m going to say create new project.\r\nDialogue: 0,0:05:15.50,0:05:17.92,yin,,0,0,0,, 隐藏其他面板 \\N{\\fs12}Let’s go ahead and also hide others here\r\nDialogue: 0,0:05:17.92,0:05:18.51,yin,,0,0,0,, 已经设置好了 \\N{\\fs12}which we are doing.\r\nDialogue: 0,0:05:18.52,0:05:22.09,yin,,0,0,0,, 我要选择单一视图应用 \\N{\\fs12}So I’m going to do a single view application.\r\nDialogue: 0,0:05:22.09,0:05:24.33,yin,,0,0,0,, 我们总是选择这项 单一的 MVC\\N{\\fs12}We almost always start with that, a single MVC.\r\nDialogue: 0,0:05:24.34,0:05:26.24,yin,,0,0,0,, 我会在下节课中 \\N{\\fs12}This demo I’m eventually going to\r\nDialogue: 0,0:05:26.26,0:05:30.14,yin,,0,0,0,, 将这个示例应用变成多 MVC 的应用 \\N{\\fs12}make into a multi-MVC application at the next lecture,\r\nDialogue: 0,0:05:30.30,0:05:33.75,yin,,0,0,0,, 但是这里我们先选择单一视图 \\N{\\fs12}but we’re going to start here with this.\r\nDialogue: 0,0:05:33.75,0:05:34.97,yin,,0,0,0,, 我要叫它 Attributor 属性 \\N{\\fs12}So I’m going to call it Attributor.\r\nDialogue: 0,0:05:34.97,0:05:36.94,yin,,0,0,0,, 类前缀为 Attributor\\N{\\fs12}I’m going to have the class prefix be attributor\r\nDialogue: 0,0:05:36.94,0:05:40.09,yin,,0,0,0,, 这样我们的控制器就叫做 AttributorViewController\\N{\\fs12}so that our controller is called AttributorViewController.\r\nDialogue: 0,0:05:40.90,0:05:41.59,yin,,0,0,0,, 这样做就行了 \\N{\\fs12}Just do that.\r\nDialogue: 0,0:05:41.74,0:05:43.11,yin,,0,0,0,, 我要把它保存在 Developer 目录下 \\N{\\fs12}I’m going to put it in Developer,\r\nDialogue: 0,0:05:43.11,0:05:44.40,yin,,0,0,0,, 和 Matchismo 保存在同样的地方 \\N{\\fs12}same place I have Matchismo.\r\nDialogue: 0,0:05:44.41,0:05:45.78,yin,,0,0,0,, 这是我的根目录 Developer\\N{\\fs12}This is my home directory, Developer.\r\nDialogue: 0,0:05:45.78,0:05:47.19,yin,,0,0,0,, 这里不需要源代码控制 \\N{\\fs12}I’m not going to use source control.\r\nDialogue: 0,0:05:48.56,0:05:49.55,yin,,0,0,0,, 这就好了 \\N{\\fs12}And here we go.\r\nDialogue: 0,0:05:49.79,0:05:53.11,yin,,0,0,0,, 这只是一个普通的应用 和我们以前做过的一样 \\N{\\fs12}So this is just a regular app just as you’re used to.\r\nDialogue: 0,0:05:53.48,0:05:57.42,yin,,0,0,0,, 同样 我要将这些委托内容移到 Supporting Files 中 \\N{\\fs12}Again, I like to move these delegate things into supporting files\r\nDialogue: 0,0:05:57.44,0:05:59.45,yin,,0,0,0,, 因为我们目前用不到委托 \\N{\\fs12}because we’re not really going to be doing the delegate.\r\nDialogue: 0,0:06:00.21,0:06:01.72,yin,,0,0,0,, 这学期讲到 iOS7 多任务处理的时候 \\N{\\fs12}This quarter we might actually do the delegates\r\nDialogue: 0,0:06:01.72,0:06:04.88,yin,,0,0,0,, 我们可能才会真正用到委托 \\N{\\fs12}when we start talking about multitasking in iOS 7.\r\nDialogue: 0,0:06:04.96,0:06:06.10,yin,,0,0,0,, 大部分情况下 \\N{\\fs12}But for most of the time\r\nDialogue: 0,0:06:06.11,0:06:07.63,yin,,0,0,0,, 你可以直接将它们移走 \\N{\\fs12}you can just kind of move that out of the way.\r\nDialogue: 0,0:06:09.00,0:06:10.48,yin,,0,0,0,, 这是我的空白 storyboard\\N{\\fs12}Here’s my blank storyboard.\r\nDialogue: 0,0:06:10.48,0:06:13.56,yin,,0,0,0,, 这里我也要把它改为小尺寸的 \\N{\\fs12}Again, I’m going to go down to small size\r\nDialogue: 0,0:06:14.17,0:06:16.48,yin,,0,0,0,, 这样更适合屏幕显示 \\N{\\fs12}instead of the tall size just so it fits.\r\nDialogue: 0,0:06:16.48,0:06:18.70,yin,,0,0,0,, 这样做没什么特殊原因 只是更方便显示 \\N{\\fs12}Okay, there’s no reason to do that, except for that it fits.\r\nDialogue: 0,0:06:18.79,0:06:23.42,yin,,0,0,0,, 大家在作业中也可以用大尺寸版本 \\N{\\fs12}By the way, you’re welcome to use the larger size in your homework if you want\r\nDialogue: 0,0:06:25.22,0:06:27.68,yin,,0,0,0,, 因为我会要求大家在作业中实现越来越多的功能 \\N{\\fs12}because as I ask you to do more and more in the homework,\r\nDialogue: 0,0:06:27.70,0:06:29.87,yin,,0,0,0,, 那样你就需要更大的空间 所以大点没问题 \\N{\\fs12}then you kind of need more and more space, which is fine.\r\nDialogue: 0,0:06:31.53,0:06:32.81,yin,,0,0,0,, 当然 在设计用户界面时 \\N{\\fs12}Of course, we need to think a little bit\r\nDialogue: 0,0:06:32.81,0:06:34.20,yin,,0,0,0,, 我们需要考虑到 \\N{\\fs12}when we design user interfaces\r\nDialogue: 0,0:06:34.21,0:06:37.76,yin,,0,0,0,, 有些用户可能在小屏幕手机上运行应用 \\N{\\fs12}that this application might run on some users on smaller phones\r\nDialogue: 0,0:06:37.77,0:06:39.96,yin,,0,0,0,, 而有些用户可能用的是大屏幕手机 \\N{\\fs12}and on some users on larger phones, right?\r\nDialogue: 0,0:06:39.96,0:06:42.30,yin,,0,0,0,, 所以我们需要一个可以伸缩的用户界面 \\N{\\fs12}So we kind of need a user interface that can stretch.\r\nDialogue: 0,0:06:42.60,0:06:44.70,yin,,0,0,0,, 下周我们会介绍自动布局机制 \\N{\\fs12}And next week we’ll be talking about autolayout,\r\nDialogue: 0,0:06:45.00,0:06:48.41,yin,,0,0,0,,iOS 的这种机制可以让你在设计用户界面时 \\N{\\fs12}which is a mechanism in iOS for you to design a user interface\r\nDialogue: 0,0:06:48.41,0:06:51.65,yin,,0,0,0,, 指定它的拉伸和缩小的方式 \\N{\\fs12}and specify how it stretches and shrinks, okay,\r\nDialogue: 0,0:06:51.65,0:06:52.59,yin,,0,0,0,, 非常重要 \\N{\\fs12}which is really important.\r\nDialogue: 0,0:06:52.90,0:06:55.30,yin,,0,0,0,, 不只适用于不同大小的 iPhone\\N{\\fs12}And not just on different size iPhones\r\nDialogue: 0,0:06:55.31,0:06:57.57,yin,,0,0,0,, 还适用于不同的设备 比如 iPad\\N{\\fs12}but different devices — iPads,\r\nDialogue: 0,0:06:57.59,0:07:00.66,yin,,0,0,0,, 你可能会在 iPad 的一个小窗口中使用它们等等 \\N{\\fs12}you might be using them in a little window inside an iPad, etc.\r\nDialogue: 0,0:07:00.67,0:07:04.69,yin,,0,0,0,, 我们希望 MVC 的视图是可伸缩的 \\N{\\fs12}We want to make our views of our MVCs be shrinkable\r\nDialogue: 0,0:07:04.70,0:07:05.99,yin,,0,0,0,, 至少在某种程度上 \\N{\\fs12}to at least some extent.\r\nDialogue: 0,0:07:06.26,0:07:08.17,yin,,0,0,0,, 当然也不要忘记设备的旋转问题 \\N{\\fs12}And of course, don’t forget device rotation.\r\nDialogue: 0,0:07:08.30,0:07:09.40,yin,,0,0,0,, 当设备旋转后 \\N{\\fs12}When you turn your device,\r\nDialogue: 0,0:07:09.40,0:07:11.51,yin,,0,0,0,, 它突然变成了宽比长高 \\N{\\fs12}it all of a sudden gets wider than it is tall.\r\nDialogue: 0,0:07:11.51,0:07:14.35,yin,,0,0,0,, 所有元素都需要移动 以适应新的布局 \\N{\\fs12}Okay? Well, everything needs to move around to deal with that, too.\r\nDialogue: 0,0:07:14.54,0:07:16.83,yin,,0,0,0,, 我们会在下周讲这部分内容 \\N{\\fs12}Okay? So we’ll talk about all of that next week.\r\nDialogue: 0,0:07:17.32,0:07:20.18,yin,,0,0,0,, 我先让大家看看我要构建的用户界面 \\N{\\fs12}So let me show you the user interface I want to build here first\r\nDialogue: 0,0:07:20.19,0:07:21.76,yin,,0,0,0,, 这样你们就会明白我想实现什么目标 \\N{\\fs12}so that you can kind of understand where I’m headed,\r\nDialogue: 0,0:07:21.77,0:07:23.26,yin,,0,0,0,, 然后我们再编写代码实现它 \\N{\\fs12}and then we’ll write the code to do it.\r\nDialogue: 0,0:07:23.83,0:07:27.06,yin,,0,0,0,, 它主要以一个 UITextView 为中心 \\N{\\fs12}It’s going to be primarily centered around a UITextView.\r\nDialogue: 0,0:07:27.06,0:07:31.33,yin,,0,0,0,, 我可以在这里查看能拖拽出的各种对象 \\N{\\fs12}So here I am looking at all my various things that I can drag out.\r\nDialogue: 0,0:07:31.51,0:07:33.89,yin,,0,0,0,, 拉到下面 找到 UITextView\\N{\\fs12}So I’m going to go down here to UITextView,\r\nDialogue: 0,0:07:33.89,0:07:38.74,yin,,0,0,0,, 应该在这 在哪呢 \\N{\\fs12}which is right — where is that thing?\r\nDialogue: 0,0:07:39.12,0:07:39.93,yin,,0,0,0,, 太往下了 \\N{\\fs12}Too far down.\r\nDialogue: 0,0:07:40.09,0:07:41.92,yin,,0,0,0,, 我找不到 UITextView 了 \\N{\\fs12}UITextView — I can’t find it.\r\nDialogue: 0,0:07:41.92,0:07:43.58,yin,,0,0,0,, 在这呢 \\N{\\fs12}It’s right there.\r\nDialogue: 0,0:07:44.03,0:07:46.40,yin,,0,0,0,,UITextView 用来显示多行文本 \\N{\\fs12}Okay? So UITextView displays multiple lines of text.\r\nDialogue: 0,0:07:46.40,0:07:47.28,yin,,0,0,0,, 我把它拖出来 \\N{\\fs12}So I drag it out.\r\nDialogue: 0,0:07:47.66,0:07:50.96,yin,,0,0,0,, 默认情况下 它是充满全屏的 \\N{\\fs12}By default it wants to be the whole size of the screen.\r\nDialogue: 0,0:07:50.96,0:07:53.18,yin,,0,0,0,, 但我其实要在这里加点按钮什么的 \\N{\\fs12}But I’m actually going to put some other buttons and stuff in here,\r\nDialogue: 0,0:07:53.30,0:07:56.41,yin,,0,0,0,, 所以我要把它拉小一点 \\N{\\fs12}so I’m going to resize this to be smaller.\r\nDialogue: 0,0:07:56.93,0:07:59.21,yin,,0,0,0,, 我还想让它有一点边 \\N{\\fs12}I also want it to have a little bit of edges here.\r\nDialogue: 0,0:07:59.21,0:08:01.20,yin,,0,0,0,, 注意 我在 UI 中进行操作时 \\N{\\fs12}Now, notice that as I do everything in the UI,\r\nDialogue: 0,0:08:01.21,0:08:03.02,yin,,0,0,0,, 借助了这些蓝色的线 \\N{\\fs12}I’m using these blue lines.\r\nDialogue: 0,0:08:03.37,0:08:07.42,yin,,0,0,0,, 我还没真正告诉大家为什么要这么做 \\N{\\fs12}And I haven’t really told you exactly why that is,\r\nDialogue: 0,0:08:07.42,0:08:08.72,yin,,0,0,0,, 但是当我们讲到 \\N{\\fs12}but when we start talking about\r\nDialogue: 0,0:08:08.74,0:08:11.24,yin,,0,0,0,, 可变大小的视图 \\N{\\fs12}having these flexible-sized views\r\nDialogue: 0,0:08:11.24,0:08:12.47,yin,,0,0,0,, 需要调整视图的大小时 \\N{\\fs12}that are going to want to resize,\r\nDialogue: 0,0:08:12.68,0:08:15.15,yin,,0,0,0,, 这些蓝线有重要的作用 \\N{\\fs12}these blue lines play a crucial role.\r\nDialogue: 0,0:08:15.15,0:08:17.06,yin,,0,0,0,, 所以当你们构建自己的 UI 时 \\N{\\fs12}And so when you’re building your UIs,\r\nDialogue: 0,0:08:17.08,0:08:19.29,yin,,0,0,0,, 尽量使用蓝线 \\N{\\fs12}use the blue lines as much as possible\r\nDialogue: 0,0:08:19.31,0:08:21.15,yin,,0,0,0,, 因为这样当我们处理自动布局时 \\N{\\fs12}because then when we start doing autolayout,\r\nDialogue: 0,0:08:21.51,0:08:24.38,yin,,0,0,0,, 蓝线可以帮助自动布局系统 \\N{\\fs12}the blue lines are going to help the autolayout system\r\nDialogue: 0,0:08:24.48,0:08:26.84,yin,,0,0,0,, 明白它们需要做怎样的处理 \\N{\\fs12}kind of get a clue as to what they should be doing.\r\nDialogue: 0,0:08:27.80,0:08:28.04,yin,,0,0,0,, 好的 \\N{\\fs12}All right.\r\nDialogue: 0,0:08:28.06,0:08:29.31,yin,,0,0,0,, 我要把这个文本视图放在这 \\N{\\fs12}So I’m going to have this text view here.\r\nDialogue: 0,0:08:29.31,0:08:31.49,yin,,0,0,0,, 然后我想添加一些文本 \\N{\\fs12}And what I want to do is have some text.\r\nDialogue: 0,0:08:31.50,0:08:32.98,yin,,0,0,0,, 我就直接用默认文本了 \\N{\\fs12}And I’ll just use the default text.\r\nDialogue: 0,0:08:33.00,0:08:34.74,yin,,0,0,0,, 在创建文本视图时 如果你看这里 \\N{\\fs12}If you look over here when you create a text view,\r\nDialogue: 0,0:08:34.74,0:08:38.28,yin,,0,0,0,, 可以看到这些伪拉丁文本 \\N{\\fs12}you see you get this kind of pseudo-Latin text here.\r\nDialogue: 0,0:08:39.47,0:08:41.10,yin,,0,0,0,, 我就直接用这段默认文本了 \\N{\\fs12}Then I’ll just use that as the default.\r\nDialogue: 0,0:08:41.10,0:08:41.89,yin,,0,0,0,, 所以这就是这个应用运行时 \\N{\\fs12}So that’s going to be the text\r\nDialogue: 0,0:08:41.90,0:08:43.34,yin,,0,0,0,, 会显示出的文本 \\N{\\fs12}that’s going to be in this when I run.\r\nDialogue: 0,0:08:43.34,0:08:45.82,yin,,0,0,0,, 运行应用时 就会得到这段文本 \\N{\\fs12}And if I run this, I’ll just get this text.\r\nDialogue: 0,0:08:46.97,0:08:50.15,yin,,0,0,0,, 但是我还想要选择某些文本 \\N{\\fs12}But what I want to be able to do is select some of the text.\r\nDialogue: 0,0:08:50.15,0:08:53.02,yin,,0,0,0,, 所以我要把这段文本设置为可选择的 \\N{\\fs12}So I’m going to make this text selectable, okay –\r\nDialogue: 0,0:08:53.12,0:08:55.22,yin,,0,0,0,, 但是不能编辑 只能选择 \\N{\\fs12}not editable, though; just selectable.\r\nDialogue: 0,0:08:55.58,0:08:57.21,yin,,0,0,0,, 这样我就能选择这里的某些单词了 \\N{\\fs12}And so I can select words in here.\r\nDialogue: 0,0:08:57.21,0:08:59.47,yin,,0,0,0,, 我还想改变单词的颜色 \\N{\\fs12}And I want to be able to change the color of the words,\r\nDialogue: 0,0:08:59.66,0:09:03.31,yin,,0,0,0,, 也许在字符外加个轮廓 \\N{\\fs12}maybe put a little outline around the characters, okay?\r\nDialogue: 0,0:09:03.31,0:09:07.43,yin,,0,0,0,, 在这里做一些能用属性化字符串实现的功能 \\N{\\fs12}Do some fun stuff that we can do with attributed string in here.\r\nDialogue: 0,0:09:08.03,0:09:10.33,yin,,0,0,0,, 我会允许应用做什么呢 \\N{\\fs12}And what am I going to allow us to do?\r\nDialogue: 0,0:09:10.33,0:09:11.19,yin,,0,0,0,, 我们看看 \\N{\\fs12}Well, let’s see.\r\nDialogue: 0,0:09:11.19,0:09:13.68,yin,,0,0,0,, 我们在下面添加几个按钮 \\N{\\fs12}Let me go get some buttons down here at the bottom.\r\nDialogue: 0,0:09:13.97,0:09:16.91,yin,,0,0,0,, 我们加一个添加轮廓功能怎么样 \\N{\\fs12}How about let’s allow outlining.\r\nDialogue: 0,0:09:17.10,0:09:19.86,yin,,0,0,0,, 在下面这里添加一个按钮 叫做 Outline\\N{\\fs12}So I’m going to create a button down here called “Outline.”\r\nDialogue: 0,0:09:21.20,0:09:24.25,yin,,0,0,0,, 当然了 也可以去除轮廓 \\N{\\fs12}And of course, let’s also let us unoutline.\r\nDialogue: 0,0:09:24.99,0:09:26.07,yin,,0,0,0,, 那我就在这里再添加一个按钮 \\N{\\fs12}So I’ll create another button up here.\r\nDialogue: 0,0:09:26.08,0:09:27.52,yin,,0,0,0,, 叫它 Unoutline\\N{\\fs12}I’ll call it “Unoutline.”\r\nDialogue: 0,0:09:27.85,0:09:31.79,yin,,0,0,0,, 这也许不是个单词 但是可以理解它的功能 \\N{\\fs12}That’s probably not a word, but we know what we want.\r\nDialogue: 0,0:09:31.80,0:09:34.40,yin,,0,0,0,, 我同样还要借助蓝线 \\N{\\fs12}Again, I’m going to use the blue lines to try and get things,\r\nDialogue: 0,0:09:34.40,0:09:36.63,yin,,0,0,0,, 让它们尽量对齐 \\N{\\fs12}you know, lined up as much as possible.\r\nDialogue: 0,0:09:37.00,0:09:38.65,yin,,0,0,0,, 我们把这个按钮放在这个角 \\N{\\fs12}This guy, let’s put him right in the corner.\r\nDialogue: 0,0:09:38.65,0:09:40.36,yin,,0,0,0,, 让这些按钮基准线对齐 \\N{\\fs12}These guys will line the base lines up.\r\nDialogue: 0,0:09:40.36,0:09:42.02,yin,,0,0,0,, 这就是这两条线的含义 \\N{\\fs12}That’s what the double line right there means,\r\nDialogue: 0,0:09:42.02,0:09:45.11,yin,,0,0,0,, 代表其他按钮所对齐的基准线 \\N{\\fs12}that the baseline of the other button line up.\r\nDialogue: 0,0:09:45.79,0:09:48.49,yin,,0,0,0,, 同样 右边线也对齐了 \\N{\\fs12}And we got, also, this right line was lined up.\r\nDialogue: 0,0:09:48.49,0:09:51.10,yin,,0,0,0,, 这样它们就会紧跟边缘变化 保持对齐 \\N{\\fs12}So they’re going to stick to the edges and stay lined up.\r\nDialogue: 0,0:09:52.33,0:09:57.22,yin,,0,0,0,, 我们允许添加和去除轮廓 \\N{\\fs12}So we’ll allow outlining and unoutlining.\r\nDialogue: 0,0:09:57.24,0:09:58.90,yin,,0,0,0,, 我还要允许设置颜色 \\N{\\fs12}And then also, I’m going to allow setting colors.\r\nDialogue: 0,0:09:58.90,0:10:00.58,yin,,0,0,0,, 我要用的方法很有意思 \\N{\\fs12}And the way I’m going to do that is kind of fun.\r\nDialogue: 0,0:10:00.86,0:10:02.17,yin,,0,0,0,, 我们先拖出一个按钮 \\N{\\fs12}So let’s get a button out here.\r\nDialogue: 0,0:10:02.47,0:10:05.65,yin,,0,0,0,, 正好可以讲一下如何改变大小 \\N{\\fs12}This is a good way to talk about if I’m resizing,\r\nDialogue: 0,0:10:05.65,0:10:08.09,yin,,0,0,0,, 我想让这个按钮大小为 6464\\N{\\fs12}I want this button to be 64 by 64.\r\nDialogue: 0,0:10:08.09,0:10:09.51,yin,,0,0,0,, 我知道这个尺寸很合适 \\N{\\fs12}I know that that’s a good size.\r\nDialogue: 0,0:10:09.67,0:10:12.77,yin,,0,0,0,, 我可以一点点调整 将它设置为我想要的准确大小 \\N{\\fs12}And I could try and get it exactly the size I want.\r\nDialogue: 0,0:10:12.84,0:10:15.45,yin,,0,0,0,, 但是如果你知道目标尺寸 这样做更简单 \\N{\\fs12}But it’s actually much easier — if you know the size you want –\r\nDialogue: 0,0:10:15.70,0:10:17.74,yin,,0,0,0,, 也就是打开这里的尺寸检查器 \\N{\\fs12}to go over here in the size inspector.\r\nDialogue: 0,0:10:17.84,0:10:18.96,yin,,0,0,0,, 看到这个尺寸检查器了吗 \\N{\\fs12}You see this size inspector?\r\nDialogue: 0,0:10:19.09,0:10:22.69,yin,,0,0,0,, 你可以在这里直接输入 我想要 6464 的 \\N{\\fs12}And you can just type in, “I want 64 by 64,” okay?\r\nDialogue: 0,0:10:23.08,0:10:24.93,yin,,0,0,0,, 关于尺寸检查器的内容 \\N{\\fs12}So this size inspector, we’re going to see\r\nDialogue: 0,0:10:25.23,0:10:27.99,yin,,0,0,0,, 我们会在讲自动布局时详细讲解 \\N{\\fs12}when we start talking about autolayout a lot\r\nDialogue: 0,0:10:28.00,0:10:29.63,yin,,0,0,0,, 下面会有很多内容 \\N{\\fs12}there’s going to be a lot of stuff down here,\r\nDialogue: 0,0:10:29.63,0:10:32.17,yin,,0,0,0,, 代表元素在改变尺寸后 \\N{\\fs12}describing how this thing gets constrained\r\nDialogue: 0,0:10:32.17,0:10:33.38,yin,,0,0,0,, 具有怎样的约束 \\N{\\fs12}when things change size.\r\nDialogue: 0,0:10:33.59,0:10:35.61,yin,,0,0,0,, 这里同样可以设置尺寸 \\N{\\fs12}But it’s also good for setting the size.\r\nDialogue: 0,0:10:35.61,0:10:36.63,yin,,0,0,0,, 尺寸设置好以后 \\N{\\fs12}And then once the size is set,\r\nDialogue: 0,0:10:36.63,0:10:38.58,yin,,0,0,0,, 我把它放在一个合适的地方 像这样 \\N{\\fs12}I’ll move into a nice spot like that.\r\nDialogue: 0,0:10:39.13,0:10:41.91,yin,,0,0,0,, 现在我可以加一个单词 Red 红色 \\N{\\fs12}Now, I could put, like, the word “Red” here\r\nDialogue: 0,0:10:42.06,0:10:44.26,yin,,0,0,0,, 将 Red 显示在按钮上 \\N{\\fs12}and make this a button that has the word “Red” on it.\r\nDialogue: 0,0:10:44.26,0:10:46.10,yin,,0,0,0,, 我可以让文本变为红色 \\N{\\fs12}And I could make the text be red.\r\nDialogue: 0,0:10:46.10,0:10:47.36,yin,,0,0,0,, 这就是我希望这个按钮实现的功能 \\N{\\fs12}That’s what I want this button to do.\r\nDialogue: 0,0:10:47.36,0:10:50.52,yin,,0,0,0,, 当我点击按钮后 我希望选中的文本变为红色 \\N{\\fs12}When I click here, I want whatever’s selected to turn red.\r\nDialogue: 0,0:10:50.71,0:10:54.16,yin,,0,0,0,, 但我不想用单词表示 我想直接使用颜色 \\N{\\fs12}But instead of using words, I’m actually going to use the color.\r\nDialogue: 0,0:10:54.16,0:10:56.07,yin,,0,0,0,, 我只要转到检查器 \\N{\\fs12}I’m just going to go to the inspector.\r\nDialogue: 0,0:10:56.31,0:11:03.23,yin,,0,0,0,, 因为按钮继承自控制 而控制继承自视图 \\N{\\fs12}And since a button inherits from control and control inherits from view,\r\nDialogue: 0,0:11:03.40,0:11:05.97,yin,,0,0,0,, 明白继承层次在检查器中是怎样的了吧 \\N{\\fs12}see how that inheritance hierarchy is working in the inspector,\r\nDialogue: 0,0:11:06.16,0:11:09.96,yin,,0,0,0,, 我要到下面这里改变它的背景颜色 \\N{\\fs12}I’m going to go down here and change its background color,\r\nDialogue: 0,0:11:10.12,0:11:11.42,yin,,0,0,0,, 这和我们之前 \\N{\\fs12}which is the same thing we did\r\nDialogue: 0,0:11:11.42,0:11:14.26,yin,,0,0,0,, 设置整个视图的背景为绿色的操作是一样的 \\N{\\fs12}when we set the background of the whole view to green.\r\nDialogue: 0,0:11:14.85,0:11:17.74,yin,,0,0,0,, 我要将它设置为 比如说红色 \\N{\\fs12}And I’m going to set this one to — let’s say this one’s red.\r\nDialogue: 0,0:11:18.50,0:11:20.70,yin,,0,0,0,, 现在我就有了一个好看的红色按钮 \\N{\\fs12}Okay? So now I have a nice red button here.\r\nDialogue: 0,0:11:20.70,0:11:21.72,yin,,0,0,0,, 当我点击这个按钮 \\N{\\fs12}And when I click on this,\r\nDialogue: 0,0:11:21.74,0:11:23.81,yin,,0,0,0,, 我要将它连起来 让文本变为红色 \\N{\\fs12}I’m going to have to wire it up to make this turn red.\r\nDialogue: 0,0:11:23.81,0:11:26.76,yin,,0,0,0,, 我们再添加一些其他颜色的按钮 \\N{\\fs12}So let’s make some more buttons here of different colors.\r\nDialogue: 0,0:11:26.87,0:11:28.66,yin,,0,0,0,, 同样 借助蓝线 \\N{\\fs12}Again, I’m using the blue lines.\r\nDialogue: 0,0:11:28.84,0:11:31.13,yin,,0,0,0,, 看到它们沿线对齐了吗 \\N{\\fs12}See how they’re snapping in place?\r\nDialogue: 0,0:11:31.75,0:11:33.19,yin,,0,0,0,, 借助蓝线 \\N{\\fs12}Okay. Getting blue lines –\r\nDialogue: 0,0:11:33.20,0:11:35.26,yin,,0,0,0,, 当然要尽可能多地使用蓝线 \\N{\\fs12}definitely want blue lines as much as possible.\r\nDialogue: 0,0:11:36.80,0:11:40.36,yin,,0,0,0,, 这里我们把它的背景设为绿色 \\N{\\fs12}So here let’s make this background be green.\r\nDialogue: 0,0:11:40.83,0:11:42.69,yin,,0,0,0,, 把它设为橙色 \\N{\\fs12}I’ll make this one be orange,\r\nDialogue: 0,0:11:42.72,0:11:45.50,yin,,0,0,0,, 把它设为紫色 \\N{\\fs12}make this one be — oh, I don’t know — purple.\r\nDialogue: 0,0:11:45.65,0:11:47.98,yin,,0,0,0,, 好了 现在我们有了设置颜色和轮廓按钮 \\N{\\fs12}Okay? So now we have some colors and some outlines.\r\nDialogue: 0,0:11:48.25,0:11:51.40,yin,,0,0,0,, 然后我们把它…\\N{\\fs12}And then let’s also make this thing –\r\nDialogue: 0,0:11:52.24,0:11:54.90,yin,,0,0,0,, 我们在上面这里再加一个标题吧 \\N{\\fs12}well, let’s put a headline at the top here, too.\r\nDialogue: 0,0:11:55.20,0:11:56.50,yin,,0,0,0,, 再拖出一个按钮 \\N{\\fs12}So let me grab another button –\r\nDialogue: 0,0:11:57.51,0:11:59.13,yin,,0,0,0,, 实际上 这里用标签就可以了 \\N{\\fs12}actually, let’s do a label for this one\r\nDialogue: 0,0:11:59.13,0:12:00.60,yin,,0,0,0,, 因为它不需要点击功能 \\N{\\fs12}because we’re not going to make it clickable.\r\nDialogue: 0,0:12:00.92,0:12:02.55,yin,,0,0,0,, 所以我要在上面这里添加一个标签 \\N{\\fs12}So I’m going to put a label here at the top.\r\nDialogue: 0,0:12:02.81,0:12:06.22,yin,,0,0,0,, 加上比如说 CS193p Rocks\\N{\\fs12}I’m going to put something like “CS193p Rocks.”\r\nDialogue: 0,0:12:06.89,0:12:09.88,yin,,0,0,0,, 这就是它的标题 \\N{\\fs12}Okay. So that’s just going to be my title of this thing.\r\nDialogue: 0,0:12:09.93,0:12:11.03,yin,,0,0,0,, 我希望它居中 看起来好看一点 \\N{\\fs12}I want it nice and centered.\r\nDialogue: 0,0:12:11.70,0:12:13.75,yin,,0,0,0,, 把它移到上面 \\N{\\fs12}Let’s move this up so that it’s locked.\r\nDialogue: 0,0:12:14.00,0:12:16.95,yin,,0,0,0,, 调整至最大尺寸 \\N{\\fs12}Let’s resize it so it’s maximum space. It locks.\r\nDialogue: 0,0:12:17.25,0:12:19.00,yin,,0,0,0,, 现在我就完成了这个好看的用户界面 \\N{\\fs12}And so now I’ve got this nice user interface.\r\nDialogue: 0,0:12:19.14,0:12:20.77,yin,,0,0,0,, 所有元素都借助了蓝线 \\N{\\fs12}I’ve used blue guidelines for everything;\r\nDialogue: 0,0:12:20.78,0:12:22.32,yin,,0,0,0,, 它们都贴着某条蓝线 \\N{\\fs12}everyone’s sticking on a blue guideline.\r\nDialogue: 0,0:12:22.32,0:12:24.50,yin,,0,0,0,, 这样处理 非常有利于 \\N{\\fs12}That’s going to be really advantageous for us\r\nDialogue: 0,0:12:24.67,0:12:26.50,yin,,0,0,0,, 实现它的自动布局功能 \\N{\\fs12}when we try to do autolayout with it.\r\nDialogue: 0,0:12:27.32,0:12:28.40,yin,,0,0,0,, 现在 我们讲讲 \\N{\\fs12}Now, let’s talk a little bit\r\nDialogue: 0,0:12:28.41,0:12:29.95,yin,,0,0,0,, 我想在这里用的字体 \\N{\\fs12}about the fonts I want to use here.\r\nDialogue: 0,0:12:29.95,0:12:32.26,yin,,0,0,0,, 我在幻灯片中讲过了 \\N{\\fs12}And I told you in the slides\r\nDialogue: 0,0:12:32.44,0:12:35.65,yin,,0,0,0,, 在显示用户内容时 \\N{\\fs12}that when you’re displaying user content, okay,\r\nDialogue: 0,0:12:35.99,0:12:39.34,yin,,0,0,0,, 最好使用系统推荐字体 \\N{\\fs12}you want to use the preferred fonts of the system.\r\nDialogue: 0,0:12:39.66,0:12:42.67,yin,,0,0,0,, 我就要这样做 对它 \\N{\\fs12}Okay? And that’s what I’m going to do, both for this guy.\r\nDialogue: 0,0:12:42.67,0:12:44.44,yin,,0,0,0,, 它显然是用户内容 \\N{\\fs12}This is clearly the user content.\r\nDialogue: 0,0:12:44.68,0:12:47.12,yin,,0,0,0,, 这两个按钮不是用户内容 \\N{\\fs12}These two buttons are not user content.\r\nDialogue: 0,0:12:47.13,0:12:49.33,yin,,0,0,0,, 它们继续使用系统字体 \\N{\\fs12}They’re going to stay the system fonts, okay,\r\nDialogue: 0,0:12:49.33,0:12:50.42,yin,,0,0,0,, 因为它们是按钮 \\N{\\fs12}because they’re buttons.\r\nDialogue: 0,0:12:50.95,0:12:54.48,yin,,0,0,0,, 但是这个标题和正文是用户内容 \\N{\\fs12}But this title and this body are kind of user contents.\r\nDialogue: 0,0:12:54.49,0:12:56.79,yin,,0,0,0,, 你可以质疑这个标题算不上是用户内容 \\N{\\fs12}You could argue that the title is not quite user content,\r\nDialogue: 0,0:12:56.81,0:12:57.77,yin,,0,0,0,, 但它确实算是 \\N{\\fs12}but it kind of is.\r\nDialogue: 0,0:12:57.77,0:12:59.52,yin,,0,0,0,, 它可能通过本地化变为另外一种语言 \\N{\\fs12}It might get localized to another language\r\nDialogue: 0,0:12:59.82,0:13:01.85,yin,,0,0,0,, 或者根据应用内容的不同变为其他文本 \\N{\\fs12}or it might change, depending on what’s going on.\r\nDialogue: 0,0:13:01.85,0:13:02.36,yin,,0,0,0,, 我也不知道 \\N{\\fs12}I don’t know.\r\nDialogue: 0,0:13:02.36,0:13:04.24,yin,,0,0,0,, 但它确实属于标题 \\N{\\fs12}But it’s really kind of a headline.\r\nDialogue: 0,0:13:04.71,0:13:06.72,yin,,0,0,0,, 所以我要用标题字体 \\N{\\fs12}So I’m going to use the headline font\r\nDialogue: 0,0:13:07.15,0:13:09.92,yin,,0,0,0,, 来显示这里的标签 \\N{\\fs12}to display this guy right here –\r\nDialogue: 0,0:13:09.97,0:13:11.70,yin,,0,0,0,, 实际上 我还想让它居中 \\N{\\fs12}actually, I also want this centered.\r\nDialogue: 0,0:13:12.29,0:13:12.75,yin,,0,0,0,, 好吧 \\N{\\fs12}All right.\r\nDialogue: 0,0:13:12.75,0:13:14.42,yin,,0,0,0,, 确认一下它是居中的 \\N{\\fs12}So let’s make sure that’s centered.\r\nDialogue: 0,0:13:14.67,0:13:17.48,yin,,0,0,0,, 选择标题字体 \\N{\\fs12}And so the way you pick the headline font,\r\nDialogue: 0,0:13:17.49,0:13:19.22,yin,,0,0,0,, 标题样式推荐字体的方法是 \\N{\\fs12}the preferred font which is headline,\r\nDialogue: 0,0:13:19.53,0:13:23.07,yin,,0,0,0,, 检查标签 然后选择这里的字体 \\N{\\fs12}is you inspect the label and you go here to the fonts.\r\nDialogue: 0,0:13:23.11,0:13:25.35,yin,,0,0,0,, 可以看到目前设置为系统字体 \\N{\\fs12}And you can see that it’s currently set to be a system font.\r\nDialogue: 0,0:13:25.54,0:13:29.37,yin,,0,0,0,, 我要向下找到文本样式 选择标题 \\N{\\fs12}And I’m going to go down here to text styles and pick headline.\r\nDialogue: 0,0:13:29.85,0:13:31.20,yin,,0,0,0,, 这如果用代码来实现 \\N{\\fs12}And that’s basically in the code\r\nDialogue: 0,0:13:31.22,0:13:34.76,yin,,0,0,0,, 基本就是 preferredFontForTextStyle: Headline\\N{\\fs12}like saying preferred font for text style headline.\r\nDialogue: 0,0:13:35.09,0:13:36.55,yin,,0,0,0,, 可以看到这里变了 \\N{\\fs12}And you can see it change there.\r\nDialogue: 0,0:13:36.66,0:13:38.86,yin,,0,0,0,, 加粗了一点 \\N{\\fs12}Kind of got a little bold to it.\r\nDialogue: 0,0:13:39.85,0:13:41.25,yin,,0,0,0,, 现在它是标题字体了 \\N{\\fs12}It’s now the headline font.\r\nDialogue: 0,0:13:41.57,0:13:43.20,yin,,0,0,0,, 文本视图也是一样 \\N{\\fs12}And the same thing here, the text view,\r\nDialogue: 0,0:13:43.20,0:13:46.13,yin,,0,0,0,, 我也要将它设置为推荐字体 \\N{\\fs12}I’m also going to set it to use a preferred font.\r\nDialogue: 0,0:13:46.13,0:13:48.17,yin,,0,0,0,, 但是这里我要选择正文字体 \\N{\\fs12}But in this case I’m going to use the body font\r\nDialogue: 0,0:13:48.18,0:13:49.11,yin,,0,0,0,, 因为很明显 \\N{\\fs12}because this is clearly, like,\r\nDialogue: 0,0:13:49.11,0:13:52.92,yin,,0,0,0,, 它是这个窗口中内容的正文 \\N{\\fs12}the body of this content in this window.\r\nDialogue: 0,0:13:52.92,0:13:55.06,yin,,0,0,0,, 现在我已经将它们设置为了推荐字体 \\N{\\fs12}So now I’ve set these things to have the preferred fonts\r\nDialogue: 0,0:13:55.07,0:13:56.67,yin,,0,0,0,, 不再是系统字体了 \\N{\\fs12}rather than the system fonts.\r\nDialogue: 0,0:13:56.67,0:13:59.71,yin,,0,0,0,, 这基本上就是需要设置的全部内容了 \\N{\\fs12}And that’s pretty much all that’s required to set that up.\r\nDialogue: 0,0:13:59.71,0:14:01.41,yin,,0,0,0,, 这就是我的 UI\\N{\\fs12}So that’s my UI.\r\nDialogue: 0,0:14:01.50,0:14:02.03,yin,,0,0,0,, 明白吗 \\N{\\fs12}All right?\r\nDialogue: 0,0:14:02.26,0:14:03.50,yin,,0,0,0,, 有问题吗 \\N{\\fs12}So yeah, question?\r\nDialogue: 0,0:14:04.63,0:14:08.47,yin,,0,0,0,,iOS 中是否有制作圆角按钮的简便方法 \\N{\\fs12}In iOS is there an easy way to round out the corners of those buttons,\r\nDialogue: 0,0:14:08.49,0:14:11.73,yin,,0,0,0,, 还是说必须做很多蒙版 \\N{\\fs12}or do you have to go through, like, a lot of masking?\r\nDialogue: 0,0:14:11.88,0:14:14.18,yin,,0,0,0,, 问题是 如果我想将这些按钮 \\N{\\fs12}Yeah, so the question is: If I wanted these to be, like,\r\nDialogue: 0,0:14:14.18,0:14:15.67,yin,,0,0,0,, 变为圆角矩形 \\N{\\fs12}rounded rect buttons –\r\nDialogue: 0,0:14:15.84,0:14:18.74,yin,,0,0,0,, 在 iOS7 中 \\N{\\fs12}which it’s not really a thing in iOS 7\r\nDialogue: 0,0:14:18.74,0:14:20.36,yin,,0,0,0,, 圆角矩形按钮很容易实现 \\N{\\fs12}to have rounded rect buttons, by the way;\r\nDialogue: 0,0:14:20.37,0:14:23.44,yin,,0,0,0,, 在 iOS6 中是个问题 但在 iOS7 中就不是很麻烦了 \\N{\\fs12}it was a thing in iOS 6, but not so much a thing in iOS 7 –\r\nDialogue: 0,0:14:23.94,0:14:25.13,yin,,0,0,0,, 实现圆角矩形有多难呢 \\N{\\fs12}how difficult would this be?\r\nDialogue: 0,0:14:25.13,0:14:26.44,yin,,0,0,0,, 答案是不会那么麻烦 \\N{\\fs12}And the answer is it wouldn’t be that bad.\r\nDialogue: 0,0:14:26.55,0:14:27.41,yin,,0,0,0,, 并不是很难 \\N{\\fs12}It wouldn’t be that hard.\r\nDialogue: 0,0:14:27.41,0:14:28.16,yin,,0,0,0,, 有一个机制 \\N{\\fs12}There’s a mechanism.\r\nDialogue: 0,0:14:28.16,0:14:30.98,yin,,0,0,0,, 圆角矩形用一行代码就可以实现 \\N{\\fs12}Rounded rect is a one-liner to create a rounded rect.\r\nDialogue: 0,0:14:32.34,0:14:34.42,yin,,0,0,0,, 我们也许并不会改变这些 UI 按钮 \\N{\\fs12}And probably we wouldn’t make these UI buttons;\r\nDialogue: 0,0:14:34.42,0:14:35.60,yin,,0,0,0,, 只是改变它们的视图 \\N{\\fs12}we’d just make them views.\r\nDialogue: 0,0:14:35.82,0:14:38.68,yin,,0,0,0,, 只用一行代码就可以编写一个点击手势 \\N{\\fs12}And it’s really a one-liner to have a tap gesture,\r\nDialogue: 0,0:14:38.69,0:14:40.55,yin,,0,0,0,, 点击它 让它执行某些操作 \\N{\\fs12}to tap on it and cause it to do something.\r\nDialogue: 0,0:14:40.82,0:14:43.90,yin,,0,0,0,, 所以只用几行代码 并不是很难 \\N{\\fs12}So, you know, a few lines of code is really not that difficult.\r\nDialogue: 0,0:14:44.22,0:14:46.10,yin,,0,0,0,, 实际上 不只是圆角矩形 \\N{\\fs12}In fact, you can make it not just rounded rect\r\nDialogue: 0,0:14:46.11,0:14:48.27,yin,,0,0,0,, 你可以将它变为任意形状 \\N{\\fs12}but any shape that you wanted there, whatever.\r\nDialogue: 0,0:14:48.49,0:14:48.80,yin,,0,0,0,, 有问题吗 \\N{\\fs12}Question?\r\nDialogue: 0,0:14:48.86,0:14:51.74,yin,,0,0,0,, 有没有什么方法能够添加 CSS 文件呢 \\N{\\fs12}Is there any way to include, like, CSS in it though or no?\r\nDialogue: 0,0:14:51.93,0:14:54.28,yin,,0,0,0,, 问题是 有没有什么方法能加入 CSS 文件 \\N{\\fs12}So the question is: Is there any way to include CSS?\r\nDialogue: 0,0:14:55.87,0:14:57.68,yin,,0,0,0,, 没有什么直接的方法 \\N{\\fs12}Not really directly.\r\nDialogue: 0,0:14:57.68,0:15:00.17,yin,,0,0,0,, 但是 比如说这些推荐字体 \\N{\\fs12}However, these preferred fonts, for example,\r\nDialogue: 0,0:15:00.18,0:15:01.91,yin,,0,0,0,, 就用到了 CSS 系统 \\N{\\fs12}are plugged into the CSS system.\r\nDialogue: 0,0:15:01.93,0:15:06.26,yin,,0,0,0,, 如果你的应用中某些内容来源于 CSS\\N{\\fs12}So if you have content in your app that is coming from CSS source,\r\nDialogue: 0,0:15:06.27,0:15:07.38,yin,,0,0,0,, 比如网页视图之类的 \\N{\\fs12}you know, on a web view or something –\r\nDialogue: 0,0:15:07.40,0:15:08.61,yin,,0,0,0,, 我们还没讲过这部分内容 \\N{\\fs12}we haven’t talked about any of that yet,\r\nDialogue: 0,0:15:08.63,0:15:09.70,yin,,0,0,0,, 但是你可以这样做 \\N{\\fs12}but you could do that –\r\nDialogue: 0,0:15:09.71,0:15:12.73,yin,,0,0,0,, 字体会进行匹配 彼此同步 \\N{\\fs12}the fonts can match up and all synchronize with each other.\r\nDialogue: 0,0:15:12.80,0:15:14.23,yin,,0,0,0,, 所以有一些同步性的处理 \\N{\\fs12}So there’s some synchronicity there,\r\nDialogue: 0,0:15:14.23,0:15:15.78,yin,,0,0,0,, 但是你不能直接显示 \\N{\\fs12}but you can’t directly display.\r\nDialogue: 0,0:15:17.46,0:15:20.00,yin,,0,0,0,, 好的 接下来我们看看代码 \\N{\\fs12}Okay. So let’s look at the code\r\nDialogue: 0,0:15:20.15,0:15:22.55,yin,,0,0,0,, 让这个用户界面实现我们想要的功能 \\N{\\fs12}to make this user interface do what we want.\r\nDialogue: 0,0:15:22.55,0:15:24.78,yin,,0,0,0,, 打开系统编辑器 \\N{\\fs12}So I’m going to get my system editor up here.\r\nDialogue: 0,0:15:25.67,0:15:27.09,yin,,0,0,0,, 把这部分移到最左边 \\N{\\fs12}Let’s put that right on the edge.\r\nDialogue: 0,0:15:27.10,0:15:31.13,yin,,0,0,0,, 腾出更大地方 方便显示更多代码 \\N{\\fs12}Let’s make some more space so you can see more code.\r\nDialogue: 0,0:15:31.76,0:15:37.10,yin,,0,0,0,, 可以看到 默认的视图控制器中有一个这样的方法 \\N{\\fs12}And you can see that my default view controller has this method here,\r\nDialogue: 0,0:15:37.12,0:15:39.93,yin,,0,0,0,,viewDidLoad 它是视图控制器生命周期的一部分 \\N{\\fs12}viewDidLoad, which is part of the view controller lifecycle\r\nDialogue: 0,0:15:40.13,0:15:41.55,yin,,0,0,0,, 我们等下就会讲到这部分 \\N{\\fs12}that we’re going to talk about in a second\r\nDialogue: 0,0:15:41.77,0:15:43.32,yin,,0,0,0,, 还有这个 didReceiveMemoryWarning 方法 \\N{\\fs12}and also didReceiveMemoryWarning,\r\nDialogue: 0,0:15:43.32,0:15:46.56,yin,,0,0,0,, 严格来说 它并不属于视图控制器生命周期 \\N{\\fs12}which is not strictly speaking part of the view controller lifecycle\r\nDialogue: 0,0:15:47.29,0:15:49.03,yin,,0,0,0,, 但是我还是会把它 \\N{\\fs12}but I’m going to talk about it\r\nDialogue: 0,0:15:49.03,0:15:50.66,yin,,0,0,0,, 放在视图控制器生命周期中讲 \\N{\\fs12}as part of the view controller lifecycle.\r\nDialogue: 0,0:15:51.13,0:15:52.72,yin,,0,0,0,, 今天我不会对它进行演示 \\N{\\fs12}I’m not going to demo that today,\r\nDialogue: 0,0:15:52.72,0:15:55.37,yin,,0,0,0,, 但是稍后我会演示 viewDidLoad 的用法 \\N{\\fs12}but I am later going to demo viewDidLoad.\r\nDialogue: 0,0:15:55.55,0:15:56.91,yin,,0,0,0,, 所以我们把它留下 \\N{\\fs12}So we’ll leave that in there for now.\r\nDialogue: 0,0:15:56.91,0:16:00.02,yin,,0,0,0,, 现在它什么都做不了 只有 super 调用和一条注释 \\N{\\fs12}Right now it doesn’t do anything except for call super and have a comment.\r\nDialogue: 0,0:16:00.25,0:16:00.71,yin,,0,0,0,, 对吧 \\N{\\fs12}Okay?\r\nDialogue: 0,0:16:01.48,0:16:04.63,yin,,0,0,0,, 那么我需要在这里做什么呢 \\N{\\fs12}So what do I need to do here?\r\nDialogue: 0,0:16:04.81,0:16:05.95,yin,,0,0,0,, 两件事情 \\N{\\fs12}Couple of things.\r\nDialogue: 0,0:16:05.95,0:16:08.03,yin,,0,0,0,, 一是我想要设置 \\N{\\fs12}One, I’m going to want to be setting\r\nDialogue: 0,0:16:08.16,0:16:10.59,yin,,0,0,0,, 它的可变字符串属性 \\N{\\fs12}the mutable string attributes of this thing,\r\nDialogue: 0,0:16:10.75,0:16:12.01,yin,,0,0,0,, 所以我需要一个连接到它的输出口 \\N{\\fs12}so I need an outlet to this.\r\nDialogue: 0,0:16:12.02,0:16:15.55,yin,,0,0,0,, 我只要按住 control 键拖动到这里 创建一个输出口 \\N{\\fs12}So I’m just going to control drag here to create an outlet.\r\nDialogue: 0,0:16:15.56,0:16:17.62,yin,,0,0,0,, 我要叫它 body\\N{\\fs12}I’m going to call it “body,” okay,\r\nDialogue: 0,0:16:17.63,0:16:18.95,yin,,0,0,0,, 因为它就像是我的正文 \\N{\\fs12}because it’s kind of like my body.\r\nDialogue: 0,0:16:19.96,0:16:22.30,yin,,0,0,0,, 可以看到它是一个 UITextView\\N{\\fs12}Text view, you can see that it’s a UITextView.\r\nDialogue: 0,0:16:22.30,0:16:25.35,yin,,0,0,0,, 我可以向 body 发送消息 \\N{\\fs12}And I’m going to be able to send a message to this body\r\nDialogue: 0,0:16:25.35,0:16:27.43,yin,,0,0,0,, 得到它保存文本的可变字符串 \\N{\\fs12}to get its text storage mutable string.\r\nDialogue: 0,0:16:27.43,0:16:29.35,yin,,0,0,0,, 然后我可以设置属性了 \\N{\\fs12}And then I’m just going to start setting attributes.\r\nDialogue: 0,0:16:29.51,0:16:30.76,yin,,0,0,0,, 对吧 就是这么简单 \\N{\\fs12}Okay? It’s as simple as that.\r\nDialogue: 0,0:16:31.39,0:16:33.16,yin,,0,0,0,, 我还要再向这里添加一个输出口 \\N{\\fs12}You know, I’m also going to grab one to this,\r\nDialogue: 0,0:16:33.16,0:16:34.36,yin,,0,0,0,, 等下你们就会知道原因 \\N{\\fs12}and you’ll see why later.\r\nDialogue: 0,0:16:34.44,0:16:37.30,yin,,0,0,0,, 我要叫它 headline\\N{\\fs12}I’m going to call this my “headline,” Okay?\r\nDialogue: 0,0:16:37.58,0:16:41.51,yin,,0,0,0,, 我也可以叫它 header 或者 heading\\N{\\fs12}And so I could call that my “header,” or my “heading,”\r\nDialogue: 0,0:16:41.51,0:16:43.62,yin,,0,0,0,, 或者 title label 之类的 \\N{\\fs12}or “title label,” or something like that.\r\nDialogue: 0,0:16:43.63,0:16:45.37,yin,,0,0,0,, 这里我就要叫它 headline 了 \\N{\\fs12}I’m going to call it “headline” just here\r\nDialogue: 0,0:16:45.38,0:16:47.44,yin,,0,0,0,, 用来强调我们讨论的是推荐字体 \\N{\\fs12}to emphasize that we’re talking about preferred fonts\r\nDialogue: 0,0:16:47.44,0:16:49.32,yin,,0,0,0,, 我也会在示例中演示这一部分 \\N{\\fs12}because I’m going to be showing that in the demo as well.\r\nDialogue: 0,0:16:50.49,0:16:51.97,yin,,0,0,0,, 我们设置好了 body 和 headline 两个输出口 \\N{\\fs12}So we’ve got this body and the headline.\r\nDialogue: 0,0:16:51.97,0:16:55.43,yin,,0,0,0,, 我们可以设置标题 \\N{\\fs12}We could conceivably set things about the headline.\r\nDialogue: 0,0:16:55.43,0:16:56.49,yin,,0,0,0,, 我没有时间具体操作了 \\N{\\fs12}I don’t really have time for that,\r\nDialogue: 0,0:16:56.51,0:16:58.90,yin,,0,0,0,, 但是我们会对这里的正文进行设置 \\N{\\fs12}but we will be setting things in here.\r\nDialogue: 0,0:16:59.31,0:17:00.79,yin,,0,0,0,, 这里有这些用于改变颜色的按钮 \\N{\\fs12}We’ve got these colored buttons.\r\nDialogue: 0,0:17:00.85,0:17:02.40,yin,,0,0,0,, 我们先实现这部分 \\N{\\fs12}Let’s do those first.\r\nDialogue: 0,0:17:02.40,0:17:03.74,yin,,0,0,0,, 所以我要按住 control 键进行拖拽 \\N{\\fs12}So I’m going to control drag here\r\nDialogue: 0,0:17:03.76,0:17:07.06,yin,,0,0,0,, 这样当我们按下按钮时 会发送操作 \\N{\\fs12}to have an action sent when we press on that button.\r\nDialogue: 0,0:17:07.92,0:17:09.89,yin,,0,0,0,, 我要叫这个操作为 \\N{\\fs12}I’m going to call this action\r\nDialogue: 0,0:17:10.15,0:17:18.13,yin,,0,0,0,,changeBodySelectionColorToMatchBackgroundOfButton 将所选正文颜色变为按钮背景颜色 \\N{\\fs12}”changeBodySelectionColorToMatchBackgroundOfButton.”\r\nDialogue: 0,0:17:18.38,0:17:20.21,yin,,0,0,0,, 你们可能觉得很好笑 心里想着 \\N{\\fs12}Okay? Now, you might laugh and say,\r\nDialogue: 0,0:17:20.23,0:17:22.92,yin,,0,0,0,, 这个方法的名字真长 \\N{\\fs12}”Whoa, that’s a long name method.”\r\nDialogue: 0,0:17:23.12,0:17:25.54,yin,,0,0,0,, 但在 Objective-C 尤其是 iOS 中 \\N{\\fs12}But long name methods are kind of preferred\r\nDialogue: 0,0:17:26.11,0:17:31.34,yin,,0,0,0,, 倾向于使用较长的方法名称 \\N{\\fs12}generally in Objective-C and especially in iOS\r\nDialogue: 0,0:17:31.46,0:17:34.49,yin,,0,0,0,, 因为 Xcode 会帮助你补全名称 \\N{\\fs12}because Xcode’s going to help you escape complete these things.\r\nDialogue: 0,0:17:34.64,0:17:37.40,yin,,0,0,0,, 如果你可以为方法起一个这样的名称 \\N{\\fs12}And if you can have a method name like this\r\nDialogue: 0,0:17:37.40,0:17:40.41,yin,,0,0,0,, 准确表达出方法的作用 \\N{\\fs12}that really matches and says exactly what it does,\r\nDialogue: 0,0:17:40.41,0:17:41.50,yin,,0,0,0,, 是一件很好的事情 \\N{\\fs12}that can be a good thing.\r\nDialogue: 0,0:17:41.88,0:17:43.98,yin,,0,0,0,, 这属于编程的艺术 \\N{\\fs12}It’s an art of programming thing.\r\nDialogue: 0,0:17:44.43,0:17:46.62,yin,,0,0,0,, 我要将参数变为 UIButton\\N{\\fs12}I’m going to change the argument to be a UIButton,\r\nDialogue: 0,0:17:46.62,0:17:49.04,yin,,0,0,0,, 和我们之前在 Connect 中所做操作一样 \\N{\\fs12}just like we did before in Connect.\r\nDialogue: 0,0:17:49.28,0:17:50.72,yin,,0,0,0,, 这个方法是做什么的 \\N{\\fs12}So what does this method do?\r\nDialogue: 0,0:17:50.72,0:17:52.77,yin,,0,0,0,, 希望通过这个长名字 \\N{\\fs12}Well, hopefully with that long name\r\nDialogue: 0,0:17:52.78,0:17:54.16,yin,,0,0,0,, 可以清楚地说明它的作用 \\N{\\fs12}it’s clear what that does, right?\r\nDialogue: 0,0:17:54.37,0:17:58.52,yin,,0,0,0,, 不管选中了这里正文的哪些内容 \\N{\\fs12}It changes whatever the selection is in our body right here,\r\nDialogue: 0,0:17:58.61,0:18:00.08,yin,,0,0,0,, 这个方法都会将选中文本的颜色 \\N{\\fs12}it changes the color of that\r\nDialogue: 0,0:18:00.35,0:18:02.99,yin,,0,0,0,, 设置为这个按钮的视图背景颜色 \\N{\\fs12}to match the background view of this button.\r\nDialogue: 0,0:18:03.61,0:18:05.05,yin,,0,0,0,, 这就是这个方法的功能 \\N{\\fs12}Okay? That’s what this method is going to do.\r\nDialogue: 0,0:18:05.23,0:18:06.89,yin,,0,0,0,, 这个方法只需要一行代码 \\N{\\fs12}This method is one line of code.\r\nDialogue: 0,0:18:07.55,0:18:09.52,yin,,0,0,0,, 我们来看看这行代码 \\N{\\fs12}Okay? So let’s look at that one line of code.\r\nDialogue: 0,0:18:10.80,0:18:14.74,yin,,0,0,0,, 我们需要设置正文中可变字符串的属性 \\N{\\fs12}We need to set attributes of the mutable string of our body.\r\nDialogue: 0,0:18:14.74,0:18:17.82,yin,,0,0,0,, 所以这里我要写 self.body.textStorage\\N{\\fs12}So I’m going to say self.body.textStorage.\r\nDialogue: 0,0:18:18.09,0:18:21.51,yin,,0,0,0,, 我得到了 NSMutableAttributedString\\N{\\fs12}Now I have the NSMutableAttributedString –\r\nDialogue: 0,0:18:21.51,0:18:22.98,yin,,0,0,0,,textStorage 是它的一个子类 \\N{\\fs12}textStorage is a subclass of it –\r\nDialogue: 0,0:18:23.00,0:18:24.80,yin,,0,0,0,, 但它是一个 NSMutableString\\N{\\fs12}but it is an NSMutableString.\r\nDialogue: 0,0:18:25.35,0:18:29.08,yin,,0,0,0,, 我只想增加一个属性 \\N{\\fs12}And I just want to add an attribute,\r\nDialogue: 0,0:18:29.23,0:18:33.28,yin,,0,0,0,, 代表选中文本的前景颜色 \\N{\\fs12}which is the foreground color of whatever’s selected there.\r\nDialogue: 0,0:18:33.28,0:18:35.05,yin,,0,0,0,, 这个属性叫做 \\N{\\fs12}So the attribute is called\r\nDialogue: 0,0:18:35.07,0:18:37.64,yin,,0,0,0,,NSForegroundColorAttributeName\\N{\\fs12}”NSForegroundColorAttributeName.”\r\nDialogue: 0,0:18:38.10,0:18:41.87,yin,,0,0,0,, 它的值就是我们想要设置的颜色 \\N{\\fs12}Okay? The value — that’s the color we want to set it to –\r\nDialogue: 0,0:18:42.02,0:18:43.10,yin,,0,0,0,, 我说了 我们想让它 \\N{\\fs12}well, I said we’re going to have it\r\nDialogue: 0,0:18:43.11,0:18:45.08,yin,,0,0,0,, 与按钮的背景颜色相同 \\N{\\fs12}match the background of the button.\r\nDialogue: 0,0:18:45.08,0:18:46.84,yin,,0,0,0,, 所以我要用 sender\\N{\\fs12}So I’m going to say sender,\r\nDialogue: 0,0:18:46.86,0:18:48.59,yin,,0,0,0,, 也就是发送它的按钮 \\N{\\fs12}which is the button that’s sending this thing,\r\nDialogue: 0,0:18:48.90,0:18:51.12,yin,,0,0,0,, 然后是 backgroundColor 明白吗 \\N{\\fs12}backgroundColor, okay?\r\nDialogue: 0,0:18:52.11,0:18:57.88,yin,,0,0,0,, 范围指的是文本视图保存内容的哪部分 \\N{\\fs12}And then the range is what range of this text view’s storage\r\nDialogue: 0,0:18:58.06,0:19:00.06,yin,,0,0,0,, 是我想要设置为目标颜色的 \\N{\\fs12}do I want to set to be that color?\r\nDialogue: 0,0:19:00.18,0:19:04.18,yin,,0,0,0,, 我说了我想改变的是正文的选中部分 \\N{\\fs12}Well, I said I want it to be the selection, the body selection –\r\nDialogue: 0,0:19:04.35,0:19:09.03,yin,,0,0,0,, 文本视图中有一个方法叫做 selectedRange\\N{\\fs12}so there’s a method in text view called “selectedRange.”\r\nDialogue: 0,0:19:09.15,0:19:12.96,yin,,0,0,0,, 能够返回选中内容的 NSRange\\N{\\fs12}And it returns an NSRange of what’s selected, okay,\r\nDialogue: 0,0:19:12.96,0:19:14.29,yin,,0,0,0,, 用户选中的内容 \\N{\\fs12}what the user selection is.\r\nDialogue: 0,0:19:14.93,0:19:16.79,yin,,0,0,0,, 就是这样一行代码 \\N{\\fs12}Okay? So you can see one line of code,\r\nDialogue: 0,0:19:17.65,0:19:21.08,yin,,0,0,0,, 我们需要所有四种颜色都正常运行 \\N{\\fs12}and we’ve got our color — all four color buttons working\r\nDialogue: 0,0:19:21.18,0:19:22.52,yin,,0,0,0,, 只要它们都正确连接好 \\N{\\fs12}as long as they’re all wired up,\r\nDialogue: 0,0:19:22.53,0:19:24.96,yin,,0,0,0,, 现在它没问题了 \\N{\\fs12}which we know that this one is, right?\r\nDialogue: 0,0:19:25.25,0:19:26.40,yin,,0,0,0,, 因为我们把它连上了 \\N{\\fs12}Okay, because we wired that one up.\r\nDialogue: 0,0:19:26.41,0:19:27.28,yin,,0,0,0,, 这里显示连好了 \\N{\\fs12}There it is right there.\r\nDialogue: 0,0:19:27.59,0:19:29.68,yin,,0,0,0,, 我们还没有连接这个按钮 我们来做一下 \\N{\\fs12}We haven’t wired this one up, but let’s do that.\r\nDialogue: 0,0:19:30.02,0:19:30.83,yin,,0,0,0,, 还有这个 \\N{\\fs12}And this one.\r\nDialogue: 0,0:19:31.39,0:19:32.01,yin,,0,0,0,, 以及这个 \\N{\\fs12}And this one.\r\nDialogue: 0,0:19:33.05,0:19:35.33,yin,,0,0,0,, 我们运行一下试试 \\N{\\fs12}Okay? So let’s go ahead and run.\r\nDialogue: 0,0:19:35.33,0:19:38.92,yin,,0,0,0,, 我们试试看能不能在这个设备上运行 \\N{\\fs12}We’ll try and see if we can run it on the device over here\r\nDialogue: 0,0:19:39.89,0:19:41.09,yin,,0,0,0,, 如果今天没问题的话 \\N{\\fs12}if that works today.\r\nDialogue: 0,0:19:41.33,0:19:44.54,yin,,0,0,0,, 希望不会出现技术问题 \\N{\\fs12}Hopefully no technical issues will arise.\r\nDialogue: 0,0:19:46.42,0:19:50.13,yin,,0,0,0,, 我们运行的是一个 iPhone 应用 \\N{\\fs12}Now, this is an iPhone app that we’re running here,\r\nDialogue: 0,0:19:50.13,0:19:51.84,yin,,0,0,0,, 而我们要在 iPad 上运行 \\N{\\fs12}and we’re running it on an iPad.\r\nDialogue: 0,0:19:51.84,0:19:53.81,yin,,0,0,0,, 我的演示设备恰好是一台 iPad\\N{\\fs12}My demo machine happens to be an iPad.\r\nDialogue: 0,0:19:54.23,0:19:57.43,yin,,0,0,0,, 所以程序运行在 iPhone 模拟模式下 \\N{\\fs12}So this is running kind of in iPhone emulation mode, okay,\r\nDialogue: 0,0:19:57.43,0:19:59.42,yin,,0,0,0,,iOS7 的 iPhone 模拟模式 \\N{\\fs12}which is actually better in iOS 7\r\nDialogue: 0,0:19:59.43,0:20:01.96,yin,,0,0,0,, 比之前 iOS 版本中的更好 \\N{\\fs12}than it was in previous versions of iOS.\r\nDialogue: 0,0:20:02.61,0:20:04.35,yin,,0,0,0,, 并不完全相同 \\N{\\fs12}It’s not quite exactly the same.\r\nDialogue: 0,0:20:04.35,0:20:06.36,yin,,0,0,0,, 注意顶部的这个状态栏 \\N{\\fs12}You notice that this status bar at the top,\r\nDialogue: 0,0:20:06.37,0:20:10.78,yin,,0,0,0,, 并没有运营商 \\N{\\fs12}you don’t get the, you know, what your carrier is,\r\nDialogue: 0,0:20:10.78,0:20:12.20,yin,,0,0,0,, 电池寿命等信息 \\N{\\fs12}and the battery life, and all that stuff.\r\nDialogue: 0,0:20:12.20,0:20:13.18,yin,,0,0,0,, 这些内容被去掉了 \\N{\\fs12}That’s kind of cut off.\r\nDialogue: 0,0:20:13.83,0:20:15.99,yin,,0,0,0,, 但是除此之外还是非常相似的 \\N{\\fs12}But otherwise it’s pretty similar.\r\nDialogue: 0,0:20:15.99,0:20:20.62,yin,,0,0,0,, 可以看到这段伪拉丁文本显示在了这里 \\N{\\fs12}So you can see that we got that kind of pseudo-Latin text in there,\r\nDialogue: 0,0:20:20.63,0:20:21.79,yin,,0,0,0,, 它是可以滚动的 \\N{\\fs12}and it’s scrollable.\r\nDialogue: 0,0:20:22.32,0:20:25.16,yin,,0,0,0,, 也可以选中 \\N{\\fs12}And it’s also selectable.\r\nDialogue: 0,0:20:25.16,0:20:27.53,yin,,0,0,0,, 我只要在单词上双击 \\N{\\fs12}So I just double tapped on that word.\r\nDialogue: 0,0:20:27.86,0:20:29.99,yin,,0,0,0,, 就选中了它 \\N{\\fs12}And we got it now.\r\nDialogue: 0,0:20:30.75,0:20:34.33,yin,,0,0,0,, 这些内容是系统自动实现的 比如定义单词 \\N{\\fs12}You get things for free on this, like defining words –\r\nDialogue: 0,0:20:34.33,0:20:35.50,yin,,0,0,0,, 在词典中进行查找 \\N{\\fs12}looking them up in the dictionary.\r\nDialogue: 0,0:20:35.50,0:20:38.55,yin,,0,0,0,, 如果点击这里的定义 会转到词典进行查找 \\N{\\fs12}So if we hit define right here, it goes and looks it up –\r\nDialogue: 0,0:20:38.99,0:20:42.42,yin,,0,0,0,, 没有找到 不奇怪 \\N{\\fs12}not found, not understand, no surprise there.\r\nDialogue: 0,0:20:43.43,0:20:44.84,yin,,0,0,0,, 但是可以查单词 \\N{\\fs12}But you can look that up.\r\nDialogue: 0,0:20:45.02,0:20:46.56,yin,,0,0,0,, 当然了 希望所有按钮都运行正常 \\N{\\fs12}And of course, hopefully all our buttons work.\r\nDialogue: 0,0:20:46.57,0:20:48.57,yin,,0,0,0,, 我们试试红色 \\N{\\fs12}So let’s try red.\r\nDialogue: 0,0:20:48.93,0:20:49.53,yin,,0,0,0,, 起作用了 \\N{\\fs12}That worked.\r\nDialogue: 0,0:20:49.53,0:20:51.18,yin,,0,0,0,, 还有橙色和紫色 \\N{\\fs12}And orange and purple.\r\nDialogue: 0,0:20:51.48,0:20:52.31,yin,,0,0,0,, 没问题 绿色呢 \\N{\\fs12}Okay? Green.\r\nDialogue: 0,0:20:52.91,0:20:54.27,yin,,0,0,0,, 也运行正常 \\N{\\fs12}So that’s working.\r\nDialogue: 0,0:20:54.27,0:20:55.05,yin,,0,0,0,, 设置都没问题 \\N{\\fs12}That’s setting things right.\r\nDialogue: 0,0:20:55.05,0:20:58.22,yin,,0,0,0,, 我还可以扩大选中范围 点击橙色按钮 \\N{\\fs12}I could actually extend my selection, go orange.\r\nDialogue: 0,0:20:58.22,0:20:59.16,yin,,0,0,0,, 将它们全部设置为橙色 \\N{\\fs12}Sets it all orange.\r\nDialogue: 0,0:20:59.32,0:21:00.44,yin,,0,0,0,, 选择另一个单词 设为红色 \\N{\\fs12}Pick another word, red.\r\nDialogue: 0,0:21:00.92,0:21:02.35,yin,,0,0,0,, 没问题 \\N{\\fs12}So that’s working.\r\nDialogue: 0,0:21:02.59,0:21:03.42,yin,,0,0,0,, 非常简单 \\N{\\fs12}Super easy.\r\nDialogue: 0,0:21:03.78,0:21:06.63,yin,,0,0,0,, 以上内容 大家都明白吗 \\N{\\fs12}Okay? Everyone understand what we’ve done so far?\r\nDialogue: 0,0:21:07.45,0:21:08.46,yin,,0,0,0,, 我们继续 \\N{\\fs12}So now let’s go on\r\nDialogue: 0,0:21:08.61,0:21:14.81,yin,,0,0,0,, 实现添加和去除轮廓按钮的功能 \\N{\\fs12}and do the outline button and the unoutline button.\r\nDialogue: 0,0:21:15.35,0:21:18.05,yin,,0,0,0,, 所以我只要从这里按住 control 键进行拖拽 \\N{\\fs12}So I’m just going to control drag from there.\r\nDialogue: 0,0:21:18.22,0:21:20.50,yin,,0,0,0,, 我要叫它 outline\\N{\\fs12}I’m going to call this “outline.”\r\nDialogue: 0,0:21:21.37,0:21:22.96,yin,,0,0,0,, 这里不需要任何参数 \\N{\\fs12}I don’t need any argument here\r\nDialogue: 0,0:21:22.97,0:21:27.17,yin,,0,0,0,, 因为我们不需要根据按钮来决定操作 \\N{\\fs12}because I’m not looking at the button to determine how to do it.\r\nDialogue: 0,0:21:27.17,0:21:29.95,yin,,0,0,0,, 实际上 为了不使用长消息名称 \\N{\\fs12}And in fact, in spirit of not long message names,\r\nDialogue: 0,0:21:29.95,0:21:32.35,yin,,0,0,0,, 我们叫它 outlineBodySelection\\N{\\fs12}let’s call it “outlineBodySelection.”\r\nDialogue: 0,0:21:33.01,0:21:35.10,yin,,0,0,0,, 这样可以更清楚地表现出 \\N{\\fs12}Okay, because that’s kind of even clearer exactly\r\nDialogue: 0,0:21:35.12,0:21:37.35,yin,,0,0,0,, 要给什么元素加轮廓 \\N{\\fs12}what the outline is going to outline.\r\nDialogue: 0,0:21:37.81,0:21:38.46,yin,,0,0,0,, 我们实现一下 \\N{\\fs12}So let’s do that.\r\nDialogue: 0,0:21:38.47,0:21:40.22,yin,,0,0,0,, 我们创建好了 outlineBodySelection\\N{\\fs12}Here we have outlineBodySelection.\r\nDialogue: 0,0:21:40.62,0:21:45.78,yin,,0,0,0,, 这个也和刚才一样 body.textStorage\\N{\\fs12}Again, this one’s same thing as before — body.textStorage –\r\nDialogue: 0,0:21:46.07,0:21:47.41,yin,,0,0,0,, 我们要添加属性 \\N{\\fs12}and we’re going to add attribute.\r\nDialogue: 0,0:21:47.41,0:21:51.22,yin,,0,0,0,, 实际上 想要添加轮廓 我们需要做两件事 \\N{\\fs12}But actually, to do an outline we need to do two things.\r\nDialogue: 0,0:21:51.52,0:21:54.46,yin,,0,0,0,, 一是我们需要设置描边宽度 \\N{\\fs12}One thing is we need to set the stroke width, okay?\r\nDialogue: 0,0:21:54.46,0:21:57.20,yin,,0,0,0,, 也就是字符被描边的宽度 \\N{\\fs12}That’s the width that the character gets stroked –\r\nDialogue: 0,0:21:57.20,0:21:59.43,yin,,0,0,0,, 不是填充 而是描边 它的外边缘 \\N{\\fs12}not filled but stroked, its outer edge.\r\nDialogue: 0,0:21:59.82,0:22:01.93,yin,,0,0,0,, 我们还想设置描边的颜色 \\N{\\fs12}And we also want to set the color of that stroke.\r\nDialogue: 0,0:22:01.94,0:22:03.03,yin,,0,0,0,, 我想设成黑色 \\N{\\fs12}I want it to be black.\r\nDialogue: 0,0:22:03.51,0:22:06.47,yin,,0,0,0,, 所以如果我们有一个单词 颜色已选定 \\N{\\fs12}Okay? So if we have a word and its color is selected,\r\nDialogue: 0,0:22:06.47,0:22:08.74,yin,,0,0,0,, 这个单词还是会填充选定的颜色 \\N{\\fs12}it will still fill with that color, okay,\r\nDialogue: 0,0:22:08.76,0:22:11.53,yin,,0,0,0,, 我要指定描边 进行填充和描边 \\N{\\fs12}because I’m going to specify a stroke that does a fill and a stroke.\r\nDialogue: 0,0:22:11.75,0:22:13.44,yin,,0,0,0,, 但是轮廓会是黑色 \\N{\\fs12}But the outline’s going to be in black.\r\nDialogue: 0,0:22:13.77,0:22:18.01,yin,,0,0,0,, 所以当我们添加属性时 需要使用 addAttributes\\N{\\fs12}So when we do add attribute, we need to do add attributes –plural\r\nDialogue: 0,0:22:18.27,0:22:19.63,yin,,0,0,0,, 添加两个属性 \\N{\\fs12}because we’re going to add two attributes.\r\nDialogue: 0,0:22:19.93,0:22:21.35,yin,,0,0,0,, 这是一个词典 \\N{\\fs12}Now, this is a dictionary,\r\nDialogue: 0,0:22:21.59,0:22:24.29,yin,,0,0,0,, 我可以在这里用 @和大括号 \\N{\\fs12}and I can just create this dictionary right on the fly here\r\nDialogue: 0,0:22:24.37,0:22:26.20,yin,,0,0,0,, 创建词典 \\N{\\fs12}with our at sign curly brace.\r\nDialogue: 0,0:22:26.73,0:22:30.18,yin,,0,0,0,, 我们需要一个描边宽度属性 \\N{\\fs12}And one of the things we want is the stroke width.\r\nDialogue: 0,0:22:30.37,0:22:32.31,yin,,0,0,0,, 这是 StrokeWidthAttributeName\\N{\\fs12}So here’s the StrokeWidthAttributeName.\r\nDialogue: 0,0:22:32.50,0:22:35.62,yin,,0,0,0,, 我要将它设置为 -3\\N{\\fs12}And I’m going to set the stroke width to minus three.\r\nDialogue: 0,0:22:35.90,0:22:37.99,yin,,0,0,0,, 如果你还记得的话 \\N{\\fs12}Okay? Minus three, if you’ll recall,\r\nDialogue: 0,0:22:38.00,0:22:41.59,yin,,0,0,0,,-3 表示描边宽度为 3 并进行填充 \\N{\\fs12}means stroke width of three and also fill.\r\nDialogue: 0,0:22:42.33,0:22:45.87,yin,,0,0,0,, 如果将其设置为 3 就不会进行填充 \\N{\\fs12}If I said stroke width of at sign three, it would not fill.\r\nDialogue: 0,0:22:45.87,0:22:46.65,yin,,0,0,0,, 描边会是空心的 \\N{\\fs12}It would be clear.\r\nDialogue: 0,0:22:46.72,0:22:48.83,yin,,0,0,0,, 对吧 中间是没有颜色的 \\N{\\fs12}Right? In the middle of it would be clear.\r\nDialogue: 0,0:22:49.20,0:22:49.83,yin,,0,0,0,, 我们不想要这种效果 \\N{\\fs12}So we don’t want that.\r\nDialogue: 0,0:22:49.83,0:22:50.51,yin,,0,0,0,, 我们希望描边是实心的 \\N{\\fs12}We want to fill.\r\nDialogue: 0,0:22:50.51,0:22:52.39,yin,,0,0,0,, 无论我们选择了哪种颜色 \\N{\\fs12}Whichever color we pick, we want that to.\r\nDialogue: 0,0:22:52.70,0:22:53.43,yin,,0,0,0,, 就是这样 \\N{\\fs12}So that’s that.\r\nDialogue: 0,0:22:53.91,0:23:00.00,yin,,0,0,0,, 然后我们还要将描边颜色属性 \\N{\\fs12}And then let’s also set the stroke color attribute\r\nDialogue: 0,0:23:00.34,0:23:02.92,yin,,0,0,0,, 设置为 UIColor blackColor\\N{\\fs12}to be UIColor blackColor.\r\nDialogue: 0,0:23:03.16,0:23:06.37,yin,,0,0,0,, 我做这个操作主要是为了让大家明白 \\N{\\fs12}So I’m just doing this mostly so you can see how to put,\r\nDialogue: 0,0:23:06.56,0:23:09.67,yin,,0,0,0,, 如何在代码里直接使用颜色 \\N{\\fs12}you know, an actual color in there\r\nDialogue: 0,0:23:09.68,0:23:11.85,yin,,0,0,0,, 而这个颜色是我们从别处抓取的 \\N{\\fs12}instead of here where we grabbed a color from somewhere else.\r\nDialogue: 0,0:23:11.85,0:23:15.07,yin,,0,0,0,, 你可以用这些 UIColor 中的类方法来实现 \\N{\\fs12}You can use these class methods in UIColor to do that.\r\nDialogue: 0,0:23:15.53,0:23:16.76,yin,,0,0,0,, 我们需要范围 \\N{\\fs12}And we need the range.\r\nDialogue: 0,0:23:16.76,0:23:19.34,yin,,0,0,0,, 和之前一样 selectedRange\\N{\\fs12}Same thing as before: selectedRange.\r\nDialogue: 0,0:23:21.12,0:23:22.97,yin,,0,0,0,, 所以现在我添加了这两个属性 \\N{\\fs12}Okay? So now we’re gonna\r\nDialogue: 0,0:23:22.99,0:23:26.21,yin,,0,0,0,, 以实现添加轮廓功能 \\N{\\fs12}add both those attributes to outline it.\r\nDialogue: 0,0:23:26.30,0:23:27.23,yin,,0,0,0,, 这就是我们需要的全部内容 \\N{\\fs12}That’s all we need there.\r\nDialogue: 0,0:23:27.42,0:23:30.03,yin,,0,0,0,, 顺便在这里继续实现去除轮廓的功能 \\N{\\fs12}Let’s do unoutline while we’re here.\r\nDialogue: 0,0:23:30.33,0:23:31.37,yin,,0,0,0,, 节省一点时间 \\N{\\fs12}Save ourselves a little bit of time.\r\nDialogue: 0,0:23:31.37,0:23:34.57,yin,,0,0,0,, 我要叫它 unoutlineBodySelection\\N{\\fs12}I’m going to call this “unoutlineBodySelection.”\r\nDialogue: 0,0:23:36.58,0:23:41.28,yin,,0,0,0,, 好了 为了向大家示范一个不同的方法 \\N{\\fs12}Done. And just again to show you a different method,\r\nDialogue: 0,0:23:41.53,0:23:45.34,yin,,0,0,0,, 我们通过移除描边宽度属性来实现去除轮廓 \\N{\\fs12}let’s unoutline by removing any stroke width attribute.\r\nDialogue: 0,0:23:45.34,0:23:47.76,yin,,0,0,0,, 也可以将描边宽度设为 0\\N{\\fs12}I could probably set the stroke width to zero as well.\r\nDialogue: 0,0:23:48.06,0:23:50.96,yin,,0,0,0,, 但这里我要用移除属性的方法 这样大家就能明白 \\N{\\fs12}But I’m going to remove so that you can see\r\nDialogue: 0,0:23:51.12,0:23:54.91,yin,,0,0,0,, 如何在 NSMutableAttributedString 中移除属性了 \\N{\\fs12}how in NSMutableAttributedString we can remove attributes.\r\nDialogue: 0,0:23:54.92,0:23:55.32,yin,,0,0,0,, 我们只要写 \\N{\\fs12}We just say\r\nDialogue: 0,0:23:55.34,0:24:03.45,yin,,0,0,0,,removeAttribute: NSStrokeWidthAttributeName range: self.body.selectedRange\\N{\\fs12}removeAttribute: NSStrokeWidthAttributeName range: self.body.selectedRange.\r\nDialogue: 0,0:24:04.53,0:24:06.11,yin,,0,0,0,, 这样就可以移除那个属性 \\N{\\fs12}Okay? So that’s going to remove that attribute.\r\nDialogue: 0,0:24:06.31,0:24:08.78,yin,,0,0,0,, 我们并不需要移除描边颜色 \\N{\\fs12}We don’t really need to remove the stroke color\r\nDialogue: 0,0:24:09.14,0:24:11.34,yin,,0,0,0,, 因为如果根本就没有描边 \\N{\\fs12}because if it’s not being stroked,\r\nDialogue: 0,0:24:11.34,0:24:12.32,yin,,0,0,0,, 颜色也就无从谈起 \\N{\\fs12}then the color doesn’t matter.\r\nDialogue: 0,0:24:12.55,0:24:13.51,yin,,0,0,0,, 所以可以把它留下 \\N{\\fs12}So it’s kind of in there.\r\nDialogue: 0,0:24:13.52,0:24:14.44,yin,,0,0,0,, 有点多余 \\N{\\fs12}It’s a little extra.\r\nDialogue: 0,0:24:15.37,0:24:16.78,yin,,0,0,0,, 你可能认为这样会浪费存储空间 \\N{\\fs12}You could argue maybe wasted storage.\r\nDialogue: 0,0:24:16.78,0:24:18.64,yin,,0,0,0,, 属性化字符串的存储 \\N{\\fs12}Although the storage of attributed string\r\nDialogue: 0,0:24:18.66,0:24:21.55,yin,,0,0,0,, 得到了极好的优化 \\N{\\fs12}is really optimized to the nth degree.\r\nDialogue: 0,0:24:21.56,0:24:24.77,yin,,0,0,0,, 所以我不会过多担心 \\N{\\fs12}Okay? So I wouldn’t worry too terribly much about that.\r\nDialogue: 0,0:24:25.32,0:24:25.72,yin,,0,0,0,, 好吧 \\N{\\fs12}All right.\r\nDialogue: 0,0:24:25.73,0:24:27.06,yin,,0,0,0,, 我们看看是否能正常运行 \\N{\\fs12}So let’s go see if that works.\r\nDialogue: 0,0:24:34.25,0:24:38.01,yin,,0,0,0,, 再选择一个单词 比如它 添加轮廓 \\N{\\fs12}Okay. So let’s pick another word here like this one, outline it.\r\nDialogue: 0,0:24:38.08,0:24:39.08,yin,,0,0,0,, 添加上了 \\N{\\fs12}That is outlined.\r\nDialogue: 0,0:24:39.08,0:24:42.34,yin,,0,0,0,, 看起来只是加粗了 因为它本身填充颜色就是黑色的 \\N{\\fs12}It just looks bold because it’s filled with black still.\r\nDialogue: 0,0:24:43.18,0:24:44.67,yin,,0,0,0,, 本来就是黑色的 \\N{\\fs12}Okay? Because black was the color that’s there.\r\nDialogue: 0,0:24:44.67,0:24:45.84,yin,,0,0,0,, 但是如果我用橙色填充它 \\N{\\fs12}But if I fill it with orange,\r\nDialogue: 0,0:24:45.96,0:24:47.13,yin,,0,0,0,, 现在看起来就不太一样了 \\N{\\fs12}you can see it looks a little different.\r\nDialogue: 0,0:24:47.50,0:24:49.35,yin,,0,0,0,, 对吧 或者选这个单词 \\N{\\fs12}Right? Or go over here to this word.\r\nDialogue: 0,0:24:49.80,0:24:53.52,yin,,0,0,0,, 变为红色 然后添加轮廓 明白吗 \\N{\\fs12}Let’s make it red and then outline it, okay?\r\nDialogue: 0,0:24:54.82,0:24:55.87,yin,,0,0,0,, 大家都明白了吗 \\N{\\fs12}Everyone cool with that?\r\nDialogue: 0,0:24:56.01,0:24:57.59,yin,,0,0,0,, 我们也可以去除轮廓 \\N{\\fs12}Then we can unoutline as well.\r\nDialogue: 0,0:24:58.49,0:24:59.15,yin,,0,0,0,, 再变为红色 \\N{\\fs12}Go back to red.\r\nDialogue: 0,0:24:59.16,0:25:00.58,yin,,0,0,0,, 这就是添加和去除轮廓 \\N{\\fs12}So outline, unoutline.\r\nDialogue: 0,0:25:01.68,0:25:03.93,yin,,0,0,0,, 大家明白了吗 \\N{\\fs12}Okay? Everyone understand that?\r\nDialogue: 0,0:25:05.13,0:25:06.58,yin,,0,0,0,, 现在就先这样了 \\N{\\fs12}Okay. So that’s it for now.\r\nDialogue: 0,0:25:06.58,0:25:07.56,yin,,0,0,0,, 我们等会再回来 \\N{\\fs12}We’ll be back to this in a second.\r\nDialogue: 0,0:25:07.57,0:25:07.80,yin,,0,0,0,, 请讲 \\N{\\fs12}Yeah?\r\nDialogue: 0,0:25:08.15,0:25:10.86,yin,,0,0,0,, 我不是很清楚 \\N{\\fs12}Yeah, I’m not quite sure that I understand the difference\r\nDialogue: 0,0:25:10.87,0:25:13.09,yin,,0,0,0,,-3 和 +3 的区别 \\N{\\fs12}between the negative three and positive three.\r\nDialogue: 0,0:25:13.10,0:25:16.06,yin,,0,0,0,, 什么样子是被填充了 什么样子不是呢 \\N{\\fs12}Like, what’s getting filled or isn’t getting filled?\r\nDialogue: 0,0:25:16.07,0:25:16.92,yin,,0,0,0,, 好问题 \\N{\\fs12}Okay. Great question.\r\nDialogue: 0,0:25:16.93,0:25:18.87,yin,,0,0,0,, 确认一下 \\N{\\fs12}So let’s just be a hundred percent clear:\r\nDialogue: 0,0:25:18.87,0:25:21.53,yin,,0,0,0,, 我们这里用的 -3\\N{\\fs12}What’s the difference between the negative three\r\nDialogue: 0,0:25:21.69,0:25:25.84,yin,,0,0,0,, 和 +3 有什么区别 \\N{\\fs12}that we have right here, okay, and positive three?\r\nDialogue: 0,0:25:26.09,0:25:28.62,yin,,0,0,0,,-3 表示… 这样吧 \\N{\\fs12}Negative three means — in fact, you know what?\r\nDialogue: 0,0:25:28.63,0:25:30.45,yin,,0,0,0,, 稍后我会在演示里做一下 \\N{\\fs12}I’ll show you a demo of it a little later.\r\nDialogue: 0,0:25:31.72,0:25:33.27,yin,,0,0,0,, 看见这个 Outline 按钮了吗 \\N{\\fs12}See the button that says “Outline”?\r\nDialogue: 0,0:25:33.52,0:25:35.68,yin,,0,0,0,, 等会我们会为它添加轮廓 \\N{\\fs12}Later we’re going to change it to be Outlined.\r\nDialogue: 0,0:25:35.93,0:25:38.55,yin,,0,0,0,, 我们不会填充它 这样大家就能看到 \\N{\\fs12}Okay? And we won’t fill it, and you’ll see the difference,\r\nDialogue: 0,0:25:38.67,0:25:40.88,yin,,0,0,0,, 不用颜色填充的不同之处了 \\N{\\fs12}that it’s not going to be filled with a color, okay?\r\nDialogue: 0,0:25:41.58,0:25:43.54,yin,,0,0,0,, 我们回到幻灯片 \\N{\\fs12}So let’s get back to the slides, though.\r\nDialogue: 0,0:25:45.13,0:25:47.19,yin,,0,0,0,, 回到这里 \\N{\\fs12}And over here.\r\nDialogue: 0,0:25:49.47,0:25:50.28,yin,,0,0,0,, 看下一张幻灯片 \\N{\\fs12}Next. Okay?\r\nDialogue: 0,0:25:50.97,0:25:51.99,yin,,0,0,0,, 视图控制器生命周期 \\N{\\fs12}View controller lifecycle.\r\nDialogue: 0,0:25:52.01,0:25:54.99,yin,,0,0,0,, 理解它很重要 \\N{\\fs12}Okay. So this is important thing to understand,\r\nDialogue: 0,0:25:55.01,0:25:56.55,yin,,0,0,0,, 视图控制器生命周期 \\N{\\fs12}the view controller lifecycle,\r\nDialogue: 0,0:25:56.78,0:26:00.37,yin,,0,0,0,, 因为你需要控制的很多 \\N{\\fs12}because a lot of the things that you’re going to control\r\nDialogue: 0,0:26:00.39,0:26:04.40,yin,,0,0,0,, 关于视图控制器如何随时间变化的操作 \\N{\\fs12}about how your view controller moves through time\r\nDialogue: 0,0:26:04.74,0:26:06.56,yin,,0,0,0,, 都要用到视图控制器生命周期中的方法 \\N{\\fs12}are going to be controlled by the methods\r\nDialogue: 0,0:26:06.57,0:26:08.48,yin,,0,0,0,, 来实现控制 \\N{\\fs12}that are part of the view controller lifecycle.\r\nDialogue: 0,0:26:08.68,0:26:10.28,yin,,0,0,0,, 视图控制器生命周期 \\N{\\fs12}Now, all the view controller lifecycle is,\r\nDialogue: 0,0:26:10.29,0:26:12.04,yin,,0,0,0,, 就是一系列的方法 \\N{\\fs12}is a series of methods, okay,\r\nDialogue: 0,0:26:12.26,0:26:15.59,yin,,0,0,0,, 当事件发生时 会被发送至 UIViewController\\N{\\fs12}that are sent to UIViewController when things happen.\r\nDialogue: 0,0:26:15.60,0:26:18.37,yin,,0,0,0,, 你的控制器是 UIViewController 的一个子类 \\N{\\fs12}Now, your controller is a subclass of UIViewController.\r\nDialogue: 0,0:26:18.38,0:26:19.23,yin,,0,0,0,, 你可能已经注意到了 \\N{\\fs12}You probably noticed that.\r\nDialogue: 0,0:26:19.25,0:26:20.12,yin,,0,0,0,, 如果你看看代码 \\N{\\fs12}If you look at your code,\r\nDialogue: 0,0:26:20.13,0:26:22.94,yin,,0,0,0,, 会发现你新建应用时 \\N{\\fs12}you’ll see that your controller that gets created for you\r\nDialogue: 0,0:26:22.95,0:26:25.05,yin,,0,0,0,, 由模板创建的控制器 \\N{\\fs12}by the template when you create a new app\r\nDialogue: 0,0:26:25.24,0:26:26.67,yin,,0,0,0,, 是 UIViewController 的一个子类 \\N{\\fs12}is a subclass of UIViewController.\r\nDialogue: 0,0:26:26.68,0:26:28.14,yin,,0,0,0,, 它会发送这些消息 \\N{\\fs12}So it’s going to be sent these messages,\r\nDialogue: 0,0:26:28.31,0:26:30.04,yin,,0,0,0,, 如果你想要知道这些事件何时发生 \\N{\\fs12}and you’re going to override them\r\nDialogue: 0,0:26:30.21,0:26:32.68,yin,,0,0,0,, 就要重写这些方法 \\N{\\fs12}if you want to find out when these things are happening.\r\nDialogue: 0,0:26:32.83,0:26:34.67,yin,,0,0,0,, 不要忘了调用超类 \\N{\\fs12}Don’t forget to call super. Okay?\r\nDialogue: 0,0:26:37.04,0:26:38.62,yin,,0,0,0,, 你为什么需要这些东西 \\N{\\fs12}Why do you need these things?\r\nDialogue: 0,0:26:38.63,0:26:41.56,yin,,0,0,0,, 你需要对控制器进行初始化 \\N{\\fs12}Well, you need to be able to initialize your controller;\r\nDialogue: 0,0:26:41.57,0:26:43.63,yin,,0,0,0,, 你需要知道自己何时在屏幕上出现和消失 \\N{\\fs12}you need to be able to find when you come on and off screen;\r\nDialogue: 0,0:26:43.64,0:26:46.72,yin,,0,0,0,, 你需要知道边界何时改变 \\N{\\fs12}you need to know when your bounds change, right,\r\nDialogue: 0,0:26:46.74,0:26:47.80,yin,,0,0,0,, 你的几何变化 \\N{\\fs12}your geometry changes.\r\nDialogue: 0,0:26:47.97,0:26:49.55,yin,,0,0,0,, 你需要知道这些消息 \\N{\\fs12}You got to know these things\r\nDialogue: 0,0:26:49.56,0:26:52.46,yin,,0,0,0,, 这样你的视图控制器的视图 \\N{\\fs12}for your view controller’s view\r\nDialogue: 0,0:26:52.47,0:26:54.97,yin,,0,0,0,, 才能在 iOS 环境中正常运行 \\N{\\fs12}to successfully live in the iOS world.\r\nDialogue: 0,0:26:55.73,0:26:59.79,yin,,0,0,0,, 这个生命周期开始于创建 对吗 \\N{\\fs12}So the start of this lifecycle is creation, okay?\r\nDialogue: 0,0:26:59.96,0:27:04.66,yin,,0,0,0,, 大部分视图控制器都是从 storyboard 中创建的 \\N{\\fs12}Most view controllers are created out of storyboards.\r\nDialogue: 0,0:27:04.73,0:27:07.35,yin,,0,0,0,, 我讲过了 storyboard 不会生成代码 \\N{\\fs12}And I told you that storyboards don’t generate code.\r\nDialogue: 0,0:27:07.52,0:27:10.27,yin,,0,0,0,, 你基本上是直接编辑这些对象 \\N{\\fs12}You’re basically editing those objects live –\r\nDialogue: 0,0:27:10.27,0:27:12.01,yin,,0,0,0,, 那个 UITextView 那些按钮 \\N{\\fs12}that UITextView, those buttons –\r\nDialogue: 0,0:27:12.02,0:27:13.94,yin,,0,0,0,, 你直接在 Xcode 中编辑它们 \\N{\\fs12}you’re editing them live in Xcode.\r\nDialogue: 0,0:27:14.15,0:27:16.95,yin,,0,0,0,, 然后当保存 storyboard 时 \\N{\\fs12}And when that storyboard gets saved,\r\nDialogue: 0,0:27:16.95,0:27:18.32,yin,,0,0,0,, 它们像是被冷冻干燥了 \\N{\\fs12}they kind of get freeze-dried.\r\nDialogue: 0,0:27:18.48,0:27:20.38,yin,,0,0,0,, 然后当你运行应用时 \\N{\\fs12}And then when your application runs,\r\nDialogue: 0,0:27:20.40,0:27:23.42,yin,,0,0,0,, 水又回来了 它们又活过来了 \\N{\\fs12}water gets added back to them and they come back to life, okay?\r\nDialogue: 0,0:27:23.59,0:27:26.61,yin,,0,0,0,, 这是生命周期的创建部分 \\N{\\fs12}So that’s the creation part of the lifecycle.\r\nDialogue: 0,0:27:26.75,0:27:29.72,yin,,0,0,0,, 在创建时 我们并不做很多事情 \\N{\\fs12}And we don’t really do much at creation.\r\nDialogue: 0,0:27:29.73,0:27:31.73,yin,,0,0,0,, 实际上 我要把创建这部分的内容 \\N{\\fs12}In fact, I’m not even going to talk about creation\r\nDialogue: 0,0:27:31.74,0:27:34.22,yin,,0,0,0,, 放在视图控制器生命周期的最后讲 \\N{\\fs12}until the very end of the view controller lifecycle.\r\nDialogue: 0,0:27:34.23,0:27:36.50,yin,,0,0,0,, 尽管按发生顺序来说 它是开始 \\N{\\fs12}Even though it is chronologically the beginning,\r\nDialogue: 0,0:27:36.51,0:27:38.03,yin,,0,0,0,, 但却是目前最不重要的 \\N{\\fs12}it’s by far the least important.\r\nDialogue: 0,0:27:38.04,0:27:40.26,yin,,0,0,0,, 所以我把它放在最后 \\N{\\fs12}So I’m emphasizing that by putting it at the end.\r\nDialogue: 0,0:27:41.58,0:27:45.76,yin,,0,0,0,, 创建之后 你会经历以下过程 \\N{\\fs12}But after it’s created, you go through the following process.\r\nDialogue: 0,0:27:45.78,0:27:48.29,yin,,0,0,0,, 设置好输出口 对吧 \\N{\\fs12}Your outlets get set, okay?\r\nDialogue: 0,0:27:48.30,0:27:49.58,yin,,0,0,0,, 这些输出口必须设置好 \\N{\\fs12}Got to have those outlets set.\r\nDialogue: 0,0:27:49.78,0:27:54.06,yin,,0,0,0,, 然后你的视图控制器出现在屏幕上 \\N{\\fs12}Then your view controller appears on screen\r\nDialogue: 0,0:27:54.29,0:27:56.04,yin,,0,0,0,, 它也许会从屏幕上消失 \\N{\\fs12}and it might disappear from screen.\r\nDialogue: 0,0:27:56.10,0:27:57.05,yin,,0,0,0,, 你还没有见过它消失 \\N{\\fs12}You haven’t seen that yet\r\nDialogue: 0,0:27:57.06,0:27:57.66,yin,,0,0,0,, 因为目前 \\N{\\fs12}because right now\r\nDialogue: 0,0:27:57.67,0:27:59.75,yin,,0,0,0,, 你的整个应用中就只有一个视图控制器 \\N{\\fs12}you’ve only had one view controller in your whole app.\r\nDialogue: 0,0:27:59.76,0:28:01.45,yin,,0,0,0,, 只有应用退出时 它才会消失 \\N{\\fs12}It only disappears when the app quits.\r\nDialogue: 0,0:28:01.63,0:28:03.31,yin,,0,0,0,, 但是如果你有多个视图控制器 \\N{\\fs12}But when you have multiple view controllers,\r\nDialogue: 0,0:28:03.42,0:28:05.50,yin,,0,0,0,, 它们会交替在屏幕上出现和消失 \\N{\\fs12}they’ll appear and disappear on screen.\r\nDialogue: 0,0:28:05.68,0:28:07.17,yin,,0,0,0,, 它们的几何变化 \\N{\\fs12}Their geometry changes –\r\nDialogue: 0,0:28:07.25,0:28:08.99,yin,,0,0,0,, 无论是因为旋转 \\N{\\fs12}either device rotation\r\nDialogue: 0,0:28:09.00,0:28:12.59,yin,,0,0,0,, 还是其他原因造成的 \\N{\\fs12}or something else can cause their bounds to change\r\nDialogue: 0,0:28:12.61,0:28:14.16,yin,,0,0,0,,MVC 的视图的边界变化 \\N{\\fs12}of your view of your MVC.\r\nDialogue: 0,0:28:14.50,0:28:15.88,yin,,0,0,0,, 内存不足的情况 \\N{\\fs12}Low memory situations –\r\nDialogue: 0,0:28:15.89,0:28:18.17,yin,,0,0,0,, 严格来说并不属于视图控制器生命周期 \\N{\\fs12}again, not strictly speaking part of the view controller lifecycle\r\nDialogue: 0,0:28:18.18,0:28:19.82,yin,,0,0,0,, 但这也可能在运行时出现 \\N{\\fs12}but that can happen while you’re running.\r\nDialogue: 0,0:28:20.09,0:28:22.90,yin,,0,0,0,, 每一步都会调用一个方法 \\N{\\fs12}And at each of these steps a method gets called.\r\nDialogue: 0,0:28:22.92,0:28:25.64,yin,,0,0,0,, 我们先看第一个方法 ViewDidLoad\\N{\\fs12}So let’s look at the first one: ViewDidLoad.\r\nDialogue: 0,0:28:25.95,0:28:28.17,yin,,0,0,0,, 我们在代码中见过它 我没有删掉它 \\N{\\fs12}So that’s the one we saw in the code that I didn’t delete.\r\nDialogue: 0,0:28:28.42,0:28:30.25,yin,,0,0,0,, 这里很适合于 \\N{\\fs12}This is a really great place\r\nDialogue: 0,0:28:30.26,0:28:32.24,yin,,0,0,0,, 放置控制器初始化代码 \\N{\\fs12}to put initialization code for your controller.\r\nDialogue: 0,0:28:32.25,0:28:33.64,yin,,0,0,0,, 你可以把它看做是 \\N{\\fs12}You can kind of think of it\r\nDialogue: 0,0:28:33.95,0:28:37.47,yin,,0,0,0,, 放置 init 全部内容的地方 \\N{\\fs12}as where you would put all the stuff from your init, okay,\r\nDialogue: 0,0:28:37.66,0:28:39.64,yin,,0,0,0,, 因为你的 init 并不会被调用 \\N{\\fs12}because your init is not going to get called –\r\nDialogue: 0,0:28:39.65,0:28:41.81,yin,,0,0,0,, 不会在视图控制器中调用 等下会看到 \\N{\\fs12}as you’re going to see — for your view controller.\r\nDialogue: 0,0:28:41.82,0:28:44.12,yin,,0,0,0,, 它为什么比 init 更好呢 \\N{\\fs12}So why is this better than init?\r\nDialogue: 0,0:28:44.15,0:28:46.25,yin,,0,0,0,, 因为你已经设置好了输出口 \\N{\\fs12}Because your outlets are set.\r\nDialogue: 0,0:28:47.14,0:28:50.52,yin,,0,0,0,, 通常情况下 如果你想要初始化视图 \\N{\\fs12}Okay? Very important for your outlets to be set usually\r\nDialogue: 0,0:28:50.61,0:28:52.27,yin,,0,0,0,, 设置好输出口是十分重要的 \\N{\\fs12}if you want to initialize your view.\r\nDialogue: 0,0:28:52.28,0:28:54.74,yin,,0,0,0,, 因为你想让你的标签 \\N{\\fs12}Because you want to set your labels\r\nDialogue: 0,0:28:54.75,0:28:56.50,yin,,0,0,0,, 显示些什么 \\N{\\fs12}to say something or whatever.\r\nDialogue: 0,0:28:57.46,0:29:01.91,yin,,0,0,0,, 在 Matchismo 中 开始时是牌面向下的 \\N{\\fs12}You know, in the Matchismo game we started with the cards facedown\r\nDialogue: 0,0:29:01.92,0:29:04.01,yin,,0,0,0,, 因为我们当时不知道如何在开始时让牌面向上 \\N{\\fs12}because we didn’t really know how to start faceup.\r\nDialogue: 0,0:29:04.10,0:29:06.38,yin,,0,0,0,, 这里就可以设置第一张牌 \\N{\\fs12}Okay? Well, this is where you would set the first card.\r\nDialogue: 0,0:29:06.55,0:29:06.84,yin,,0,0,0,, 明白吗 \\N{\\fs12}All right?\r\nDialogue: 0,0:29:06.85,0:29:08.98,yin,,0,0,0,, 你可以绘制第一张牌 让它…\\N{\\fs12}You’d draw the first card, have it –\r\nDialogue: 0,0:29:09.41,0:29:11.88,yin,,0,0,0,, 说的是 Matchismo 不是你们的作业 是我们在课上做的 \\N{\\fs12}this is the Matchismo, not your assignment but what we did in class –\r\nDialogue: 0,0:29:12.14,0:29:14.11,yin,,0,0,0,, 想让卡牌在开始时牌面向上 \\N{\\fs12}have it start with the card faceup.\r\nDialogue: 0,0:29:14.13,0:29:15.45,yin,,0,0,0,, 你要在 viewDidLoad 中实现 \\N{\\fs12}You would do this in viewDidLoad\r\nDialogue: 0,0:29:15.46,0:29:17.33,yin,,0,0,0,, 因为这里输出口都设置好了 \\N{\\fs12}because here your outlets are set.\r\nDialogue: 0,0:29:17.34,0:29:18.69,yin,,0,0,0,, 我可以向按钮发送消息 \\N{\\fs12}So I can talk to that button.\r\nDialogue: 0,0:29:18.75,0:29:20.76,yin,,0,0,0,, 当时 Matchismo 只有一个按钮 \\N{\\fs12}It was a single button in Matchismo at the time.\r\nDialogue: 0,0:29:21.86,0:29:23.54,yin,,0,0,0,, 但是我还没有出现在屏幕上 \\N{\\fs12}But I’m not on screen yet.\r\nDialogue: 0,0:29:23.81,0:29:26.27,yin,,0,0,0,, 你在屏幕上出现之前 viewDidLoad 会被调用 \\N{\\fs12}ViewDidLoad gets called before you come on screen.\r\nDialogue: 0,0:29:27.02,0:29:28.65,yin,,0,0,0,, 所以这里很适合执行这类操作 \\N{\\fs12}So it’s a great place to do stuff like that.\r\nDialogue: 0,0:29:28.88,0:29:31.93,yin,,0,0,0,, 在控制器生命周期中 \\N{\\fs12}ViewDidLoad will only ever be called once\r\nDialogue: 0,0:29:32.61,0:29:34.05,yin,,0,0,0,,viewDidLoad 只会被调用一次 \\N{\\fs12}in the lifetime of your controller.\r\nDialogue: 0,0:29:34.42,0:29:35.65,yin,,0,0,0,, 一个周期中只会被调用一次 \\N{\\fs12}Period. Once.\r\nDialogue: 0,0:29:35.66,0:29:36.98,yin,,0,0,0,, 绝不会多于一次 \\N{\\fs12}It never gets called more than once.\r\nDialogue: 0,0:29:37.75,0:29:40.27,yin,,0,0,0,, 这是一个绝好的地方 \\N{\\fs12}Okay? It is a spectacularly great place\r\nDialogue: 0,0:29:40.28,0:29:41.59,yin,,0,0,0,, 来放置初始化代码 \\N{\\fs12}to put initialization code.\r\nDialogue: 0,0:29:41.60,0:29:44.96,yin,,0,0,0,, 但是有一些操作是不可以在 viewDidLoad 中可执行的 \\N{\\fs12}However, there are limits to what can go in viewDidLoad,\r\nDialogue: 0,0:29:45.12,0:29:47.51,yin,,0,0,0,, 尤其是关于几何的代码 \\N{\\fs12}most especially geometry code.\r\nDialogue: 0,0:29:47.81,0:29:49.74,yin,,0,0,0,,viewDidLoad 被调用时 \\N{\\fs12}At the time viewDidLoad is called,\r\nDialogue: 0,0:29:50.05,0:29:54.22,yin,,0,0,0,, 视图的边界还没有定下来 \\N{\\fs12}the bounds of your view is not finalized.\r\nDialogue: 0,0:29:54.52,0:29:57.38,yin,,0,0,0,, 它也许只是待在 storyboard 里 \\N{\\fs12}It’s probably just sitting at whatever it was in the storyboard,\r\nDialogue: 0,0:29:57.46,0:30:00.53,yin,,0,0,0,, 当它出现在屏幕上时 也许不会出现在预定位置 \\N{\\fs12}which may or may not be what’s going to happen when it’s on screen\r\nDialogue: 0,0:30:00.54,0:30:01.89,yin,,0,0,0,, 因为它运行在一个不同的设备上 \\N{\\fs12}because it might be on a little different device,\r\nDialogue: 0,0:30:01.90,0:30:04.71,yin,,0,0,0,, 在不同的地点 或者被旋转了之类的 \\N{\\fs12}or different place, or it might be rotated, or something like that.\r\nDialogue: 0,0:30:05.04,0:30:08.40,yin,,0,0,0,, 所以不要在 viewDidLoad 中添加与几何相关的代码 \\N{\\fs12}So you do not want to put geometry-related code –\r\nDialogue: 0,0:30:08.42,0:30:10.88,yin,,0,0,0,, 换句话说 不要在 viewDidLoad 中 \\N{\\fs12}in other words, any initialization that has to do\r\nDialogue: 0,0:30:10.89,0:30:15.34,yin,,0,0,0,, 添加任何关于视图形状的初始化信息 \\N{\\fs12}with what the shape of your view is — in viewDidLoad.\r\nDialogue: 0,0:30:16.36,0:30:16.83,yin,,0,0,0,, 明白吗 \\N{\\fs12}Okay?\r\nDialogue: 0,0:30:17.78,0:30:19.69,yin,,0,0,0,, 这是 viewDidLoad 中的主要限制 \\N{\\fs12}That’s the major restriction in viewDidLoad.\r\nDialogue: 0,0:30:20.00,0:30:21.06,yin,,0,0,0,, 但除此之外 这是执行初始化的好地方 \\N{\\fs12}But otherwise, it’s a great place\r\nDialogue: 0,0:30:21.06,0:30:24.01,yin,,0,0,0,, 因为它在输出口设置好 你出现在屏幕上之前 \\N{\\fs12}because it only gets called once before you go on screen\r\nDialogue: 0,0:30:24.05,0:30:25.47,yin,,0,0,0,, 只会被调用一次 \\N{\\fs12}after your outlets get set.\r\nDialogue: 0,0:30:25.48,0:30:26.38,yin,,0,0,0,, 这是一个很棒的方法 \\N{\\fs12}It’s an awesome method.\r\nDialogue: 0,0:30:26.68,0:30:27.68,yin,,0,0,0,, 强烈推荐 \\N{\\fs12}Okay? Highly recommend it.\r\nDialogue: 0,0:30:29.63,0:30:35.62,yin,,0,0,0,, 在你的视图控制器的视图就要出现在屏幕上之前 \\N{\\fs12}Now, just before your view controller view appears on screen,\r\nDialogue: 0,0:30:36.02,0:30:37.29,yin,,0,0,0,, 系统会调用 viewWillAppear 方法 \\N{\\fs12}you get viewWillAppear.\r\nDialogue: 0,0:30:37.76,0:30:41.16,yin,,0,0,0,, 这是一个放置代码的好地方 \\N{\\fs12}Okay? This is a pretty good place to put things.\r\nDialogue: 0,0:30:41.28,0:30:45.46,yin,,0,0,0,, 在某些方面 它不如 viewDidLoad\\N{\\fs12}It’s not really as awesome as viewDidLoad in some ways.\r\nDialogue: 0,0:30:45.86,0:30:49.05,yin,,0,0,0,, 我甚至不确定是否在这里添加了几何相关内容 \\N{\\fs12}And I’m not even sure I’d put geometry-related stuff in here,\r\nDialogue: 0,0:30:49.05,0:30:50.68,yin,,0,0,0,, 下面的幻灯片中可以看到 \\N{\\fs12}as you’ll see in a couple of slides.\r\nDialogue: 0,0:30:51.05,0:30:53.37,yin,,0,0,0,, 但是 确实有一些内容要放在这里 \\N{\\fs12}However, there are some things you do want to put in here.\r\nDialogue: 0,0:30:53.37,0:30:55.91,yin,,0,0,0,, 需要注意的一点是 \\N{\\fs12}Now, one thing you want to be careful about\r\nDialogue: 0,0:30:55.92,0:30:59.52,yin,,0,0,0,, 不要在 viewWillAppear 中添加一次性初始化内容 \\N{\\fs12}not putting in viewWillAppear is one-time initialization\r\nDialogue: 0,0:30:59.52,0:31:01.12,yin,,0,0,0,, 这属于 viewDidLoad 的内容 \\N{\\fs12}that really belongs in ViewDidLoad\r\nDialogue: 0,0:31:01.42,0:31:04.41,yin,,0,0,0,, 因为当应用中有多个 MVC 时 \\N{\\fs12}because, again, when you have multiple MVCs in your app,\r\nDialogue: 0,0:31:04.52,0:31:06.23,yin,,0,0,0,, 它们会交替出现消失 \\N{\\fs12}they’re going to be appearing and disappearing.\r\nDialogue: 0,0:31:06.50,0:31:07.95,yin,,0,0,0,, 所以 viewWillAppear\\N{\\fs12}And so viewWillAppear is going to\r\nDialogue: 0,0:31:07.96,0:31:10.13,yin,,0,0,0,, 会被多次调用 \\N{\\fs12}get called multiple times, okay?\r\nDialogue: 0,0:31:10.13,0:31:12.04,yin,,0,0,0,, 每次视图重新在屏幕上显示时 \\N{\\fs12}Every time your view appears back on screen,\r\nDialogue: 0,0:31:12.09,0:31:13.56,yin,,0,0,0,,viewWillAppear 都会被再次调用 \\N{\\fs12}viewWillAppear gets called again.\r\nDialogue: 0,0:31:14.04,0:31:15.74,yin,,0,0,0,, 所以如果你把一次性初始化操作 \\N{\\fs12}So if it’s a one-time initialization,\r\nDialogue: 0,0:31:15.74,0:31:16.69,yin,,0,0,0,, 放在了 viewWillAppear 中 \\N{\\fs12}you put it in viewWillAppear,\r\nDialogue: 0,0:31:16.69,0:31:18.63,yin,,0,0,0,, 每次视图重新出现时 都会被执行 \\N{\\fs12}it’s going to happen every time your thing reappears.\r\nDialogue: 0,0:31:19.23,0:31:20.86,yin,,0,0,0,, 那么 viewWillAppear 中应该放些什么呢 \\N{\\fs12}So what does go in viewWillAppear?\r\nDialogue: 0,0:31:20.86,0:31:26.48,yin,,0,0,0,, 如果你需要执行的某些初始化 \\N{\\fs12}Well, one thing is if there’s some initialization you need to do,\r\nDialogue: 0,0:31:26.74,0:31:29.64,yin,,0,0,0,, 基于某些数据 而这些数据 \\N{\\fs12}based on some data that might have changed\r\nDialogue: 0,0:31:29.77,0:31:31.78,yin,,0,0,0,, 可能会在视图控制器的视图离开屏幕时发生变化 \\N{\\fs12}while your view controller’s view was off screen.\r\nDialogue: 0,0:31:32.40,0:31:33.69,yin,,0,0,0,, 懂吗 比如说你的模型 \\N{\\fs12}Okay? So like your model.\r\nDialogue: 0,0:31:33.69,0:31:35.15,yin,,0,0,0,, 模型中的某些内容变了 \\N{\\fs12}Something changed in your model.\r\nDialogue: 0,0:31:35.40,0:31:36.72,yin,,0,0,0,, 你的视图控制器不在屏幕上了 \\N{\\fs12}Your view controller was off screen,\r\nDialogue: 0,0:31:36.72,0:31:38.91,yin,,0,0,0,, 它并没有监听模型的变化 \\N{\\fs12}so it wasn’t really listening for changes in the model.\r\nDialogue: 0,0:31:39.16,0:31:40.90,yin,,0,0,0,, 然后它又回到了屏幕上 \\N{\\fs12}And then coming back on screen,\r\nDialogue: 0,0:31:41.06,0:31:42.49,yin,,0,0,0,, 这时你最好与模型进行同步 \\N{\\fs12}you better sync up with the model.\r\nDialogue: 0,0:31:43.22,0:31:44.09,yin,,0,0,0,, 这么说明白吗 \\N{\\fs12}Does that make sense?\r\nDialogue: 0,0:31:44.64,0:31:47.61,yin,,0,0,0,, 你之前不在屏幕上了 现在又重新出现在屏幕上 \\N{\\fs12}Because you were off screen and now you’re appearing.\r\nDialogue: 0,0:31:47.97,0:31:50.14,yin,,0,0,0,,viewWillAppear 方法适合于 \\N{\\fs12}And so this is a good thing to put in viewWillAppear:\r\nDialogue: 0,0:31:50.15,0:31:52.56,yin,,0,0,0,, 对不可见时可能改变的内容 \\N{\\fs12}Synchronization with things that might have changed\r\nDialogue: 0,0:31:52.57,0:31:53.66,yin,,0,0,0,, 进行同步 \\N{\\fs12}while you weren’t visible,\r\nDialogue: 0,0:31:53.66,0:31:55.71,yin,,0,0,0,, 包括 \\N{\\fs12}including things that, you know,\r\nDialogue: 0,0:31:55.71,0:31:58.53,yin,,0,0,0,, 准备第一次出现前发生的变化 \\N{\\fs12}were changing before you appeared for the first time.\r\nDialogue: 0,0:31:58.53,0:31:59.55,yin,,0,0,0,, 因为 viewWillAppear\\N{\\fs12}Because viewWillAppear, of course,\r\nDialogue: 0,0:31:59.55,0:32:01.47,yin,,0,0,0,, 也会在第一次出现时被调用 \\N{\\fs12}gets called the first time you appear as well.\r\nDialogue: 0,0:32:01.65,0:32:04.08,yin,,0,0,0,, 这个方法不叫视图将要再次出现 叫视图将要出现 \\N{\\fs12}Okay? This is not view will reappear; it’s viewWillAppear.\r\nDialogue: 0,0:32:04.84,0:32:07.63,yin,,0,0,0,, 所以放在这里很合适 \\N{\\fs12}Okay. So that’s a good thing to put in here.\r\nDialogue: 0,0:32:08.94,0:32:10.41,yin,,0,0,0,, 我们会在后面的课程中讲到 \\N{\\fs12}We’ll talk later in the course\r\nDialogue: 0,0:32:10.42,0:32:14.06,yin,,0,0,0,, 在这里添加代码以实现优化 \\N{\\fs12}about putting code in here for optimization purposes\r\nDialogue: 0,0:32:14.08,0:32:17.60,yin,,0,0,0,, 因为如果你添加的操作需要大量资源 \\N{\\fs12}because if you put something that’s going to take lot of resources,\r\nDialogue: 0,0:32:17.62,0:32:20.30,yin,,0,0,0,, 比如要在 viewDidLoad 中进行网络调用 \\N{\\fs12}like you’re going to make some network call in viewDidLoad,\r\nDialogue: 0,0:32:20.48,0:32:22.92,yin,,0,0,0,, 如果你的 MVC 始终没有出现在屏幕上呢 \\N{\\fs12}and what if your MVC never appears on screen?\r\nDialogue: 0,0:32:23.37,0:32:26.60,yin,,0,0,0,, 那 viewDidLoad 中的网络调用就浪费了时间 \\N{\\fs12}Well, you wasted that time doing that network call on viewDidLoad.\r\nDialogue: 0,0:32:27.02,0:32:28.95,yin,,0,0,0,, 而如果放在 viewWillAppear 中执行 \\N{\\fs12}Whereas if you do it in viewWillAppear,\r\nDialogue: 0,0:32:29.08,0:32:31.13,yin,,0,0,0,, 尽管你也要对它进行设计 \\N{\\fs12}even though you’re going to have to design it –\r\nDialogue: 0,0:32:31.14,0:32:32.44,yin,,0,0,0,, 因为如果你要在网络中执行什么操作 \\N{\\fs12}because if you do something in the network,\r\nDialogue: 0,0:32:32.45,0:32:33.56,yin,,0,0,0,, 会延迟一些才能返回结果 \\N{\\fs12}it’s going to come later;\r\nDialogue: 0,0:32:33.57,0:32:35.70,yin,,0,0,0,, 并不会立即得到 这也没问题 \\N{\\fs12}it’s not going to be instantaneously available, that’s okay,\r\nDialogue: 0,0:32:35.70,0:32:38.12,yin,,0,0,0,, 我们会讲到如何利用多线程解决这个问题 \\N{\\fs12}we’ll talk about how to do multithreaded, make that all work –\r\nDialogue: 0,0:32:38.88,0:32:40.30,yin,,0,0,0,, 在 viewWillAppear 中开始 \\N{\\fs12}kicking it off in viewWillAppear\r\nDialogue: 0,0:32:40.31,0:32:41.65,yin,,0,0,0,, 效果可能更好一些 \\N{\\fs12}might be a little better performance\r\nDialogue: 0,0:32:41.65,0:32:43.39,yin,,0,0,0,, 因为当你收到 viewWillAppear 时 \\N{\\fs12}because you know when you get viewWillAppear\r\nDialogue: 0,0:32:43.39,0:32:45.50,yin,,0,0,0,, 代表你的视图就要在屏幕上显示 \\N{\\fs12}that your view is going to appear on screen.\r\nDialogue: 0,0:32:45.96,0:32:48.05,yin,,0,0,0,, 这时做些花销大的操作是值得的 \\N{\\fs12}Okay? So it’s worth it to do something expensive.\r\nDialogue: 0,0:32:48.28,0:32:49.47,yin,,0,0,0,, 这是高级内容了 \\N{\\fs12}But that’s kind of advanced stuff.\r\nDialogue: 0,0:32:49.47,0:32:51.13,yin,,0,0,0,, 目前不用太过担心这部分内容 \\N{\\fs12}So I won’t worry about that too much for now.\r\nDialogue: 0,0:32:52.33,0:32:54.52,yin,,0,0,0,, 在这里视图的几何信息已经设置 \\N{\\fs12}The view’s geometry is set here.\r\nDialogue: 0,0:32:54.76,0:32:57.29,yin,,0,0,0,, 所以可以在这里执行一些基于几何的初始化 \\N{\\fs12}So you could do some initialization based on geometry here.\r\nDialogue: 0,0:32:57.29,0:32:59.39,yin,,0,0,0,, 很多人这样做 因为很简单 \\N{\\fs12}And a lot of people do it because it’s kind of simple.\r\nDialogue: 0,0:32:59.70,0:33:00.83,yin,,0,0,0,, 但是还有一个地方 \\N{\\fs12}But there’s actually a better place\r\nDialogue: 0,0:33:00.83,0:33:03.81,yin,,0,0,0,, 更适合于基于几何的初始化 \\N{\\fs12}to do geometry-based initialization.\r\nDialogue: 0,0:33:04.06,0:33:05.47,yin,,0,0,0,, 但是没关系 \\N{\\fs12}But it’s okay.\r\nDialogue: 0,0:33:05.48,0:33:07.71,yin,,0,0,0,, 可以在 viewWillAppear 中执行 \\N{\\fs12}It’s quote “Okay to do it in viewWillAppear”\r\nDialogue: 0,0:33:08.20,0:33:10.47,yin,,0,0,0,, 只要你明白 \\N{\\fs12}as long as you understand\r\nDialogue: 0,0:33:10.48,0:33:13.38,yin,,0,0,0,, 几何内容是可以在 viewWillAppear 之后改变的 \\N{\\fs12}that your geometry could change after viewWillAppear.\r\nDialogue: 0,0:33:13.38,0:33:15.16,yin,,0,0,0,, 换句话说 你在屏幕上时 \\N{\\fs12}In other words, you can be on screen\r\nDialogue: 0,0:33:15.29,0:33:16.79,yin,,0,0,0,, 有人旋转了手机 \\N{\\fs12}and someone could rotate the phone,\r\nDialogue: 0,0:33:16.80,0:33:18.45,yin,,0,0,0,, 这样几何内容就被改变了 \\N{\\fs12}and now your geometry just changed.\r\nDialogue: 0,0:33:18.45,0:33:20.67,yin,,0,0,0,, 你最好对这种情况进行处理 \\N{\\fs12}Okay? So you better deal with that, okay,\r\nDialogue: 0,0:33:20.67,0:33:23.63,yin,,0,0,0,, 旋转时并不会得到 viewWillAppear\\N{\\fs12}that you’re not going to get viewWillAppear when you rotate,\r\nDialogue: 0,0:33:23.63,0:33:24.67,yin,,0,0,0,, 而是别的方法 \\N{\\fs12}you’re going to get other things.\r\nDialogue: 0,0:33:26.01,0:33:29.81,yin,,0,0,0,, 当视图从屏幕上离开时 你也会得到通知 \\N{\\fs12}Okay. You also get notified when your view goes off screen.\r\nDialogue: 0,0:33:29.85,0:33:31.86,yin,,0,0,0,, 也就是这个 viewWillDisappear\\N{\\fs12}So that viewWillDisappear, okay?\r\nDialogue: 0,0:33:32.14,0:33:33.96,yin,,0,0,0,, 要在这个方法里做些什么呢 \\N{\\fs12}And what do you want to do in here?\r\nDialogue: 0,0:33:34.21,0:33:36.39,yin,,0,0,0,, 通常不会在这个方法中执行太多内容 \\N{\\fs12}You don’t usually do a lot of stuff in here.\r\nDialogue: 0,0:33:36.39,0:33:40.52,yin,,0,0,0,, 如果你要做些动画之类的 \\N{\\fs12}If you’re doing something like animation or something,\r\nDialogue: 0,0:33:40.52,0:33:42.76,yin,,0,0,0,, 显然可以在这里停止动画 \\N{\\fs12}obviously this would be a good place to stop doing that\r\nDialogue: 0,0:33:42.77,0:33:44.19,yin,,0,0,0,, 因为出现 viewWillDisappear 时 \\N{\\fs12}because when viewWillDisappear happen,\r\nDialogue: 0,0:33:44.20,0:33:47.37,yin,,0,0,0,, 你希望你的控制器能做一个好人 \\N{\\fs12}really you want your controller to become a good citizen:\r\nDialogue: 0,0:33:47.40,0:33:48.84,yin,,0,0,0,, 不再占用资源 \\N{\\fs12}Stop using resources.\r\nDialogue: 0,0:33:48.84,0:33:50.96,yin,,0,0,0,, 你不在屏幕上了 停止吧 好吗 \\N{\\fs12}You’re not on screen, stop it. Okay?\r\nDialogue: 0,0:33:50.97,0:33:52.88,yin,,0,0,0,, 当你再回到屏幕上的时候 会再次调用 viewWillAppear\\N{\\fs12}You’ll get viewWillAppear when you go back\r\nDialogue: 0,0:33:52.88,0:33:55.04,yin,,0,0,0,, 可以再同步回去 \\N{\\fs12}and you can sync back up to the world.\r\nDialogue: 0,0:33:55.47,0:33:59.04,yin,,0,0,0,, 但是当你从屏幕上消失后 就要保持低调 \\N{\\fs12}But after you disappear, you kind of want to lay low, right,\r\nDialogue: 0,0:33:59.04,0:34:01.74,yin,,0,0,0,, 少占用内存空间和 CPU 性能 \\N{\\fs12}in terms of memory usage and certainly CPU –\r\nDialogue: 0,0:34:01.75,0:34:03.46,yin,,0,0,0,, 你并不想再继续使用 CPU\\N{\\fs12}you don’t want to be using CPU.\r\nDialogue: 0,0:34:03.69,0:34:05.90,yin,,0,0,0,, 这里很适合停止某项操作 \\N{\\fs12}So this is a good place to do stuff like that\r\nDialogue: 0,0:34:05.90,0:34:07.22,yin,,0,0,0,, 也许还要记住当前状态 \\N{\\fs12}and to maybe remember state\r\nDialogue: 0,0:34:07.23,0:34:09.90,yin,,0,0,0,, 以便之后在 viewWillAppear 中恢复等等 \\N{\\fs12}that you’re going to restore in viewWillAppear again, whatever.\r\nDialogue: 0,0:34:10.01,0:34:11.09,yin,,0,0,0,, 都是你们可能想要做的事情 \\N{\\fs12}Kind of what you might think.\r\nDialogue: 0,0:34:11.52,0:34:13.19,yin,,0,0,0,, 这些方法都有 did 已完成的版本 \\N{\\fs12}There’s also did versions of these.\r\nDialogue: 0,0:34:13.37,0:34:16.12,yin,,0,0,0,,viewDidAppear 和 viewDidDisappear\\N{\\fs12}viewDidAppear and viewDidDisappear.\r\nDialogue: 0,0:34:16.12,0:34:18.18,yin,,0,0,0,, 和大家可能想到的作用一样 \\N{\\fs12}And that happens exactly what you might think, right?\r\nDialogue: 0,0:34:18.18,0:34:21.00,yin,,0,0,0,,viewDidAppear 会在你出现在屏幕上后被调用 \\N{\\fs12}ViewDidAppear gets called after you’re now on screen.\r\nDialogue: 0,0:34:21.35,0:34:24.38,yin,,0,0,0,, 你一出现在屏幕上 然后这个方法就被调用了 \\N{\\fs12}Okay? You just appeared and you just got called, okay?\r\nDialogue: 0,0:34:24.68,0:34:26.83,yin,,0,0,0,, 而 viewDidDisappear 是在你从屏幕上消失后被调用 \\N{\\fs12}Same thing, viewDidDisappear — you just disappeared.\r\nDialogue: 0,0:34:28.35,0:34:30.96,yin,,0,0,0,, 现在 我们来讲讲几何方面的内容 \\N{\\fs12}Okay. Now, let’s talk about geometry.\r\nDialogue: 0,0:34:31.10,0:34:33.38,yin,,0,0,0,, 我把这部分单独放在了一张幻灯片上 \\N{\\fs12}Okay. I put this off to this slide.\r\nDialogue: 0,0:34:33.89,0:34:38.26,yin,,0,0,0,, 关于几何部分 在 iOS6 中引入了两个很棒的方法 \\N{\\fs12}Your geometry, in iOS 6 they introduced these really cool two methods\r\nDialogue: 0,0:34:38.40,0:34:42.04,yin,,0,0,0,,viewWillLayoutSubviews 和 viewDidLayoutSubviews\\N{\\fs12}viewWillLayoutSubviews and viewDidLayoutSubviews.\r\nDialogue: 0,0:34:42.72,0:34:45.89,yin,,0,0,0,, 就是在这里面添加几何相关的代码 \\N{\\fs12}This is where to put geometry-related code.\r\nDialogue: 0,0:34:46.22,0:34:50.32,yin,,0,0,0,, 在 iOS7 想要布局你的子视图 布局视图之前 \\N{\\fs12}So viewWillLayoutSubviews is called just before\r\nDialogue: 0,0:34:50.72,0:34:55.30,yin,,0,0,0,,viewWillLayoutSubviews 被调用 \\N{\\fs12}iOS 7 tries to layout your subviews, tries to layout your view.\r\nDialogue: 0,0:34:55.30,0:34:57.49,yin,,0,0,0,, 你可能刚刚从竖屏 \\N{\\fs12}Okay? So your geometry just changed\r\nDialogue: 0,0:34:57.50,0:34:59.16,yin,,0,0,0,, 换到了横屏 \\N{\\fs12}maybe from portrait to landscape.\r\nDialogue: 0,0:34:59.37,0:35:02.88,yin,,0,0,0,, 而在 iOS7 中 有很多自动操作内容 叫做自动布局 \\N{\\fs12}And there’s a lot of automated stuff in iOS 7 called autolayout\r\nDialogue: 0,0:35:03.04,0:35:05.91,yin,,0,0,0,, 会尝试将所有元素移动至合适位置 \\N{\\fs12}that will try and move everything around to fit.\r\nDialogue: 0,0:35:06.05,0:35:08.73,yin,,0,0,0,, 并不总能实现 但它会尝试 \\N{\\fs12}Now, it can’t always do it but it tries.\r\nDialogue: 0,0:35:08.73,0:35:11.65,yin,,0,0,0,, 在此之前 系统会调用 viewWillLayoutSubviews\\N{\\fs12}Okay? So viewWillLayoutSubviews is called before that.\r\nDialogue: 0,0:35:12.16,0:35:15.79,yin,,0,0,0,, 而 viewDidLayoutSubviews 会在完成之后被调用 \\N{\\fs12}And viewDidLayoutSubviews is called after it’s done that,\r\nDialogue: 0,0:35:15.81,0:35:17.80,yin,,0,0,0,, 完成尝试之后 \\N{\\fs12}after it’s made that attempt. Okay?\r\nDialogue: 0,0:35:18.14,0:35:21.52,yin,,0,0,0,, 如果某些东西被手动移动了 \\N{\\fs12}Now, if there’s some things that have been moved manually,\r\nDialogue: 0,0:35:21.53,0:35:23.16,yin,,0,0,0,, 你需要手动移动它们 \\N{\\fs12}you have to move them by hand,\r\nDialogue: 0,0:35:23.63,0:35:26.44,yin,,0,0,0,, 在自动布局规则中 \\N{\\fs12}okay, that there’s just no way to express\r\nDialogue: 0,0:35:26.44,0:35:29.18,yin,,0,0,0,, 不能清楚表达要移动到哪里 \\N{\\fs12}in the automatic layout rules where things go,\r\nDialogue: 0,0:35:29.40,0:35:31.52,yin,,0,0,0,, 那么最适合执行它的地方 \\N{\\fs12}then best place to do it\r\nDialogue: 0,0:35:31.53,0:35:34.21,yin,,0,0,0,, 也许就是 viewDidLayoutSubviews 中了 \\N{\\fs12}is probably in viewDidLayoutSubviews, okay,\r\nDialogue: 0,0:35:34.21,0:35:35.73,yin,,0,0,0,, 因为系统已经将各元素摆出来 \\N{\\fs12}because the system’s already laid things out.\r\nDialogue: 0,0:35:35.95,0:35:38.47,yin,,0,0,0,, 现在你可以移动调整 \\N{\\fs12}Now you can move around the last few pieces\r\nDialogue: 0,0:35:39.33,0:35:40.26,yin,,0,0,0,, 最后几个需要布局的元素 \\N{\\fs12}that need to be laid out.\r\nDialogue: 0,0:35:40.40,0:35:41.72,yin,,0,0,0,, 但是按钮这类对象 \\N{\\fs12}But things like buttons, you know,\r\nDialogue: 0,0:35:41.73,0:35:43.74,yin,,0,0,0,, 比如添加和去除轮廓按钮 \\N{\\fs12}like that outline and unoutline button,\r\nDialogue: 0,0:35:43.95,0:35:44.96,yin,,0,0,0,, 很容易实现布局 \\N{\\fs12}it’s really easy to make it\r\nDialogue: 0,0:35:44.97,0:35:48.27,yin,,0,0,0,, 当你旋转至横屏时 它们就会移动到下角 \\N{\\fs12}so that when you rotate to landscape they move down to the corners.\r\nDialogue: 0,0:35:49.04,0:35:50.97,yin,,0,0,0,, 这应该是我们想要的效果 \\N{\\fs12}Okay? That’s what you probably want there.\r\nDialogue: 0,0:35:51.07,0:35:52.29,yin,,0,0,0,, 文本视图也是一样的 \\N{\\fs12}Same thing, the text view,\r\nDialogue: 0,0:35:52.43,0:35:55.22,yin,,0,0,0,, 当转为横屏时 \\N{\\fs12}pretty easy to make it widen out and get shorter\r\nDialogue: 0,0:35:55.22,0:35:56.22,yin,,0,0,0,, 可以轻松地加宽变短 \\N{\\fs12}when it goes to landscape.\r\nDialogue: 0,0:35:56.55,0:36:00.40,yin,,0,0,0,, 但是像 Matchismo 那样 你有很多卡牌 \\N{\\fs12}Okay? But like in Matchismo, you got all those cards.\r\nDialogue: 0,0:36:00.60,0:36:05.64,yin,,0,0,0,, 当旋转屏幕时 你希望使用某种逻辑来判断出 \\N{\\fs12}When you turn it, you might want to use some logic to figure out:\r\nDialogue: 0,0:36:05.64,0:36:07.25,yin,,0,0,0,, 竖屏转为横屏时 \\N{\\fs12}Where are you going to lay the cards out\r\nDialogue: 0,0:36:07.39,0:36:09.70,yin,,0,0,0,, 这些卡牌要放在哪里 \\N{\\fs12}in a landscape orientation versus portrait?\r\nDialogue: 0,0:36:10.12,0:36:12.39,yin,,0,0,0,, 大家下周要实现这个功能 \\N{\\fs12}Okay? And you’re going to have to do that next week.\r\nDialogue: 0,0:36:12.67,0:36:13.82,yin,,0,0,0,, 不是这周的内容 \\N{\\fs12}Okay? Not this week.\r\nDialogue: 0,0:36:15.97,0:36:19.45,yin,,0,0,0,, 我想再讲一些关于自动旋转的内容 \\N{\\fs12}So I want to talk a little more about autorotation.\r\nDialogue: 0,0:36:19.57,0:36:21.63,yin,,0,0,0,, 也就是 当你旋转手机时 \\N{\\fs12}So this is the thing where you turn the phone\r\nDialogue: 0,0:36:21.77,0:36:23.89,yin,,0,0,0,, 几何布局会自动变化 \\N{\\fs12}and your geometry automatically gets changed.\r\nDialogue: 0,0:36:24.12,0:36:28.07,yin,,0,0,0,, 这种自动调整至新的几何布局的功能 \\N{\\fs12}That automatic change to the new geometry only happens\r\nDialogue: 0,0:36:28.09,0:36:29.65,yin,,0,0,0,, 只会在这些条件为真时会发生 \\N{\\fs12}if these conditions are true.\r\nDialogue: 0,0:36:29.88,0:36:32.90,yin,,0,0,0,, 视图控制器的 shouldAutorotate 方法是否返回 YES\\N{\\fs12}Your view controller has to return yes from shouldAutorotate,\r\nDialogue: 0,0:36:32.91,0:36:33.80,yin,,0,0,0,, 这是默认值 \\N{\\fs12}which is the default.\r\nDialogue: 0,0:36:34.33,0:36:37.61,yin,,0,0,0,, 你的视图控制器需要从 supportedInterfaceOrientations\\N{\\fs12}Your view controller has to return that new orientation\r\nDialogue: 0,0:36:37.61,0:36:40.08,yin,,0,0,0,, 返回那个新方向 \\N{\\fs12}from supportedInterfaceOrientations.\r\nDialogue: 0,0:36:40.08,0:36:42.63,yin,,0,0,0,, 这是一个方法 它返回一个数字 \\N{\\fs12}That is a method that returns an e num\r\nDialogue: 0,0:36:43.42,0:36:47.23,yin,,0,0,0,, 代表横屏 竖屏和倒立竖屏方向 \\N{\\fs12}with landscape and portrait, portrait upside down in there.\r\nDialogue: 0,0:36:47.23,0:36:50.76,yin,,0,0,0,, 你需要声明支持多个旋转方向 \\N{\\fs12}So you have to say that you support the various rotations.\r\nDialogue: 0,0:36:50.76,0:36:53.20,yin,,0,0,0,, 我相信默认是支持全部旋转方向的 \\N{\\fs12}I believe by default it supports all rotations.\r\nDialogue: 0,0:36:53.76,0:36:56.25,yin,,0,0,0,, 你的整个应用 \\N{\\fs12}And your application as a whole\r\nDialogue: 0,0:36:56.35,0:36:59.22,yin,,0,0,0,, 需要支持那个新方向 \\N{\\fs12}has to say that it supports that new orientation.\r\nDialogue: 0,0:36:59.50,0:37:00.85,yin,,0,0,0,, 这个设置…\\N{\\fs12}Okay? And that is set –\r\nDialogue: 0,0:37:00.85,0:37:03.17,yin,,0,0,0,, 还记得我们第一次创建应用 运行它的时候吗 \\N{\\fs12}remember when we first built our application and it ran?\r\nDialogue: 0,0:37:03.37,0:37:06.71,yin,,0,0,0,, 当时出现了应用的各种设置 \\N{\\fs12}There was, like, all these kind the settings for our app\r\nDialogue: 0,0:37:06.71,0:37:08.24,yin,,0,0,0,, 我挥了挥手说 \\N{\\fs12}that I just waved my hand and said,\r\nDialogue: 0,0:37:08.24,0:37:09.15,yin,,0,0,0,, 我们后面再讲 \\N{\\fs12}”We’ll look at this later”?\r\nDialogue: 0,0:37:09.37,0:37:10.81,yin,,0,0,0,, 里面有一个设置 \\N{\\fs12}Well, one of the settings in there\r\nDialogue: 0,0:37:10.82,0:37:13.09,yin,,0,0,0,, 是应用支持设备的哪个方向 \\N{\\fs12}is which orientations of a device –\r\nDialogue: 0,0:37:13.10,0:37:16.71,yin,,0,0,0,, 竖屏 横屏 倒立竖屏 \\N{\\fs12}portrait, landscape, portrait upside down — do you support?\r\nDialogue: 0,0:37:17.08,0:37:20.08,yin,,0,0,0,, 你需要在那里选中应用支持的方向 \\N{\\fs12}Okay? So you have to click on the ones that you support.\r\nDialogue: 0,0:37:20.48,0:37:23.93,yin,,0,0,0,, 如果这些都做了 那么当设备旋转时 \\N{\\fs12}And if you do all these things, then when the device rotates,\r\nDialogue: 0,0:37:23.93,0:37:26.38,yin,,0,0,0,, 你的视图的边界就会自动变化 \\N{\\fs12}your bounds of your view will automatically be changed\r\nDialogue: 0,0:37:26.43,0:37:28.55,yin,,0,0,0,, 你会得到 viewWillLayoutSubviews\\N{\\fs12}and you’ll get the whole viewWillLayoutSubviews,\r\nDialogue: 0,0:37:28.55,0:37:30.52,yin,,0,0,0,,viewDidLayoutSubviews 自动旋转 \\N{\\fs12}viewDidLayoutSubviews, autorotate,\r\nDialogue: 0,0:37:30.52,0:37:31.92,yin,,0,0,0,, 自动布局 都会实现 \\N{\\fs12}autolayout, all that happening.\r\nDialogue: 0,0:37:32.71,0:37:36.26,yin,,0,0,0,, 也会调用其他方法 \\N{\\fs12}Okay? There are also methods that get called.\r\nDialogue: 0,0:37:36.26,0:37:37.67,yin,,0,0,0,, 我把它们设成了灰色 \\N{\\fs12}I put them in gray here\r\nDialogue: 0,0:37:37.68,0:37:39.10,yin,,0,0,0,, 因为我们不会讲解这些方法 \\N{\\fs12}because we’re not really going to look at them.\r\nDialogue: 0,0:37:39.31,0:37:40.43,yin,,0,0,0,, 很少会用到它们 \\N{\\fs12}They’re rarely needed.\r\nDialogue: 0,0:37:40.64,0:37:43.56,yin,,0,0,0,, 自动布局和 viewDidLayoutSubviews\\N{\\fs12}Autolayout and viewDidLayoutSubviews\r\nDialogue: 0,0:37:43.58,0:37:45.29,yin,,0,0,0,, 通常包含了所有需要的内容 \\N{\\fs12}are usually going to cover everything you need.\r\nDialogue: 0,0:37:45.29,0:37:47.30,yin,,0,0,0,, 但是如果你想要改变旋转动画等内容 \\N{\\fs12}But if you wanted to get involved in the animation\r\nDialogue: 0,0:37:47.30,0:37:49.29,yin,,0,0,0,, 也都是可以的 \\N{\\fs12}of the rotation and all that, it’s all possible.\r\nDialogue: 0,0:37:49.29,0:37:51.69,yin,,0,0,0,, 但我们就不详细讲了 \\N{\\fs12}But we’re not really looking at that.\r\nDialogue: 0,0:37:52.53,0:37:54.48,yin,,0,0,0,, 在内存不足情况下 \\N{\\fs12}Okay. In low-memory situations,\r\nDialogue: 0,0:37:54.49,0:37:57.14,yin,,0,0,0,, 你的视图控制器会收到这条消息 \\N{\\fs12}you’re going to get this message to your view controller\r\nDialogue: 0,0:37:57.15,0:37:58.80,yin,,0,0,0,, 叫做 didReceiveMemoryWarning\\N{\\fs12}called “didReceiveMemoryWarning.”\r\nDialogue: 0,0:37:59.37,0:38:02.62,yin,,0,0,0,, 内存不足并不代表 \\N{\\fs12}Okay? And low memory doesn’t necessarily mean\r\nDialogue: 0,0:38:02.76,0:38:04.46,yin,,0,0,0,, 你的应用占用了很大的内存空间 \\N{\\fs12}your app is using a lot of memory;\r\nDialogue: 0,0:38:04.47,0:38:06.90,yin,,0,0,0,, 也许只是手机上运行的所有应用 \\N{\\fs12}it just might be all apps on the phone combined\r\nDialogue: 0,0:38:06.92,0:38:08.31,yin,,0,0,0,, 一块占用了很大的内存 \\N{\\fs12}are using a lot of the memory\r\nDialogue: 0,0:38:08.31,0:38:09.76,yin,,0,0,0,, 需要释放一些空间 \\N{\\fs12}and it needs some of it back.\r\nDialogue: 0,0:38:09.77,0:38:12.65,yin,,0,0,0,, 它也许向很多应用都发送了这个消息 \\N{\\fs12}So it might be sending this to lots of applications.\r\nDialogue: 0,0:38:13.23,0:38:14.90,yin,,0,0,0,, 是否生成这个警告 \\N{\\fs12}It’s completely up to the system\r\nDialogue: 0,0:38:14.92,0:38:17.12,yin,,0,0,0,, 完全由系统决定 \\N{\\fs12}to decide whether it wants to generate this warning.\r\nDialogue: 0,0:38:17.41,0:38:20.14,yin,,0,0,0,, 当你收到警告后 唯一的责任就是 \\N{\\fs12}And your only responsibility when you get this thing\r\nDialogue: 0,0:38:20.24,0:38:21.71,yin,,0,0,0,, 试着释放内存 \\N{\\fs12}is to try and free up memory.\r\nDialogue: 0,0:38:22.17,0:38:24.61,yin,,0,0,0,, 也就是堆中的内容 \\N{\\fs12}Okay? That means in the heap.\r\nDialogue: 0,0:38:25.28,0:38:28.36,yin,,0,0,0,, 也就是将强指针设为 nil\\N{\\fs12}And that means setting strong pointers you have to nil.\r\nDialogue: 0,0:38:28.98,0:38:32.81,yin,,0,0,0,, 如果你展示一幅图像 \\N{\\fs12}Okay? Now, if you display an image, okay,\r\nDialogue: 0,0:38:32.82,0:38:35.70,yin,,0,0,0,, 如果你的 MVC 展示一幅图像 会占据很大内存 \\N{\\fs12}if your MVC displays an image, that’s big memory.\r\nDialogue: 0,0:38:35.83,0:38:37.26,yin,,0,0,0,, 图像需要很多内存空间 \\N{\\fs12}Images are a lot of memory.\r\nDialogue: 0,0:38:37.56,0:38:40.83,yin,,0,0,0,, 或者播放一段声音 也需要很多内存 \\N{\\fs12}Okay? Or it plays a sound — that’s a lot of memory.\r\nDialogue: 0,0:38:41.37,0:38:43.04,yin,,0,0,0,, 但是如果你的视图控制器 \\N{\\fs12}But if your thing is on screen,\r\nDialogue: 0,0:38:43.05,0:38:44.44,yin,,0,0,0,, 正在屏幕上显示 \\N{\\fs12}if your view controller is on screen,\r\nDialogue: 0,0:38:44.60,0:38:46.53,yin,,0,0,0,, 就不能释放那张图像 \\N{\\fs12}you can’t throw that image out.\r\nDialogue: 0,0:38:46.54,0:38:47.79,yin,,0,0,0,, 它需要显示在屏幕上 \\N{\\fs12}It needs to be on screen.\r\nDialogue: 0,0:38:47.79,0:38:49.35,yin,,0,0,0,, 所以如果你在屏幕上 \\N{\\fs12}So there’s really not much you can do\r\nDialogue: 0,0:38:49.56,0:38:51.94,yin,,0,0,0,, 收到了 didReceiveMemoryWarning 你其实没有太多可做的 \\N{\\fs12}when you get didReceiveMemoryWarning if you’re on screen.\r\nDialogue: 0,0:38:52.21,0:38:54.60,yin,,0,0,0,, 但是如果你有一张可选图像之类的 \\N{\\fs12}Now, however, if you have an alternate image\r\nDialogue: 0,0:38:54.60,0:38:56.74,yin,,0,0,0,, 现在不在屏幕上 \\N{\\fs12}or something that’s not on screen right now,\r\nDialogue: 0,0:38:56.88,0:39:00.41,yin,,0,0,0,, 只要你可以重新创建它 就可以先将它设为 nil\\N{\\fs12}you could set that to nil as long as you can recreate it, okay –\r\nDialogue: 0,0:39:00.62,0:39:03.13,yin,,0,0,0,, 不管你是从文件系统中重新创建 \\N{\\fs12}either recreate it by getting it from the file system,\r\nDialogue: 0,0:39:03.42,0:39:06.26,yin,,0,0,0,, 还是网络调用 重新下载一幅 \\N{\\fs12}even making a network call to download an image\r\nDialogue: 0,0:39:06.28,0:39:09.08,yin,,0,0,0,, 只要图像不是立刻需要就可以 \\N{\\fs12}as long as the image doesn’t need to be instantly available.\r\nDialogue: 0,0:39:10.38,0:39:13.23,yin,,0,0,0,, 这是处理内存警告的一个例子 \\N{\\fs12}But that’s an example of how you could respond to this.\r\nDialogue: 0,0:39:13.25,0:39:15.77,yin,,0,0,0,, 尤其是当你不在屏幕上时 你可以响应这个警告 \\N{\\fs12}Especially if you’re off screen you could respond to this,\r\nDialogue: 0,0:39:15.77,0:39:18.21,yin,,0,0,0,, 尽管我认为 当你离开屏幕时 \\N{\\fs12}although my argument is when you go off screen\r\nDialogue: 0,0:39:18.21,0:39:20.95,yin,,0,0,0,, 会调用 viewDidDisappear 和 viewWillDisappear\\N{\\fs12}and you get viewDidDisappear or viewWillDisappear,\r\nDialogue: 0,0:39:21.34,0:39:22.88,yin,,0,0,0,, 不管怎样 你都应该释放它 \\N{\\fs12}you should free up that stuff anyway.\r\nDialogue: 0,0:39:23.22,0:39:25.77,yin,,0,0,0,, 调用 viewWillAppear 时再重新获取 \\N{\\fs12}Okay? And get it back when you do viewWillAppear.\r\nDialogue: 0,0:39:26.13,0:39:27.93,yin,,0,0,0,, 因为你不希望自己成为内存占用大户 \\N{\\fs12}Because you don’t want to be a memory pig.\r\nDialogue: 0,0:39:28.02,0:39:31.68,yin,,0,0,0,, 成为内存占用大户会怎么样呢 \\N{\\fs12}Okay? Now what does it matter to be a memory pig?\r\nDialogue: 0,0:39:31.68,0:39:32.47,yin,,0,0,0,, 我们为什么要在意 \\N{\\fs12}Why do we care?\r\nDialogue: 0,0:39:32.74,0:39:33.77,yin,,0,0,0,, 有两点原因 \\N{\\fs12}Well, couple of things.\r\nDialogue: 0,0:39:34.33,0:39:37.24,yin,,0,0,0,, 首先 只针对内存大户 \\N{\\fs12}Okay. First of all, by the way, only things that use a lot of memory\r\nDialogue: 0,0:39:37.26,0:39:40.75,yin,,0,0,0,, 比如图像 视频 声音 \\N{\\fs12}are things like images, video, sound –\r\nDialogue: 0,0:39:41.02,0:39:42.12,yin,,0,0,0,, 这些内容需要很大内存 \\N{\\fs12}those can use a lot of memory.\r\nDialogue: 0,0:39:42.41,0:39:45.94,yin,,0,0,0,, 像内含五项内容的词典这类小东西 \\N{\\fs12}Small things like little dictionaries with five things in them,\r\nDialogue: 0,0:39:46.19,0:39:47.92,yin,,0,0,0,, 几乎不占什么内存 \\N{\\fs12}that’s using virtually no memory.\r\nDialogue: 0,0:39:47.92,0:39:50.69,yin,,0,0,0,, 不用浪费时间释放它们 \\N{\\fs12}I wouldn’t even waste your time freeing those up.\r\nDialogue: 0,0:39:50.91,0:39:52.96,yin,,0,0,0,, 那样只会让你的代码变得复杂 \\N{\\fs12}Okay? That’s just going to make your code complex for nothing.\r\nDialogue: 0,0:39:53.24,0:39:55.96,yin,,0,0,0,, 所以在说释放内存问题时 \\N{\\fs12}So we’re talking about good-sized things, okay,\r\nDialogue: 0,0:39:55.96,0:39:57.30,yin,,0,0,0,, 我们说的是大型内容 \\N{\\fs12}when we say “Free things up.”\r\nDialogue: 0,0:39:57.45,0:39:59.36,yin,,0,0,0,, 但是这里我们为什么要乖乖释放内存呢 \\N{\\fs12}But anyway, why do we want to be a good citizen here?\r\nDialogue: 0,0:39:59.50,0:40:02.54,yin,,0,0,0,, 如果 iOS 认为你大量侵占了内存 \\N{\\fs12}Well, iOS has the right to kill your app\r\nDialogue: 0,0:40:02.61,0:40:04.14,yin,,0,0,0,, 它是可以终止你的应用的 \\N{\\fs12}if it thinks you’re being a memory hog.\r\nDialogue: 0,0:40:04.57,0:40:07.23,yin,,0,0,0,, 如果系统内存不足 \\N{\\fs12}Okay? If there’s not enough memory on the system\r\nDialogue: 0,0:40:07.28,0:40:09.69,yin,,0,0,0,, 而你的应用恰好占用了很多内存 \\N{\\fs12}and your app happens to be using a lot of memory,\r\nDialogue: 0,0:40:09.87,0:40:12.83,yin,,0,0,0,, 它就可以过来说 杀掉它 \\N{\\fs12}it can just come along and say, “Bam-o, killing that baby.”\r\nDialogue: 0,0:40:13.52,0:40:15.22,yin,,0,0,0,, 它完全可以这样做 \\N{\\fs12}It’s perfectly within its rights.\r\nDialogue: 0,0:40:15.90,0:40:18.69,yin,,0,0,0,, 如果你合理使用内存 它绝不会这样做 \\N{\\fs12}If you’re a good memory citizen, it’s never going to do that.\r\nDialogue: 0,0:40:19.02,0:40:21.08,yin,,0,0,0,, 但是想要做一个好的内存使用者 \\N{\\fs12}Okay? But being a good memory citizen\r\nDialogue: 0,0:40:21.09,0:40:24.12,yin,,0,0,0,, 你所用的内存不应该超过 \\N{\\fs12}means you shouldn’t be using a lot more memory than, you know,\r\nDialogue: 0,0:40:24.14,0:40:26.26,yin,,0,0,0,, 一个 MVC 出现在屏幕上所占的内存 \\N{\\fs12}a single MVC that’s on screen right now.\r\nDialogue: 0,0:40:26.26,0:40:28.64,yin,,0,0,0,, 如果应用是运行在 iPad 上的 也许是三到四个 MVC\\N{\\fs12}Or if you’re on the iPad, maybe it’s three or four MVCs,\r\nDialogue: 0,0:40:28.65,0:40:30.29,yin,,0,0,0,, 取决于你的布局 \\N{\\fs12}depending on what your layout is.\r\nDialogue: 0,0:40:30.80,0:40:33.61,yin,,0,0,0,, 不管用多少内存 都应该合理使用 \\N{\\fs12}You know, however much memory, that would be reasonable to use.\r\nDialogue: 0,0:40:33.62,0:40:36.92,yin,,0,0,0,, 放个视频 没问题 可以的 \\N{\\fs12}A video in there, no problem, etc. That’s fine.\r\nDialogue: 0,0:40:36.92,0:40:39.27,yin,,0,0,0,, 但是如果你要在堆中保存 20 个视频 \\N{\\fs12}But if you have, like, twenty videos sitting in the heap,\r\nDialogue: 0,0:40:39.60,0:40:42.16,yin,,0,0,0,, 你就是下一个被杀掉的应用 \\N{\\fs12}okay, you’re going to be a candidate to get blasted.\r\nDialogue: 0,0:40:42.43,0:40:47.04,yin,,0,0,0,, 另外一点是 你显然希望用户切换应用时 \\N{\\fs12}Okay? So the other thing is you obviously want other applications\r\nDialogue: 0,0:40:47.05,0:40:48.52,yin,,0,0,0,, 其他应用 \\N{\\fs12}to have as much memory available to them\r\nDialogue: 0,0:40:48.52,0:40:49.78,yin,,0,0,0,, 得到同样多的可用内存 \\N{\\fs12}when the user switches back and forth.\r\nDialogue: 0,0:40:49.78,0:40:52.37,yin,,0,0,0,, 如果用户对你的应用所占的内存有一个不好的印象 \\N{\\fs12}If you’ve got a reputation as a memory pig like,\r\nDialogue: 0,0:40:52.38,0:40:56.31,yin,,0,0,0,, 每次运行这个应用 其他应用就卡到不行 \\N{\\fs12}”Oh, when I run this app, all my other apps slow way down.\r\nDialogue: 0,0:40:56.31,0:40:57.04,yin,,0,0,0,, 真讨厌 \\N{\\fs12}Oh, it’s terrible.”\r\nDialogue: 0,0:40:57.23,0:40:59.49,yin,,0,0,0,, 然后他们会到应用商店进行评论 \\N{\\fs12}Then on the App Store people are going to say that,\r\nDialogue: 0,0:40:59.49,0:41:00.70,yin,,0,0,0,, 你会得到一个不太好的名声 \\N{\\fs12}and you’re going to get a bad reputation,\r\nDialogue: 0,0:41:00.70,0:41:02.15,yin,,0,0,0,, 大家就不想用你的应用了 \\N{\\fs12}and people aren’t going to want your application.\r\nDialogue: 0,0:41:02.15,0:41:03.97,yin,,0,0,0,, 这是不要侵占内存的另外一个原因 \\N{\\fs12}So that’s another reason not to be a memory pig.\r\nDialogue: 0,0:41:04.47,0:41:06.54,yin,,0,0,0,, 苹果能不能在审核应用时 \\N{\\fs12}Can Apple check this kind of stuff\r\nDialogue: 0,0:41:06.54,0:41:08.97,yin,,0,0,0,, 检查你的应用使用了多少内存呢 \\N{\\fs12}to see how much memory you use before they approve an app?\r\nDialogue: 0,0:41:08.98,0:41:09.87,yin,,0,0,0,, 是检查的内容吗 \\N{\\fs12}Is that a thing?\r\nDialogue: 0,0:41:10.19,0:41:12.16,yin,,0,0,0,, 问题是 苹果公司会不会 \\N{\\fs12}So the question is: Does Apple go and check\r\nDialogue: 0,0:41:12.24,0:41:14.21,yin,,0,0,0,, 在批准应用前检查确认 \\N{\\fs12}to make sure you’re being a good memory citizen\r\nDialogue: 0,0:41:14.22,0:41:15.16,yin,,0,0,0,, 应用是否合理使用内存 \\N{\\fs12}before they approve you?\r\nDialogue: 0,0:41:15.51,0:41:18.05,yin,,0,0,0,, 我不知道 \\N{\\fs12}I would say I don’t know.\r\nDialogue: 0,0:41:18.05,0:41:18.68,yin,,0,0,0,, 我不在苹果公司工作 \\N{\\fs12}I don’t work for Apple.\r\nDialogue: 0,0:41:18.68,0:41:20.52,yin,,0,0,0,, 我并不知道他们的审核流程 \\N{\\fs12}I don’t know what’s going on behind the scenes there\r\nDialogue: 0,0:41:20.53,0:41:22.04,yin,,0,0,0,, 具体是怎样的 \\N{\\fs12}in terms of their approval process.\r\nDialogue: 0,0:41:22.25,0:41:23.83,yin,,0,0,0,, 我猜 如果他们运行你的应用后 \\N{\\fs12}My guess is if they ran your app\r\nDialogue: 0,0:41:23.83,0:41:26.15,yin,,0,0,0,, 应用立刻占用了大量内存 \\N{\\fs12}and it just immediately ballooned up a huge amount of memory,\r\nDialogue: 0,0:41:26.16,0:41:27.16,yin,,0,0,0,, 他们是不会通过审核的 \\N{\\fs12}they would not approve it.\r\nDialogue: 0,0:41:27.16,0:41:28.15,yin,,0,0,0,, 这只是我的猜测 \\N{\\fs12}That’s just my guess.\r\nDialogue: 0,0:41:28.15,0:41:29.90,yin,,0,0,0,, 如果我是他们 我不会通过的 \\N{\\fs12}I mean, I wouldn’t if I were them.\r\nDialogue: 0,0:41:30.79,0:41:33.42,yin,,0,0,0,, 当然了 现在市面上有一些应用 \\N{\\fs12}And you know, certainly apps that are out there\r\nDialogue: 0,0:41:33.42,0:41:35.20,yin,,0,0,0,, 以占用大量内存著称 \\N{\\fs12}that have a reputation of being big memory pigs,\r\nDialogue: 0,0:41:35.20,0:41:37.63,yin,,0,0,0,, 当这些应用提交新版本等内容时 \\N{\\fs12}maybe when you submit your next version or something,\r\nDialogue: 0,0:41:37.64,0:41:39.85,yin,,0,0,0,, 审核人员会说 等等 你们修复内存问题了吗 \\N{\\fs12}they’re like, “Wait a second, did you fix that memory thing?”\r\nDialogue: 0,0:41:39.85,0:41:40.77,yin,,0,0,0,, 明白我的意思吗 \\N{\\fs12}You know what I’m saying?\r\nDialogue: 0,0:41:40.96,0:41:42.37,yin,,0,0,0,, 这是常识 \\N{\\fs12}It’s common sense, common sense.\r\nDialogue: 0,0:41:43.57,0:41:44.73,yin,,0,0,0,, 好的 就是这样 \\N{\\fs12}Okay. So that’s that.\r\nDialogue: 0,0:41:45.15,0:41:47.04,yin,,0,0,0,, 我刚才说过 我会讲讲 \\N{\\fs12}Okay. Now I told I would talk about\r\nDialogue: 0,0:41:47.05,0:41:49.38,yin,,0,0,0,, 视图控制器的创建 \\N{\\fs12}creation of the view controller.\r\nDialogue: 0,0:41:49.70,0:41:51.61,yin,,0,0,0,, 我回来 讲一下这部分内容 \\N{\\fs12}And so I’m going back and talking about it here.\r\nDialogue: 0,0:41:51.61,0:41:52.87,yin,,0,0,0,, 我只会简单介绍一下 \\N{\\fs12}I’m only going to talk about it briefly\r\nDialogue: 0,0:41:52.87,0:41:55.03,yin,,0,0,0,, 因为它真的不太重要 \\N{\\fs12}because it’s really not super important\r\nDialogue: 0,0:41:55.04,0:41:57.69,yin,,0,0,0,, 大多数情况下都会在 viewDidLoad 中进行初始化 \\N{\\fs12}because viewDidLoad is where you want most of your initialization.\r\nDialogue: 0,0:41:58.00,0:42:00.87,yin,,0,0,0,, 但是当你的视图控制器创建时 \\N{\\fs12}But when your view controller is created,\r\nDialogue: 0,0:42:00.88,0:42:04.14,yin,,0,0,0,, 当它从 storyboard 中取出并加水解冻 \\N{\\fs12}when it’s pulled out of that storyboard and unfreeze-dried,\r\nDialogue: 0,0:42:04.53,0:42:08.08,yin,,0,0,0,, 你的 init 方法并没有被调用 \\N{\\fs12}your init method is not called.\r\nDialogue: 0,0:42:08.58,0:42:10.76,yin,,0,0,0,, 另外一个初始化方法被调用了 \\N{\\fs12}Okay? A different init method is called.\r\nDialogue: 0,0:42:10.84,0:42:12.31,yin,,0,0,0,, 化冻的初始化方法 \\N{\\fs12}The unfreeze-drying init method,\r\nDialogue: 0,0:42:12.31,0:42:16.25,yin,,0,0,0,, 它是一个通用的初始化方法机制 \\N{\\fs12}which is a generic init method mechanism\r\nDialogue: 0,0:42:16.26,0:42:18.39,yin,,0,0,0,, 我们不会… 也许会讲讲 \\N{\\fs12}that we’re not going to — well, we might talk about it\r\nDialogue: 0,0:42:18.53,0:42:19.76,yin,,0,0,0,, 在课程第八周或者第九周的时候 \\N{\\fs12}in week eight or nine of this course.\r\nDialogue: 0,0:42:20.07,0:42:20.97,yin,,0,0,0,, 不太重要 \\N{\\fs12}Not that important.\r\nDialogue: 0,0:42:21.26,0:42:24.25,yin,,0,0,0,, 但 Xcode 就是用这个方法冻干你的应用的 \\N{\\fs12}But that’s what Xcode uses to freeze-dry your apps.\r\nDialogue: 0,0:42:24.26,0:42:29.25,yin,,0,0,0,, 那个初始化方法 你并不会生成它的子类 对吧 \\N{\\fs12}So that init — you don’t subclass that init, okay?\r\nDialogue: 0,0:42:29.77,0:42:30.62,yin,,0,0,0,, 它是个初始化方法 \\N{\\fs12}Okay, it’s an init;\r\nDialogue: 0,0:42:30.63,0:42:31.81,yin,,0,0,0,, 我甚至不会告诉大家它的名字 \\N{\\fs12}I’m not even going to tell you the name of it.\r\nDialogue: 0,0:42:31.81,0:42:33.12,yin,,0,0,0,, 不要生成它的子类 \\N{\\fs12}You don’t subclass it.\r\nDialogue: 0,0:42:35.54,0:42:39.57,yin,,0,0,0,, 而当某个元素从 storyboard 中解冻时 \\N{\\fs12}Instead, when something gets unfreeze-dried from a storyboard –\r\nDialogue: 0,0:42:39.92,0:42:41.78,yin,,0,0,0,, 任何东西 不只是你的控制器 \\N{\\fs12}anything, not just your controller\r\nDialogue: 0,0:42:41.87,0:42:44.13,yin,,0,0,0,, 甚至是按钮之类的东西解冻时 \\N{\\fs12}but even, like, a button or anything else comes out of there –\r\nDialogue: 0,0:42:44.30,0:42:46.44,yin,,0,0,0,, 这个方法 awakeFromNib\\N{\\fs12}this method, awakeFromNib –\r\nDialogue: 0,0:42:47.10,0:42:50.52,yin,,0,0,0,,Nib 是延续以前的名称 \\N{\\fs12}Nib is an old historical name;\r\nDialogue: 0,0:42:50.76,0:42:52.93,yin,,0,0,0,, 你可以理解为 awakeFromStoryboard\\N{\\fs12}you could think of it as awake from storyboard –\r\nDialogue: 0,0:42:53.73,0:42:54.73,yin,,0,0,0,, 这个方法会被调用 \\N{\\fs12}this gets called.\r\nDialogue: 0,0:42:54.93,0:42:56.59,yin,,0,0,0,, 你可以在这里执行 \\N{\\fs12}And you can put in here things\r\nDialogue: 0,0:42:56.59,0:42:58.51,yin,,0,0,0,, 通常会放在初始化方法中的内容 \\N{\\fs12}that you might normally put in your init.\r\nDialogue: 0,0:42:59.04,0:43:01.65,yin,,0,0,0,, 虽然这个时候你的输出口还没有设好 \\N{\\fs12}Although, again, your outlets are not set at this point.\r\nDialogue: 0,0:43:01.91,0:43:04.65,yin,,0,0,0,, 所以最好放在 viewDidLoad 中 \\N{\\fs12}So you’re better off putting stuff in viewDidLoad. Okay?\r\nDialogue: 0,0:43:04.95,0:43:06.47,yin,,0,0,0,, 但是如果因为某些原因 \\N{\\fs12}But if there’s some reason\r\nDialogue: 0,0:43:06.59,0:43:07.73,yin,,0,0,0,, 无法将某些操作放到 viewDidLoad 中执行 \\N{\\fs12}you can’t put something in viewDidLoad –\r\nDialogue: 0,0:43:07.75,0:43:09.83,yin,,0,0,0,, 我想不出一个好的例子 \\N{\\fs12}I can’t even think of a good example why that would be –\r\nDialogue: 0,0:43:09.97,0:43:11.63,yin,,0,0,0,, 这种情况下 你可以放到 awakeFromNib 中 \\N{\\fs12}you can put things in awakeFromNib.\r\nDialogue: 0,0:43:12.38,0:43:15.83,yin,,0,0,0,, 如果想要把它变得复杂一点 \\N{\\fs12}Now, to make this a little more complicated\r\nDialogue: 0,0:43:16.00,0:43:17.90,yin,,0,0,0,, 也更加正确 \\N{\\fs12}but also a little more correct,\r\nDialogue: 0,0:43:18.36,0:43:20.37,yin,,0,0,0,, 可以在代码中 \\N{\\fs12}it is possible that your view controller\r\nDialogue: 0,0:43:20.38,0:43:23.41,yin,,0,0,0,, 用 alloc/init 来创建你的视图控制器 \\N{\\fs12}could be created in code using alloc init.\r\nDialogue: 0,0:43:24.00,0:43:27.50,yin,,0,0,0,, 允许使用 alloc/init\\N{\\fs12}It is legal for someone to alloc init –\r\nDialogue: 0,0:43:27.80,0:43:30.90,yin,,0,0,0,,init 并不是视图控制器的指定初始化方法 \\N{\\fs12}init is not the designated initializer for view controller\r\nDialogue: 0,0:43:30.90,0:43:33.99,yin,,0,0,0,, 但是 init 可以调用指定初始化方法 \\N{\\fs12}but init calls the designated initializer –\r\nDialogue: 0,0:43:34.23,0:43:36.08,yin,,0,0,0,, 所以这样做是可以的 \\N{\\fs12}so it is legal for people to do that.\r\nDialogue: 0,0:43:37.27,0:43:38.83,yin,,0,0,0,, 但是这门课上我们不会这样做 \\N{\\fs12}Not going to happen in this class.\r\nDialogue: 0,0:43:38.99,0:43:43.07,yin,,0,0,0,, 我们在课上会全部使用 storyboard 来创建 \\N{\\fs12}Okay? We’re going to make things out of storyboards for 100% of this class,\r\nDialogue: 0,0:43:43.08,0:43:43.93,yin,,0,0,0,, 所以不用担心 \\N{\\fs12}so don’t worry about it.\r\nDialogue: 0,0:43:44.35,0:43:47.53,yin,,0,0,0,, 但是 UIViewController 的指定初始化方法是 \\N{\\fs12}But the designated initializer for UIViewController\r\nDialogue: 0,0:43:47.54,0:43:50.32,yin,,0,0,0,,initWithNibName: bundle:\\N{\\fs12}is initWithNibName colon bundle colon.\r\nDialogue: 0,0:43:50.81,0:43:54.41,yin,,0,0,0,, 同样出于历史原因 这里使用 nib\\N{\\fs12}Okay? Again, historical reasons here with old nib files.\r\nDialogue: 0,0:43:54.92,0:43:58.81,yin,,0,0,0,, 为了保证正确 通常情况下 \\N{\\fs12}And so to be correct, we usually like to call\r\nDialogue: 0,0:43:58.82,0:44:02.14,yin,,0,0,0,, 也会在初始化方法中调用 awakeFromNib 中调用的内容 \\N{\\fs12}whatever we’re going to call from awakeFromNib also in that init method.\r\nDialogue: 0,0:44:02.37,0:44:03.63,yin,,0,0,0,, 所以你使用这个模板 \\N{\\fs12}And so you use this little template\r\nDialogue: 0,0:44:03.63,0:44:05.60,yin,,0,0,0,, 自己创建了一个方法叫 setup 之类的 \\N{\\fs12}where you have some method called setup or something,\r\nDialogue: 0,0:44:05.83,0:44:07.23,yin,,0,0,0,,awakeFromNib 调用它 \\N{\\fs12}awakeFromNib calls that,\r\nDialogue: 0,0:44:07.39,0:44:11.18,yin,,0,0,0,, 然后 initWithNibName 中写 self=[super initWithNibName: bundle:]\\N{\\fs12}and then initWithNibName says self super initWithNibName bundle –\r\nDialogue: 0,0:44:11.18,0:44:12.83,yin,,0,0,0,, 因为它是指定初始化方法 \\N{\\fs12}because that’s the designated initializer –\r\nDialogue: 0,0:44:13.14,0:44:14.74,yin,,0,0,0,, 然后是 [self setup] return self\\N{\\fs12}self setup return self.\r\nDialogue: 0,0:44:15.05,0:44:17.96,yin,,0,0,0,, 所以如果你要把 awakeFromNib 放在那 \\N{\\fs12}Okay? So if you’re going to put awakeFromNib in there,\r\nDialogue: 0,0:44:17.97,0:44:21.43,yin,,0,0,0,, 也要把这三行 initWithNibName 代码一块放进去 \\N{\\fs12}go ahead and put this little three-line initWithNibName also in there,\r\nDialogue: 0,0:44:21.62,0:44:23.59,yin,,0,0,0,, 这样才对 \\N{\\fs12}just to be correct.\r\nDialogue: 0,0:44:24.33,0:44:26.60,yin,,0,0,0,, 也许在这门课上不用这样做 \\N{\\fs12}Okay? Probably not necessary in this class.\r\nDialogue: 0,0:44:26.60,0:44:29.25,yin,,0,0,0,, 你们在课上不需要用到 awakeFromNib\\N{\\fs12}I don’t think you’re going to need awakeFromNib in this class;\r\nDialogue: 0,0:44:29.58,0:44:31.36,yin,,0,0,0,,viewDidLoad 就足够了 \\N{\\fs12}viewDidLoad is what you want.\r\nDialogue: 0,0:44:32.81,0:44:35.82,yin,,0,0,0,, 好了 这是视图控制器生命周期的总结 \\N{\\fs12}Okay. So here’s a summary of the view controller lifecycle:\r\nDialogue: 0,0:44:36.34,0:44:38.83,yin,,0,0,0,, 从 storyboard 中进行实例化 \\N{\\fs12}It’s instantiated from the storyboard\r\nDialogue: 0,0:44:38.83,0:44:40.93,yin,,0,0,0,, 或者通过调用 alloc/init\\N{\\fs12}or someone could say alloc init, okay;\r\nDialogue: 0,0:44:41.39,0:44:44.74,yin,,0,0,0,, 如果是从 storyboard 中出来的 就会调用 awakeFromNib\\N{\\fs12}awakeFromNib gets called if it came out of a storyboard,\r\nDialogue: 0,0:44:44.75,0:44:47.62,yin,,0,0,0,, 不然就是调用 initWithNibName bundle\\N{\\fs12}otherwise init with nib name with bundle gets called;\r\nDialogue: 0,0:44:47.99,0:44:51.04,yin,,0,0,0,, 如果是从 storyboard 中出来的 设置好输出口 \\N{\\fs12}the outlets get set if it comes from a storyboard;\r\nDialogue: 0,0:44:51.62,0:44:53.01,yin,,0,0,0,, 然后 viewDidload 被调用 \\N{\\fs12}then viewDidLoad is called;\r\nDialogue: 0,0:44:54.00,0:44:56.31,yin,,0,0,0,, 然后当几何内容都确定之后 \\N{\\fs12}then when the geometry is determined,\r\nDialogue: 0,0:44:56.54,0:44:58.89,yin,,0,0,0,,viewWillLayoutSubviews 和 viewDidLayoutSubviews 被调用 \\N{\\fs12}viewWillLayoutSubviews and viewDidLayoutSubviews –\r\nDialogue: 0,0:44:58.89,0:45:00.07,yin,,0,0,0,, 这里没有冒号 \\N{\\fs12}there should be no colons there;\r\nDialogue: 0,0:45:00.08,0:45:04.06,yin,,0,0,0,, 不知道为什么打错了 \\N{\\fs12}I don’t know what, that’s a mistake — get called;\r\nDialogue: 0,0:45:04.75,0:45:06.77,yin,,0,0,0,, 然后 viewWillAppear 被调用 \\N{\\fs12}then viewWillAppear gets called;\r\nDialogue: 0,0:45:07.64,0:45:10.77,yin,,0,0,0,, 如果在可见时 几何内容有变化 \\N{\\fs12}then if the geometry changes again while it’s visible,\r\nDialogue: 0,0:45:10.77,0:45:13.40,yin,,0,0,0,,viewWillLayoutSubviews 和 viewDidLayoutSubviews\\N{\\fs12}viewWillLayoutSubviews and viewDidLayoutSubviews\r\nDialogue: 0,0:45:13.63,0:45:14.60,yin,,0,0,0,, 会被再次调用 \\N{\\fs12}will get called again.\r\nDialogue: 0,0:45:15.23,0:45:18.14,yin,,0,0,0,, 如果有自动旋转功能 \\N{\\fs12}Okay? If there’s autorotation,\r\nDialogue: 0,0:45:18.14,0:45:20.00,yin,,0,0,0,, 就还要加上自动旋转的内容 \\N{\\fs12}you also get those autorotation things.\r\nDialogue: 0,0:45:20.00,0:45:21.01,yin,,0,0,0,, 但是不用担心这部分内容 \\N{\\fs12}But don’t worry about those\r\nDialogue: 0,0:45:21.01,0:45:22.43,yin,,0,0,0,, 因为通常情况下 你想做的操作 \\N{\\fs12}because you’re usually doing what you want to do\r\nDialogue: 0,0:45:22.43,0:45:23.59,yin,,0,0,0,, 都在 viewDidLayoutSubviews 中实现 \\N{\\fs12}in viewDidLayoutSubviews.\r\nDialogue: 0,0:45:24.17,0:45:26.02,yin,,0,0,0,, 然后当你的视图控制器从屏幕上离开时 \\N{\\fs12}Then when your view controller goes off screen,\r\nDialogue: 0,0:45:26.02,0:45:27.47,yin,,0,0,0,, 会收到 viewWillDisappear 消息 \\N{\\fs12}it will get viewWillDisappear.\r\nDialogue: 0,0:45:28.17,0:45:33.15,yin,,0,0,0,, 在此过程中 如果出现内存不足的情况 \\N{\\fs12}Okay? If you have a low memory thing at any time going on there,\r\nDialogue: 0,0:45:33.16,0:45:33.79,yin,,0,0,0,, 你会得到这个通知 \\N{\\fs12}you’ll get that.\r\nDialogue: 0,0:45:33.95,0:45:35.57,yin,,0,0,0,, 不管是否在屏幕上 \\N{\\fs12}That could be while you’re visible or not.\r\nDialogue: 0,0:45:36.17,0:45:37.47,yin,,0,0,0,, 就是这样 \\N{\\fs12}And that’s it.\r\nDialogue: 0,0:45:37.92,0:45:40.19,yin,,0,0,0,, 视图控制器生命周期从头到尾的过程就是这样 \\N{\\fs12}That’s the view controller lifecycle from start to finish.\r\nDialogue: 0,0:45:41.30,0:45:44.38,yin,,0,0,0,, 好的 \\N{\\fs12}Okay? All right.\r\nDialogue: 0,0:45:44.71,0:45:45.86,yin,,0,0,0,, 我们来演示一下 \\N{\\fs12}So let’s see a little demo\r\nDialogue: 0,0:45:45.86,0:45:47.62,yin,,0,0,0,, 如何使用视图控制器生命周期 \\N{\\fs12}of using the view controller lifecycle.\r\nDialogue: 0,0:45:48.61,0:45:49.94,yin,,0,0,0,, 我要做的是 \\N{\\fs12}So what I’m going to do is\r\nDialogue: 0,0:45:49.94,0:45:51.79,yin,,0,0,0,, 记得之前讲过的添加轮廓按钮吧 \\N{\\fs12}that outline button we talked about before.\r\nDialogue: 0,0:45:52.03,0:45:54.94,yin,,0,0,0,, 我们让这个按钮上的文字也加上轮廓 \\N{\\fs12}Let’s make it so the outline button is itself outlined.\r\nDialogue: 0,0:45:54.94,0:45:56.29,yin,,0,0,0,, 这样是一个很好的 UI\\N{\\fs12}That would be kind of a good UI.\r\nDialogue: 0,0:45:56.59,0:45:58.90,yin,,0,0,0,, 可以更好地表现出这个按钮是做什么的 \\N{\\fs12}Okay? So it’s kind of a little more indication of what it does.\r\nDialogue: 0,0:45:59.17,0:46:02.98,yin,,0,0,0,, 问题是 如果我得到这里的这个添加轮廓按钮 \\N{\\fs12}Well, the question is: If I have this outline button right here,\r\nDialogue: 0,0:46:06.12,0:46:08.76,yin,,0,0,0,, 我应该何时以怎样的方法为它添加轮廓呢 \\N{\\fs12}how and when am I going to outline it?\r\nDialogue: 0,0:46:08.77,0:46:10.84,yin,,0,0,0,, 很遗憾 我不能在 Xcode 里实现 \\N{\\fs12}I can’t do it in Xcode unfortunately.\r\nDialogue: 0,0:46:11.12,0:46:12.46,yin,,0,0,0,, 所以我需要用代码来实现 \\N{\\fs12}So I need to do it in code.\r\nDialogue: 0,0:46:12.82,0:46:15.54,yin,,0,0,0,, 我想让它一出来就加上轮廓 \\N{\\fs12}But I want it to be outlined when the thing first comes up,\r\nDialogue: 0,0:46:15.89,0:46:18.26,yin,,0,0,0,, 而且始终保持这种状态 \\N{\\fs12}but — and I want it to always be outlined.\r\nDialogue: 0,0:46:18.47,0:46:20.51,yin,,0,0,0,, 这属于一次性初始化操作 \\N{\\fs12}So that’s a one-time initialization thing,\r\nDialogue: 0,0:46:20.73,0:46:23.25,yin,,0,0,0,, 但是这显然要在输出口设置好之后才能发生 \\N{\\fs12}but it obviously has to happen after my outlets are set\r\nDialogue: 0,0:46:23.32,0:46:25.53,yin,,0,0,0,, 因为我需要向这个按钮发送消息 \\N{\\fs12}because I need to be able to talk to this button.\r\nDialogue: 0,0:46:25.53,0:46:27.29,yin,,0,0,0,, 那么我们先来创建一个对应的输出口 \\N{\\fs12}So let’s make an outlet for this.\r\nDialogue: 0,0:46:27.30,0:46:29.46,yin,,0,0,0,, 按住 control 键拖拽到这里 \\N{\\fs12}I’m just going to control drag here.\r\nDialogue: 0,0:46:29.66,0:46:33.10,yin,,0,0,0,, 我要叫它 outlineButton\\N{\\fs12}I’m going to call this the “outlineButton,” okay?\r\nDialogue: 0,0:46:33.58,0:46:35.96,yin,,0,0,0,, 我要用到 viewDidLoad\\N{\\fs12}And I’m going to take viewDidLoad.\r\nDialogue: 0,0:46:35.96,0:46:38.84,yin,,0,0,0,, 我要把它移到上面这里 \\N{\\fs12}I’m actually going to move it up to the top here.\r\nDialogue: 0,0:46:39.90,0:46:41.08,yin,,0,0,0,, 好了 这是 viewDidLoad\\N{\\fs12}Okay. So there’s viewDidLoad.\r\nDialogue: 0,0:46:41.50,0:46:43.87,yin,,0,0,0,, 我要完全按照注释说的做 \\N{\\fs12}And I’m going to do exactly what it says here,\r\nDialogue: 0,0:46:44.11,0:46:46.94,yin,,0,0,0,, 在加载视图后 进行追加设置 \\N{\\fs12}do any additional setup after loading the view.\r\nDialogue: 0,0:46:46.97,0:46:49.20,yin,,0,0,0,, 这里应该写 storyboard\\N{\\fs12}This should say typically from a storyboard.\r\nDialogue: 0,0:46:49.61,0:46:51.20,yin,,0,0,0,, 到现在还没有改过来 很好笑 \\N{\\fs12}It’s funny that that has not changed.\r\nDialogue: 0,0:46:51.27,0:46:53.42,yin,,0,0,0,,storyboard 出现在各个 iOS 版本中 \\N{\\fs12}I mean, storyboards have been around for — I don’t know –\r\nDialogue: 0,0:46:53.43,0:46:55.37,yin,,0,0,0,,iOS4 5 6 7 都有 \\N{\\fs12}iOS four, five, six, seven, something like that.\r\nDialogue: 0,0:46:55.39,0:46:56.54,yin,,0,0,0,, 到现在还在用 nib\\N{\\fs12}They’re still saying from nib.\r\nDialogue: 0,0:46:56.55,0:47:00.41,yin,,0,0,0,, 但不管怎样 viewDidLoad 就是用来做这个的 \\N{\\fs12}But anyway, viewDidLoad is the place to do this.\r\nDialogue: 0,0:47:00.65,0:47:04.86,yin,,0,0,0,, 我们只要设置这个按钮的属性化标题 \\N{\\fs12}And all we need to do is set the attributed title of this button\r\nDialogue: 0,0:47:05.19,0:47:06.89,yin,,0,0,0,, 添加轮廓属性 \\N{\\fs12}to have the attributes of outline.\r\nDialogue: 0,0:47:06.89,0:47:08.02,yin,,0,0,0,, 我们要怎么做呢 \\N{\\fs12}So how are we going to do that?\r\nDialogue: 0,0:47:08.03,0:47:10.31,yin,,0,0,0,, 这里需要大家特别注意 \\N{\\fs12}Okay? And this is important for you to pay attention here.\r\nDialogue: 0,0:47:10.31,0:47:11.58,yin,,0,0,0,, 大家都醒着呢 不错 \\N{\\fs12}You all look awake, that’s good\r\nDialogue: 0,0:47:11.90,0:47:16.30,yin,,0,0,0,, 周三将要布置的那个作业 \\N{\\fs12}because your homework that’s going to be assigned on Wednesday\r\nDialogue: 0,0:47:16.74,0:47:19.02,yin,,0,0,0,, 要用到这部分内容 \\N{\\fs12}is going to require this.\r\nDialogue: 0,0:47:19.02,0:47:22.15,yin,,0,0,0,, 你需要设置一个按钮的属性化标题 \\N{\\fs12}You’re going to have to set an attributed title of a button.\r\nDialogue: 0,0:47:22.89,0:47:25.80,yin,,0,0,0,, 因为很不巧 作业中的卡牌都是按钮 \\N{\\fs12}Okay? Because your cards are buttons unfortunately.\r\nDialogue: 0,0:47:25.90,0:47:27.30,yin,,0,0,0,, 下周之后 它们就不再是按钮了 \\N{\\fs12}They won’t be buttons the week after that.\r\nDialogue: 0,0:47:27.61,0:47:28.81,yin,,0,0,0,, 但它们现在是按钮 \\N{\\fs12}But they’re buttons right now.\r\nDialogue: 0,0:47:28.81,0:47:31.04,yin,,0,0,0,, 所以你需要用属性化字符串 \\N{\\fs12}And so you’re going to need attributed strings\r\nDialogue: 0,0:47:31.04,0:47:33.05,yin,,0,0,0,, 显示我们下周要做的内容 \\N{\\fs12}to display what we want to do next week.\r\nDialogue: 0,0:47:33.06,0:47:34.79,yin,,0,0,0,, 所以你们需要设置按钮的属性化标题 \\N{\\fs12}And so you’re going to have to set attributed titles to button.\r\nDialogue: 0,0:47:34.79,0:47:37.04,yin,,0,0,0,, 我们来讲一下怎么做 \\N{\\fs12}So let’s talk about how we do that.\r\nDialogue: 0,0:47:37.50,0:47:39.59,yin,,0,0,0,, 首先我要写 \\N{\\fs12}First thing I’m going to do is\r\nDialogue: 0,0:47:39.85,0:47:47.38,yin,,0,0,0,,NSMutableAttributedString *title =\\N{\\fs12}I’m going to say NSMutableAttributedString *title equals.\r\nDialogue: 0,0:47:47.38,0:47:51.70,yin,,0,0,0,, 我想得到这个按钮标题的可变属性化字符串形式 \\N{\\fs12}So I want to get the title of this button as a mutable attributed string\r\nDialogue: 0,0:47:51.71,0:47:54.96,yin,,0,0,0,, 这样我就能将属性设为轮廓属性 \\N{\\fs12}so that I can set the attributes to be the outline attributes\r\nDialogue: 0,0:47:54.97,0:47:56.03,yin,,0,0,0,, 也就是描边宽度等等 \\N{\\fs12}that stroke width thing.\r\nDialogue: 0,0:47:56.56,0:47:59.69,yin,,0,0,0,, 所以这里我要写 \\N{\\fs12}So the way to do that is I’m going to say\r\nDialogue: 0,0:48:00.48,0:48:03.93,yin,,0,0,0,,[NSMutableAttributedString alloc]\\N{\\fs12}[NSMutableAttributedString alloc]\r\nDialogue: 0,0:48:04.58,0:48:12.58,yin,,0,0,0,,initWithString: self.outlineButton.currentTitle\\N{\\fs12}initWithString: self dot outline button dot current title.\r\nDialogue: 0,0:48:12.67,0:48:14.33,yin,,0,0,0,, 不管目前标题是什么 \\N{\\fs12}So whatever’s on there currently,\r\nDialogue: 0,0:48:14.34,0:48:15.88,yin,,0,0,0,, 现在是 Outline 这个词 \\N{\\fs12}which is the word “Outline” right now,\r\nDialogue: 0,0:48:15.89,0:48:16.83,yin,,0,0,0,, 都要使用它 \\N{\\fs12}going to use that.\r\nDialogue: 0,0:48:17.70,0:48:21.79,yin,,0,0,0,, 就是这样 \\N{\\fs12}And then that’s it.\r\nDialogue: 0,0:48:21.80,0:48:22.66,yin,,0,0,0,, 这里我要示范的操作就是这些了 \\N{\\fs12}That’s all I’m going to do there,\r\nDialogue: 0,0:48:22.77,0:48:24.84,yin,,0,0,0,, 为了告诉大家如何实现 \\N{\\fs12}just show you how to do this, this way.\r\nDialogue: 0,0:48:24.84,0:48:26.73,yin,,0,0,0,, 其实还可以在这里设置属性 但是…\\N{\\fs12}I could set the attributes there, actually, but –\r\nDialogue: 0,0:48:26.86,0:48:29.00,yin,,0,0,0,, 糟糕 我做对了吗 \\N{\\fs12}oops, did I get that right?\r\nDialogue: 0,0:48:30.13,0:48:35.95,yin,,0,0,0,, 现在我得到了标题的可变属性化字符串 \\N{\\fs12}Okay. So now I have the title as a mutable attributed string.\r\nDialogue: 0,0:48:35.95,0:48:39.22,yin,,0,0,0,, 我就可以设置这个标题的属性了 \\N{\\fs12}So now I can set the attributes in this title.\r\nDialogue: 0,0:48:39.44,0:48:42.33,yin,,0,0,0,, 这个标题现在是一个 NSMutableAttributedString\\N{\\fs12}Okay? Now this title is an NSMutableAttributedString\r\nDialogue: 0,0:48:42.33,0:48:43.18,yin,,0,0,0,, 是我刚刚创建的 \\N{\\fs12}that I just created.\r\nDialogue: 0,0:48:43.18,0:48:44.32,yin,,0,0,0,, 它是一个局部变量 \\N{\\fs12}It’s a local variable.\r\nDialogue: 0,0:48:44.71,0:48:46.93,yin,,0,0,0,, 它是通过按钮的标题创建的 \\N{\\fs12}It’s created with the button’s title,\r\nDialogue: 0,0:48:47.17,0:48:48.36,yin,,0,0,0,, 但它是一个局部变量 \\N{\\fs12}but it’s a local variable.\r\nDialogue: 0,0:48:49.03,0:48:51.13,yin,,0,0,0,, 我们继续 设置我们想要的属性 \\N{\\fs12}So let’s go ahead and set the attributes we want.\r\nDialogue: 0,0:48:51.65,0:48:54.38,yin,,0,0,0,, 和下面的代码很类似 \\N{\\fs12}Okay? Again, it’s very similar to this down here.\r\nDialogue: 0,0:48:54.39,0:48:56.86,yin,,0,0,0,, 那我就直接复制粘贴这段代码 \\N{\\fs12}In fact, I’m going to just copy and paste this\r\nDialogue: 0,0:48:56.87,0:48:58.76,yin,,0,0,0,, 稍微改一下 \\N{\\fs12}and make one small change.\r\nDialogue: 0,0:49:00.06,0:49:03.55,yin,,0,0,0,, 这里不用 -3 了 \\N{\\fs12}Okay. So here, instead of the minus three, okay,\r\nDialogue: 0,0:49:03.76,0:49:04.82,yin,,0,0,0,, 我把它改成 3\\N{\\fs12}I’m going to make it three.\r\nDialogue: 0,0:49:04.82,0:49:08.10,yin,,0,0,0,, 这样就只加轮廓 \\N{\\fs12}And that’s going to make this outline thing be outlined\r\nDialogue: 0,0:49:08.24,0:49:09.77,yin,,0,0,0,, 不填充蓝色 \\N{\\fs12}with no blue in the middle.\r\nDialogue: 0,0:49:10.30,0:49:13.23,yin,,0,0,0,, 这个按钮的前景色是蓝色 \\N{\\fs12}Okay? So the foreground color of this button is blue\r\nDialogue: 0,0:49:13.24,0:49:14.51,yin,,0,0,0,, 或者是默认的黑色 \\N{\\fs12}or whatever the default is, black.\r\nDialogue: 0,0:49:14.89,0:49:16.33,yin,,0,0,0,, 但是我这样设置之后 \\N{\\fs12}But I’m going to make it\r\nDialogue: 0,0:49:16.34,0:49:18.00,yin,,0,0,0,, 就成为了空心轮廓的样式 \\N{\\fs12}so it’s outlined with nothing in the middle.\r\nDialogue: 0,0:49:18.40,0:49:19.06,yin,,0,0,0,, 另外一件事是 \\N{\\fs12}The other thing is\r\nDialogue: 0,0:49:19.06,0:49:22.51,yin,,0,0,0,, 我不想让这个按钮是黑色的 \\N{\\fs12}I don’t really want this button to be black, okay?\r\nDialogue: 0,0:49:22.73,0:49:24.09,yin,,0,0,0,, 因为按钮都不是黑色的 \\N{\\fs12}Because buttons are not black.\r\nDialogue: 0,0:49:24.51,0:49:26.11,yin,,0,0,0,, 按钮是什么颜色的 \\N{\\fs12}Now, what color are buttons?\r\nDialogue: 0,0:49:26.47,0:49:29.96,yin,,0,0,0,, 这就引出了另一个有趣的问题 \\N{\\fs12}Okay? And this brings up another interesting thing\r\nDialogue: 0,0:49:29.97,0:49:31.26,yin,,0,0,0,, 我们一直还没机会讲 \\N{\\fs12}we really haven’t had a chance to talk about,\r\nDialogue: 0,0:49:31.27,0:49:32.37,yin,,0,0,0,, 也就是颜色和色调 \\N{\\fs12}which is the tint color.\r\nDialogue: 0,0:49:32.97,0:49:35.07,yin,,0,0,0,, 有些同学已经发现了这个问题 \\N{\\fs12}Okay? And some of you have discovered this on your own\r\nDialogue: 0,0:49:35.07,0:49:36.88,yin,,0,0,0,, 因为你们不喜欢 Matchismo 中 \\N{\\fs12}because you didn’t like the blue tint\r\nDialogue: 0,0:49:36.88,0:49:38.57,yin,,0,0,0,, 绿色背景配蓝色元素 \\N{\\fs12}on the green background in Matchismo.\r\nDialogue: 0,0:49:38.57,0:49:40.89,yin,,0,0,0,, 我对大家对 UI 的直觉 \\N{\\fs12}And I applaud you and your UI instincts\r\nDialogue: 0,0:49:40.90,0:49:43.02,yin,,0,0,0,, 和寻找改变方法表示赞赏 \\N{\\fs12}to go searching for a way to change that.\r\nDialogue: 0,0:49:43.34,0:49:45.01,yin,,0,0,0,, 正确的更改方法是 \\N{\\fs12}And the right way to change it is\r\nDialogue: 0,0:49:45.19,0:49:47.21,yin,,0,0,0,, 有一个全局色调颜色设置 \\N{\\fs12}there’s actually a global tint color,\r\nDialogue: 0,0:49:47.32,0:49:49.47,yin,,0,0,0,, 你的整个应用的色调颜色 \\N{\\fs12}a tint color for your entire application.\r\nDialogue: 0,0:49:49.69,0:49:51.85,yin,,0,0,0,, 设置方法是打开 storyboard\\N{\\fs12}And you set that by going to your storyboard.\r\nDialogue: 0,0:49:51.85,0:49:54.13,yin,,0,0,0,, 看到这里我的 storyboard 是选中的了吗 \\N{\\fs12}See how my storyboard is selected over here?\r\nDialogue: 0,0:49:54.46,0:49:58.91,yin,,0,0,0,, 如果我转到这里 \\N{\\fs12}And if I go to the little area here\r\nDialogue: 0,0:49:59.18,0:50:00.80,yin,,0,0,0,, 这是全部属性检查器 \\N{\\fs12}that has all my attributes inspector,\r\nDialogue: 0,0:50:00.82,0:50:02.94,yin,,0,0,0,, 如果我点击最左边这项 \\N{\\fs12}if I click the left to most one,\r\nDialogue: 0,0:50:03.13,0:50:04.91,yin,,0,0,0,, 也就是文件检查器 \\N{\\fs12}which is the file inspector –\r\nDialogue: 0,0:50:04.91,0:50:06.43,yin,,0,0,0,, 它会检查这个 storyboard 文件 \\N{\\fs12}it’s inspecting this storyboard file –\r\nDialogue: 0,0:50:06.77,0:50:08.71,yin,,0,0,0,, 可以看到 这里有一个全局色调 \\N{\\fs12}you’ll see there’s global tint.\r\nDialogue: 0,0:50:09.55,0:50:09.85,yin,,0,0,0,, 看到了吗 \\N{\\fs12}Okay?\r\nDialogue: 0,0:50:10.18,0:50:13.10,yin,,0,0,0,, 全局色调控制你的应用中 \\N{\\fs12}So global tint affects all clickable things\r\nDialogue: 0,0:50:13.10,0:50:14.12,yin,,0,0,0,, 全部可点击元素的颜色 \\N{\\fs12}in your app everywhere.\r\nDialogue: 0,0:50:15.06,0:50:17.88,yin,,0,0,0,, 所以你可以选择蓝色以外的颜色 \\N{\\fs12}Okay? So you could pick a different color than blue.\r\nDialogue: 0,0:50:18.29,0:50:19.14,yin,,0,0,0,, 我们就这样了 \\N{\\fs12}And we do that.\r\nDialogue: 0,0:50:19.44,0:50:22.64,yin,,0,0,0,, 另外 像 UIButton 这样的单个元素 \\N{\\fs12}The other thing is individual elements like UIButtons,\r\nDialogue: 0,0:50:22.83,0:50:24.26,yin,,0,0,0,, 也有自己的色调颜色 \\N{\\fs12}they also have a tint color.\r\nDialogue: 0,0:50:24.93,0:50:27.07,yin,,0,0,0,, 通常情况下 不会单独设置它们 \\N{\\fs12}Now, usually you don’t want to set them separately,\r\nDialogue: 0,0:50:27.16,0:50:31.33,yin,,0,0,0,, 尽管很多人发现在模拟器中似乎有一个错误 \\N{\\fs12}although a couple people noticed what seems to be a bug in the simulator\r\nDialogue: 0,0:50:31.48,0:50:33.62,yin,,0,0,0,, 如果你设置了全局色调 \\N{\\fs12}where if you set the global tint,\r\nDialogue: 0,0:50:33.71,0:50:38.23,yin,,0,0,0,, 在模拟器中会绘制出错误的分段控件 \\N{\\fs12}it draws improperly segmented control in the simulator.\r\nDialogue: 0,0:50:38.23,0:50:40.05,yin,,0,0,0,, 我不知道在设备上是否会这样 \\N{\\fs12}I haven’t heard back whether it does it on a device.\r\nDialogue: 0,0:50:40.06,0:50:44.16,yin,,0,0,0,, 替代方法就是单独设置色调颜色 \\N{\\fs12}But so the workaround was to set the individual tint color.\r\nDialogue: 0,0:50:45.06,0:50:46.94,yin,,0,0,0,, 你可以设置各元素的色调颜色 \\N{\\fs12}So you can set tint color individual items\r\nDialogue: 0,0:50:46.94,0:50:49.04,yin,,0,0,0,, 或者设置整个 storyboard 的色调颜色 \\N{\\fs12}or you can set it at the storyboard level.\r\nDialogue: 0,0:50:49.65,0:50:51.63,yin,,0,0,0,, 这里我不会设置它 \\N{\\fs12}Here what I’m going to do, I’m not going to set it\r\nDialogue: 0,0:50:51.73,0:50:52.96,yin,,0,0,0,, 但我要得到它 \\N{\\fs12}but I am going to get it.\r\nDialogue: 0,0:50:53.06,0:50:54.42,yin,,0,0,0,, 我要得到这个色调颜色 \\N{\\fs12}I’m going to get the tint color\r\nDialogue: 0,0:50:54.64,0:50:56.52,yin,,0,0,0,, 因为不管这个色调颜色是什么 \\N{\\fs12}because whatever this tint color is,\r\nDialogue: 0,0:50:56.65,0:50:59.53,yin,,0,0,0,, 我都要用它进行描边 \\N{\\fs12}I want that to be the color that I’m stroking it with,\r\nDialogue: 0,0:50:59.54,0:51:00.34,yin,,0,0,0,, 也就是轮廓颜色 \\N{\\fs12}the outline color.\r\nDialogue: 0,0:51:00.34,0:51:03.60,yin,,0,0,0,, 也就是 self.outlineButton.tintColor\\N{\\fs12}So that is going to be self dot outlineButton dot tintColor –\r\nDialogue: 0,0:51:04.48,0:51:05.39,yin,,0,0,0,,tintColor\\N{\\fs12}tintColor.\r\nDialogue: 0,0:51:06.28,0:51:10.00,yin,,0,0,0,, 明白我在做什么吗 \\N{\\fs12}Okay? Understand what I’m doing there?\r\nDialogue: 0,0:51:10.01,0:51:12.81,yin,,0,0,0,, 所以我想让它保持蓝色或其他默认颜色 \\N{\\fs12}So I want it stay blue or whatever this color is,\r\nDialogue: 0,0:51:13.55,0:51:15.81,yin,,0,0,0,, 但我只想要描边 \\N{\\fs12}but I want it to be outlined only.\r\nDialogue: 0,0:51:16.54,0:51:20.14,yin,,0,0,0,, 范围呢 我需要整个文本范围 \\N{\\fs12}And then the range, I need the entire range of text.\r\nDialogue: 0,0:51:20.14,0:51:23.16,yin,,0,0,0,, 也就是说 这里的整个可变字符串标题 \\N{\\fs12}In other words, I have this mutable string title here;\r\nDialogue: 0,0:51:23.36,0:51:24.94,yin,,0,0,0,, 我希望全部添加轮廓 \\N{\\fs12}I want the entire thing done.\r\nDialogue: 0,0:51:24.94,0:51:27.30,yin,,0,0,0,, 所以我要用到 NSMakeRange\\N{\\fs12}So I’m going to use NSMakeRange,\r\nDialogue: 0,0:51:27.42,0:51:29.63,yin,,0,0,0,, 这是一个 C 结构体 \\N{\\fs12}and you’re going to find that for C structs\r\nDialogue: 0,0:51:29.92,0:51:34.20,yin,,0,0,0,,iOS 中通常会用 NSMakeXX\\N{\\fs12}in iOS there’s usually an NSMake whatever you want\r\nDialogue: 0,0:51:34.46,0:51:35.63,yin,,0,0,0,, 创建 C 结构体 \\N{\\fs12}that will make the C struct\r\nDialogue: 0,0:51:35.92,0:51:38.30,yin,,0,0,0,, 让你来指定结构体的成员 \\N{\\fs12}by letting you specify the members of the struct.\r\nDialogue: 0,0:51:38.30,0:51:41.72,yin,,0,0,0,, 所以在这个例子中 范围包含一个位置 \\N{\\fs12}So in this case a range has a location –\r\nDialogue: 0,0:51:41.72,0:51:42.47,yin,,0,0,0,, 一个起始位置 \\N{\\fs12}a starting location –\r\nDialogue: 0,0:51:42.47,0:51:45.28,yin,,0,0,0,, 也就是 0 还有一个长度 \\N{\\fs12}which will be zero and it has a length.\r\nDialogue: 0,0:51:45.71,0:51:47.53,yin,,0,0,0,, 长度是这个标题的长度 \\N{\\fs12}Okay? Which is going to be title length.\r\nDialogue: 0,0:51:49.45,0:51:51.22,yin,,0,0,0,, 这样就得到了范围 \\N{\\fs12}Okay? So that makes a little range.\r\nDialogue: 0,0:51:51.22,0:51:54.07,yin,,0,0,0,, 会将整个范围都设有这些属性 \\N{\\fs12}That’s going to set the entire range to have these attributes.\r\nDialogue: 0,0:51:54.95,0:51:59.22,yin,,0,0,0,, 现在我得到了标题的可变字符串形式 \\N{\\fs12}Okay? Now I have the title I want as a mutable string,\r\nDialogue: 0,0:51:59.39,0:52:01.29,yin,,0,0,0,, 但我需要再将其设置为按钮标题 \\N{\\fs12}but I need to set this back on the button.\r\nDialogue: 0,0:52:01.85,0:52:02.93,yin,,0,0,0,, 因为这里 只有在它是局部变量的情况下 \\N{\\fs12}Okay? Because I’ve only can done this\r\nDialogue: 0,0:52:02.93,0:52:04.27,yin,,0,0,0,, 我才能这样做 \\N{\\fs12}as a local variable right here.\r\nDialogue: 0,0:52:04.77,0:52:08.45,yin,,0,0,0,, 因为按钮中没有像文本视图中那样的可变属性化字符串 \\N{\\fs12}Because there’s no mutable attributed string in button\r\nDialogue: 0,0:52:08.45,0:52:10.46,yin,,0,0,0,, 可以让你随意修改 \\N{\\fs12}like there is in text view that you can just modify;\r\nDialogue: 0,0:52:10.46,0:52:14.06,yin,,0,0,0,, 你必须得到它 做一个可变版本 \\N{\\fs12}you have to get it, make a mutable version, you know,\r\nDialogue: 0,0:52:14.06,0:52:15.65,yin,,0,0,0,, 编辑后再设置回去 \\N{\\fs12}edit it, and then set it back.\r\nDialogue: 0,0:52:15.65,0:52:18.63,yin,,0,0,0,, 我们这样实现 self.outlineButton\\N{\\fs12}And the way we do that is self dot outlineButton\r\nDialogue: 0,0:52:18.83,0:52:25.15,yin,,0,0,0,,setAttributedTitle: title forState: UIControlStateNormal\\N{\\fs12}setAttributedTitle: title forState: UIControlStateNormal.\r\nDialogue: 0,0:52:26.65,0:52:29.65,yin,,0,0,0,, 就像是在设置标题 但是设置的是属性化标题 \\N{\\fs12}Okay? So it’s just like set title but set attributed title.\r\nDialogue: 0,0:52:30.81,0:52:33.39,yin,,0,0,0,, 我们看看是否管用 \\N{\\fs12}Okay? So let’s see if that works.\r\nDialogue: 0,0:52:42.42,0:52:43.13,yin,,0,0,0,, 好的 成功了 \\N{\\fs12}Okay. And it did.\r\nDialogue: 0,0:52:43.36,0:52:46.11,yin,,0,0,0,, 可以看到 Outline 现在是有轮廓的 \\N{\\fs12}So you can see the outline right there is outlined.\r\nDialogue: 0,0:52:46.59,0:52:48.86,yin,,0,0,0,, 轮廓效果不是很明显 \\N{\\fs12}It’s not awesomely outlined,\r\nDialogue: 0,0:52:48.87,0:52:51.03,yin,,0,0,0,, 很难看出来 \\N{\\fs12}or it’s kind of hard to see that it’s outlined.\r\nDialogue: 0,0:52:51.40,0:52:55.29,yin,,0,0,0,, 我也许可以回到这里再设置一下 比如说 \\N{\\fs12}I might want to go back to here and set this, for example –\r\nDialogue: 0,0:52:55.29,0:52:58.71,yin,,0,0,0,, 这个添加轮廓按钮 不再是系统字体了 \\N{\\fs12}this outline button — instead of being just the system font,\r\nDialogue: 0,0:52:58.96,0:53:01.88,yin,,0,0,0,, 也许我想让它变成加粗的系统字体 \\N{\\fs12}maybe I want this to be bold system font, which — oops –\r\nDialogue: 0,0:53:01.98,0:53:03.93,yin,,0,0,0,, 这样看起来轮廓效果更好 \\N{\\fs12}which will make it outline a little better.\r\nDialogue: 0,0:53:03.93,0:53:06.71,yin,,0,0,0,, 所以我们转到这里 检查它 \\N{\\fs12}So let’s go to here, inspect it,\r\nDialogue: 0,0:53:07.19,0:53:09.54,yin,,0,0,0,, 字体这一栏不再选择系统字体了 \\N{\\fs12}and in the font here instead of using the system font,\r\nDialogue: 0,0:53:09.80,0:53:12.64,yin,,0,0,0,, 我要选择加粗系统字体 \\N{\\fs12}I’m going to use the bold system font.\r\nDialogue: 0,0:53:13.89,0:53:15.07,yin,,0,0,0,, 现在再运行 \\N{\\fs12}And now when I ran,\r\nDialogue: 0,0:53:18.75,0:53:20.82,yin,,0,0,0,, 它会看起来更粗一点 \\N{\\fs12}it will look a little bolder.\r\nDialogue: 0,0:53:20.83,0:53:21.69,yin,,0,0,0,, 这样好点了 \\N{\\fs12}So it’s a little better,\r\nDialogue: 0,0:53:21.69,0:53:23.29,yin,,0,0,0,, 更容易看清轮廓 \\N{\\fs12}a little easier to see the outline.\r\nDialogue: 0,0:53:23.69,0:53:24.86,yin,,0,0,0,, 它依旧是一个按钮 \\N{\\fs12}Okay? And it’s still a button.\r\nDialogue: 0,0:53:25.09,0:53:27.19,yin,,0,0,0,, 如果我点击它 它还是会为文本添加轮廓 \\N{\\fs12}If I click it, it still outlines the text.\r\nDialogue: 0,0:53:28.05,0:53:30.42,yin,,0,0,0,, 好的 \\N{\\fs12}Okay? All right.\r\nDialogue: 0,0:53:30.42,0:53:31.94,yin,,0,0,0,, 这里我想展示的内容就是这些 \\N{\\fs12}That’s all I wanted to show you there.\r\nDialogue: 0,0:53:32.23,0:53:35.76,yin,,0,0,0,, 我要再演示一个视图控制器生命周期的内容 \\N{\\fs12}I’m going to show you another view controller lifecycle thing.\r\nDialogue: 0,0:53:36.13,0:53:38.21,yin,,0,0,0,, 但我们先来再讲几张幻灯片 \\N{\\fs12}But first, let’s do a couple of slides.\r\nDialogue: 0,0:53:38.21,0:53:40.00,yin,,0,0,0,, 我想给大家介绍另外一个东西 \\N{\\fs12}I want to show you one other thing,\r\nDialogue: 0,0:53:40.00,0:53:41.35,yin,,0,0,0,, 我说过我会讲到的 \\N{\\fs12}which I promised I would show,\r\nDialogue: 0,0:53:41.58,0:53:44.67,yin,,0,0,0,, 也就是广播站机制 \\N{\\fs12}which is this radio station thing.\r\nDialogue: 0,0:53:45.07,0:53:48.41,yin,,0,0,0,, 对象间的通信 \\N{\\fs12}So the way of communicating between objects\r\nDialogue: 0,0:53:48.55,0:53:50.38,yin,,0,0,0,, 以一种盲目结构进行 \\N{\\fs12}in a blind structured way,\r\nDialogue: 0,0:53:50.62,0:53:54.44,yin,,0,0,0,, 也就是 MVC 的广播站机制 \\N{\\fs12}which we refer to as this radio station thing from MVC\r\nDialogue: 0,0:53:54.62,0:53:57.22,yin,,0,0,0,, 在 iOS7 中叫做通知 \\N{\\fs12}is called “Notifications” in iOS 7.\r\nDialogue: 0,0:53:57.74,0:54:00.49,yin,,0,0,0,, 今天我们只会介绍 \\N{\\fs12}And we’re only going to talk today\r\nDialogue: 0,0:54:00.50,0:54:02.50,yin,,0,0,0,, 如何收听广播 \\N{\\fs12}about how to tune into the radio station;\r\nDialogue: 0,0:54:02.52,0:54:05.21,yin,,0,0,0,, 不会介绍如何进行广播 \\N{\\fs12}we’re not going to talk about how to broadcast on the radio station.\r\nDialogue: 0,0:54:05.59,0:54:06.90,yin,,0,0,0,, 而且今天 \\N{\\fs12}And in specific today,\r\nDialogue: 0,0:54:06.92,0:54:09.44,yin,,0,0,0,, 我们只会介绍收听系统广播 \\N{\\fs12}we’re only going to tune into a system radio station,\r\nDialogue: 0,0:54:09.48,0:54:10.97,yin,,0,0,0,, 一种 iOS7 的广播 \\N{\\fs12}an iOS 7 radio station.\r\nDialogue: 0,0:54:11.90,0:54:14.04,yin,,0,0,0,, 在后面的课程中 当我们讲到 \\N{\\fs12}Later in the course when we start talking about\r\nDialogue: 0,0:54:14.21,0:54:16.94,yin,,0,0,0,, 使用数据库构建更复杂模型的时候 \\N{\\fs12}building more sophisticated models using databases,\r\nDialogue: 0,0:54:17.09,0:54:19.10,yin,,0,0,0,, 我们才会介绍如何使用广播站机制 \\N{\\fs12}then we’ll really start using the radio stations\r\nDialogue: 0,0:54:19.10,0:54:20.68,yin,,0,0,0,, 来监听模型的变化 \\N{\\fs12}to hear about changes in the model. Okay?\r\nDialogue: 0,0:54:21.25,0:54:23.47,yin,,0,0,0,, 但是今天我们只要监听系统的变化 \\N{\\fs12}But today we’re just going to hear about change in the system\r\nDialogue: 0,0:54:23.48,0:54:24.64,yin,,0,0,0,, 因为我只是希望大家能有一个印象 \\N{\\fs12}because I just want you to get an idea\r\nDialogue: 0,0:54:24.65,0:54:26.72,yin,,0,0,0,, 知道接收端的广播站机制是怎样的 \\N{\\fs12}of what that radio station looks like on the receiving end.\r\nDialogue: 0,0:54:26.89,0:54:28.15,yin,,0,0,0,, 真的非常简单 \\N{\\fs12}And it’s really, really easy.\r\nDialogue: 0,0:54:28.43,0:54:30.83,yin,,0,0,0,, 有一个类叫做 NSNotificationCenter\\N{\\fs12}There is a class called NSNotificationCenter.\r\nDialogue: 0,0:54:31.16,0:54:33.46,yin,,0,0,0,, 这个类有一个方法叫做 defaultCenter\\N{\\fs12}It has a class method called defaultCenter.\r\nDialogue: 0,0:54:33.67,0:54:37.01,yin,,0,0,0,, 返回一个类似于 NSUserDefault 的共享实例 \\N{\\fs12}That returns a shared instance kind of like NSUserDefault,\r\nDialogue: 0,0:54:37.01,0:54:39.57,yin,,0,0,0,, 类似于标准的 UserDefault\\N{\\fs12}standard UserDefault did — a shared instance\r\nDialogue: 0,0:54:39.88,0:54:42.93,yin,,0,0,0,, 你就用这个对象来收听广播 \\N{\\fs12}That’s the object you use to tune into radio stations.\r\nDialogue: 0,0:54:43.36,0:54:45.93,yin,,0,0,0,, 方法是向它发送这个消息 \\N{\\fs12}And you do it by sending it this message:\r\nDialogue: 0,0:54:45.93,0:54:47.97,yin,,0,0,0,,addObserver selector name object\\N{\\fs12}addObserver selector name object.\r\nDialogue: 0,0:54:48.96,0:54:51.64,yin,,0,0,0,, 第一个参数 observer 代表 \\N{\\fs12}The first argument observer, that is,\r\nDialogue: 0,0:54:51.74,0:54:53.93,yin,,0,0,0,, 想要收听广播的对象 \\N{\\fs12}the object that wants to listen to the radio station.\r\nDialogue: 0,0:54:54.32,0:54:56.12,yin,,0,0,0,, 所以在你的控制器中 \\N{\\fs12}So in your controller –\r\nDialogue: 0,0:54:56.13,0:54:58.51,yin,,0,0,0,, 因为控制器是最常见的广播收听者 \\N{\\fs12}because controllers are the most common radio station listeners –\r\nDialogue: 0,0:54:58.56,0:54:59.78,yin,,0,0,0,, 这个参数可能就是 self\\N{\\fs12}this would probably just be self.\r\nDialogue: 0,0:55:00.18,0:55:01.39,yin,,0,0,0,,addObserver: self\\N{\\fs12}addObserver: self\r\nDialogue: 0,0:55:01.78,0:55:03.21,yin,,0,0,0,, 这是你的控制器代码中的内容 \\N{\\fs12}This is somewhere in your controller code.\r\nDialogue: 0,0:55:03.71,0:55:08.83,yin,,0,0,0,,selector 是 observer 中的方法 \\N{\\fs12}Selector is the method inside of the observer\r\nDialogue: 0,0:55:08.99,0:55:12.96,yin,,0,0,0,, 当广播上出现内容时会调用它 \\N{\\fs12}that you want to be called when something appears on the radio station.\r\nDialogue: 0,0:55:13.38,0:55:14.52,yin,,0,0,0,, 当进行广播时 \\N{\\fs12}Some broadcast happens.\r\nDialogue: 0,0:55:15.13,0:55:18.09,yin,,0,0,0,,name 是广播站的名称 \\N{\\fs12}Okay? Name is the name of the radio station.\r\nDialogue: 0,0:55:18.89,0:55:20.69,yin,,0,0,0,, 你想要收听哪个广播站 \\N{\\fs12}Okay? Which radio station you want to listen to.\r\nDialogue: 0,0:55:21.07,0:55:23.33,yin,,0,0,0,, 而这里的 sender object: sender\\N{\\fs12}And sender there — object sender –\r\nDialogue: 0,0:55:23.52,0:55:26.42,yin,,0,0,0,, 代表你是否只想收听某个特定对象 \\N{\\fs12}that’s if you only want to listen to radio station broadcasts\r\nDialogue: 0,0:55:26.43,0:55:28.45,yin,,0,0,0,, 发出的广播 \\N{\\fs12}that come from a certain other object.\r\nDialogue: 0,0:55:28.98,0:55:30.22,yin,,0,0,0,, 通常这里都会写 nil\\N{\\fs12}Often you pass nil here,\r\nDialogue: 0,0:55:30.24,0:55:33.68,yin,,0,0,0,, 表示频率上任何广播 \\N{\\fs12}which means if anyone broadcasts on that frequency,\r\nDialogue: 0,0:55:33.70,0:55:34.40,yin,,0,0,0,, 我都想收听 \\N{\\fs12}I want to hear it.\r\nDialogue: 0,0:55:35.08,0:55:37.41,yin,,0,0,0,, 但可能会在某种特定情况下 \\N{\\fs12}Okay? But it is possible in certain cases to say,\r\nDialogue: 0,0:55:37.41,0:55:38.88,yin,,0,0,0,, 我只对某个对象 \\N{\\fs12}”I’m only interested in changes\r\nDialogue: 0,0:55:38.89,0:55:40.93,yin,,0,0,0,, 发出的广播内容变化感兴趣 \\N{\\fs12}in the radio station generated by this object.”\r\nDialogue: 0,0:55:40.93,0:55:43.46,yin,,0,0,0,, 这种情况下 这里就要加上 sender\\N{\\fs12}So that’s the sender there that you would put.\r\nDialogue: 0,0:55:44.05,0:55:46.63,yin,,0,0,0,, 这里将要被调用的方法 \\N{\\fs12}Okay? The method that’s going to get invoked here –\r\nDialogue: 0,0:55:46.63,0:55:48.15,yin,,0,0,0,, 如果出现广播时将要调用的方法 \\N{\\fs12}method to invoke if something happens –\r\nDialogue: 0,0:55:48.73,0:55:52.67,yin,,0,0,0,, 总有一个参数 是一个 NSNotification\\N{\\fs12}always has one argument, which is an NSNotification.\r\nDialogue: 0,0:55:53.15,0:55:55.80,yin,,0,0,0,,NSNotification 有三个属性 \\N{\\fs12}Inside an NSNotification there are three properties:\r\nDialogue: 0,0:55:56.07,0:55:59.03,yin,,0,0,0,, 一是 name 广播站的名称 \\N{\\fs12}One is name, that’s the name of the radio station –\r\nDialogue: 0,0:55:59.03,0:56:00.44,yin,,0,0,0,, 和上面传递的参数是一样的 \\N{\\fs12}same thing that was passed above;\r\nDialogue: 0,0:56:00.86,0:56:06.21,yin,,0,0,0,,object 就是向你发送这个通知的对象 \\N{\\fs12}object, okay, that’s the object sending you this notification,\r\nDialogue: 0,0:56:06.21,0:56:08.32,yin,,0,0,0,, 就是上面的 sender\\N{\\fs12}so that would be the sender anything above;\r\nDialogue: 0,0:56:08.69,0:56:11.20,yin,,0,0,0,, 然后是 userInfo 是一个 ID\\N{\\fs12}and then userInfo, which is an ID.\r\nDialogue: 0,0:56:11.55,0:56:15.18,yin,,0,0,0,, 想要知道它是什么 你需要知道 \\N{\\fs12}And to know what that is, you have to know\r\nDialogue: 0,0:56:15.26,0:56:17.76,yin,,0,0,0,, 进行广播的那个人 \\N{\\fs12}what the person who broadcasts on the radio station\r\nDialogue: 0,0:56:17.98,0:56:19.37,yin,,0,0,0,, 会提供什么 \\N{\\fs12}says they will provide there.\r\nDialogue: 0,0:56:20.15,0:56:20.80,yin,,0,0,0,, 明白了吗 \\N{\\fs12}Does that make sense?\r\nDialogue: 0,0:56:21.18,0:56:24.10,yin,,0,0,0,, 所以这个 userInfo 是取决于广播站的 \\N{\\fs12}So that userInfo is radio station-dependent.\r\nDialogue: 0,0:56:24.73,0:56:26.97,yin,,0,0,0,, 但是如果你知道广播站的名称 \\N{\\fs12}But if you know the name of the radio station,\r\nDialogue: 0,0:56:26.97,0:56:29.64,yin,,0,0,0,, 你也许就可以去文档中查找 \\N{\\fs12}you probably are looking in the documentation to find it,\r\nDialogue: 0,0:56:29.64,0:56:30.52,yin,,0,0,0,, 文档也许会告诉你 \\N{\\fs12}it probably says there,\r\nDialogue: 0,0:56:30.53,0:56:33.23,yin,,0,0,0,, 你要得到的用户信息是 X Y 或者 Z\\N{\\fs12}”Oh, and the user info you’ll get is X, Y, or Z.”\r\nDialogue: 0,0:56:33.62,0:56:34.45,yin,,0,0,0,, 但它是一个 ID\\N{\\fs12}But it’s an ID.\r\nDialogue: 0,0:56:34.45,0:56:35.46,yin,,0,0,0,, 所以你要知道它是什么 \\N{\\fs12}So you have to know what it is.\r\nDialogue: 0,0:56:35.46,0:56:37.52,yin,,0,0,0,, 你也许需要对它执行 isKindOfClass\\N{\\fs12}You’re probably going to do is kind of class on it,\r\nDialogue: 0,0:56:37.52,0:56:42.65,yin,,0,0,0,, 或者 respondsToSelector 等来使用它 \\N{\\fs12}or response to selector, or something like that to use it.\r\nDialogue: 0,0:56:42.78,0:56:43.97,yin,,0,0,0,, 很多情况下它都是 nil\\N{\\fs12}A lot of times that’s nil\r\nDialogue: 0,0:56:43.97,0:56:45.49,yin,,0,0,0,, 因为我们真正关注的是 \\N{\\fs12}because all we’re really interested in\r\nDialogue: 0,0:56:45.49,0:56:47.28,yin,,0,0,0,, 是否有广播 \\N{\\fs12}is whether there was a broadcast,\r\nDialogue: 0,0:56:47.52,0:56:50.10,yin,,0,0,0,, 而不是是否广播了某个特定信息 \\N{\\fs12}not any particular information that was broadcast.\r\nDialogue: 0,0:56:50.41,0:56:50.71,yin,,0,0,0,, 有问题吗 \\N{\\fs12}Question?\r\nDialogue: 0,0:56:51.55,0:56:54.36,yin,,0,0,0,,sender 是应用中全局变量 \\N{\\fs12}About sender is that global over just your app,\r\nDialogue: 0,0:56:54.37,0:56:55.75,yin,,0,0,0,, 还是整个系统中的全局变量 \\N{\\fs12}or global over the whole system?\r\nDialogue: 0,0:56:55.95,0:56:56.79,yin,,0,0,0,, 这些东西 \\N{\\fs12}All this stuff –\r\nDialogue: 0,0:56:56.81,0:57:00.68,yin,,0,0,0,, 问题是 sender 是整个系统的全局变量 \\N{\\fs12}the question is: Is the sender there global to the whole system\r\nDialogue: 0,0:57:00.68,0:57:01.75,yin,,0,0,0,, 还是只是应用中的呢 \\N{\\fs12}or just inside your app?\r\nDialogue: 0,0:57:02.20,0:57:04.14,yin,,0,0,0,, 通常情况下 所有关于通知的内容 \\N{\\fs12}Always everything about notifications\r\nDialogue: 0,0:57:04.16,0:57:05.61,yin,,0,0,0,, 都是应用内的 \\N{\\fs12}inside your app, okay?\r\nDialogue: 0,0:57:05.88,0:57:08.93,yin,,0,0,0,, 因为堆中对象的空间 \\N{\\fs12}Because the space of objects in the heap\r\nDialogue: 0,0:57:08.95,0:57:10.22,yin,,0,0,0,, 是在应用内的 \\N{\\fs12}is only inside your app.\r\nDialogue: 0,0:57:10.41,0:57:11.91,yin,,0,0,0,, 你不能查看其他应用的数据 \\N{\\fs12}You can’t see in other apps.\r\nDialogue: 0,0:57:12.01,0:57:14.47,yin,,0,0,0,, 出于安全考虑 \\N{\\fs12}You know, they have their own segregated\r\nDialogue: 0,0:57:14.47,0:57:16.37,yin,,0,0,0,, 各个应用都被分隔在单独的空间 \\N{\\fs12}for security reasons space.\r\nDialogue: 0,0:57:16.45,0:57:19.48,yin,,0,0,0,, 所以如果你在这里得到一条系统消息 \\N{\\fs12}So if you’re getting a message here from the system,\r\nDialogue: 0,0:57:19.54,0:57:21.21,yin,,0,0,0,, 这里就要是 nil 对吧 \\N{\\fs12}this is going to be nil, okay?\r\nDialogue: 0,0:57:21.21,0:57:21.96,yin,,0,0,0,,sender 会是 nil\\N{\\fs12}The sender’s going to be nil.\r\nDialogue: 0,0:57:22.46,0:57:23.79,yin,,0,0,0,, 什么问题 一样的问题吗 \\N{\\fs12}Question? That was your question?\r\nDialogue: 0,0:57:24.53,0:57:24.91,yin,,0,0,0,, 好的 \\N{\\fs12}All right.\r\nDialogue: 0,0:57:25.67,0:57:28.10,yin,,0,0,0,, 另外一点需要理解的是 \\N{\\fs12}So another thing to understand is\r\nDialogue: 0,0:57:28.15,0:57:30.77,yin,,0,0,0,, 当你结束收听 关掉广播 \\N{\\fs12}when you’re done listening, tune out.\r\nDialogue: 0,0:57:30.87,0:57:32.13,yin,,0,0,0,, 将广播关掉 \\N{\\fs12}Turn your radio off. Okay?\r\nDialogue: 0,0:57:32.41,0:57:34.56,yin,,0,0,0,, 方法是 向通知中心发送一条消息 \\N{\\fs12}And you do that by sending a message\r\nDialogue: 0,0:57:34.56,0:57:37.21,yin,,0,0,0,, 告诉它 removeObserver\\N{\\fs12}to the notification center saying “removeObserver.”\r\nDialogue: 0,0:57:37.21,0:57:39.10,yin,,0,0,0,, 你可以将自己作为观察者 \\N{\\fs12}And you can remove yourself as an observer\r\nDialogue: 0,0:57:39.10,0:57:40.92,yin,,0,0,0,, 从全部广播站中移除 就是上面这行代码 \\N{\\fs12}of all radio stations with the first one\r\nDialogue: 0,0:57:41.08,0:57:44.12,yin,,0,0,0,, 或者将自己从某个广播站的收听列表中移除 \\N{\\fs12}or you can just remove yourself from listening to certain radio stations,\r\nDialogue: 0,0:57:44.42,0:57:46.55,yin,,0,0,0,, 通过指定广播站的名称 \\N{\\fs12}okay, by specifying the name of the radio station\r\nDialogue: 0,0:57:46.56,0:57:48.74,yin,,0,0,0,, 和你不想再收听的 sender 来实现 \\N{\\fs12}and who the sender is you don’t want to listen to anymore.\r\nDialogue: 0,0:57:49.74,0:57:53.73,yin,,0,0,0,, 做这步很重要 \\N{\\fs12}Okay? It’s important to do this because,\r\nDialogue: 0,0:57:54.16,0:57:58.80,yin,,0,0,0,, 因为不幸的是 通知中心始终用一个指针指向你 \\N{\\fs12}unfortunately, the notification center keeps a pointer to you\r\nDialogue: 0,0:57:59.11,0:58:01.20,yin,,0,0,0,, 叫做 Unsafe retained 不安全保留 \\N{\\fs12}that is called “Unsafe retained.”\r\nDialogue: 0,0:58:01.54,0:58:04.51,yin,,0,0,0,, 指针类型不是强或弱 而是不安全保留类型 \\N{\\fs12}So it’s not strong or weak; it’s unsafe retained.\r\nDialogue: 0,0:58:04.94,0:58:07.44,yin,,0,0,0,, 不安全保留类型指的是 \\N{\\fs12}And what unsafe retained means is that\r\nDialogue: 0,0:58:07.45,0:58:10.28,yin,,0,0,0,, 如果没有调用它就离开了堆 \\N{\\fs12}if you go out of the heap without calling this first,\r\nDialogue: 0,0:58:10.42,0:58:13.18,yin,,0,0,0,, 通知中心可能会试着给你发送一个通知 \\N{\\fs12}the notification center might try and send you a notification\r\nDialogue: 0,0:58:13.19,0:58:13.95,yin,,0,0,0,, 然后应用就崩溃了 \\N{\\fs12}and crash your app.\r\nDialogue: 0,0:58:14.60,0:58:15.82,yin,,0,0,0,, 这就是为什么它是不安全的 \\N{\\fs12}That’s why it’s unsafe.\r\nDialogue: 0,0:58:16.30,0:58:18.75,yin,,0,0,0,, 这里为什么要用这些不安全保留指针呢 \\N{\\fs12}Now, why are these unsafe retained here?\r\nDialogue: 0,0:58:18.98,0:58:21.19,yin,,0,0,0,, 显然是为了向后兼容 \\N{\\fs12}Clearly for backwards compatibility.\r\nDialogue: 0,0:58:21.20,0:58:22.56,yin,,0,0,0,, 这里实际上应该是弱类型 \\N{\\fs12}This really should be weak.\r\nDialogue: 0,0:58:23.03,0:58:25.83,yin,,0,0,0,, 如果这是一个指向你的弱指针就太好了 \\N{\\fs12}Okay? It would be awesome for this to be a weak pointer to you\r\nDialogue: 0,0:58:25.83,0:58:27.17,yin,,0,0,0,, 因为这时如果你离开堆 \\N{\\fs12}because then if you went out of the heap,\r\nDialogue: 0,0:58:27.39,0:58:29.45,yin,,0,0,0,, 通知中心中会设为 nil\\N{\\fs12}it would be set to nil inside the notification center;\r\nDialogue: 0,0:58:29.46,0:58:31.04,yin,,0,0,0,, 绝不会再向你发送任何消息了 \\N{\\fs12}it would never try and send you any messages.\r\nDialogue: 0,0:58:32.39,0:58:37.50,yin,,0,0,0,, 将指针自动设为 nil 的这种弱指针机制 \\N{\\fs12}But, you know, the whole weak mechanism of setting things to nil automatically,\r\nDialogue: 0,0:58:37.51,0:58:39.96,yin,,0,0,0,, 是 iOS6 和 iOS7 中特有的 \\N{\\fs12}that’s an iOS 6, iOS 7 only thing.\r\nDialogue: 0,0:58:40.15,0:58:41.94,yin,,0,0,0,, 如果你的应用是运行于 iOS5 的 \\N{\\fs12}So if you had an app that was running on iOS 5,\r\nDialogue: 0,0:58:41.95,0:58:42.81,yin,,0,0,0,, 就不会起作用了 \\N{\\fs12}that wouldn’t work.\r\nDialogue: 0,0:58:42.81,0:58:45.47,yin,,0,0,0,, 如果这个应用依赖于这个机制 就会变得很糟糕 \\N{\\fs12}And if this depended on that, it would be bad.\r\nDialogue: 0,0:58:46.15,0:58:48.67,yin,,0,0,0,, 我相信最终他们也许会将它们设为弱类型 \\N{\\fs12}I’m sure eventually they would probably move these things to weak\r\nDialogue: 0,0:58:48.68,0:58:52.53,yin,,0,0,0,, 直接告诉用户 如果你使用这个 API 性能会降低 \\N{\\fs12}and just say, “If you use this API, it’s depreciated;\r\nDialogue: 0,0:58:52.54,0:58:53.86,yin,,0,0,0,, 不能在 iOS5 上运行 \\N{\\fs12}you can’t run in iOS 5.”\r\nDialogue: 0,0:58:53.86,0:58:55.97,yin,,0,0,0,, 没准他们会在 iOS8 或者 iOS9 中这样做 \\N{\\fs12}I don’t know, maybe they’ll do that in iOS 8 or 9.\r\nDialogue: 0,0:58:55.99,0:58:56.44,yin,,0,0,0,, 我也不知道 \\N{\\fs12}I don’t know.\r\nDialogue: 0,0:58:56.85,0:58:57.81,yin,,0,0,0,, 但是这里要注意 \\N{\\fs12}But be careful there.\r\nDialogue: 0,0:58:57.82,0:58:58.58,yin,,0,0,0,, 它是不安全保留类型 \\N{\\fs12}It’s unsafe retained.\r\nDialogue: 0,0:58:58.58,0:59:00.42,yin,,0,0,0,, 这是你们在这门课程中 \\N{\\fs12}It’s the only unsafe retained really\r\nDialogue: 0,0:59:00.43,0:59:02.48,yin,,0,0,0,, 需要注意的唯一一不安全保留类型 \\N{\\fs12}you’re probably going to have to worry about in this course.\r\nDialogue: 0,0:59:02.48,0:59:04.24,yin,,0,0,0,, 总之 结束收听广播后 \\N{\\fs12}But the bottom line is: Remove yourself\r\nDialogue: 0,0:59:04.24,0:59:05.16,yin,,0,0,0,, 要移除自己 \\N{\\fs12}when you’re done listening.\r\nDialogue: 0,0:59:05.83,0:59:08.32,yin,,0,0,0,, 通常情况下 在你的 MVC 离开屏幕后 \\N{\\fs12}Now, normally you’re going to remove yourself\r\nDialogue: 0,0:59:08.50,0:59:11.37,yin,,0,0,0,, 就要移除自己 \\N{\\fs12}when your MVC goes off screen, okay?\r\nDialogue: 0,0:59:11.65,0:59:15.23,yin,,0,0,0,, 通常只有在 MVC 处于激活状态出现在屏幕上的时候 \\N{\\fs12}Because you’re usually only interested in radio station happenings\r\nDialogue: 0,0:59:15.48,0:59:17.77,yin,,0,0,0,, 你才会关注广播消息 \\N{\\fs12}when your MVC is active and on screen.\r\nDialogue: 0,0:59:18.30,0:59:20.87,yin,,0,0,0,, 如果出于某些原因 这个没法实现 \\N{\\fs12}But if for some reason that doesn’t make sense,\r\nDialogue: 0,0:59:21.06,0:59:23.92,yin,,0,0,0,, 有个方法叫做 dealloc\\N{\\fs12}there is a method called “dealloc.”\r\nDialogue: 0,0:59:24.79,0:59:27.07,yin,,0,0,0,, 所有对象都有这个方法 \\N{\\fs12}Every object has this.\r\nDialogue: 0,0:59:27.71,0:59:31.03,yin,,0,0,0,, 会在你的对象将要离开堆前被调用 \\N{\\fs12}It gets called just before your object leaves to the heap.\r\nDialogue: 0,0:59:31.87,0:59:34.30,yin,,0,0,0,, 所有属性都为 nil\\N{\\fs12}Okay? All your properties are nil.\r\nDialogue: 0,0:59:34.55,0:59:37.85,yin,,0,0,0,, 几乎已经不再是一个对象的时候 调用这个方法 \\N{\\fs12}You are barely existing as an object and this gets called.\r\nDialogue: 0,0:59:38.31,0:59:39.72,yin,,0,0,0,, 是最后的关联 \\N{\\fs12}Okay? It’s that last hook.\r\nDialogue: 0,0:59:40.18,0:59:43.57,yin,,0,0,0,, 所以也可以在这里解决不安全保留指针的问题 \\N{\\fs12}And so you can fix unsafe retained pointers to you there.\r\nDialogue: 0,0:59:44.22,0:59:46.56,yin,,0,0,0,, 我不建议使用 dealloc\\N{\\fs12}Okay? I don’t recommend using dealloc.\r\nDialogue: 0,0:59:46.76,0:59:50.39,yin,,0,0,0,, 可以肯定的是 在这门课中 不要为了其他原因使用它 \\N{\\fs12}Don’t use it for anything else, that’s for sure in this class.\r\nDialogue: 0,0:59:50.59,0:59:52.63,yin,,0,0,0,, 我建议使用移除 更合理 \\N{\\fs12}I suggest removing, it would make sense.\r\nDialogue: 0,0:59:52.63,0:59:53.13,yin,,0,0,0,, 有问题吗 \\N{\\fs12}Question?\r\nDialogue: 0,0:59:53.40,0:59:55.02,yin,,0,0,0,, 如果你将自己从观察者中移除 \\N{\\fs12}How do you remove yourself as an observer\r\nDialogue: 0,0:59:55.02,0:59:56.85,yin,,0,0,0,, 但你却不是一个观察者呢 \\N{\\fs12}and you’re not an observer on anything?\r\nDialogue: 0,0:59:57.20,0:59:57.72,yin,,0,0,0,, 好问题 \\N{\\fs12}Great question.\r\nDialogue: 0,0:59:57.72,0:59:59.47,yin,,0,0,0,, 问题是 如果我调用了 removeObserver\\N{\\fs12}So the question is: What if I call removeObserver\r\nDialogue: 0,0:59:59.48,1:00:00.81,yin,,0,0,0,, 但我却没有观察任何对象会怎样 \\N{\\fs12}and I’m not observing anything?\r\nDialogue: 0,1:00:01.09,1:00:01.58,yin,,0,0,0,, 没问题 \\N{\\fs12}No problem.\r\nDialogue: 0,1:00:01.80,1:00:03.05,yin,,0,0,0,, 不会发生不好的事情 \\N{\\fs12}Nothing bad will happen.\r\nDialogue: 0,1:00:03.14,1:00:04.31,yin,,0,0,0,, 那么你可以直接放到 dealloc 中 \\N{\\fs12}So you could just throw that in dealloc.\r\nDialogue: 0,1:00:04.32,1:00:04.87,yin,,0,0,0,, 可以的 \\N{\\fs12}You could.\r\nDialogue: 0,1:00:04.87,1:00:05.20,yin,,0,0,0,, 你可以这样做 \\N{\\fs12}You could.\r\nDialogue: 0,1:00:05.20,1:00:06.72,yin,,0,0,0,, 并不是很好的编程方法 \\N{\\fs12}It wouldn’t be very nice programming.\r\nDialogue: 0,1:00:06.74,1:00:07.94,yin,,0,0,0,, 不是很好看 \\N{\\fs12}It’s kind of not very pretty,\r\nDialogue: 0,1:00:07.95,1:00:11.63,yin,,0,0,0,, 但是为了安全 你可以直接放到 dealloc 中 \\N{\\fs12}but you could just throw that in your dealloc to be safe.\r\nDialogue: 0,1:00:12.03,1:00:15.40,yin,,0,0,0,, 但是更好的方法你们知道的 \\N{\\fs12}But better to, you know — okay.\r\nDialogue: 0,1:00:15.66,1:00:16.57,yin,,0,0,0,, 接下来是一个示例 \\N{\\fs12}So here’s an example.\r\nDialogue: 0,1:00:16.58,1:00:18.55,yin,,0,0,0,, 这个示例我会快速演示一下 \\N{\\fs12}This is an example I’m going to demo real quick here,\r\nDialogue: 0,1:00:18.70,1:00:20.05,yin,,0,0,0,, 是关于文本大小的 \\N{\\fs12}which is text size.\r\nDialogue: 0,1:00:20.05,1:00:23.79,yin,,0,0,0,, 在 iOS7 之前的版本中都没有这个功能 \\N{\\fs12}So in iOS 7 — not in any iOS before that, but in iOS 7 –\r\nDialogue: 0,1:00:23.94,1:00:26.96,yin,,0,0,0,, 但在 iOS7 中 如果你使用了推荐字体 \\N{\\fs12}if you use preferred fonts, then the user can actually\r\nDialogue: 0,1:00:26.96,1:00:29.29,yin,,0,0,0,, 用户可以进入设置界面改变字体大小 \\N{\\fs12}go into settings and change the size of their font.\r\nDialogue: 0,1:00:29.53,1:00:30.84,yin,,0,0,0,, 如果他们像我一样 \\N{\\fs12}So if they’re like me\r\nDialogue: 0,1:00:31.03,1:00:34.89,yin,,0,0,0,, 随着年龄的增长 手机要拿得更远一些才能看清 \\N{\\fs12}and the phone has to be held farther and farther away as the years go by,\r\nDialogue: 0,1:00:35.09,1:00:36.49,yin,,0,0,0,, 你就可以将字号调大 \\N{\\fs12}you can set the text size up\r\nDialogue: 0,1:00:36.49,1:00:38.15,yin,,0,0,0,, 然后把手机拿近一点 \\N{\\fs12}and move that phone back in a little bit.\r\nDialogue: 0,1:00:38.15,1:00:40.92,yin,,0,0,0,, 文本大小就可以实现这样的功能 \\N{\\fs12}So that’s what this text size thing allows you to do.\r\nDialogue: 0,1:00:40.92,1:00:43.89,yin,,0,0,0,, 如果文本大小发生了变化 \\N{\\fs12}Well, if that text size font change happens,\r\nDialogue: 0,1:00:44.10,1:00:47.42,yin,,0,0,0,, 你需要收到通知 然后改变字体 \\N{\\fs12}you have to get notified so that you can change the fonts,\r\nDialogue: 0,1:00:47.42,1:00:51.71,yin,,0,0,0,, 变为用户设置的新的推荐字体 对吧 \\N{\\fs12}use the new preferred font that the user set, okay?\r\nDialogue: 0,1:00:52.00,1:00:53.91,yin,,0,0,0,, 获取这个通知的方法是 \\N{\\fs12}So you get that notification\r\nDialogue: 0,1:00:54.05,1:00:56.77,yin,,0,0,0,, 在广播站通知中心登记 \\N{\\fs12}by signing up in the default center for the radio station\r\nDialogue: 0,1:00:56.78,1:01:00.69,yin,,0,0,0,, 使用 UIContentSizeCategoryDidChangeNotification\\N{\\fs12}called UIContentSizeCategoryDidChangeNotification.\r\nDialogue: 0,1:01:01.10,1:01:03.57,yin,,0,0,0,, 你可以认为它可以是 \\N{\\fs12}Okay? You could argue it could be something\r\nDialogue: 0,1:01:03.57,1:01:04.90,yin,,0,0,0,, 推荐字体改变之类的东西 \\N{\\fs12}like preferred fonts change.\r\nDialogue: 0,1:01:04.90,1:01:05.61,yin,,0,0,0,, 但它不是 \\N{\\fs12}But it’s not.\r\nDialogue: 0,1:01:05.61,1:01:08.44,yin,,0,0,0,, 而是 UIContentSizeCategoryDidChangeNotification\\N{\\fs12}UIContentSizeCategoryDidChangeNotification, okay?\r\nDialogue: 0,1:01:08.80,1:01:09.78,yin,,0,0,0,, 登记进去之后 \\N{\\fs12}You sign up for that,\r\nDialogue: 0,1:01:09.78,1:01:13.39,yin,,0,0,0,, 无论何时这些字体改变了大小 你的方法 \\N{\\fs12}and whenever those fonts change size, your method –\r\nDialogue: 0,1:01:13.47,1:01:15.72,yin,,0,0,0,, 我这里叫做 preferredFontSizeChange\\N{\\fs12}”preferredFontSizeChange” is what I called mine –\r\nDialogue: 0,1:01:15.97,1:01:18.29,yin,,0,0,0,, 会被调用 \\N{\\fs12}will get called. Okay?\r\nDialogue: 0,1:01:18.99,1:01:23.57,yin,,0,0,0,, 我们来看一下如何将其添加到 Attributor 中 \\N{\\fs12}So let’s take a look at how we would add that to Attributor\r\nDialogue: 0,1:01:23.58,1:01:25.29,yin,,0,0,0,, 因为 Attributor 使用了推荐字体 \\N{\\fs12}because Attributor uses preferred fonts.\r\nDialogue: 0,1:01:25.43,1:01:26.62,yin,,0,0,0,, 如果我们改变了字体大小 \\N{\\fs12}And if we change the font size,\r\nDialogue: 0,1:01:26.63,1:01:28.66,yin,,0,0,0,, 我们希望正文和标题 \\N{\\fs12}we want the body and the headline\r\nDialogue: 0,1:01:28.84,1:01:31.28,yin,,0,0,0,, 都变成更大或更小的字体 \\N{\\fs12}both to change to the bigger or smaller font.\r\nDialogue: 0,1:01:31.62,1:01:32.53,yin,,0,0,0,, 我们来做一下 \\N{\\fs12}So let’s do that.\r\nDialogue: 0,1:01:33.46,1:01:36.72,yin,,0,0,0,, 回到 Xcode\\N{\\fs12}I’m going to go back here to Xcode.\r\nDialogue: 0,1:01:37.01,1:01:37.80,yin,,0,0,0,, 好了 \\N{\\fs12}So here we are.\r\nDialogue: 0,1:01:37.81,1:01:39.82,yin,,0,0,0,, 想要实现这个功能 \\N{\\fs12}The other thing we’re going to need to make this work\r\nDialogue: 0,1:01:39.96,1:01:41.65,yin,,0,0,0,, 我们还需要视图控制器生命周期 \\N{\\fs12}is the view controller lifecycle.\r\nDialogue: 0,1:01:41.99,1:01:45.21,yin,,0,0,0,, 只有在我们是在屏幕上的 MVC 的情况下 \\N{\\fs12}Okay? Because we’re only interested in those font changes\r\nDialogue: 0,1:01:45.21,1:01:47.52,yin,,0,0,0,, 才会关注这些字体的变化 \\N{\\fs12}if we’re the MVC that’s on screen,\r\nDialogue: 0,1:01:47.65,1:01:48.66,yin,,0,0,0,, 我们一直都在 \\N{\\fs12}which we always are,\r\nDialogue: 0,1:01:48.66,1:01:51.21,yin,,0,0,0,, 当然是这样 因为我们只有这一个 MVC\\N{\\fs12}of course, because we only have this one MVC.\r\nDialogue: 0,1:01:51.22,1:01:52.67,yin,,0,0,0,, 但很快 我们会添加其他 MVC\\N{\\fs12}But soon we will have other MVCs\r\nDialogue: 0,1:01:52.68,1:01:53.89,yin,,0,0,0,, 就不会始终都在屏幕上了 \\N{\\fs12}and we won’t always be on screen.\r\nDialogue: 0,1:01:54.52,1:01:58.95,yin,,0,0,0,, 我们用视图控制器生命周期方法 viewWillAppear\\N{\\fs12}So let’s use the view controller lifecycle method viewWillAppear.\r\nDialogue: 0,1:01:59.70,1:02:01.63,yin,,0,0,0,, 当一个视图将要出现时 \\N{\\fs12}Okay? So when a view will appear –\r\nDialogue: 0,1:02:01.63,1:02:05.28,yin,,0,0,0,, 注意这里始终都要加上 super\\N{\\fs12}notice I’m always going to do super there.\r\nDialogue: 0,1:02:05.61,1:02:09.38,yin,,0,0,0,, 你可以在具体操作之前或之后调用 super\\N{\\fs12}You can call super before or after you do your work.\r\nDialogue: 0,1:02:09.79,1:02:11.65,yin,,0,0,0,, 取决于你想要什么 \\N{\\fs12}It kind of depends on what you want.\r\nDialogue: 0,1:02:11.65,1:02:13.05,yin,,0,0,0,, 你想让你的超类 \\N{\\fs12}Do you want your super class to get a chance\r\nDialogue: 0,1:02:13.05,1:02:15.48,yin,,0,0,0,, 在操作之前还是之后被调用 \\N{\\fs12}after you’ve done what you want to do or before?\r\nDialogue: 0,1:02:16.26,1:02:17.62,yin,,0,0,0,, 通常是无所谓的 \\N{\\fs12}Usually it doesn’t matter too much.\r\nDialogue: 0,1:02:17.70,1:02:19.03,yin,,0,0,0,, 我并不知道那个 UIViewController\\N{\\fs12}I don’t know that UIViewController\r\nDialogue: 0,1:02:19.05,1:02:20.85,yin,,0,0,0,, 是否真的在这些超类中执行了操作 \\N{\\fs12}actually does things in these supers,\r\nDialogue: 0,1:02:20.86,1:02:23.74,yin,,0,0,0,, 但是依旧要给它们机会 对吧 \\N{\\fs12}but you always want to give them the opportunity, okay?\r\nDialogue: 0,1:02:23.75,1:02:26.36,yin,,0,0,0,, 这只是视图控制器生命周期的一部分 \\N{\\fs12}It’s just part of the view controller lifecycle.\r\nDialogue: 0,1:02:26.63,1:02:28.69,yin,,0,0,0,, 当视图出现时 \\N{\\fs12}So when the view appears,\r\nDialogue: 0,1:02:28.70,1:02:31.05,yin,,0,0,0,, 我想在通知中心中登记 \\N{\\fs12}I just want to sign up with the notification center\r\nDialogue: 0,1:02:31.26,1:02:33.99,yin,,0,0,0,, 这样我才能接收到这些消息 \\N{\\fs12}so that I can receive these messages.\r\nDialogue: 0,1:02:33.99,1:02:35.41,yin,,0,0,0,, 所以这里我要写 \\N{\\fs12}So I’m going to say is\r\nDialogue: 0,1:02:35.95,1:02:43.74,yin,,0,0,0,,[NSNotificationCenter defaultCenter] addObserver: self\\N{\\fs12}[NSNotificationCenter defaultCenter] addObserver: self,\r\nDialogue: 0,1:02:44.09,1:02:44.55,yin,,0,0,0,, 明白吧 \\N{\\fs12}Okay?\r\nDialogue: 0,1:02:44.60,1:02:46.53,yin,,0,0,0,, 我想让这些消息发送给我 \\N{\\fs12}I want these messages sent to myself.\r\nDialogue: 0,1:02:46.58,1:02:49.11,yin,,0,0,0,, 而 selector 要记得用 @selector\\N{\\fs12}The selector, remember we have to say “at sign selector”\r\nDialogue: 0,1:02:49.11,1:02:50.24,yin,,0,0,0,, 来指定内容 \\N{\\fs12}when we want to specify a thing.\r\nDialogue: 0,1:02:50.24,1:02:54.08,yin,,0,0,0,, 我要叫它 preferredFontsChanged\\N{\\fs12}I’m going to call it “preferredFontsChanged.”\r\nDialogue: 0,1:02:55.09,1:03:00.18,yin,,0,0,0,,name 是 UIContentSizeCategoryDidChangeNotification\\N{\\fs12}Okay? Name is UIContentSizeCategory –\r\nDialogue: 0,1:03:00.18,1:03:01.77,yin,,0,0,0,, 太好了 可以直接补全 \\N{\\fs12}lucky, I get to tab through that one.\r\nDialogue: 0,1:03:01.94,1:03:04.31,yin,,0,0,0,,object 是 nil\\N{\\fs12}Okay? And the object is nil.\r\nDialogue: 0,1:03:04.31,1:03:06.05,yin,,0,0,0,, 也就是说 如果有人发送了消息 \\N{\\fs12}In other words, if anybody sends that,\r\nDialogue: 0,1:03:06.09,1:03:07.75,yin,,0,0,0,, 我就要改变我的推荐字体 \\N{\\fs12}I’m going to change my preferred fonts.\r\nDialogue: 0,1:03:08.43,1:03:10.50,yin,,0,0,0,, 注意这里有一个警告 \\N{\\fs12}Okay? Notice there’s a warning here,\r\nDialogue: 0,1:03:10.81,1:03:13.43,yin,,0,0,0,, 因为我没有实现这个 \\N{\\fs12}that’s because I don’t implement this.\r\nDialogue: 0,1:03:13.75,1:03:15.72,yin,,0,0,0,, 我觉得这是 iOS7 中的新内容 \\N{\\fs12}I believe that’s new in iOS 7.\r\nDialogue: 0,1:03:15.91,1:03:18.77,yin,,0,0,0,, 我不记得以前见过 \\N{\\fs12}I don’t remember seeing that before.\r\nDialogue: 0,1:03:19.74,1:03:20.55,yin,,0,0,0,, 好的 谢谢 \\N{\\fs12}Okay. Thank you.\r\nDialogue: 0,1:03:20.95,1:03:21.70,yin,,0,0,0,, 这里太多 r 了 \\N{\\fs12}Too many Rs.\r\nDialogue: 0,1:03:23.22,1:03:26.34,yin,,0,0,0,,(void)preferred\\N{\\fs12}Okay. View — void here preferred.\r\nDialogue: 0,1:03:27.99,1:03:29.43,yin,,0,0,0,, 糟糕 多了个 f\\N{\\fs12}Oops. Two Fs now.\r\nDialogue: 0,1:03:29.44,1:03:34.86,yin,,0,0,0,,preferredFontsChanged 参数为 NSNotification\\N{\\fs12}Okay, preferredFontsChanged takes an NSNotification star,\r\nDialogue: 0,1:03:35.31,1:03:36.32,yin,,0,0,0,, 然后是 notification\\N{\\fs12}okay, notification,\r\nDialogue: 0,1:03:36.33,1:03:37.24,yin,,0,0,0,, 我不会用它 \\N{\\fs12}I’m not going to use that\r\nDialogue: 0,1:03:37.25,1:03:38.62,yin,,0,0,0,, 因为基本上它只是一个布尔值 \\N{\\fs12}because it’s just basically Boolean.\r\nDialogue: 0,1:03:39.00,1:03:40.68,yin,,0,0,0,, 实际上我要调用另外一个方法 \\N{\\fs12}And I’m actually going to call another method.\r\nDialogue: 0,1:03:40.68,1:03:42.99,yin,,0,0,0,, 我要调用 usePreferredFonts\\N{\\fs12}I’m going to call usePreferredFonts,\r\nDialogue: 0,1:03:43.00,1:03:44.85,yin,,0,0,0,, 你们马上就能明白这里为什么要这么做 \\N{\\fs12}and you’re going to see why here in a second.\r\nDialogue: 0,1:03:45.62,1:03:49.32,yin,,0,0,0,, 这样设置好之后 只要我的视图出现 \\N{\\fs12}Okay? So that set it up so that anytime my view appears,\r\nDialogue: 0,1:03:49.50,1:03:53.46,yin,,0,0,0,, 我就会得到这个 usePreferredFonts\\N{\\fs12}I’m going to get this usePreferredFonts sent to me –\r\nDialogue: 0,1:03:53.73,1:03:55.90,yin,,0,0,0,, 会发送给我 \\N{\\fs12}preferred fonts sent.\r\nDialogue: 0,1:03:55.90,1:03:59.68,yin,,0,0,0,, 在这里 我要让我的文本视图和标题 \\N{\\fs12}And in here I have to make my text view\r\nDialogue: 0,1:03:59.68,1:04:02.63,yin,,0,0,0,, 使用新的推荐字体 \\N{\\fs12}and my headline use the new preferred fonts.\r\nDialogue: 0,1:04:02.63,1:04:04.75,yin,,0,0,0,, 非常简单 \\N{\\fs12}And that’s really, really easy to do.\r\nDialogue: 0,1:04:04.99,1:04:14.94,yin,,0,0,0,,self.body.font=[UIFont preferredFontForTextStyle: UIFontTextStyle\\N{\\fs12}self.body.font equals UIFont preferredFontForTextStyle UIFontTextStyle –\r\nDialogue: 0,1:04:14.95,1:04:16.53,yin,,0,0,0,, 这是正文 所以这里我要写 Body\\N{\\fs12}this is the body, so I’m going to do Body.\r\nDialogue: 0,1:04:16.83,1:04:18.65,yin,,0,0,0,, 我正好可以借此机会介绍一下 \\N{\\fs12}So this has allowed me an excuse to show you\r\nDialogue: 0,1:04:18.66,1:04:20.80,yin,,0,0,0,, 如何使用代码设置推荐字体 \\N{\\fs12}how to set these preferred fonts in code\r\nDialogue: 0,1:04:20.81,1:04:22.09,yin,,0,0,0,, 而不是在 Xcode 中进行设置 \\N{\\fs12}instead of setting them in Xcode.\r\nDialogue: 0,1:04:22.34,1:04:23.55,yin,,0,0,0,, 就是这么简单 \\N{\\fs12}This is how easy it is.\r\nDialogue: 0,1:04:23.79,1:04:26.73,yin,,0,0,0,, 现在我在设置 UITextView 的字体 \\N{\\fs12}Okay? Now I’m setting the font of the UITextView.\r\nDialogue: 0,1:04:26.73,1:04:28.60,yin,,0,0,0,, 所以如果我之前设置了加粗或者斜体 \\N{\\fs12}So if I had any bolds or italics,\r\nDialogue: 0,1:04:28.68,1:04:30.05,yin,,0,0,0,, 这里设置之后就不再有这些效果了 \\N{\\fs12}unfortunately this would blast them.\r\nDialogue: 0,1:04:30.61,1:04:34.27,yin,,0,0,0,, 显然 我需要逐一查看各个属性 \\N{\\fs12}So obviously, I would need to iterate through all the attributes\r\nDialogue: 0,1:04:34.28,1:04:35.32,yin,,0,0,0,, 查看字体 \\N{\\fs12}and look at the font,\r\nDialogue: 0,1:04:35.58,1:04:36.51,yin,,0,0,0,, 得到符号特征 \\N{\\fs12}get the symbolic traits,\r\nDialogue: 0,1:04:36.51,1:04:38.03,yin,,0,0,0,, 像我之前讲过的那样 应用它们 \\N{\\fs12}apply them like I talked about earlier.\r\nDialogue: 0,1:04:38.46,1:04:40.45,yin,,0,0,0,, 接下来 我们对标题进行同样的操作 \\N{\\fs12}And then let’s do the same thing for the headline,\r\nDialogue: 0,1:04:41.01,1:04:47.20,yin,,0,0,0,, 但是它的字体要是标题推荐字体 \\N{\\fs12}but its font wants to be the preferred font for headline,\r\nDialogue: 0,1:04:47.67,1:04:48.77,yin,,0,0,0,, 也就是这个 \\N{\\fs12}which is this one.\r\nDialogue: 0,1:04:50.18,1:04:52.69,yin,,0,0,0,, 就是这样 \\N{\\fs12}Okay? So that’s that.\r\nDialogue: 0,1:04:54.58,1:05:00.70,yin,,0,0,0,, 还有一点要考虑的是 我需要停止收听 \\N{\\fs12}One last thing to consider here is I need to stop listening –\r\nDialogue: 0,1:05:02.47,1:05:04.10,yin,,0,0,0,, 我们在 viewWillDisappear 中执行 \\N{\\fs12}we’ll do it in will disappear.\r\nDialogue: 0,1:05:04.10,1:05:09.12,yin,,0,0,0,, 也可以在其他方法中实现 但是这里就这样 \\N{\\fs12}Could do it in either but — Okay.\r\nDialogue: 0,1:05:09.35,1:05:12.34,yin,,0,0,0,, 当我要消失时 我想要停止收听 \\N{\\fs12}When I’m going to disappear I want to stop listening.\r\nDialogue: 0,1:05:12.63,1:05:15.38,yin,,0,0,0,, 这里也是一样的 NSNotificationCenter\\N{\\fs12}And so, again, NSNotificationCenter,\r\nDialogue: 0,1:05:16.69,1:05:19.69,yin,,0,0,0,,defaultCenter removeObserver\\N{\\fs12}defaultCenter, removeObserver.\r\nDialogue: 0,1:05:19.96,1:05:21.70,yin,,0,0,0,, 有些同学可能会认为这里直接写 self 就行了 \\N{\\fs12}Now, some would argue just putting self here,\r\nDialogue: 0,1:05:21.70,1:05:25.52,yin,,0,0,0,, 但我认为这是一个不好的编程方法 \\N{\\fs12}but I actually think that’s bad coding because, you know,\r\nDialogue: 0,1:05:25.52,1:05:27.37,yin,,0,0,0,, 如果你在后面又添加了一个新功能 \\N{\\fs12}what happens if you add a new feature down the road\r\nDialogue: 0,1:05:27.37,1:05:28.92,yin,,0,0,0,, 你收听了另外一个广播 \\N{\\fs12}where you’re listening on a different radio station\r\nDialogue: 0,1:05:28.92,1:05:30.53,yin,,0,0,0,, 而你并不想在视图消失时 \\N{\\fs12}that you don’t want to stop listening to\r\nDialogue: 0,1:05:30.54,1:05:31.76,yin,,0,0,0,, 停止收听这个广播 \\N{\\fs12}when your view disappears?\r\nDialogue: 0,1:05:32.01,1:05:33.89,yin,,0,0,0,, 这种情况很少见 但也是有可能的 \\N{\\fs12}Which is rare, but it’s possible.\r\nDialogue: 0,1:05:34.28,1:05:38.44,yin,,0,0,0,, 所以我认为这里使用这个版本更好 \\N{\\fs12}So I actually think it’s better here to use the version of this,\r\nDialogue: 0,1:05:38.74,1:05:42.00,yin,,0,0,0,, 以名称为参数的 removeObserver\\N{\\fs12}which remove observer that takes the name.\r\nDialogue: 0,1:05:42.29,1:05:43.90,yin,,0,0,0,, 我要写 removeObserver: self\\N{\\fs12}So I’m going to say remove yourself\r\nDialogue: 0,1:05:44.15,1:05:47.16,yin,,0,0,0,,name: UIContentSizeCategoryDidChangeNotification\\N{\\fs12}name is UIContent blah-blah-blah.\r\nDialogue: 0,1:05:48.57,1:05:50.39,yin,,0,0,0,,object 依旧是 nil\\N{\\fs12}And the object is still nil.\r\nDialogue: 0,1:05:50.85,1:05:55.01,yin,,0,0,0,, 我只从那一个广播站的收听列表中 \\N{\\fs12}So I’m only going to remove myself as a listener\r\nDialogue: 0,1:05:55.01,1:05:56.42,yin,,0,0,0,, 将自己移除 \\N{\\fs12}from that one radio station.\r\nDialogue: 0,1:05:57.70,1:05:59.62,yin,,0,0,0,, 还有最后一件事 \\N{\\fs12}And there’s one last thing to do here,\r\nDialogue: 0,1:06:00.07,1:06:03.30,yin,,0,0,0,, 如果我的视图出现了 \\N{\\fs12}which is what happens if my view appears,\r\nDialogue: 0,1:06:03.43,1:06:05.76,yin,,0,0,0,, 我开始监听 它消失了 \\N{\\fs12}I start listening, it disappears,\r\nDialogue: 0,1:06:06.30,1:06:08.05,yin,,0,0,0,, 然后改变了文本样式 \\N{\\fs12}and then they go change the text style?\r\nDialogue: 0,1:06:09.52,1:06:10.80,yin,,0,0,0,, 然后视图又重新出现了 \\N{\\fs12}And then I reappear?\r\nDialogue: 0,1:06:12.25,1:06:16.00,yin,,0,0,0,, 这里我并不会得到通知 \\N{\\fs12}Okay? I will not be notified at that point\r\nDialogue: 0,1:06:16.30,1:06:18.03,yin,,0,0,0,, 因为这个文本样式的改变 \\N{\\fs12}because the change — the text style change –\r\nDialogue: 0,1:06:18.03,1:06:19.39,yin,,0,0,0,, 发生在我没有收听的时候 \\N{\\fs12}happened while I wasn’t listening.\r\nDialogue: 0,1:06:19.87,1:06:21.77,yin,,0,0,0,, 所以你回来继续收听时 \\N{\\fs12}So turning your listening back on,\r\nDialogue: 0,1:06:21.78,1:06:23.06,yin,,0,0,0,, 不会收到没有收听时 \\N{\\fs12}you don’t get all the messages\r\nDialogue: 0,1:06:23.06,1:06:24.31,yin,,0,0,0,, 发出的那些消息 \\N{\\fs12}that happened while you weren’t listening;\r\nDialogue: 0,1:06:24.31,1:06:25.52,yin,,0,0,0,, 你只会收到新消息 \\N{\\fs12}you only get new messages.\r\nDialogue: 0,1:06:25.92,1:06:27.33,yin,,0,0,0,, 这也就是我们为什么 \\N{\\fs12}So that’s why we probably want\r\nDialogue: 0,1:06:27.34,1:06:31.26,yin,,0,0,0,, 要在 viewWillAppear 中加上 self usePreferredFonts\\N{\\fs12}to say self usePreferredFonts in viewWillAppear.\r\nDialogue: 0,1:06:31.49,1:06:33.66,yin,,0,0,0,, 这也就是为什么我说 \\N{\\fs12}This is why I’m talking about where viewWillAppear\r\nDialogue: 0,1:06:33.66,1:06:36.86,yin,,0,0,0,, 在 viewWillAppear 执行同步操作 \\N{\\fs12}wants to sync up with the world when it starts.\r\nDialogue: 0,1:06:36.86,1:06:38.42,yin,,0,0,0,,viewWillAppear 就是这个作用 \\N{\\fs12}That’s what viewWillAppear is for.\r\nDialogue: 0,1:06:38.71,1:06:40.94,yin,,0,0,0,, 所以 viewWillAppear 会使用推荐字体 \\N{\\fs12}So viewWillAppear is going to use preferred fonts,\r\nDialogue: 0,1:06:40.94,1:06:42.89,yin,,0,0,0,, 不管目前是什么样式 \\N{\\fs12}whatever are currently out there.\r\nDialogue: 0,1:06:43.25,1:06:45.94,yin,,0,0,0,, 明白我为什么这样做了吗 \\N{\\fs12}Okay? That make sense why I’m doing that?\r\nDialogue: 0,1:06:46.89,1:06:51.42,yin,,0,0,0,, 我们运行一下 看看是否运行正常 \\N{\\fs12}So let’s run this and see if it works.\r\nDialogue: 0,1:06:53.13,1:06:54.56,yin,,0,0,0,, 我是在设备上运行的 \\N{\\fs12}Now, I’m running this on a device\r\nDialogue: 0,1:06:54.76,1:06:59.00,yin,,0,0,0,, 但是你们在模拟器上运行的时候 也可以打开设置 \\N{\\fs12}but on your simulator you can also go to the settings.\r\nDialogue: 0,1:06:59.00,1:07:00.86,yin,,0,0,0,, 这是我的文本 对吧 \\N{\\fs12}So here’s my text, right?\r\nDialogue: 0,1:07:00.86,1:07:03.46,yin,,0,0,0,, 我们加点橙色的文本 \\N{\\fs12}So let’s even go ahead and put some orange text in there.\r\nDialogue: 0,1:07:04.12,1:07:06.17,yin,,0,0,0,, 现在我要点击 home 键 \\N{\\fs12}Okay. Now I’m going to hit the home button\r\nDialogue: 0,1:07:06.86,1:07:10.10,yin,,0,0,0,, 转到设置 就在这里 \\N{\\fs12}and I’m going to go to settings, which is right here.\r\nDialogue: 0,1:07:10.54,1:07:14.59,yin,,0,0,0,, 找到下面的通用 我觉得是它 \\N{\\fs12}I’m going to go down to general, I believe it is.\r\nDialogue: 0,1:07:15.58,1:07:16.18,yin,,0,0,0,, 是它吗 \\N{\\fs12}Is that it?\r\nDialogue: 0,1:07:16.20,1:07:17.16,yin,,0,0,0,, 没错 文本大小 \\N{\\fs12}Yeah, text size.\r\nDialogue: 0,1:07:17.16,1:07:18.54,yin,,0,0,0,, 看到这个文本大小了吗 \\N{\\fs12}You see text size right there?\r\nDialogue: 0,1:07:19.22,1:07:20.51,yin,,0,0,0,, 可以看到这里有一个滑动条 \\N{\\fs12}You can see there’s a slider.\r\nDialogue: 0,1:07:20.71,1:07:24.29,yin,,0,0,0,, 我们把字体放到最大 \\N{\\fs12}So let’s make our text really big, okay?\r\nDialogue: 0,1:07:24.85,1:07:27.77,yin,,0,0,0,, 回去 我可以直接回到这里 \\N{\\fs12}Go back. I can just go back to here.\r\nDialogue: 0,1:07:27.78,1:07:30.58,yin,,0,0,0,, 它还在模拟器中运行 \\N{\\fs12}It’s still running in the simulator.\r\nDialogue: 0,1:07:30.69,1:07:32.78,yin,,0,0,0,, 如果我设置了断点之类的 \\N{\\fs12}Okay? So if I had breakpoints and stuff,\r\nDialogue: 0,1:07:32.78,1:07:33.73,yin,,0,0,0,, 还是可以使用的 \\N{\\fs12}that would all still work.\r\nDialogue: 0,1:07:33.87,1:07:35.23,yin,,0,0,0,, 可以看到 字体变大了 \\N{\\fs12}And now I can see my font is big.\r\nDialogue: 0,1:07:35.23,1:07:37.46,yin,,0,0,0,, 橙色文本还在这里 \\N{\\fs12}I kept my orange right there.\r\nDialogue: 0,1:07:37.68,1:07:38.25,yin,,0,0,0,, 可以这样做 \\N{\\fs12}You can do this.\r\nDialogue: 0,1:07:38.26,1:07:39.71,yin,,0,0,0,, 我可以为它添加轮廓 \\N{\\fs12}I can put an outline on there.\r\nDialogue: 0,1:07:40.32,1:07:41.20,yin,,0,0,0,, 绿色的吧 \\N{\\fs12}Green maybe.\r\nDialogue: 0,1:07:41.42,1:07:43.22,yin,,0,0,0,, 绿色轮廓更容易看清楚 \\N{\\fs12}Okay, you can see the outline a little better with green.\r\nDialogue: 0,1:07:43.45,1:07:45.57,yin,,0,0,0,, 现在如果我再回到设置页面 \\N{\\fs12}And now if I go back again to settings –\r\nDialogue: 0,1:07:46.83,1:07:50.98,yin,,0,0,0,, 将字体大小设为最小 回去 \\N{\\fs12}and let’s set this all the way to small and go back.\r\nDialogue: 0,1:07:51.76,1:07:54.32,yin,,0,0,0,, 再回到应用中 可以看到页面变化了 \\N{\\fs12}Back to our thing, you can see it updates it.\r\nDialogue: 0,1:07:54.91,1:07:58.12,yin,,0,0,0,, 明白了吗 \\N{\\fs12}Okay? So make sense?\r\nDialogue: 0,1:07:58.32,1:07:59.97,yin,,0,0,0,, 大家都明白这里发生了什么吗 \\N{\\fs12}Everyone understand what’s going on there?\r\nDialogue: 0,1:08:01.42,1:08:03.69,yin,,0,0,0,, 大家可以看到 在这一部分 我们使用了…\\N{\\fs12}Okay. So there you can see in that part we used –\r\nDialogue: 0,1:08:04.01,1:08:06.23,yin,,0,0,0,, 介绍了如何用代码设置推荐字体 \\N{\\fs12}we showed you how to do the preferred fonts in code,\r\nDialogue: 0,1:08:06.34,1:08:09.64,yin,,0,0,0,, 我们还用通知中心收听了广播 \\N{\\fs12}and we also used notification center to do the radio station,\r\nDialogue: 0,1:08:09.80,1:08:13.09,yin,,0,0,0,, 还使用了更多视图控制器生命周期方法 \\N{\\fs12}and we also used some more of the view controller lifecycle.\r\nDialogue: 0,1:08:13.09,1:08:16.15,yin,,0,0,0,, 涵盖了很多内容 \\N{\\fs12}So that was multihit there.\r\nDialogue: 0,1:08:16.83,1:08:23.88,yin,,0,0,0,, 下次课 周三的课上 \\N{\\fs12}And so next time — what’s coming up on Wednesday –\r\nDialogue: 0,1:08:24.01,1:08:25.23,yin,,0,0,0,, 我们要继续修改这个应用 \\N{\\fs12}we’re going to take this app\r\nDialogue: 0,1:08:25.50,1:08:28.02,yin,,0,0,0,, 添加更多的视图控制器 \\N{\\fs12}and we’re going to add some more view controllers to it.\r\nDialogue: 0,1:08:28.22,1:08:29.22,yin,,0,0,0,, 多个视图控制器 \\N{\\fs12}So multiple view controllers.\r\nDialogue: 0,1:08:29.22,1:08:31.95,yin,,0,0,0,, 为了完成作业 要特别注意这部分内容 \\N{\\fs12}Now, it’s very important to pay attention for that for your assignment\r\nDialogue: 0,1:08:32.09,1:08:33.36,yin,,0,0,0,, 因为这是作业要求中 \\N{\\fs12}because that’s the fundamental thing\r\nDialogue: 0,1:08:33.36,1:08:35.06,yin,,0,0,0,, 最基础的内容 \\N{\\fs12}we’re asking you to do in the assignment\r\nDialogue: 0,1:08:35.07,1:08:37.65,yin,,0,0,0,, 就是我们周三要讲的内容 创建多 MVC\\N{\\fs12}that’s going to go out on Wednesday is make multiple MVCs –\r\nDialogue: 0,1:08:38.09,1:08:39.46,yin,,0,0,0,, 依旧是 Matchismo\\N{\\fs12}it’s still going to be Matchismo\r\nDialogue: 0,1:08:39.59,1:08:41.48,yin,,0,0,0,, 但是要再增加一个游戏 \\N{\\fs12}but you’re going to have to do another game,\r\nDialogue: 0,1:08:41.55,1:08:43.24,yin,,0,0,0,, 都显示在屏幕上 \\N{\\fs12}have both on screen,\r\nDialogue: 0,1:08:43.34,1:08:45.78,yin,,0,0,0,, 在屏幕上再显示一项内容 \\N{\\fs12}have yet another thing appearing on screen.\r\nDialogue: 0,1:08:45.78,1:08:47.64,yin,,0,0,0,, 最少要有三个 MVC\\N{\\fs12}So you’re going to have at least three\r\nDialogue: 0,1:08:47.64,1:08:51.09,yin,,0,0,0,, 如果想要获得额外加分 需要实现四到五个不同的 MVC\\N{\\fs12}and if you do extra credit, four or five different MVCs.\r\nDialogue: 0,1:08:51.10,1:08:53.47,yin,,0,0,0,, 我们会快速实现多个 MVC\\N{\\fs12}So we’re going to rapidly start going up to multiple MVCs.\r\nDialogue: 0,1:08:53.65,1:08:55.34,yin,,0,0,0,, 会讲到如何通过 \\N{\\fs12}We’re going to talk about how to add MVCs\r\nDialogue: 0,1:08:55.35,1:08:58.10,yin,,0,0,0,, 选项卡栏和导航控制器添加 MVC\\N{\\fs12}with the tab bar and also navigation controller.\r\nDialogue: 0,1:08:58.10,1:09:00.51,yin,,0,0,0,, 这是我们会最先学到的两个实现方法 \\N{\\fs12}That’s the first two ways we’re going to learn how to do that.\r\nDialogue: 0,1:09:01.06,1:09:03.42,yin,,0,0,0,, 周三还有一项内容需要重点理解 \\N{\\fs12}Really important to understand for Wednesday\r\nDialogue: 0,1:09:03.51,1:09:05.31,yin,,0,0,0,, 就是我们将要用到继承 \\N{\\fs12}is we’re going to use inheritance\r\nDialogue: 0,1:09:05.44,1:09:09.24,yin,,0,0,0,, 因为你的两个 MVC 会很相似 \\N{\\fs12}because two of your MVCs are going to be very similar.\r\nDialogue: 0,1:09:09.24,1:09:10.57,yin,,0,0,0,, 它们都是卡牌游戏 \\N{\\fs12}They’re both going to be card games,\r\nDialogue: 0,1:09:10.58,1:09:11.68,yin,,0,0,0,, 但会有一点不同 \\N{\\fs12}but they’re going to be a little different.\r\nDialogue: 0,1:09:11.91,1:09:13.14,yin,,0,0,0,, 你要用继承 \\N{\\fs12}You’re going to want to use inheritance\r\nDialogue: 0,1:09:13.14,1:09:14.11,yin,,0,0,0,, 来实现二者之间的代码共享 \\N{\\fs12}to share a code between them.\r\nDialogue: 0,1:09:14.11,1:09:16.46,yin,,0,0,0,, 周三会开始讲这部分内容 \\N{\\fs12}So I’m going to kind of get you started on that on Wednesday.\r\nDialogue: 0,1:09:16.81,1:09:19.26,yin,,0,0,0,, 我会在周三发布第三个作业 \\N{\\fs12}And so I’ll be sending out assignment three on Wednesday.\r\nDialogue: 0,1:09:19.44,1:09:22.64,yin,,0,0,0,, 我们本来要在周五演示使用免费的大学开发者计划 \\N{\\fs12}Friday we were going to be doing getting your device working\r\nDialogue: 0,1:09:22.64,1:09:25.03,yin,,0,0,0,, 帮助大家在设备上运行应用 \\N{\\fs12}with the free university developer program;\r\nDialogue: 0,1:09:25.24,1:09:27.94,yin,,0,0,0,, 但是现在技术不可用 \\N{\\fs12}however, that’s not working technically right now.\r\nDialogue: 0,1:09:27.94,1:09:29.50,yin,,0,0,0,, 所以我们移到下周讲 \\N{\\fs12}So we’re going to put that off until next week.\r\nDialogue: 0,1:09:29.50,1:09:32.13,yin,,0,0,0,, 下周五 不是这周五 \\N{\\fs12}So next Friday — not this week’s Friday,\r\nDialogue: 0,1:09:32.13,1:09:34.65,yin,,0,0,0,, 下周五我们会有一个课外辅导 \\N{\\fs12}but next Friday — we’ll be having a section\r\nDialogue: 0,1:09:34.82,1:09:35.97,yin,,0,0,0,, 大家可以来参加 \\N{\\fs12}where you can come to the section\r\nDialogue: 0,1:09:35.97,1:09:39.09,yin,,0,0,0,, 我们会帮助大家在设备上运行应用 \\N{\\fs12}and we’ll help you get it so it’s working on your device.\r\nDialogue: 0,1:09:40.79,1:09:44.18,yin,,0,0,0,, 更多内容 请访问斯坦福网站 \\N{\\fs12}For more, please visit us at stanford.edu."
  },
  {
    "path": "Subtitles/6. Polymorphism with Controllers, UINavigation, UITabBar.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.1.2\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\nLast Style Storage: Default\r\nAegisub Video Zoom Percent: 1.000000\r\nAegisub Scroll Position: 0\r\nAegisub Active Line: 0\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin, 冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.04,0:00:07.01,yin,,0,0,0,, 斯坦福大学 \\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:08.51,0:00:10.63,yin,,0,0,0,, 欢迎来到 CS193P\\N{\\fs12}Okay. Well, welcome to CS193P.\r\nDialogue: 0,0:00:10.63,0:00:16.78,yin,,0,0,0,, 这是 2013 至 2014 秋季学期第六讲 \\N{\\fs12}This is lecture six, yes, of fall 2013-14.\r\nDialogue: 0,0:00:17.05,0:00:21.23,yin,,0,0,0,, 今天我们会先做一个小小的演示 \\N{\\fs12}So, today we are going to have a little demo at the beginning.\r\nDialogue: 0,0:00:21.35,0:00:22.97,yin,,0,0,0,, 我想讲一下 \\N{\\fs12}I want to talk to you a little bit\r\nDialogue: 0,0:00:22.99,0:00:25.36,yin,,0,0,0,, 控制器的多态性 \\N{\\fs12}about polymorphism with controllers.\r\nDialogue: 0,0:00:25.37,0:00:25.88,yin,,0,0,0,, 也就是说 \\N{\\fs12}In other words,\r\nDialogue: 0,0:00:25.99,0:00:30.31,yin,,0,0,0,, 在控制器中使用继承 \\N{\\fs12}using inheritance for — in the world of controllers,\r\nDialogue: 0,0:00:30.33,0:00:33.35,yin,,0,0,0,, 有些同学如果对于面向对象编程 \\N{\\fs12}and those of you who — for whom object-oriented programming\r\nDialogue: 0,0:00:33.37,0:00:35.07,yin,,0,0,0,, 还不是那么熟练 \\N{\\fs12}is not that facile quite yet,\r\nDialogue: 0,0:00:36.44,0:00:37.95,yin,,0,0,0,, 可能会认为 \\N{\\fs12}you might be kind of like, oh yeah,\r\nDialogue: 0,0:00:37.95,0:00:39.58,yin,,0,0,0,, 可以生成控制器的子类 \\N{\\fs12}I guess I could subclass my controller,\r\nDialogue: 0,0:00:39.59,0:00:42.52,yin,,0,0,0,, 实际上 你确实要生成控制器的子类 \\N{\\fs12}and in fact, you do want to subclass your controller,\r\nDialogue: 0,0:00:42.62,0:00:45.19,yin,,0,0,0,, 这很常见 \\N{\\fs12}and it’s quite common to subclass controllers.\r\nDialogue: 0,0:00:46.58,0:00:48.09,yin,,0,0,0,, 我讲过 \\N{\\fs12}As I said, iOS is kind of\r\nDialogue: 0,0:00:48.10,0:00:50.17,yin,,0,0,0,,iOS 是基于面向对象编程设计的 \\N{\\fs12}all designed around object-oriented programming,\r\nDialogue: 0,0:00:50.19,0:00:52.33,yin,,0,0,0,, 所以你要在系统中各处 \\N{\\fs12}so you get to apply object-oriented principles\r\nDialogue: 0,0:00:52.50,0:00:54.40,yin,,0,0,0,, 应用面向对象原理 \\N{\\fs12}everywhere in the system,\r\nDialogue: 0,0:00:54.41,0:00:55.88,yin,,0,0,0,, 今天我就要演示这部分内容 \\N{\\fs12}so I’m going to show you that today,\r\nDialogue: 0,0:00:56.04,0:00:57.14,yin,,0,0,0,, 能够帮助大家 \\N{\\fs12}and that’s to help you a little bit\r\nDialogue: 0,0:00:57.15,0:00:58.31,yin,,0,0,0,, 开始做作业 \\N{\\fs12}get you started on your homework,\r\nDialogue: 0,0:00:58.31,0:00:59.82,yin,,0,0,0,, 因为我要布置的作业内容 \\N{\\fs12}because what I’m going to ask for your homework\r\nDialogue: 0,0:01:00.03,0:01:04.64,yin,,0,0,0,, 是需要你在 Matchismo 中再添加一个卡牌配对游戏 \\N{\\fs12}is for you to add a second card matching game to your Matchismo.\r\nDialogue: 0,0:01:04.65,0:01:06.99,yin,,0,0,0,, 第二个游戏几乎是一样的 \\N{\\fs12}Now this second game is almost identical,\r\nDialogue: 0,0:01:06.99,0:01:08.35,yin,,0,0,0,, 游戏规则等都一样 \\N{\\fs12}plays by the same rules and everything,\r\nDialogue: 0,0:01:08.35,0:01:10.49,yin,,0,0,0,, 只是用了另外一副卡牌 \\N{\\fs12}it really just uses a different deck of cards.\r\nDialogue: 0,0:01:10.75,0:01:12.84,yin,,0,0,0,, 这是主要的不同 \\N{\\fs12}Okay, that’s the primary difference,\r\nDialogue: 0,0:01:13.43,0:01:15.44,yin,,0,0,0,, 所以显然你需要更新模型 \\N{\\fs12}so you’ll obviously have to update your model\r\nDialogue: 0,0:01:15.44,0:01:18.27,yin,,0,0,0,, 添加另外一副卡牌 \\N{\\fs12}to have this extra different deck of cards,\r\nDialogue: 0,0:01:18.61,0:01:20.50,yin,,0,0,0,, 但是游戏的逻辑 \\N{\\fs12}but your game playing logic\r\nDialogue: 0,0:01:20.51,0:01:23.89,yin,,0,0,0,, 和控制器的基础部分都是一样的 \\N{\\fs12}and the basic part of your controller is the same,\r\nDialogue: 0,0:01:24.04,0:01:24.89,yin,,0,0,0,, 但是我们并不想 \\N{\\fs12}but we don’t want to have\r\nDialogue: 0,0:01:24.89,0:01:27.19,yin,,0,0,0,, 让卡牌和控制器相连 \\N{\\fs12}playing card wiring into our controller,\r\nDialogue: 0,0:01:27.20,0:01:28.44,yin,,0,0,0,, 所以我们要用继承 \\N{\\fs12}so we’re going to use inheritance\r\nDialogue: 0,0:01:28.45,0:01:30.20,yin,,0,0,0,, 创建一副特定卡牌 \\N{\\fs12}to create a playing card specific one,\r\nDialogue: 0,0:01:30.21,0:01:33.48,yin,,0,0,0,, 再用一副通用卡牌与其他游戏共享 \\N{\\fs12}and then keep a generic one that we can share for the other game,\r\nDialogue: 0,0:01:33.49,0:01:34.84,yin,,0,0,0,, 我们会先来做这个演示 \\N{\\fs12}so we’ll show that at the beginning.\r\nDialogue: 0,0:01:35.46,0:01:37.67,yin,,0,0,0,, 然后我们会详细讲解 \\N{\\fs12}Then we’re going to dive into\r\nDialogue: 0,0:01:37.68,0:01:39.72,yin,,0,0,0,, 如何为应用添加多个 MVC\\N{\\fs12}how to get multiple MVCs in your application.\r\nDialogue: 0,0:01:39.73,0:01:42.70,yin,,0,0,0,, 换句话说 如何让你的应用实现更多的功能 \\N{\\fs12}In other words, how to make your application have more features\r\nDialogue: 0,0:01:42.72,0:01:44.56,yin,,0,0,0,, 不仅局限于一个小小的屏幕 \\N{\\fs12}than you can just fit on one little screen.\r\nDialogue: 0,0:01:44.72,0:01:46.73,yin,,0,0,0,, 显然 \\N{\\fs12}Okay. And the critical, obviously,\r\nDialogue: 0,0:01:46.74,0:01:49.38,yin,,0,0,0,, 想要构建复杂精细的应用 \\N{\\fs12}to building any kind of complicated or sophisticated app\r\nDialogue: 0,0:01:49.39,0:01:51.19,yin,,0,0,0,, 关键在于扩大应用的功能集 \\N{\\fs12}is to be able to expand your feature set,\r\nDialogue: 0,0:01:51.20,0:01:53.34,yin,,0,0,0,, 即便是在一个设备上 \\N{\\fs12}even though you’re talking about being on a device,\r\nDialogue: 0,0:01:53.34,0:01:55.36,yin,,0,0,0,, 很小的设备 屏幕很小 \\N{\\fs12}it’s a small device, it’s a very small screen,\r\nDialogue: 0,0:01:56.21,0:01:58.89,yin,,0,0,0,, 在一屏上只能放置有限个 UI 元素 \\N{\\fs12}that limits how much UI you can put on there at a time.\r\nDialogue: 0,0:02:00.52,0:02:03.56,yin,,0,0,0,, 然后 这节课结束之前 我会再演示一个示例 \\N{\\fs12}And then I’m going to do a demo towards the end\r\nDialogue: 0,0:02:03.82,0:02:06.24,yin,,0,0,0,, 我会为大家演示 \\N{\\fs12}where I’m just going to basically show you –\r\nDialogue: 0,0:02:06.24,0:02:09.03,yin,,0,0,0,, 我说过 我总会先讲讲我们要做什么 \\N{\\fs12}I tell you I always talk about what we’re going to do,\r\nDialogue: 0,0:02:09.04,0:02:10.38,yin,,0,0,0,, 然后进行演示 \\N{\\fs12}then I demonstrate what we’re going to do,\r\nDialogue: 0,0:02:10.39,0:02:11.48,yin,,0,0,0,, 然后大家在作业中实现讲过的内容 \\N{\\fs12}and then you do it for your homework,\r\nDialogue: 0,0:02:11.49,0:02:12.88,yin,,0,0,0,, 今天也是这样的 \\N{\\fs12}and that’s exactly going to be true today.\r\nDialogue: 0,0:02:12.90,0:02:16.93,yin,,0,0,0,, 我要接着演示周一的示例 Attributor\\N{\\fs12}So I’ll do the demo with Attributor that we worked on Monday.\r\nDialogue: 0,0:02:16.93,0:02:19.17,yin,,0,0,0,, 增强它的功能 让它具有多个 MVC\\N{\\fs12}We’ll enhance it to have multiple MVCs.\r\nDialogue: 0,0:02:19.98,0:02:22.64,yin,,0,0,0,, 好的 我们先来演示 \\N{\\fs12}Okay, so let’s do that demo first.\r\nDialogue: 0,0:02:24.04,0:02:25.61,yin,,0,0,0,, 打开 Matchismo\\N{\\fs12}So, we’re going to take the Matchismo\r\nDialogue: 0,0:02:25.67,0:02:28.44,yin,,0,0,0,, 第三节课最后的示例 \\N{\\fs12}as of last — at the end of lecture three,\r\nDialogue: 0,0:02:28.51,0:02:31.37,yin,,0,0,0,, 这个示例是在作业之前演示的 \\N{\\fs12}so this is prior to all your homework,\r\nDialogue: 0,0:02:31.87,0:02:33.18,yin,,0,0,0,, 如果你们还记得的话 \\N{\\fs12}and if you remember then,\r\nDialogue: 0,0:02:33.64,0:02:34.95,yin,,0,0,0,,storyboard 是这个样子的 \\N{\\fs12}the storyboard looks like this,\r\nDialogue: 0,0:02:34.95,0:02:36.72,yin,,0,0,0,, 只有 12 张卡牌和得分 \\N{\\fs12}we just have 12 cards and the score,\r\nDialogue: 0,0:02:36.72,0:02:37.89,yin,,0,0,0,, 非常简单 \\N{\\fs12}really, really simple.\r\nDialogue: 0,0:02:38.26,0:02:40.76,yin,,0,0,0,, 有一个卡牌游戏视图控制器 \\N{\\fs12}And we have this card game view controller.\r\nDialogue: 0,0:02:40.90,0:02:42.49,yin,,0,0,0,, 这是卡牌游戏视图控制器 \\N{\\fs12}Right. This is the card game view controller,\r\nDialogue: 0,0:02:42.50,0:02:43.89,yin,,0,0,0,, 也非常简单 \\N{\\fs12}also quite simple.\r\nDialogue: 0,0:02:43.89,0:02:45.78,yin,,0,0,0,, 这是上周的内容 还记得吧 \\N{\\fs12}You remember that from last week.\r\nDialogue: 0,0:02:46.36,0:02:48.58,yin,,0,0,0,, 当时我说它有一个问题 \\N{\\fs12}The problem with it and I mentioned this at the time,\r\nDialogue: 0,0:02:48.59,0:02:51.06,yin,,0,0,0,, 就是它导入了 PlayingCardDeck\\N{\\fs12}is that it imports PlayingCardDeck.\r\nDialogue: 0,0:02:51.20,0:02:51.66,yin,,0,0,0,, 换句话说 \\N{\\fs12}In other words,\r\nDialogue: 0,0:02:51.67,0:02:54.88,yin,,0,0,0,, 这个卡牌游戏控制器 \\N{\\fs12}this card game playing controller\r\nDialogue: 0,0:02:55.14,0:02:57.70,yin,,0,0,0,, 算是通用的卡牌游戏机 \\N{\\fs12}is pretty generic card game player,\r\nDialogue: 0,0:02:57.73,0:02:59.54,yin,,0,0,0,, 如果在其中增加其他卡牌 \\N{\\fs12}and if you put other kinds of cards in there\r\nDialogue: 0,0:02:59.56,0:03:00.54,yin,,0,0,0,, 可能可以正常匹配 \\N{\\fs12}it could probably match them,\r\nDialogue: 0,0:03:00.56,0:03:03.83,yin,,0,0,0,, 除了下面的这行代码 \\N{\\fs12}except for this one line of code down here\r\nDialogue: 0,0:03:04.16,0:03:06.61,yin,,0,0,0,, 这行代码要求我们导入 PlayingCardDeck\\N{\\fs12}that causes us to drag in PlayingCardDeck\r\nDialogue: 0,0:03:06.62,0:03:10.04,yin,,0,0,0,, 让这个 CardGameViewController 只适用于 PlayingCard 扑克牌 \\N{\\fs12}and make this CardGameViewController be playing card specific.\r\nDialogue: 0,0:03:10.05,0:03:12.21,yin,,0,0,0,, 我们要做的很简单 \\N{\\fs12}So, what we’re going to do, it’s very simple,\r\nDialogue: 0,0:03:12.29,0:03:16.11,yin,,0,0,0,, 我们要生成一个 CardGameViewController 的子类 \\N{\\fs12}we’ re going to create a subclass of this CardGameViewController\r\nDialogue: 0,0:03:16.23,0:03:17.75,yin,,0,0,0,, 只针对扑克牌 \\N{\\fs12}that’s specific to playing cards,\r\nDialogue: 0,0:03:17.90,0:03:19.91,yin,,0,0,0,, 然后我们会把所有扑克牌的内容 \\N{\\fs12}then we’ll move all the playing card specific stuff\r\nDialogue: 0,0:03:19.92,0:03:20.95,yin,,0,0,0,, 都放到那个子类中 \\N{\\fs12}into that subclass,\r\nDialogue: 0,0:03:21.11,0:03:23.36,yin,,0,0,0,, 让当前类整洁和通用 \\N{\\fs12}and we’ll keep this one nice and generic.\r\nDialogue: 0,0:03:23.37,0:03:25.06,yin,,0,0,0,, 这个 CardGameViewController 类 \\N{\\fs12}This CardGameViewController class\r\nDialogue: 0,0:03:25.26,0:03:29.95,yin,,0,0,0,, 会成为通用的卡牌匹配游戏的视图控制器 \\N{\\fs12}is going to be a generic card game matching view controller.\r\nDialogue: 0,0:03:30.15,0:03:31.47,yin,,0,0,0,, 大家明白我要做什么吗 \\N{\\fs12}Does that make sense what I’m going to do here?\r\nDialogue: 0,0:03:32.69,0:03:34.48,yin,,0,0,0,, 我们的实现方法是 \\N{\\fs12}Okay. So the way we’re going to do that\r\nDialogue: 0,0:03:34.64,0:03:37.51,yin,,0,0,0,, 删掉这行有冲突的代码 \\N{\\fs12}is we’re going to get rid of this offending line of code.\r\nDialogue: 0,0:03:37.57,0:03:38.95,yin,,0,0,0,, 这行代码 \\N{\\fs12}Okay. This is the line of code\r\nDialogue: 0,0:03:38.95,0:03:41.07,yin,,0,0,0,, 让这个类只针对于扑克牌 \\N{\\fs12}that makes this class depend on playing cards,\r\nDialogue: 0,0:03:41.23,0:03:43.42,yin,,0,0,0,, 我要删掉它 \\N{\\fs12}and I’m just going to delete it\r\nDialogue: 0,0:03:43.64,0:03:45.99,yin,,0,0,0,, 在 creatDeck 中返回 nil\\N{\\fs12}and return nil here in createDeck.\r\nDialogue: 0,0:03:46.43,0:03:47.75,yin,,0,0,0,, 这样就完成了 \\N{\\fs12}Okay, well, that’s done it.\r\nDialogue: 0,0:03:47.75,0:03:49.28,yin,,0,0,0,, 我们变成了通用的卡牌 \\N{\\fs12}Okay. We have a generic card,\r\nDialogue: 0,0:03:49.28,0:03:50.57,yin,,0,0,0,, 现在就可以删掉这行了 \\N{\\fs12}now I can get rid of that\r\nDialogue: 0,0:03:50.68,0:03:51.65,yin,,0,0,0,, 现在它都是通用的 \\N{\\fs12}and it’s all generic,\r\nDialogue: 0,0:03:51.65,0:03:53.83,yin,,0,0,0,, 但是显然这里是有问题的 \\N{\\fs12}but obviously, this is going to be a problem\r\nDialogue: 0,0:03:53.85,0:03:55.24,yin,,0,0,0,, 因为没有牌 deck\\N{\\fs12}because now there’s no deck.\r\nDialogue: 0,0:03:55.55,0:03:57.18,yin,,0,0,0,, 对吧 这里会返回 nil\\N{\\fs12}Right. This is going to return nil,\r\nDialogue: 0,0:03:57.18,0:03:58.87,yin,,0,0,0,, 这里会返回 nil\\N{\\fs12}this is going to return nil right here.\r\nDialogue: 0,0:03:58.97,0:04:01.29,yin,,0,0,0,, 这里实际上也会返回 nil\\N{\\fs12}This is actually going to return nil as well,\r\nDialogue: 0,0:04:01.35,0:04:03.46,yin,,0,0,0,, 因为它无法绘制任何卡牌 \\N{\\fs12}because it’s not going to be able to draw any cards,\r\nDialogue: 0,0:04:03.66,0:04:05.14,yin,,0,0,0,, 所以是有这个问题的 \\N{\\fs12}so this is a problem.\r\nDialogue: 0,0:04:05.25,0:04:08.53,yin,,0,0,0,, 通过修改 把这里改成 nil 以后 \\N{\\fs12}So by doing this, by putting this nil right here,\r\nDialogue: 0,0:04:08.63,0:04:13.40,yin,,0,0,0,, 基本上 我们是把 CardGameViewController 类抽象了 \\N{\\fs12}we’ve essentially made this class CardGameViewController abstract.\r\nDialogue: 0,0:04:13.83,0:04:16.20,yin,,0,0,0,, 希望大家熟悉面向对象编程 \\N{\\fs12}Okay. So, hopefully all of you know enough object-oriented programming\r\nDialogue: 0,0:04:16.22,0:04:17.70,yin,,0,0,0,, 知道抽象这个术语 \\N{\\fs12}to know the term abstract.\r\nDialogue: 0,0:04:17.96,0:04:22.32,yin,,0,0,0,, 抽象表示这个类不能被实例化使用 \\N{\\fs12}Abstract means that this class cannot be instantiated and used,\r\nDialogue: 0,0:04:22.43,0:04:25.15,yin,,0,0,0,, 它只能用于作为 \\N{\\fs12}it’s only useful as a superclass\r\nDialogue: 0,0:04:25.30,0:04:27.03,yin,,0,0,0,, 具体类的超类 \\N{\\fs12}for other classes that are concrete –\r\nDialogue: 0,0:04:27.09,0:04:28.19,yin,,0,0,0,, 与之相对的我们叫做具体 \\N{\\fs12}what we call concrete.\r\nDialogue: 0,0:04:28.74,0:04:32.55,yin,,0,0,0,, 所以如果我们想对它进行操作的话 \\N{\\fs12}Okay. So we need to make a concrete subclass of this\r\nDialogue: 0,0:04:32.56,0:04:34.70,yin,,0,0,0,, 需要创建一个它的具体子类 \\N{\\fs12}if we want to do anything with it,\r\nDialogue: 0,0:04:34.82,0:04:37.33,yin,,0,0,0,, 就我自己而言–\\N{\\fs12}and I personally when I –\r\nDialogue: 0,0:04:37.36,0:04:40.85,yin,,0,0,0,, 在 Objective-C 中 没有 abstract 关键词 \\N{\\fs12}okay, in objective-c, there’s no abstract keyword\r\nDialogue: 0,0:04:41.01,0:04:43.85,yin,,0,0,0,, 不能直接声明某个类是抽象类 \\N{\\fs12}that you can use to specify that this is an abstract class,\r\nDialogue: 0,0:04:43.87,0:04:46.15,yin,,0,0,0,, 你需要在头文件中进行记录 \\N{\\fs12}you just have to document it in your header file\r\nDialogue: 0,0:04:46.15,0:04:49.58,yin,,0,0,0,, 标明这个类是抽象类 不能实例化 \\N{\\fs12}that this class is abstract, you can’t instantiate.\r\nDialogue: 0,0:04:50.12,0:04:54.17,yin,,0,0,0,, 我还喜欢在其他地方也记录上 甚至在实现文件中 \\N{\\fs12}And I also like to document, even on my implementation,\r\nDialogue: 0,0:04:54.38,0:04:57.56,yin,,0,0,0,, 标明哪些方法是抽象的 \\N{\\fs12}any methods that basically are abstract.\r\nDialogue: 0,0:04:57.56,0:05:01.40,yin,,0,0,0,, 需要你对其进行重写 \\N{\\fs12}Any method that is required that you override this method.\r\nDialogue: 0,0:05:01.56,0:05:04.33,yin,,0,0,0,, 还要注意 所有抽象方法 \\N{\\fs12}And also any abstract method,\r\nDialogue: 0,0:05:04.34,0:05:06.65,yin,,0,0,0,, 都应该是公有的 \\N{\\fs12}you’ve got to make them public. Okay.\r\nDialogue: 0,0:05:06.82,0:05:10.04,yin,,0,0,0,, 否则具体子类会无法知道 \\N{\\fs12}Because otherwise the concrete subclasses won’t be able to know\r\nDialogue: 0,0:05:10.04,0:05:11.45,yin,,0,0,0,, 它们需要实现这些方法 \\N{\\fs12}that they’re supposed to implement them.\r\nDialogue: 0,0:05:11.45,0:05:12.91,yin,,0,0,0,, 它们依然可以重写这些方法 \\N{\\fs12}Okay. They could still override them\r\nDialogue: 0,0:05:12.91,0:05:15.33,yin,,0,0,0,, 如果有人偷偷告诉它们了 \\N{\\fs12}as someone sneakily told them about it,\r\nDialogue: 0,0:05:15.34,0:05:16.98,yin,,0,0,0,, 但是我们不想要偷偷摸摸的 \\N{\\fs12}but we don’t want any sneaking around here,\r\nDialogue: 0,0:05:17.13,0:05:18.81,yin,,0,0,0,, 我们想让 createDeck 变成公有的 \\N{\\fs12}we want createDeck to be public,\r\nDialogue: 0,0:05:18.81,0:05:20.61,yin,,0,0,0,, 所以我要复制 createDeck 方法 \\N{\\fs12}so I’m going to copy createDeck\r\nDialogue: 0,0:05:20.74,0:05:24.23,yin,,0,0,0,, 把它放到公有接口中 \\N{\\fs12}and put it in our public interface.\r\nDialogue: 0,0:05:24.49,0:05:27.60,yin,,0,0,0,, 这个抽象注释可以留着 \\N{\\fs12}I’m going to leave that thing there that says it’s abstract.\r\nDialogue: 0,0:05:28.06,0:05:30.91,yin,,0,0,0,, 我还要在这里添加一条类的注释 \\N{\\fs12}Okay. I’m also going to put a class comment here\r\nDialogue: 0,0:05:31.59,0:05:35.32,yin,,0,0,0,, 写上 抽象类 \\N{\\fs12}that says abstract class,\r\nDialogue: 0,0:05:36.75,0:05:42.37,yin,,0,0,0,, 必须按照下面要求实现方法 \\N{\\fs12}you know, must implement methods as described below,\r\nDialogue: 0,0:05:42.37,0:05:43.37,yin,,0,0,0,, 或者类似的说明 \\N{\\fs12}or something like that,\r\nDialogue: 0,0:05:43.37,0:05:45.14,yin,,0,0,0,, 这样有人看到这个类时 \\N{\\fs12}so that when people come to this class\r\nDialogue: 0,0:05:45.14,0:05:46.75,yin,,0,0,0,, 就会知道 这个类是抽象的 \\N{\\fs12}they know ooh, this class is abstract.\r\nDialogue: 0,0:05:46.91,0:05:47.54,yin,,0,0,0,, 转到下面 \\N{\\fs12}And then we go down here,\r\nDialogue: 0,0:05:47.54,0:05:49.99,yin,,0,0,0,, 通常情况下 我还会在这里添加注释 \\N{\\fs12}and then a lot of times I’ll put right here,\r\nDialogue: 0,0:05:50.91,0:05:52.78,yin,,0,0,0,, 比如 protected 受保护的 \\N{\\fs12}maybe the word protected\r\nDialogue: 0,0:05:53.49,0:05:57.87,yin,,0,0,0,, 或者 for subclasses 用于超类 之类的 \\N{\\fs12}or for subclasses, something like that\r\nDialogue: 0,0:05:58.07,0:06:01.10,yin,,0,0,0,, 以注释来区分两种方法 \\N{\\fs12}to kind of make it clear the difference between methods\r\nDialogue: 0,0:06:01.10,0:06:02.54,yin,,0,0,0,, 一种是仅适用于子类的方法 \\N{\\fs12}that are just for subclassers,\r\nDialogue: 0,0:06:02.54,0:06:05.92,yin,,0,0,0,, 需要重写之类的 \\N{\\fs12}that they’re going to override or something like that,\r\nDialogue: 0,0:06:06.02,0:06:07.73,yin,,0,0,0,, 另一种是公有方法 \\N{\\fs12}versus public methods\r\nDialogue: 0,0:06:07.74,0:06:09.42,yin,,0,0,0,, 可能要放到上面这里 \\N{\\fs12}which would probably go up here,\r\nDialogue: 0,0:06:09.58,0:06:13.18,yin,,0,0,0,, 是使用这个卡牌游戏控制器的对象要调用的方法 \\N{\\fs12}which someone using this card game controller would call.\r\nDialogue: 0,0:06:14.01,0:06:17.42,yin,,0,0,0,, 当然了 这里有一个错误 因为 Deck 没有声明 \\N{\\fs12}Okay. So of course, we have an error here because of deck,\r\nDialogue: 0,0:06:17.63,0:06:19.64,yin,,0,0,0,, 所以我们需要导入 Deck\\N{\\fs12}so we have to import deck,\r\nDialogue: 0,0:06:19.71,0:06:22.93,yin,,0,0,0,, 但是这样比导入 PlayingCardDeck 要好多了 \\N{\\fs12}but that’s a lot better than importing PlayingCardDeck,\r\nDialogue: 0,0:06:23.12,0:06:26.17,yin,,0,0,0,, 因为目前我们并没有绑定某种卡牌 \\N{\\fs12}because we are not now tied to any kind of deck,\r\nDialogue: 0,0:06:26.18,0:06:28.97,yin,,0,0,0,, 任何卡牌都可以 \\N{\\fs12}any deck of cards will do. Okay.\r\nDialogue: 0,0:06:29.99,0:06:30.90,yin,,0,0,0,, 明白吗 \\N{\\fs12}That make sense?\r\nDialogue: 0,0:06:31.06,0:06:32.92,yin,,0,0,0,, 现在 我们有了这个抽象类 \\N{\\fs12}So now that we have this abstract class\r\nDialogue: 0,0:06:32.92,0:06:34.92,yin,,0,0,0,, 它有一个这样的方法 需要实现 \\N{\\fs12}that has this method that has to be implemented,\r\nDialogue: 0,0:06:35.04,0:06:38.25,yin,,0,0,0,, 我们创建一个它的具体子类 \\N{\\fs12}let’s make that concrete subclass of this\r\nDialogue: 0,0:06:38.36,0:06:40.02,yin,,0,0,0,, 实现 createDeck 方法 \\N{\\fs12}that implements createDeck.\r\nDialogue: 0,0:06:40.25,0:06:43.85,yin,,0,0,0,, 和新建类的方法一样 \\N{\\fs12}Okay. And we just do that in the same way we create any new class.\r\nDialogue: 0,0:06:43.99,0:06:46.02,yin,,0,0,0,, 选择文件菜单下 新建菜单中的文件 \\N{\\fs12}Right. File menu, new file\r\nDialogue: 0,0:06:46.76,0:06:49.50,yin,,0,0,0,, 选择 Objective-C 类 \\N{\\fs12}and then we’re going to say we want an objective-c class.\r\nDialogue: 0,0:06:49.99,0:06:51.74,yin,,0,0,0,, 可以在这里指定超类 \\N{\\fs12}We can specify the superclass here\r\nDialogue: 0,0:06:51.74,0:06:54.74,yin,,0,0,0,, 输入 CardGameViewController\\N{\\fs12}is gonna be CardGameViewController,\r\nDialogue: 0,0:06:55.00,0:06:58.38,yin,,0,0,0,, 我要叫这个类 PlayingCardGameViewController\\N{\\fs12}and I’m going to call this class PlayingCardGameViewController,\r\nDialogue: 0,0:06:58.88,0:07:00.55,yin,,0,0,0,, 因为这就是它的功能 \\N{\\fs12}okay, because that’s what it’s going to do.\r\nDialogue: 0,0:07:00.66,0:07:02.32,yin,,0,0,0,, 它是一个 CardGameViewController\\N{\\fs12}It’s going to be a CardGameViewController,\r\nDialogue: 0,0:07:02.32,0:07:04.56,yin,,0,0,0,, 但是它是具体的 \\N{\\fs12}but it’s going to have the concrete thing\r\nDialogue: 0,0:07:04.61,0:07:06.95,yin,,0,0,0,, 它在游戏中使用的是扑克牌 \\N{\\fs12}that it is going to play with playing cards.\r\nDialogue: 0,0:07:07.31,0:07:08.29,yin,,0,0,0,, 点击下一步 \\N{\\fs12}So, I hit next.\r\nDialogue: 0,0:07:08.39,0:07:12.40,yin,,0,0,0,, 和其他视图控制器放在一个目录下 \\N{\\fs12}I’m going to put it in the same place as my other view controller.\r\nDialogue: 0,0:07:12.51,0:07:13.10,yin,,0,0,0,, 出来了 \\N{\\fs12}Here it is.\r\nDialogue: 0,0:07:13.10,0:07:16.85,yin,,0,0,0,, 可以看到系统自动添加了一些视图控制器生命周期的代码 \\N{\\fs12}You can see a couple of view controller lifecycle stubs in here.\r\nDialogue: 0,0:07:16.96,0:07:18.00,yin,,0,0,0,, 我不需要这些 \\N{\\fs12}I don’t need those.\r\nDialogue: 0,0:07:18.10,0:07:20.70,yin,,0,0,0,, 这个方法实际上是指定初始化方法 \\N{\\fs12}This is actually the designated initializer.\r\nDialogue: 0,0:07:20.70,0:07:22.25,yin,,0,0,0,, 我也不确定为什么要把它放在这 \\N{\\fs12}I’m not sure why it throws that in there,\r\nDialogue: 0,0:07:22.26,0:07:24.73,yin,,0,0,0,, 因为现在我们都从 storyboard 开始执行 \\N{\\fs12}because nowadays we pull these things out of storyboard.\r\nDialogue: 0,0:07:24.88,0:07:28.69,yin,,0,0,0,, 我们会用 awakeFromNib viewDidLoad 更好 \\N{\\fs12}We would use awakeFromNib, or even better, viewDidLoad. Okay.\r\nDialogue: 0,0:07:28.83,0:07:30.12,yin,,0,0,0,, 所以我们也不需要这个方法 \\N{\\fs12}So we don’t want that either.\r\nDialogue: 0,0:07:30.55,0:07:33.86,yin,,0,0,0,, 现在这个具体子类看起来就很整洁了 \\N{\\fs12}So we have this nice concrete subclass,\r\nDialogue: 0,0:07:33.88,0:07:37.30,yin,,0,0,0,, 它只需要实现 createDeck\\N{\\fs12}and all this thing needs to do is implement createDeck.\r\nDialogue: 0,0:07:38.21,0:07:38.62,yin,,0,0,0,, 对吧 \\N{\\fs12}Okay.\r\nDialogue: 0,0:07:39.07,0:07:40.91,yin,,0,0,0,, 我来实现一下 这里返回–\\N{\\fs12}So I’m going to do that. I’m going to return –\r\nDialogue: 0,0:07:41.11,0:07:45.59,yin,,0,0,0,, 这里确实需要导入 PlayingCardDeck\\N{\\fs12}Okay. Here I do need to import PlayingCardDeck,\r\nDialogue: 0,0:07:45.84,0:07:46.73,yin,,0,0,0,, 但在这里导入没问题 \\N{\\fs12}but that’s okay here,\r\nDialogue: 0,0:07:46.73,0:07:49.13,yin,,0,0,0,, 因为这个类就是用于扑克牌的 \\N{\\fs12}because that this class is for playing cards.\r\nDialogue: 0,0:07:49.13,0:07:50.18,yin,,0,0,0,, 它就是做这个的 \\N{\\fs12}That’s what it’s for,\r\nDialogue: 0,0:07:50.28,0:07:51.44,yin,,0,0,0,, 所以这样做没问题 \\N{\\fs12}so I have no problem doing that.\r\nDialogue: 0,0:07:52.21,0:07:53.06,yin,,0,0,0,, 我们再回到下面这里 \\N{\\fs12}So let’s go down here –\r\nDialogue: 0,0:07:53.45,0:07:57.52,yin,,0,0,0,,[PlayingCardDeck alloc] init\\N{\\fs12}PlayingCardDeck alloc init. Okay.\r\nDialogue: 0,0:07:57.95,0:08:00.45,yin,,0,0,0,, 好了 我创建了一个具体子类 \\N{\\fs12}Bingo, I’ve created a concrete subclass.\r\nDialogue: 0,0:08:00.66,0:08:01.72,yin,,0,0,0,, 可以用了 \\N{\\fs12}It’s ready to go.\r\nDialogue: 0,0:08:02.65,0:08:06.85,yin,,0,0,0,, 如果我回到 storyboard 运行一下 \\N{\\fs12}If I were to go back to my storyboard here and run –\r\nDialogue: 0,0:08:06.86,0:08:07.99,yin,,0,0,0,, 我们来运行一下 \\N{\\fs12}let’s go ahead and run this.\r\nDialogue: 0,0:08:08.13,0:08:09.84,yin,,0,0,0,, 我们何不在设备上运行一下呢 \\N{\\fs12}We’ll do this on the device, why not.\r\nDialogue: 0,0:08:10.53,0:08:11.28,yin,,0,0,0,, 看看会发生什么 \\N{\\fs12}See what happens.\r\nDialogue: 0,0:08:11.79,0:08:13.80,yin,,0,0,0,, 有谁可以预测一下运行时会发生什么吗 \\N{\\fs12}Can anyone predict what’s going to happen if I run this?\r\nDialogue: 0,0:08:14.46,0:08:15.14,yin,,0,0,0,, 会正常运行吗 \\N{\\fs12}Is it going to work?\r\nDialogue: 0,0:08:17.30,0:08:18.00,yin,,0,0,0,, 没人猜一下吗 \\N{\\fs12}No guesses?\r\nDialogue: 0,0:08:18.68,0:08:19.78,yin,,0,0,0,, 这里是不能正常运行的 \\N{\\fs12}It’s not going to work here,\r\nDialogue: 0,0:08:19.80,0:08:21.22,yin,,0,0,0,, 我看到有人摇头了 \\N{\\fs12}I see heads shaking.\r\nDialogue: 0,0:08:21.22,0:08:22.35,yin,,0,0,0,, 应用不能正常运行 \\N{\\fs12}No, it’s not going to work.\r\nDialogue: 0,0:08:22.54,0:08:24.92,yin,,0,0,0,, 实际上 它不能正常运行 \\N{\\fs12}And in fact, it isn’t going to work,\r\nDialogue: 0,0:08:26.22,0:08:27.42,yin,,0,0,0,, 我们看看它会怎样 \\N{\\fs12}and we’ll see what it does.\r\nDialogue: 0,0:08:27.42,0:08:29.44,yin,,0,0,0,, 我试着翻开卡牌 \\N{\\fs12}Okay, so I’ m trying to flip cards\r\nDialogue: 0,0:08:29.45,0:08:32.81,yin,,0,0,0,, 现在什么牌都没有 对吧 \\N{\\fs12}and all these cards there’s no cards here. Okay.\r\nDialogue: 0,0:08:33.50,0:08:35.40,yin,,0,0,0,, 我刚才创建了具体子类呀 \\N{\\fs12}I just made that concrete subclass,\r\nDialogue: 0,0:08:35.40,0:08:37.17,yin,,0,0,0,, 怎么回事 为什么不能用呢 \\N{\\fs12}what’s going on? How come it’s not working?\r\nDialogue: 0,0:08:37.85,0:08:40.13,yin,,0,0,0,,storyboard 还和抽象控制器连在一起 \\N{\\fs12}The storyboard’s still tied to the abstract controller.\r\nDialogue: 0,0:08:40.15,0:08:40.87,yin,,0,0,0,, 没错 \\N{\\fs12}That’s right.\r\nDialogue: 0,0:08:40.88,0:08:43.54,yin,,0,0,0,, 原因就是 这里的这个 storyboard\\N{\\fs12}So the answer is my storyboard right here,\r\nDialogue: 0,0:08:43.62,0:08:47.87,yin,,0,0,0,, 如果看这里 这个控制器还是抽象的那个 \\N{\\fs12}if I look at this, this controller is still the abstract one.\r\nDialogue: 0,0:08:48.06,0:08:50.16,yin,,0,0,0,, 所以它当然不能正常运行 \\N{\\fs12}So, it’s actually properly not working.\r\nDialogue: 0,0:08:50.49,0:08:52.88,yin,,0,0,0,, 因为它是抽象的 \\N{\\fs12}Okay. Because it is abstract,\r\nDialogue: 0,0:08:53.07,0:08:55.65,yin,,0,0,0,, 没有与之关联的卡牌 \\N{\\fs12}it has no cards that are associated with it\r\nDialogue: 0,0:08:55.77,0:08:56.59,yin,,0,0,0,, 没有特定 deck\\N{\\fs12}because it has not deck,\r\nDialogue: 0,0:08:56.84,0:08:57.42,yin,,0,0,0,, 就不能运行 \\N{\\fs12}so it doesn’t work.\r\nDialogue: 0,0:08:57.42,0:08:59.83,yin,,0,0,0,, 问题是 我们如何告诉 storyboard\\N{\\fs12}So the question is how do we tell our storyboard\r\nDialogue: 0,0:08:59.83,0:09:03.37,yin,,0,0,0,, 我们想让这个控制器使用具体子类 \\N{\\fs12}that we want this controller to use the concrete subclass\r\nDialogue: 0,0:09:03.44,0:09:05.56,yin,,0,0,0,, 而不是抽象超类呢 \\N{\\fs12}instead of using that abstract superclass?\r\nDialogue: 0,0:09:05.74,0:09:08.34,yin,,0,0,0,, 答案很简单 我们只要选中它 \\N{\\fs12}The answer is very simple, we just select it.\r\nDialogue: 0,0:09:08.34,0:09:11.30,yin,,0,0,0,, 我们可以点击下面的图标进行选中 \\N{\\fs12}We can select a controller either by selecting here,\r\nDialogue: 0,0:09:11.51,0:09:14.37,yin,,0,0,0,, 直接点击这里时要注意 \\N{\\fs12}be a little careful when you click here, it didn’t–\r\nDialogue: 0,0:09:14.43,0:09:16.98,yin,,0,0,0,, 这样实际上选择的是顶级视图 \\N{\\fs12}this actually selected the top level view.\r\nDialogue: 0,0:09:17.15,0:09:19.86,yin,,0,0,0,, 正确选中时 边缘会有蓝色边框 \\N{\\fs12}You can see, we need the blue border around the edge.\r\nDialogue: 0,0:09:20.39,0:09:22.57,yin,,0,0,0,, 实际上 在选择元素时 \\N{\\fs12}There’s actually a little trick that you can do\r\nDialogue: 0,0:09:23.21,0:09:25.59,yin,,0,0,0,, 可以使用一个小技巧 \\N{\\fs12}when you’re selecting things.\r\nDialogue: 0,0:09:26.09,0:09:28.03,yin,,0,0,0,, 让我想想是哪个键 \\N{\\fs12}Let’s see if I can remember which one it is.\r\nDialogue: 0,0:09:29.27,0:09:32.78,yin,,0,0,0,, 按住 command 单击 是什么呢 出来了 \\N{\\fs12}Go to command, click. Oh, what is that? There is it.\r\nDialogue: 0,0:09:33.71,0:09:37.18,yin,,0,0,0,, 按住 Shift 单击吗 不是 是按住 control 和 shift 键单击 \\N{\\fs12}Shift click? No. Okay. Control, shift, click.\r\nDialogue: 0,0:09:37.58,0:09:40.03,yin,,0,0,0,, 当你在某个地方按住 control 和 shift 键单击时 \\N{\\fs12}When you go to control, shift, click on something,\r\nDialogue: 0,0:09:40.14,0:09:43.03,yin,,0,0,0,, 会显示出鼠标指针下的所有元素 \\N{\\fs12}it will actually show you all the things that are under your mouse.\r\nDialogue: 0,0:09:43.32,0:09:45.42,yin,,0,0,0,, 所以如果我在这里按住 control 和 shift 键单击时 \\N{\\fs12}So actually if I control, shift, click here –\r\nDialogue: 0,0:09:45.94,0:09:47.37,yin,,0,0,0,, 对吗 对的 \\N{\\fs12}is that what it is? Yeah.\r\nDialogue: 0,0:09:47.99,0:09:49.35,yin,,0,0,0,, 会显示出按钮 \\N{\\fs12}Then it’s showing me the button,\r\nDialogue: 0,0:09:49.35,0:09:50.14,yin,,0,0,0,, 它就在鼠标指针下面 \\N{\\fs12}which is under right under my mouse,\r\nDialogue: 0,0:09:50.15,0:09:53.27,yin,,0,0,0,, 然后是视图 然后是后面的控制器 \\N{\\fs12}then the view, and then the controller behind it,\r\nDialogue: 0,0:09:53.62,0:09:55.20,yin,,0,0,0,, 现在我可以直接选择 \\N{\\fs12}and so now I can pick which one of these\r\nDialogue: 0,0:09:55.21,0:09:58.06,yin,,0,0,0,, 我想要选择的元素 \\N{\\fs12}I actually meant to select like that. Okay.\r\nDialogue: 0,0:09:58.26,0:10:00.98,yin,,0,0,0,, 不是 control 和 shift 就是 command 和 shift\\N{\\fs12}So I think it’s control, shift, or something command shift.\r\nDialogue: 0,0:10:00.98,0:10:02.70,yin,,0,0,0,, 我老是记不住 记性不好 \\N{\\fs12}I can never remember it. Loss of memory.\r\nDialogue: 0,0:10:03.24,0:10:04.79,yin,,0,0,0,, 我的键盘和现在用的这个也不太一样 \\N{\\fs12}And my keyboard’s slightly different in this one.\r\nDialogue: 0,0:10:05.01,0:10:06.57,yin,,0,0,0,, 不管怎样 现在我选中了它 \\N{\\fs12}So anyway, so now I’ve got it selected,\r\nDialogue: 0,0:10:06.57,0:10:08.06,yin,,0,0,0,, 出现了蓝色边框 \\N{\\fs12}it’s got this blue thing around it,\r\nDialogue: 0,0:10:08.06,0:10:09.40,yin,,0,0,0,, 现在我要检查它 \\N{\\fs12}so now I’m going to inspect it.\r\nDialogue: 0,0:10:09.49,0:10:10.95,yin,,0,0,0,, 打开检查器 \\N{\\fs12}Okay. I’m going to bring up the inspector,\r\nDialogue: 0,0:10:11.08,0:10:13.22,yin,,0,0,0,, 但是我不需要属性检查器 \\N{\\fs12}but I don’t want the attributes inspector.\r\nDialogue: 0,0:10:13.62,0:10:17.17,yin,,0,0,0,, 我要检查的是它的标识符 \\N{\\fs12}Okay. I’m going to inspect the identity of this thing,\r\nDialogue: 0,0:10:17.17,0:10:18.98,yin,,0,0,0,, 转到标识符检查器 \\N{\\fs12}so I go to the identity inspector.\r\nDialogue: 0,0:10:18.98,0:10:20.11,yin,,0,0,0,, 就是这个 \\N{\\fs12}That’s this one right here.\r\nDialogue: 0,0:10:20.43,0:10:22.46,yin,,0,0,0,, 在标识符检查器中 \\N{\\fs12}Okay. And if you look at the identity inspector,\r\nDialogue: 0,0:10:22.46,0:10:23.74,yin,,0,0,0,, 如果选中了一个控制器 \\N{\\fs12}if you have a controller selected,\r\nDialogue: 0,0:10:23.74,0:10:27.63,yin,,0,0,0,, 最上面一项就是这个控制器所属的类 \\N{\\fs12}the very top thing is what class is this controller.\r\nDialogue: 0,0:10:27.65,0:10:29.77,yin,,0,0,0,, 可以看到现在是 CardGameViewController\\N{\\fs12}You can see that right now it’s CardGameViewController,\r\nDialogue: 0,0:10:29.77,0:10:31.09,yin,,0,0,0,, 抽象超类 \\N{\\fs12}the abstract superclass.\r\nDialogue: 0,0:10:31.32,0:10:32.65,yin,,0,0,0,, 如果我点击这里 \\N{\\fs12}So if I click here,\r\nDialogue: 0,0:10:32.65,0:10:34.55,yin,,0,0,0,, 我可以直接输入 PlayingCardViewController\\N{\\fs12}I can either just type PlayingCardViewController,\r\nDialogue: 0,0:10:34.55,0:10:36.45,yin,,0,0,0,, 或者从列表中进行选择 \\N{\\fs12}or it could be in the list right here.\r\nDialogue: 0,0:10:36.45,0:10:37.61,yin,,0,0,0,, 滚动一下 \\N{\\fs12}So if I scroll around\r\nDialogue: 0,0:10:37.62,0:10:39.45,yin,,0,0,0,, 可以看到 iOS 中的其他类 \\N{\\fs12}you can see some other classes that are in iOS,\r\nDialogue: 0,0:10:39.64,0:10:41.59,yin,,0,0,0,,PlayingCardViewController 在这里 \\N{\\fs12}and here’s our PlayingCard one right there.\r\nDialogue: 0,0:10:41.93,0:10:43.25,yin,,0,0,0,, 如果我选择它 \\N{\\fs12}If I select that one,\r\nDialogue: 0,0:10:43.40,0:10:44.53,yin,,0,0,0,, 现在再运行时 \\N{\\fs12}now when we run,\r\nDialogue: 0,0:10:46.32,0:10:49.09,yin,,0,0,0,, 它就会使用那个具体子类 \\N{\\fs12}it’ll be using that concrete subclass,\r\nDialogue: 0,0:10:49.12,0:10:51.64,yin,,0,0,0,, 在游戏中发出扑克牌 \\N{\\fs12}which will be dealing out playing cards in our game,\r\nDialogue: 0,0:10:51.89,0:10:53.85,yin,,0,0,0,, 所以应用就又可以正常运行了 \\N{\\fs12}so we’re back to having this work.\r\nDialogue: 0,0:10:54.81,0:10:55.22,yin,,0,0,0,, 对吧 \\N{\\fs12}Okay.\r\nDialogue: 0,0:10:55.86,0:10:57.14,yin,,0,0,0,, 大家都明白刚才的操作吗 \\N{\\fs12}Everybody understand what we did there?\r\nDialogue: 0,0:10:57.72,0:11:01.07,yin,,0,0,0,, 你需要设置控制器的类 \\N{\\fs12}Now you’ll have to do this — setting the class of controllers,\r\nDialogue: 0,0:11:01.16,0:11:02.92,yin,,0,0,0,, 如果应用中有多个视图控制器 \\N{\\fs12}and this is especially common to have to do\r\nDialogue: 0,0:11:02.92,0:11:04.58,yin,,0,0,0,, 这个操作是特别常见的 \\N{\\fs12}when you have multiple view controllers,\r\nDialogue: 0,0:11:04.64,0:11:06.24,yin,,0,0,0,, 当你拖出一个新的视图控制器时 \\N{\\fs12}because when you drag out a new view controller,\r\nDialogue: 0,0:11:06.28,0:11:07.86,yin,,0,0,0,, 需要选择它的类 \\N{\\fs12}you’ll need to say what class it is.\r\nDialogue: 0,0:11:08.17,0:11:10.29,yin,,0,0,0,, 否则你就不能将输出口和操作 \\N{\\fs12}Okay. Otherwise, you won’t be able to hook up your outlets and actions\r\nDialogue: 0,0:11:10.32,0:11:12.88,yin,,0,0,0,, 连接到你的 UIViewController 的子类上了 \\N{\\fs12}to your subclass of UIViewController.\r\nDialogue: 0,0:11:13.69,0:11:16.10,yin,,0,0,0,, 好的 这会帮你们开个头 \\N{\\fs12}All right. So, that’ll get you started on that,\r\nDialogue: 0,0:11:16.10,0:11:18.98,yin,,0,0,0,, 你们需要再添加一个游戏 \\N{\\fs12}and again, you’re going to have another game.\r\nDialogue: 0,0:11:19.84,0:11:20.92,yin,,0,0,0,, 两个游戏 \\N{\\fs12}Both of them are going –\r\nDialogue: 0,0:11:20.93,0:11:23.34,yin,,0,0,0,, 你的应用中的两个游戏应该都可以运行 \\N{\\fs12}your app is going to be able to play either game.\r\nDialogue: 0,0:11:24.33,0:11:26.31,yin,,0,0,0,, 好的 我要演示的就是这些 \\N{\\fs12}All right. That’s it. That’s all I wanted to show there.\r\nDialogue: 0,0:11:27.03,0:11:30.45,yin,,0,0,0,, 我们回来开始讲多个 MVC 的内容 \\N{\\fs12}So let’s go back and start talking about multiple MVCs now.\r\nDialogue: 0,0:11:31.01,0:11:33.27,yin,,0,0,0,, 我们为什么需要多个 MVC 呢 \\N{\\fs12}Why do we want multiple MVCs?\r\nDialogue: 0,0:11:33.34,0:11:34.51,yin,,0,0,0,, 当然是因为我们可以–\\N{\\fs12}Obviously, so we can have more –\r\nDialogue: 0,0:11:34.51,0:11:35.23,yin,,0,0,0,, 抱歉 有问题吗 \\N{\\fs12}Oh, sorry, question.\r\nDialogue: 0,0:11:35.52,0:11:36.79,yin,,0,0,0,,- 很短的问题 - 说吧 \\N{\\fs12}- Just really quickly. – Yeah.\r\nDialogue: 0,0:11:36.81,0:11:38.98,yin,,0,0,0,, 假如说 如果你 \\N{\\fs12}So if you — if you, say,\r\nDialogue: 0,0:11:39.19,0:11:42.42,yin,,0,0,0,, 将一个方法与 storyboard 中的某个元素绑定在一起 \\N{\\fs12}bind a method to something in the storyboard\r\nDialogue: 0,0:11:42.73,0:11:45.28,yin,,0,0,0,, 和抽象类绑定在一起了 然后你重写了它 \\N{\\fs12}and you bind it in the abstract class and then you override it,\r\nDialogue: 0,0:11:45.28,0:11:48.74,yin,,0,0,0,, 是否会自动继承相同的监听者呢 \\N{\\fs12}does it automatically inherit the same listener steps?\r\nDialogue: 0,0:11:48.75,0:11:49.60,yin,,0,0,0,, 这是一个好问题 \\N{\\fs12}Yeah. So that’s a good question.\r\nDialogue: 0,0:11:49.60,0:11:52.16,yin,,0,0,0,, 问题是 如果我有一个输出口或者操作 \\N{\\fs12}The question is, what if I have an outlet or an action\r\nDialogue: 0,0:11:52.32,0:11:56.31,yin,,0,0,0,, 将它连接到了抽象超类中的 \\N{\\fs12}that I’ve connected up to some outlet or action\r\nDialogue: 0,0:11:56.32,0:11:57.96,yin,,0,0,0,, 某个输出口或操作上 \\N{\\fs12}that’s in your abstract superclass,\r\nDialogue: 0,0:11:58.17,0:12:00.56,yin,,0,0,0,, 然后我将它的类改为了某个具体子类 \\N{\\fs12}and then I set the class to be a concrete subclass,\r\nDialogue: 0,0:12:00.71,0:12:02.58,yin,,0,0,0,, 输出口和操作还可以正常使用吗 \\N{\\fs12}will all my outlets and actions still work?\r\nDialogue: 0,0:12:02.95,0:12:04.37,yin,,0,0,0,, 是的 它们还会正常工作的 \\N{\\fs12}Yes, in fact they will still work.\r\nDialogue: 0,0:12:04.47,0:12:06.55,yin,,0,0,0,, 完全没问题 实际上 \\N{\\fs12}They’ll work great, and in fact, if you –\r\nDialogue: 0,0:12:06.56,0:12:09.69,yin,,0,0,0,, 如果你有抽象超类的代码 像这里一样 \\N{\\fs12}if you have the code for the abstract superclass like we do here,\r\nDialogue: 0,0:12:09.84,0:12:12.26,yin,,0,0,0,, 实际上 你可以打开 storyboard\\N{\\fs12}you can actually have your storyboard up,\r\nDialogue: 0,0:12:12.38,0:12:15.28,yin,,0,0,0,, 在辅助编辑器中打开抽象超类 \\N{\\fs12}and in the assistant editor, open up the abstract superclass\r\nDialogue: 0,0:12:15.28,0:12:17.23,yin,,0,0,0,, 然后连接输出口和操作 \\N{\\fs12}and you can wire up outlets and actions,\r\nDialogue: 0,0:12:17.69,0:12:19.05,yin,,0,0,0,, 甚至私有的也可以 \\N{\\fs12}okay, even private ones.\r\nDialogue: 0,0:12:19.59,0:12:22.55,yin,,0,0,0,, 抽象超类中的输出口和操作不一定要是私有的 \\N{\\fs12}Something doesn’t have to be private in the abstract superclass,\r\nDialogue: 0,0:12:22.55,0:12:25.32,yin,,0,0,0,, 都可以进行连接 \\N{\\fs12}the outlets and actions, to wire it up. Okay.\r\nDialogue: 0,0:12:25.77,0:12:29.80,yin,,0,0,0,, 如果辅助编辑器的右侧是自动模式 \\N{\\fs12}Now, if you have the right side of your assistant editor set on automatic,\r\nDialogue: 0,0:12:29.80,0:12:31.52,yin,,0,0,0,, 你需要切换到手动 \\N{\\fs12}you’ll have to switch it to manual\r\nDialogue: 0,0:12:31.52,0:12:33.48,yin,,0,0,0,, 才能选择抽象超类 \\N{\\fs12}to go and pick the abstract superclass,\r\nDialogue: 0,0:12:33.59,0:12:35.81,yin,,0,0,0,, 因为自动模式下显示的是具体子类 \\N{\\fs12}because automatic’s going to want to show you the concrete one,\r\nDialogue: 0,0:12:36.24,0:12:37.74,yin,,0,0,0,, 但是和我们这里的示例一样 \\N{\\fs12}but like in our example here,\r\nDialogue: 0,0:12:37.74,0:12:42.92,yin,,0,0,0,, 我们不能将卡牌与 PlayingCardViewController 相连接 \\N{\\fs12}we can’t wire those cards up to PlayingCardViewController,\r\nDialogue: 0,0:12:42.93,0:12:45.10,yin,,0,0,0,, 因为它没有卡牌按钮对应的输出口 \\N{\\fs12}because it doesn’t have that outlet for card buttons.\r\nDialogue: 0,0:12:45.39,0:12:47.18,yin,,0,0,0,, 那是在它的抽象超类中的 \\N{\\fs12}That’s in its abstract superclass.\r\nDialogue: 0,0:12:47.69,0:12:49.93,yin,,0,0,0,, 明白吗 所以我们只要打开抽象超类 \\N{\\fs12}All right. So we just open up the abstract superclass,\r\nDialogue: 0,0:12:49.95,0:12:50.81,yin,,0,0,0,, 然后进行连接 \\N{\\fs12}and we can wire it up.\r\nDialogue: 0,0:12:50.82,0:12:53.54,yin,,0,0,0,, 换句话说 Xcode 很智能 知道继承关系 \\N{\\fs12}In other words, Xcode is smart about knowing the inheritance,\r\nDialogue: 0,0:12:53.56,0:12:57.82,yin,,0,0,0,, 允许你与抽象超类 \\N{\\fs12}to let you wire up to abstract superclasses,\r\nDialogue: 0,0:12:57.83,0:12:59.61,yin,,0,0,0,, 甚至具体超类相连接 \\N{\\fs12}or even concrete superclasses,\r\nDialogue: 0,0:13:00.39,0:13:01.43,yin,,0,0,0,, 即便它们是私有的 \\N{\\fs12}and even if they’re private.\r\nDialogue: 0,0:13:01.73,0:13:05.07,yin,,0,0,0,, 输出口和操作是被当作私有内容的 \\N{\\fs12}So outlet and action connecting is kind of considered a private thing.\r\nDialogue: 0,0:13:05.48,0:13:06.40,yin,,0,0,0,, 是私有的 \\N{\\fs12}All right. It’s kind of a private thing.\r\nDialogue: 0,0:13:06.40,0:13:09.00,yin,,0,0,0,, 不需要都设成公有的 也可以进行连接 \\N{\\fs12}You don’t have to make all those public to be able to connect those.\r\nDialogue: 0,0:13:09.19,0:13:12.25,yin,,0,0,0,, 但是调用方法是公有的 \\N{\\fs12}But calling methods is something that’s public.\r\nDialogue: 0,0:13:12.28,0:13:14.40,yin,,0,0,0,, 如果你想调用超类中的方法 \\N{\\fs12}Okay. If you want to call a method in the superclass,\r\nDialogue: 0,0:13:14.64,0:13:15.99,yin,,0,0,0,, 需要设置为公有的 \\N{\\fs12}that needs to be made public,\r\nDialogue: 0,0:13:16.21,0:13:17.53,yin,,0,0,0,, 因为没有保护 \\N{\\fs12}because there’s no protected.\r\nDialogue: 0,0:13:18.17,0:13:20.18,yin,,0,0,0,, 明白吗 好问题 \\N{\\fs12}Okay. Good question.\r\nDialogue: 0,0:13:21.22,0:13:22.61,yin,,0,0,0,, 好了 接着讲多 MVC\\N{\\fs12}All right so, multiple MVCs.\r\nDialogue: 0,0:13:22.74,0:13:24.73,yin,,0,0,0,, 我们为什么需要多个 MVC 呢 \\N{\\fs12}Why we want multiple MVCs?\r\nDialogue: 0,0:13:24.73,0:13:26.56,yin,,0,0,0,, 显然是为了向应用中添加更多内容 \\N{\\fs12}Obviously, we can put more stuff in our app.\r\nDialogue: 0,0:13:26.83,0:13:29.12,yin,,0,0,0,, 怎么做呢 其实非常简单 \\N{\\fs12}How do we do it? It’s very simple actually,\r\nDialogue: 0,0:13:29.18,0:13:31.77,yin,,0,0,0,, 只要转到对象面板 \\N{\\fs12}you just go to the object palette –\r\nDialogue: 0,0:13:31.77,0:13:34.14,yin,,0,0,0,, 就是拖出按钮和滑动条的地方 \\N{\\fs12}the same place you drag a button or a slider out of,\r\nDialogue: 0,0:13:34.22,0:13:35.95,yin,,0,0,0,, 从那里拖出一个视图控制器 \\N{\\fs12}and you drag out a view controller,\r\nDialogue: 0,0:13:36.19,0:13:38.46,yin,,0,0,0,, 这样拖出时 它是一个通用的视图控制器 \\N{\\fs12}and when you drag it out, it’ll be a generic view controller.\r\nDialogue: 0,0:13:38.46,0:13:40.81,yin,,0,0,0,, 也就是说它的类是 UIViewController\\N{\\fs12}In other words, its class will be UIViewController\r\nDialogue: 0,0:13:40.83,0:13:42.10,yin,,0,0,0,, 显然它会是空白的 \\N{\\fs12}and it’ll be blank obviously.\r\nDialogue: 0,0:13:42.37,0:13:45.42,yin,,0,0,0,, 然后创建 UIViewController 的子类 \\N{\\fs12}Then you go create your subclass of UIViewController.\r\nDialogue: 0,0:13:45.57,0:13:47.63,yin,,0,0,0,, 在我刚才做过的示例中 \\N{\\fs12}Okay. In this case, in the demo I just did\r\nDialogue: 0,0:13:47.64,0:13:49.76,yin,,0,0,0,, 我创建了一个已有类的子类 \\N{\\fs12}I created a subclass of a class I already had,\r\nDialogue: 0,0:13:49.76,0:13:52.48,yin,,0,0,0,, 但是你可以直接创建 UIViewController 的子类 \\N{\\fs12}but you can create this direct subclass of UIViewController,\r\nDialogue: 0,0:13:52.68,0:13:55.10,yin,,0,0,0,, 然后用属性检查器查看它的属性 \\N{\\fs12}and then you go and inspect it with the attributes inspector\r\nDialogue: 0,0:13:55.10,0:13:56.06,yin,,0,0,0,, 设置它的类 \\N{\\fs12}and you set its class.\r\nDialogue: 0,0:13:56.23,0:13:58.82,yin,,0,0,0,, 就是这样拖入一个新的 MVC\\N{\\fs12}That’s it. That’s how you drag a new MVC in\r\nDialogue: 0,0:13:59.20,0:14:00.74,yin,,0,0,0,, 添加到应用中 \\N{\\fs12}and create one for your app.\r\nDialogue: 0,0:14:00.74,0:14:02.43,yin,,0,0,0,, 添加 MVC 很容易 \\N{\\fs12}So it’s easy to add MVCs.\r\nDialogue: 0,0:14:02.43,0:14:04.06,yin,,0,0,0,, 添加了 MVC 之后 \\N{\\fs12}Now, once you have an MVC added,\r\nDialogue: 0,0:14:04.07,0:14:06.72,yin,,0,0,0,, 就可以向它的视图中添加元素 \\N{\\fs12}you can put things in its view,\r\nDialogue: 0,0:14:06.73,0:14:08.61,yin,,0,0,0,, 按钮和标签等等 \\N{\\fs12}buttons and labels and stuff,\r\nDialogue: 0,0:14:08.62,0:14:11.45,yin,,0,0,0,, 还可以连接输出口和操作等 \\N{\\fs12}and you can hook up outlets and actions and all that stuff\r\nDialogue: 0,0:14:11.74,0:14:14.81,yin,,0,0,0,, 创建第二个 MVC 甚至第三四五个 \\N{\\fs12}to create a second MVC, or a third, a fourth, a fifth,\r\nDialogue: 0,0:14:14.82,0:14:17.75,yin,,0,0,0,, 大型应用可能会有 100 个 MVC\\N{\\fs12}or a large app might have 100 MVCs in it,\r\nDialogue: 0,0:14:17.76,0:14:19.21,yin,,0,0,0,, 甚至更多 \\N{\\fs12}okay, or more.\r\nDialogue: 0,0:14:19.78,0:14:21.36,yin,,0,0,0,, 添加了这些 MVC 之后 \\N{\\fs12}So, you got all these MVCs,\r\nDialogue: 0,0:14:21.36,0:14:23.18,yin,,0,0,0,, 如何展示给用户呢 \\N{\\fs12}how do you present them to the use?\r\nDialogue: 0,0:14:23.32,0:14:25.27,yin,,0,0,0,, 有很多方法可以实现 \\N{\\fs12}Okay. Well, there’s a number of ways to do it,\r\nDialogue: 0,0:14:25.46,0:14:27.32,yin,,0,0,0,, 但是最基本的方法是 \\N{\\fs12}but the fundamental answer is\r\nDialogue: 0,0:14:27.39,0:14:32.18,yin,,0,0,0,, 使用一个视图为其他 MVC 的控制器 \\N{\\fs12}you use a controller whose view is other MVCs.\r\nDialogue: 0,0:14:33.89,0:14:35.35,yin,,0,0,0,, 理解一下 \\N{\\fs12}Let that sink in a little. Okay.\r\nDialogue: 0,0:14:35.66,0:14:40.11,yin,,0,0,0,, 和所有 MVC 一样 我的这个 MVC 也有一个控制器 \\N{\\fs12}So I can have a MVC that has a controller like all MVCs,\r\nDialogue: 0,0:14:40.32,0:14:44.26,yin,,0,0,0,, 而这个控制器的视图是其他 MVC\\N{\\fs12}the view of that controller is other MVCs.\r\nDialogue: 0,0:14:44.57,0:14:46.67,yin,,0,0,0,, 从概念上讲 \\N{\\fs12}This is the kind of conceptual way\r\nDialogue: 0,0:14:46.77,0:14:48.30,yin,,0,0,0,, 这就是实现多个 MVC 的方法 \\N{\\fs12}we’re going to put multiple MVCs.\r\nDialogue: 0,0:14:48.64,0:14:52.49,yin,,0,0,0,, 今天我要讲两个 iOS 的类 \\N{\\fs12}And I’m gonna talk about two classes provided by iOS today,\r\nDialogue: 0,0:14:52.49,0:14:53.55,yin,,0,0,0,, 两个控制器 \\N{\\fs12}two controllers,\r\nDialogue: 0,0:14:53.70,0:14:55.61,yin,,0,0,0,, 它们的视图是其他 MVC\\N{\\fs12}whose view is other MVCs.\r\nDialogue: 0,0:14:55.61,0:14:58.19,yin,,0,0,0,, 一个是 UITabBarController 大家都熟悉 \\N{\\fs12}One is UITabBarController, you’re used to that.\r\nDialogue: 0,0:14:58.19,0:14:59.37,yin,,0,0,0,, 这种控制器底部有一排选项卡 \\N{\\fs12}It’s got tabs along the bottom.\r\nDialogue: 0,0:14:59.37,0:15:00.59,yin,,0,0,0,, 点击不同的选项卡 \\N{\\fs12}Every time you click on a tab,\r\nDialogue: 0,0:15:00.60,0:15:02.45,yin,,0,0,0,, 就可以看到不同 MVC 的视图 \\N{\\fs12}you can see a different MVC’s view,\r\nDialogue: 0,0:15:03.34,0:15:05.12,yin,,0,0,0,, 再简单不过了 \\N{\\fs12}okay, couldn’t be simpler.\r\nDialogue: 0,0:15:05.14,0:15:08.99,yin,,0,0,0,, 这是在屏幕上显示多个 MVC 的最简单的方法 \\N{\\fs12}That’s the simplest, you know, way to get multiple MVCs on screen.\r\nDialogue: 0,0:15:09.22,0:15:10.39,yin,,0,0,0,, 然后我会用更多的时间 \\N{\\fs12}And then I’m going to spend more time\r\nDialogue: 0,0:15:10.39,0:15:12.89,yin,,0,0,0,, 讲解 UINavigationController\\N{\\fs12}talking about UINavigationController,\r\nDialogue: 0,0:15:13.11,0:15:16.22,yin,,0,0,0,, 这种是在屏幕上显示一个视图 \\N{\\fs12}which is the thing where you have something on screen\r\nDialogue: 0,0:15:16.22,0:15:18.36,yin,,0,0,0,, 然后你点击了屏幕上的某个按钮之类的 \\N{\\fs12}and you click on a button or something that’s on screen,\r\nDialogue: 0,0:15:18.36,0:15:20.12,yin,,0,0,0,, 一个新视图就会滑进来 \\N{\\fs12}and a new view slides in.\r\nDialogue: 0,0:15:20.90,0:15:23.80,yin,,0,0,0,, 然后再点击一次 滑进另一个视图 \\N{\\fs12}Okay. And then you maybe click again and another one slides in,\r\nDialogue: 0,0:15:23.80,0:15:25.87,yin,,0,0,0,, 还会出现返回按钮 可以返回 \\N{\\fs12}and then there’s a back button and you can back up,\r\nDialogue: 0,0:15:26.09,0:15:27.15,yin,,0,0,0,, 所以可以继续和返回 \\N{\\fs12}so go down and back up.\r\nDialogue: 0,0:15:27.16,0:15:29.71,yin,,0,0,0,, 可以深入查看信息或者返回 \\N{\\fs12}So when you want to drill down information or back up.\r\nDialogue: 0,0:15:30.16,0:15:31.91,yin,,0,0,0,, 这种稍微复杂些 \\N{\\fs12}Okay. So that one’s a little more complicated,\r\nDialogue: 0,0:15:32.27,0:15:34.66,yin,,0,0,0,, 今天大部分时间都会讲解这部分内容 \\N{\\fs12}and that’s what I’m going to spend most of the time on today.\r\nDialogue: 0,0:15:34.88,0:15:38.14,yin,,0,0,0,, 还有其他方法可以显示多个 MVC\\N{\\fs12}Now there’s other ways to put multiple MVCs on screen –\r\nDialogue: 0,0:15:38.14,0:15:40.70,yin,,0,0,0,,iPad 的弹出窗口和模态展示 \\N{\\fs12}popovers on iPad and modal presentations.\r\nDialogue: 0,0:15:40.71,0:15:42.11,yin,,0,0,0,, 今天我不会讲 \\N{\\fs12}Though I’m not going to talk about those today,\r\nDialogue: 0,0:15:42.13,0:15:45.13,yin,,0,0,0,, 但是后面几周会讲到的 \\N{\\fs12}we will cover them all in the next few weeks. Okay.\r\nDialogue: 0,0:15:45.15,0:15:48.35,yin,,0,0,0,, 我想把内容分解成容易理解的小块 \\N{\\fs12}I’m just trying to meter this out to you in bite-size chunks.\r\nDialogue: 0,0:15:49.13,0:15:51.54,yin,,0,0,0,, 好的 那我们来讲讲 UINavigationController\\N{\\fs12}All right. So, let’s talk about UINavigationController.\r\nDialogue: 0,0:15:51.73,0:15:55.18,yin,,0,0,0,, 使用 UINavigationController 的最好的示例 \\N{\\fs12}So, a great app to look at that uses of UINavigationController\r\nDialogue: 0,0:15:55.18,0:15:56.32,yin,,0,0,0,, 就是日历应用 \\N{\\fs12}is the calendar app.\r\nDialogue: 0,0:15:56.32,0:15:58.24,yin,,0,0,0,, 这是显示顶层视图的日历应用 \\N{\\fs12}So, here’s the calendar app at its top level.\r\nDialogue: 0,0:15:58.25,0:16:01.09,yin,,0,0,0,, 基本上显示了一整年的日历 \\N{\\fs12}You can see it’s basically a year — an entire year.\r\nDialogue: 0,0:16:01.34,0:16:04.33,yin,,0,0,0,, 今天是选中的状态 用红色圆形标出了 \\N{\\fs12}Today’s date is selected, the little red in there.\r\nDialogue: 0,0:16:04.33,0:16:06.52,yin,,0,0,0,, 大一点的灰色圆形代表手指 \\N{\\fs12}That big gray dot is supposed to be the finger.\r\nDialogue: 0,0:16:06.54,0:16:08.60,yin,,0,0,0,, 在后面的幻灯片中可以看到 \\N{\\fs12}You’re going to see it touching various spaces\r\nDialogue: 0,0:16:08.63,0:16:10.36,yin,,0,0,0,, 它点击着不同的地方 \\N{\\fs12}as we go through these slides.\r\nDialogue: 0,0:16:11.37,0:16:13.26,yin,,0,0,0,,UINavigationController 适用于 \\N{\\fs12}And we use the UINavigationController\r\nDialogue: 0,0:16:13.32,0:16:16.11,yin,,0,0,0,, 屏幕上有很多内容 \\N{\\fs12}when we have a bunch of stuff on screen\r\nDialogue: 0,0:16:16.11,0:16:18.40,yin,,0,0,0,, 而我们想向用户展示更多内容 \\N{\\fs12}and we want to show the user more,\r\nDialogue: 0,0:16:18.59,0:16:20.51,yin,,0,0,0,, 更多详细的信息 \\N{\\fs12}more detailed, more information.\r\nDialogue: 0,0:16:20.73,0:16:22.74,yin,,0,0,0,, 通常用于这种情况 \\N{\\fs12}Okay. Generally, what this navigation –\r\nDialogue: 0,0:16:22.75,0:16:24.60,yin,,0,0,0,, 这很常见 \\N{\\fs12}Now, it’s very common to want to do that.\r\nDialogue: 0,0:16:24.77,0:16:26.21,yin,,0,0,0,, 当前显示的是高层级的信息 \\N{\\fs12}You’re kind of showing high level information\r\nDialogue: 0,0:16:26.21,0:16:28.00,yin,,0,0,0,, 而你想要展示更多详细的内容 \\N{\\fs12}and you want to show more detail, more detail.\r\nDialogue: 0,0:16:29.06,0:16:30.31,yin,,0,0,0,, 在日历应用中 \\N{\\fs12}So, the calendar app,\r\nDialogue: 0,0:16:30.42,0:16:33.42,yin,,0,0,0,, 如果手指移到某个日期上 然后点击 \\N{\\fs12}if you go over to the day with your finger and you touch,\r\nDialogue: 0,0:16:33.85,0:16:35.98,yin,,0,0,0,, 一个月视图就会滑进来 \\N{\\fs12}then a month view slides in.\r\nDialogue: 0,0:16:36.68,0:16:41.24,yin,,0,0,0,, 所有这些都发生在一个 MVC 中 \\N{\\fs12}Okay. So all of that happened in a single MVC,\r\nDialogue: 0,0:16:41.32,0:16:45.11,yin,,0,0,0,, 也就是导航控制器对应的 MVC\\N{\\fs12}which was a UINavigationController’s MVC.\r\nDialogue: 0,0:16:45.21,0:16:47.63,yin,,0,0,0,, 紫色或者浅蓝色圈出的这部分 \\N{\\fs12}Okay. So the purple or the light blue,\r\nDialogue: 0,0:16:47.92,0:16:49.65,yin,,0,0,0,, 无论大家看起来是什么颜色 \\N{\\fs12}whatever color that looks like to you on the screen,\r\nDialogue: 0,0:16:50.12,0:16:54.62,yin,,0,0,0,, 它是 UINavigationController 的视图 \\N{\\fs12}that is the view of a UINavigationController.\r\nDialogue: 0,0:16:54.98,0:16:56.41,yin,,0,0,0,, 基础 MVC 明白吗 \\N{\\fs12}Based MVC. Okay.\r\nDialogue: 0,0:16:57.14,0:17:01.38,yin,,0,0,0,, 里面有另一个 MVC 的视图 \\N{\\fs12}Now, inside there, there’s another MVC’s view,\r\nDialogue: 0,0:17:01.38,0:17:02.47,yin,,0,0,0,, 月视图 \\N{\\fs12}the month view.\r\nDialogue: 0,0:17:02.78,0:17:05.46,yin,,0,0,0,, 所以黄色区域是另一个 MVC 的视图 \\N{\\fs12}So the little yellow area is another MVC’s view.\r\nDialogue: 0,0:17:05.87,0:17:09.18,yin,,0,0,0,, 在此之前 里面是一个年 MVC 的视图 \\N{\\fs12}Okay. And what used to be in there was a year MVC’s view,\r\nDialogue: 0,0:17:09.19,0:17:11.43,yin,,0,0,0,, 又是另外一个 MVC\\N{\\fs12}which was yet another MVC.\r\nDialogue: 0,0:17:11.45,0:17:13.00,yin,,0,0,0,, 可以看到它们是如何嵌入的 \\N{\\fs12}Okay. So you can see how it’s imbedded.\r\nDialogue: 0,0:17:13.47,0:17:14.95,yin,,0,0,0,, 而且不只是嵌入 \\N{\\fs12}And not only is it embedded,\r\nDialogue: 0,0:17:15.06,0:17:20.11,yin,,0,0,0,, 导航控制器还控制着自己的 UI\\N{\\fs12}but the navigation controller is kind of controlling its own UI,\r\nDialogue: 0,0:17:20.16,0:17:22.35,yin,,0,0,0,, 根据嵌入内容的不同而变化 \\N{\\fs12}based on what happens to be embedded at the time.\r\nDialogue: 0,0:17:22.97,0:17:25.24,yin,,0,0,0,, 我可以在某一天上点击 \\N{\\fs12}And so, I could click on the day\r\nDialogue: 0,0:17:25.35,0:17:28.57,yin,,0,0,0,, 日视图就会进来 这里就换成了日 MVC\\N{\\fs12}and a day view comes in, so this is a day MVC.\r\nDialogue: 0,0:17:28.58,0:17:30.94,yin,,0,0,0,, 所以这里我们看到了四个 MVC\\N{\\fs12}So this is four MVCs we’ve seen here.\r\nDialogue: 0,0:17:31.11,0:17:34.14,yin,,0,0,0,, 最外层的导航控制器是一个 \\N{\\fs12}The surrounding navigation controller one,\r\nDialogue: 0,0:17:34.15,0:17:38.42,yin,,0,0,0,, 显示出来的年月日 \\N{\\fs12}and now three separate year, month and day MVCs\r\nDialogue: 0,0:17:38.43,0:17:39.56,yin,,0,0,0,, 分别是三个 MVC\\N{\\fs12}that are being shown in here.\r\nDialogue: 0,0:17:40.03,0:17:40.48,yin,,0,0,0,, 明白吗 \\N{\\fs12}Okay.\r\nDialogue: 0,0:17:41.39,0:17:43.15,yin,,0,0,0,, 我们来看一下 \\N{\\fs12}So let’s take a look –\r\nDialogue: 0,0:17:43.15,0:17:44.57,yin,,0,0,0,, 当然了 我们还可以继续点击 \\N{\\fs12}Of course, we can click again\r\nDialogue: 0,0:17:44.57,0:17:46.30,yin,,0,0,0,, 打开事件详情页面 \\N{\\fs12}and now get the details for an event,\r\nDialogue: 0,0:17:46.31,0:17:48.16,yin,,0,0,0,, 所以这里我们看到了五个 MVC\\N{\\fs12}so there’s five MVCs that we’ve seen.\r\nDialogue: 0,0:17:49.14,0:17:52.11,yin,,0,0,0,, 我们来看一下这个导航控制器的组成部分 \\N{\\fs12}So let’s look at the components of this UINavigationController.\r\nDialogue: 0,0:17:52.29,0:17:54.48,yin,,0,0,0,, 顶部有浅灰色的一栏 \\N{\\fs12}So at the top, there’s this light gray bar\r\nDialogue: 0,0:17:54.59,0:17:56.57,yin,,0,0,0,, 不管下面显示的是哪个 MVC\\N{\\fs12}that stayed on the screen, you notice,\r\nDialogue: 0,0:17:56.58,0:17:59.10,yin,,0,0,0,, 它始终都显示在屏幕上 \\N{\\fs12}for all of the MVCs as they come swiping in.\r\nDialogue: 0,0:17:59.27,0:18:02.41,yin,,0,0,0,, 但是不同 MVC 出现时 它会略微变化 \\N{\\fs12}Okay. But it changed slightly as they all swiped in,\r\nDialogue: 0,0:18:02.70,0:18:04.97,yin,,0,0,0,, 我们来看看它的组成部分 \\N{\\fs12}so let’s look at all the parts.\r\nDialogue: 0,0:18:05.60,0:18:08.34,yin,,0,0,0,, 这个导航栏包括三个主要部分 \\N{\\fs12}There’s three major parts there of that navigation bar.\r\nDialogue: 0,0:18:09.39,0:18:12.01,yin,,0,0,0,, 首先是标题 Event Details 事件详情 \\N{\\fs12}First is the title, okay, Event Details.\r\nDialogue: 0,0:18:12.01,0:18:13.61,yin,,0,0,0,, 你会发现显示月和日时 \\N{\\fs12}You’ll notice that the month and the day –\r\nDialogue: 0,0:18:13.61,0:18:15.07,yin,,0,0,0,, 是没有标题的 \\N{\\fs12}actually, I don’t think they even had titles,\r\nDialogue: 0,0:18:15.08,0:18:16.26,yin,,0,0,0,, 这是合理的 \\N{\\fs12}which is perfectly legal.\r\nDialogue: 0,0:18:17.06,0:18:20.23,yin,,0,0,0,, 这里会显示事件详情 \\N{\\fs12}This says Event Detail because the navigation controller\r\nDialogue: 0,0:18:20.26,0:18:23.11,yin,,0,0,0,, 是因为导航控制器询问嵌入的控制器 \\N{\\fs12}is basically asking the embedded controller，\r\nDialogue: 0,0:18:23.11,0:18:25.97,yin,,0,0,0,, 也就是日历事件 MVC\\N{\\fs12}the calendar event MVC，\r\nDialogue: 0,0:18:25.98,0:18:27.47,yin,,0,0,0,, 你的标题是什么 \\N{\\fs12}what’s your title,\r\nDialogue: 0,0:18:27.78,0:18:30.17,yin,,0,0,0,, 得到它的标题之后 将它显示在顶部 \\N{\\fs12}and then it gets that and it puts that at the top.\r\nDialogue: 0,0:18:30.17,0:18:32.75,yin,,0,0,0,, 也可以在 storyboard 中设置这个标题 \\N{\\fs12}You can also set that title in your storyboard if you want to.\r\nDialogue: 0,0:18:33.45,0:18:33.84,yin,,0,0,0,, 明白吧 \\N{\\fs12}Okay.\r\nDialogue: 0,0:18:34.21,0:18:35.43,yin,,0,0,0,, 这个标题 \\N{\\fs12}But it’s associated –\r\nDialogue: 0,0:18:35.60,0:18:38.51,yin,,0,0,0,, 和内部显示的内容有关 \\N{\\fs12}that title’s associated with what’s inside，\r\nDialogue: 0,0:18:38.51,0:18:40.28,yin,,0,0,0,, 根据导航控制器中嵌入 MVC 的不同 \\N{\\fs12}what’s embedded in the navigation controller\r\nDialogue: 0,0:18:40.29,0:18:42.20,yin,,0,0,0,, 在滑进不同视图时改变标题 \\N{\\fs12}and it changes as things slide in.\r\nDialogue: 0,0:18:42.86,0:18:43.31,yin,,0,0,0,, 明白吧 \\N{\\fs12}Okay.\r\nDialogue: 0,0:18:44.36,0:18:49.41,yin,,0,0,0,, 右边这里还有按钮 \\N{\\fs12}Also, we have the buttons on the right here.\r\nDialogue: 0,0:18:49.41,0:18:51.21,yin,,0,0,0,, 现在只有一个 Edit 编辑按钮 \\N{\\fs12}So, there’s only one button here — Edit,\r\nDialogue: 0,0:18:51.21,0:18:52.92,yin,,0,0,0,, 但是如果大家还记得 \\N{\\fs12}but if you remember back to the month and day,\r\nDialogue: 0,0:18:52.92,0:18:53.74,yin,,0,0,0,, 在月和日页面中有两个按钮 \\N{\\fs12}there were actually two buttons,\r\nDialogue: 0,0:18:53.74,0:18:57.63,yin,,0,0,0,, 可能有一个加号按钮 用来增加事件 \\N{\\fs12}like a little plus sign to add an event maybe,\r\nDialogue: 0,0:18:57.64,0:19:01.06,yin,,0,0,0,, 有一个放大镜用来搜索等等 \\N{\\fs12}and a little magnifying glass to search, things like that.\r\nDialogue: 0,0:19:01.08,0:19:02.54,yin,,0,0,0,, 所以这里其实可以放多个按钮 \\N{\\fs12}So you can actually have multiple buttons here,\r\nDialogue: 0,0:19:02.54,0:19:03.76,yin,,0,0,0,, 这也就是为什么它是一个 NSArray\\N{\\fs12}that’s why it’s an NSArray.\r\nDialogue: 0,0:19:03.76,0:19:06.63,yin,,0,0,0,, 这些按钮并不是 UIButton\\N{\\fs12}Now, these buttons are not UIButtons,\r\nDialogue: 0,0:19:06.63,0:19:08.46,yin,,0,0,0,, 它们是 UIBarButtonItem\\N{\\fs12}they’re UIBarButtonItems.\r\nDialogue: 0,0:19:08.91,0:19:10.55,yin,,0,0,0,, 类似于轻量级的按钮 \\N{\\fs12}Okay. Kind of lightweight buttons.\r\nDialogue: 0,0:19:10.72,0:19:15.38,yin,,0,0,0,, 导航控制器如果想要确定显示哪个按钮 \\N{\\fs12}And the navigation controller figures out which one to put there\r\nDialogue: 0,0:19:15.48,0:19:20.19,yin,,0,0,0,, 需要向嵌入的视图请求一个对象 叫做 navigationItem\\N{\\fs12}by asking the embedded view for an object called a navigationItem,\r\nDialogue: 0,0:19:20.20,0:19:23.79,yin,,0,0,0,, 所有 UIViewController 都有这个 navigationItem 属性 \\N{\\fs12}so all UIViewControllers have this property navigationItem,\r\nDialogue: 0,0:19:23.91,0:19:26.01,yin,,0,0,0,, 返回的对象中 \\N{\\fs12}and it returns this object that has some stuff in there\r\nDialogue: 0,0:19:26.02,0:19:27.91,yin,,0,0,0,, 包括 rightBarButtonItems 等 \\N{\\fs12}like rightBarButtonItems,\r\nDialogue: 0,0:19:28.05,0:19:29.92,yin,,0,0,0,,rightBarButtonItem 是个数组 \\N{\\fs12}which is an array. Okay.\r\nDialogue: 0,0:19:29.97,0:19:32.39,yin,,0,0,0,, 大家明白这个属性表示法吗 \\N{\\fs12}Everybody understand the property notation I’m using there?\r\nDialogue: 0,0:19:32.39,0:19:34.35,yin,,0,0,0,,navigationItem.rightBarButtonItems\\N{\\fs12}navigationItem dot rightBarButtonItems.\r\nDialogue: 0,0:19:34.80,0:19:36.60,yin,,0,0,0,, 这是从嵌入的视图中得到的 \\N{\\fs12}I’m getting that from the embedded view,\r\nDialogue: 0,0:19:37.02,0:19:38.93,yin,,0,0,0,, 日视图 月视图等等 \\N{\\fs12}you know, the day view, or the month view or whatever.\r\nDialogue: 0,0:19:38.93,0:19:40.79,yin,,0,0,0,, 根据它们决定上面出现的按钮 \\N{\\fs12}That’s what’s determining the buttons that are up there.\r\nDialogue: 0,0:19:41.70,0:19:43.73,yin,,0,0,0,, 左边的返回按钮 \\N{\\fs12}This back button over here on the left,\r\nDialogue: 0,0:19:43.73,0:19:44.96,yin,,0,0,0,, 如果我点击它 \\N{\\fs12}if I click that button,\r\nDialogue: 0,0:19:44.96,0:19:47.37,yin,,0,0,0,, 就会返回到上一个页面 \\N{\\fs12}it’s going to go back to the last thing that was there,\r\nDialogue: 0,0:19:47.40,0:19:50.15,yin,,0,0,0,, 在这个示例中 会回到日视图 \\N{\\fs12}which in this case was the day view. All right.\r\nDialogue: 0,0:19:50.37,0:19:53.88,yin,,0,0,0,, 这是由 UINavigationController 自动实现的 \\N{\\fs12}And that’s automatically done by UINavigationController,\r\nDialogue: 0,0:19:53.93,0:19:56.81,yin,,0,0,0,, 而按钮上显示的单词 \\N{\\fs12}and the word it’s going to use there is,\r\nDialogue: 0,0:19:56.90,0:19:57.86,yin,,0,0,0,, 如果放得下的话 \\N{\\fs12}if it’ll fit,\r\nDialogue: 0,0:19:57.91,0:20:00.82,yin,,0,0,0,, 就是上一个 MVC 的标题 \\N{\\fs12}the title of the previous MVC.\r\nDialogue: 0,0:20:00.99,0:20:04.11,yin,,0,0,0,, 这里是 Day 可以放得下 \\N{\\fs12}So this case is day, works, it fits.\r\nDialogue: 0,0:20:04.12,0:20:05.37,yin,,0,0,0,, 也可以进行设置 \\N{\\fs12}It can also be set,\r\nDialogue: 0,0:20:05.54,0:20:07.16,yin,,0,0,0,, 因为我并不知道日 MVC\\N{\\fs12}because I don’t know that the day MVC\r\nDialogue: 0,0:20:07.17,0:20:08.81,yin,,0,0,0,, 真的有一个标题 Day\\N{\\fs12}actually had a title that said day,\r\nDialogue: 0,0:20:08.81,0:20:10.08,yin,,0,0,0,, 也许有 但我不知道 \\N{\\fs12}might have, but I don’t think so,\r\nDialogue: 0,0:20:10.08,0:20:11.04,yin,,0,0,0,, 所以这里也可以设置 \\N{\\fs12}so it can be set.\r\nDialogue: 0,0:20:11.59,0:20:14.28,yin,,0,0,0,, 如果放不下的话 就会直接显示 Back 返回 \\N{\\fs12}Also if it doesn’t fit, it’ll just say the word back.\r\nDialogue: 0,0:20:15.04,0:20:16.52,yin,,0,0,0,, 有时也会遇到这种情况 \\N{\\fs12}Okay. So you’ll see that sometimes.\r\nDialogue: 0,0:20:16.53,0:20:19.69,yin,,0,0,0,, 但是用户知道左上角是用来返回的 \\N{\\fs12}But the user knows that upper left hand corner is how they go back,\r\nDialogue: 0,0:20:20.06,0:20:21.54,yin,,0,0,0,, 他们进入下面的层级后 可以返回 \\N{\\fs12}so they drill down, they can go back.\r\nDialogue: 0,0:20:21.54,0:20:23.46,yin,,0,0,0,, 如果我点击那个返回按钮 \\N{\\fs12}And if I click on that back button,\r\nDialogue: 0,0:20:24.61,0:20:26.23,yin,,0,0,0,, 显然我会返回到日视图 \\N{\\fs12}obviously, I’m going to go back to the day.\r\nDialogue: 0,0:20:26.26,0:20:27.43,yin,,0,0,0,, 如果我再点击一下 \\N{\\fs12}If I click again,\r\nDialogue: 0,0:20:27.65,0:20:28.92,yin,,0,0,0,, 就会返回到月视图 \\N{\\fs12}I’m going back to the month.\r\nDialogue: 0,0:20:30.28,0:20:32.10,yin,,0,0,0,, 好的 这就是返回按钮 \\N{\\fs12}All right. So that’s the back button.\r\nDialogue: 0,0:20:32.36,0:20:33.41,yin,,0,0,0,, 而在底部 \\N{\\fs12}Now down at the bottom,\r\nDialogue: 0,0:20:33.41,0:20:35.00,yin,,0,0,0,, 也有一小条灰色栏 \\N{\\fs12}you see there’s a little light gray bar there.\r\nDialogue: 0,0:20:35.00,0:20:36.03,yin,,0,0,0,, 它并不是总显示在那里的 \\N{\\fs12}That’s not always there.\r\nDialogue: 0,0:20:36.03,0:20:39.39,yin,,0,0,0,, 日历事件 MVC 中就没有这一栏 \\N{\\fs12}That wasn’t there on the calendar event MVC, by the way.\r\nDialogue: 0,0:20:40.31,0:20:43.01,yin,,0,0,0,, 这只是一些 UIBarButtonItems\\N{\\fs12}This is just a bunch of UIBarButtonItems\r\nDialogue: 0,0:20:43.01,0:20:45.73,yin,,0,0,0,, 只有在嵌入的 MVC 视图需要时 \\N{\\fs12}that again, the navigation controller only displays\r\nDialogue: 0,0:20:45.75,0:20:49.70,yin,,0,0,0,, 导航控制器才会显示这一栏 \\N{\\fs12}if the embedded MVC’s view says that it wants them.\r\nDialogue: 0,0:20:50.13,0:20:53.18,yin,,0,0,0,, 对应着另外一个属性 叫做 toolbarItems\\N{\\fs12}Okay. And there’s another property for that called toolbarItems,\r\nDialogue: 0,0:20:53.96,0:20:57.46,yin,,0,0,0,, 导航控制器调用嵌入视图控制器的 \\N{\\fs12}so you call — the navigation controller calls toolbarItems\r\nDialogue: 0,0:20:57.73,0:21:01.12,yin,,0,0,0,,toolbarItems 属性 \\N{\\fs12}on the embedded view controller,\r\nDialogue: 0,0:21:01.19,0:21:03.91,yin,,0,0,0,, 会得到一个 UIBarButtonItem 的 NSArray\\N{\\fs12}and it returns an NSArray of UIBarButtonItems\r\nDialogue: 0,0:21:03.92,0:21:05.09,yin,,0,0,0,, 然后将它们显示在底部 \\N{\\fs12}and it puts them in the bottom.\r\nDialogue: 0,0:21:05.36,0:21:08.21,yin,,0,0,0,, 如果嵌入的视图控制器 \\N{\\fs12}And if the embedded view controller\r\nDialogue: 0,0:21:08.22,0:21:09.82,yin,,0,0,0,, 不需要在底部显示栏按钮 \\N{\\fs12}doesn’t want any bar buttons at the bottom,\r\nDialogue: 0,0:21:09.83,0:21:12.29,yin,,0,0,0,, 导航控制器就不会显示灰色这栏 \\N{\\fs12}then it just animates that gray thing away\r\nDialogue: 0,0:21:12.48,0:21:13.58,yin,,0,0,0,, 如果转到需要显示底部栏按钮的视图控制器 \\N{\\fs12}and then animates it back,\r\nDialogue: 0,0:21:13.58,0:21:15.55,yin,,0,0,0,, 会再显示出这一栏 \\N{\\fs12}if you navigate it back to one that does.\r\nDialogue: 0,0:21:15.55,0:21:17.15,yin,,0,0,0,, 大家都明白它的组成部分了吗 \\N{\\fs12}So everyone understand the components\r\nDialogue: 0,0:21:18.11,0:21:19.42,yin,,0,0,0,,UINavigationController 的组成部分 \\N{\\fs12}of UINavigationController?\r\nDialogue: 0,0:21:20.06,0:21:22.50,yin,,0,0,0,, 现在我们讲讲它是如何工作的 \\N{\\fs12}Okay. So now let’s talk about how this thing works.\r\nDialogue: 0,0:21:22.50,0:21:24.28,yin,,0,0,0,, 我们知道它的组成部分 \\N{\\fs12}We know the parts of it.\r\nDialogue: 0,0:21:25.84,0:21:30.53,yin,,0,0,0,, 我从 MVC 的角度讲一下 \\N{\\fs12}I’m going to do this kind of in a MVC like view of this.\r\nDialogue: 0,0:21:30.73,0:21:33.16,yin,,0,0,0,, 这里我有一个 MVC\\N{\\fs12}So, here I have an MVC. Right.\r\nDialogue: 0,0:21:33.16,0:21:35.86,yin,,0,0,0,, 和第一节课用到的是一样的 记得吧 \\N{\\fs12}You recognize this from the very first lecture. Right.\r\nDialogue: 0,0:21:36.15,0:21:41.62,yin,,0,0,0,, 假设我有很多功能 屏幕上放不下 \\N{\\fs12}And let’s say I have more features than I can fit onscreen.\r\nDialogue: 0,0:21:41.85,0:21:44.92,yin,,0,0,0,, 需要在屏幕上显示更多的视图和按钮等等 \\N{\\fs12}So got extra views and buttons and stuff I want to put on screen,\r\nDialogue: 0,0:21:44.92,0:21:45.73,yin,,0,0,0,, 但就是放不下 \\N{\\fs12}but they just won’t fit.\r\nDialogue: 0,0:21:46.18,0:21:47.16,yin,,0,0,0,, 我该怎么做呢 \\N{\\fs12}Okay. So what do I do?\r\nDialogue: 0,0:21:47.18,0:21:50.58,yin,,0,0,0,, 像我刚才说过的 我们创建第二个 MVC\\N{\\fs12}Well, like I said, we create a second MVC.\r\nDialogue: 0,0:21:50.86,0:21:52.79,yin,,0,0,0,, 这里有很重要的一点需要理解 \\N{\\fs12}Now, what’s really important to understand here\r\nDialogue: 0,0:21:52.79,0:21:56.13,yin,,0,0,0,, 就是 MVC 需要各自独立 \\N{\\fs12}is that MVCs need to be independent.\r\nDialogue: 0,0:21:56.87,0:22:01.12,yin,,0,0,0,, 所以第二个 MVC 需要封装一些功能 \\N{\\fs12}Okay. So this second MVC has to encapsulate some amount of functionality\r\nDialogue: 0,0:22:01.20,0:22:03.72,yin,,0,0,0,, 需要能够创建好 \\N{\\fs12}and it has to be able to be set up,\r\nDialogue: 0,0:22:04.34,0:22:06.41,yin,,0,0,0,, 准备出现在屏幕上 \\N{\\fs12}prepared to be onscreen,\r\nDialogue: 0,0:22:06.41,0:22:07.79,yin,,0,0,0,, 然后能够独自运行 \\N{\\fs12}and then it has to be able to run by itself.\r\nDialogue: 0,0:22:08.49,0:22:09.48,yin,,0,0,0,, 为什么呢 \\N{\\fs12}Okay. Why is that?\r\nDialogue: 0,0:22:09.61,0:22:11.63,yin,,0,0,0,, 因为这个 MVC\\N{\\fs12}That’s because this MVC\r\nDialogue: 0,0:22:11.63,0:22:14.62,yin,,0,0,0,, 是要作为另一个 MVC 的视图 \\N{\\fs12}is gonna serve as the view of another MVC.\r\nDialogue: 0,0:22:14.63,0:22:17.17,yin,,0,0,0,, 还记得我们在讲 MVC 时讲过 \\N{\\fs12}And remember from the MVC discussion,\r\nDialogue: 0,0:22:17.21,0:22:20.49,yin,,0,0,0,, 视图并不能向控制器发送消息 \\N{\\fs12}that the views can’t really talk back to their controllers.\r\nDialogue: 0,0:22:20.71,0:22:22.32,yin,,0,0,0,, 控制器可以向视图发送消息 \\N{\\fs12}The controller can talk to the view.\r\nDialogue: 0,0:22:22.51,0:22:23.99,yin,,0,0,0,, 视图想要向控制器发回消息只有一种方法 \\N{\\fs12}The only way the view can talk back\r\nDialogue: 0,0:22:24.02,0:22:26.07,yin,,0,0,0,, 就是通过不可视结构化通信 \\N{\\fs12}is by this blind structured communication\r\nDialogue: 0,0:22:26.10,0:22:28.12,yin,,0,0,0,, 比如目标操作等等 \\N{\\fs12}like target action and things like that.\r\nDialogue: 0,0:22:28.12,0:22:30.82,yin,,0,0,0,, 有一种不可视结构化通信方法 \\N{\\fs12}And there is blind structure communication –\r\nDialogue: 0,0:22:30.83,0:22:32.59,yin,,0,0,0,, 是我们讲过的委托 \\N{\\fs12}delegation, basically, we talked about,\r\nDialogue: 0,0:22:32.74,0:22:36.00,yin,,0,0,0,, 可以实现作为视图的 MVC 向控制器发送消息 \\N{\\fs12}for an MVC — part of a view to talk back,\r\nDialogue: 0,0:22:36.15,0:22:37.39,yin,,0,0,0,, 但是这种方法就复杂多了 \\N{\\fs12}but it’s much more complicated,\r\nDialogue: 0,0:22:37.39,0:22:38.87,yin,,0,0,0,, 通常情况下我们尽量不用它 \\N{\\fs12}and usually we try to avoid it.\r\nDialogue: 0,0:22:39.08,0:22:42.43,yin,,0,0,0,, 我们真正想要的是设置好这个 MVC 让它独自运行 \\N{\\fs12}We really want to set this MVC up and have it live on its own.\r\nDialogue: 0,0:22:43.09,0:22:45.53,yin,,0,0,0,, 这在尝试和设计时非常重要 \\N{\\fs12}Okay. It’s really important to try and design,\r\nDialogue: 0,0:22:45.63,0:22:48.14,yin,,0,0,0,, 是面向对象编程的一部分 \\N{\\fs12}it’s really just part of object-oriented programming\r\nDialogue: 0,0:22:48.14,0:22:50.01,yin,,0,0,0,, 进行封装 \\N{\\fs12}to encapsulate things.\r\nDialogue: 0,0:22:50.08,0:22:51.82,yin,,0,0,0,, 这个 MVC 希望被封装 \\N{\\fs12}So this MVC wants to be encapsulated.\r\nDialogue: 0,0:22:51.82,0:22:55.66,yin,,0,0,0,, 希望能自力更生 \\N{\\fs12}It wants to have its own life. Okay.\r\nDialogue: 0,0:22:56.16,0:22:57.67,yin,,0,0,0,, 我们接下来讲讲 \\N{\\fs12}So, let’s talk about then\r\nDialogue: 0,0:22:57.67,0:23:00.80,yin,,0,0,0,,UINavigationController 是如何加进来的 \\N{\\fs12}how UINavigationController comes into this.\r\nDialogue: 0,0:23:00.82,0:23:03.22,yin,,0,0,0,, 如果第二个 MVC 想要展示的内容 \\N{\\fs12}If the second MVC, what is wants to show,\r\nDialogue: 0,0:23:03.29,0:23:05.46,yin,,0,0,0,, 是第一个 MVC 的详细信息 \\N{\\fs12}is more detail of the first MVC,\r\nDialogue: 0,0:23:05.46,0:23:08.10,yin,,0,0,0,, 那 UINavigationController 很适合这种情况 \\N{\\fs12}then a UINavigationController is appropriate.\r\nDialogue: 0,0:23:08.55,0:23:11.23,yin,,0,0,0,,UINavigationController 看起来是这样的 \\N{\\fs12}All right. A UINavigationController looks like this.\r\nDialogue: 0,0:23:11.23,0:23:12.46,yin,,0,0,0,, 它是一个 MVC\\N{\\fs12}It’s an MVC,\r\nDialogue: 0,0:23:12.71,0:23:15.03,yin,,0,0,0,, 它的控制器是 UINavigationController\\N{\\fs12}its controller is the UINavigationController,\r\nDialogue: 0,0:23:15.14,0:23:18.34,yin,,0,0,0,, 它的视图是这个白色的长方形 \\N{\\fs12}its view is this kind of white rectangular thing\r\nDialogue: 0,0:23:18.34,0:23:19.86,yin,,0,0,0,, 顶部有一条灰色栏 \\N{\\fs12}with the gray bar at the top,\r\nDialogue: 0,0:23:19.86,0:23:21.56,yin,,0,0,0,, 底部也可能有一条灰色栏 \\N{\\fs12}and possibly a gray bar at the bottom,\r\nDialogue: 0,0:23:21.94,0:23:26.67,yin,,0,0,0,, 它有一个 rootViewController 根视图控制器 \\N{\\fs12}and it includes a rootViewController,\r\nDialogue: 0,0:23:26.75,0:23:28.20,yin,,0,0,0,, 是一个特殊的输出口 \\N{\\fs12}which is a special outlet\r\nDialogue: 0,0:23:28.42,0:23:32.37,yin,,0,0,0,, 指向另一个 MVC 的控制器 \\N{\\fs12}that comes out that points to the controller of the MVC\r\nDialogue: 0,0:23:32.38,0:23:35.34,yin,,0,0,0,, 而这个 MVC 会在应用开始运行时显示在导航控制器中 \\N{\\fs12}that’s going to appear in the navigation controller when it starts up,\r\nDialogue: 0,0:23:35.34,0:23:36.96,yin,,0,0,0,, 就是它的根视图控制器 \\N{\\fs12}its root view controller.\r\nDialogue: 0,0:23:37.54,0:23:40.58,yin,,0,0,0,, 如果将这个 MVC 设为根视图控制器 \\N{\\fs12}Okay. So when you set that to be this MVC,\r\nDialogue: 0,0:23:41.12,0:23:43.12,yin,,0,0,0,, 导航控制器看起来就会是这样的 \\N{\\fs12}the navigation controller is going to look like this.\r\nDialogue: 0,0:23:43.38,0:23:47.10,yin,,0,0,0,, 它会将根视图控制器 MVC 的视图 \\N{\\fs12}It’s gonna put the view of that root view controller’s MVC into –\r\nDialogue: 0,0:23:47.18,0:23:49.04,yin,,0,0,0,, 嵌入它的视图中 \\N{\\fs12}embedded inside of its view.\r\nDialogue: 0,0:23:49.92,0:23:51.56,yin,,0,0,0,, 大家都明白吗 \\N{\\fs12}Right. Everyone understand that?\r\nDialogue: 0,0:23:52.46,0:23:56.14,yin,,0,0,0,, 如果这个视图中或者顶栏中 \\N{\\fs12}Okay. Now, if you then have some button or something\r\nDialogue: 0,0:23:56.15,0:23:59.59,yin,,0,0,0,, 有一些按钮之类的 \\N{\\fs12}inside this view or maybe in the bar at the top\r\nDialogue: 0,0:24:00.16,0:24:02.61,yin,,0,0,0,, 用来提供更多详细信息 \\N{\\fs12}that wants to give that more detail\r\nDialogue: 0,0:24:02.67,0:24:05.95,yin,,0,0,0,, 通过另外一个 MVC 来展示 \\N{\\fs12}and have this other MVC provides,\r\nDialogue: 0,0:24:06.10,0:24:08.13,yin,,0,0,0,, 点击了那个按钮之后 \\N{\\fs12}you click on that button\r\nDialogue: 0,0:24:08.39,0:24:12.48,yin,,0,0,0,, 就会滑入另一个 MVC 的视图 \\N{\\fs12}and it slides in the view for this other MVC,\r\nDialogue: 0,0:24:12.91,0:24:15.22,yin,,0,0,0,, 可以看到 还会在左上角添加返回按钮 \\N{\\fs12}okay, and puts a back button there as you see.\r\nDialogue: 0,0:24:15.63,0:24:17.76,yin,,0,0,0,, 现在 当 MVC\\N{\\fs12}Now again, when the MVC –\r\nDialogue: 0,0:24:17.77,0:24:19.86,yin,,0,0,0,, 当导航控制器处于当前状态时 \\N{\\fs12}when the navigation controller’s in this state,\r\nDialogue: 0,0:24:20.11,0:24:23.91,yin,,0,0,0,, 左侧的 MVC 最好毫无声息 \\N{\\fs12}okay, the MVC that’s on the left kind of wants to be quite.\r\nDialogue: 0,0:24:24.00,0:24:26.18,yin,,0,0,0,, 它不希望做任何操作 \\N{\\fs12}It doesn’t want to be doing anything. Okay.\r\nDialogue: 0,0:24:26.42,0:24:28.33,yin,,0,0,0,, 现在它并没有参与进来 \\N{\\fs12}It’s not really involved right now.\r\nDialogue: 0,0:24:28.51,0:24:31.29,yin,,0,0,0,, 而右侧的 MVC 完全处于控制状态 \\N{\\fs12}Then MVC on the right is completely in control.\r\nDialogue: 0,0:24:31.66,0:24:33.49,yin,,0,0,0,, 所以它要做的所有事情 \\N{\\fs12}Okay. And so it should be doing everything it’s doing\r\nDialogue: 0,0:24:33.49,0:24:35.15,yin,,0,0,0,, 都应该可以自己独立完成 \\N{\\fs12}on its own, independently.\r\nDialogue: 0,0:24:35.62,0:24:37.73,yin,,0,0,0,, 当然 那个小小的返回按钮 \\N{\\fs12}Now of course, that little back button\r\nDialogue: 0,0:24:37.74,0:24:40.00,yin,,0,0,0,, 会在 MVC 切换时自动出现 \\N{\\fs12}which automatically appears when you do this –\r\nDialogue: 0,0:24:40.43,0:24:41.54,yin,,0,0,0,, 我们会讲到这部分的 \\N{\\fs12}we’re going to talk about, by the way,\r\nDialogue: 0,0:24:41.54,0:24:44.15,yin,,0,0,0,, 会讲到如何转到另一个 MVC\\N{\\fs12}how to make this happen, to go to another MVC.\r\nDialogue: 0,0:24:44.28,0:24:46.20,yin,,0,0,0,, 当你点击这个小返回按钮时 \\N{\\fs12}This little back button, when you press it,\r\nDialogue: 0,0:24:47.03,0:24:50.60,yin,,0,0,0,, 显然它会移回到原来的 MVC\\N{\\fs12}it’s obviously just going to move back to the original one,\r\nDialogue: 0,0:24:50.61,0:24:52.84,yin,,0,0,0,, 这时这个 MVC 又处于活动状态了 \\N{\\fs12}then this MVC is now live again.\r\nDialogue: 0,0:24:53.54,0:24:55.40,yin,,0,0,0,, 当我们点击返回按钮时 \\N{\\fs12}What happened to the MVC on the right\r\nDialogue: 0,0:24:55.40,0:24:56.56,yin,,0,0,0,, 右侧的 MVC 会发生什么呢 \\N{\\fs12}when we clicked the back button?\r\nDialogue: 0,0:24:57.86,0:25:00.37,yin,,0,0,0,, 答案是 它会被从堆中释放 \\N{\\fs12}The answer is, it got de-allocated from the heap.\r\nDialogue: 0,0:25:02.13,0:25:04.59,yin,,0,0,0,, 这也是需要理解的重要的一点 \\N{\\fs12}Okay. This is an important thing to understand as well.\r\nDialogue: 0,0:25:05.01,0:25:06.74,yin,,0,0,0,, 右侧的那个 MVC\\N{\\fs12}Okay. That MVC on the right\r\nDialogue: 0,0:25:07.00,0:25:10.87,yin,,0,0,0,, 从 storyboard 中化冻 显示在屏幕上 \\N{\\fs12}got unfreeze-dried from the storyboard when we put it onscreen,\r\nDialogue: 0,0:25:11.00,0:25:14.11,yin,,0,0,0,, 当它离开屏幕时 会被释放 \\N{\\fs12}and when it went back off screen, it got de-allocated.\r\nDialogue: 0,0:25:15.58,0:25:18.56,yin,,0,0,0,, 每次我们向 UINavigationController 上 \\N{\\fs12}Okay. Every time we push a new thing\r\nDialogue: 0,0:25:18.89,0:25:21.55,yin,,0,0,0,, 压入新 MVC 时 \\N{\\fs12}onto a UINavigationController,\r\nDialogue: 0,0:25:21.75,0:25:23.94,yin,,0,0,0,, 都是从 storyboard 中新建一个 \\N{\\fs12}we’re creating a new one from the storyboard.\r\nDialogue: 0,0:25:24.78,0:25:26.44,yin,,0,0,0,, 在堆中新实例化一个 \\N{\\fs12}Okay. We’re instantiating a new one in the heap,\r\nDialogue: 0,0:25:26.44,0:25:28.43,yin,,0,0,0,, 返回之后 它就会消失 \\N{\\fs12}and every time we go back and it goes away,\r\nDialogue: 0,0:25:28.72,0:25:29.70,yin,,0,0,0,, 被释放了 \\N{\\fs12}it’s de-allocated.\r\nDialogue: 0,0:25:30.37,0:25:34.19,yin,,0,0,0,, 所以这些 MVC 需要知道如何变为活动状态 \\N{\\fs12}So these MVCs need to know how to come to life,\r\nDialogue: 0,0:25:34.49,0:25:37.40,yin,,0,0,0,, 准备出现在屏幕上 做要做的事情 \\N{\\fs12}be prepared to come onscreen, do what they do,\r\nDialogue: 0,0:25:37.62,0:25:40.20,yin,,0,0,0,, 完成之后 保存工作进度 \\N{\\fs12}finish what they’ve done, save whatever work it is,\r\nDialogue: 0,0:25:40.21,0:25:41.23,yin,,0,0,0,, 然后离开 \\N{\\fs12}and then just go away.\r\nDialogue: 0,0:25:41.91,0:25:43.48,yin,,0,0,0,, 就是这种模式 \\N{\\fs12}Okay. That is the modal.\r\nDialogue: 0,0:25:44.01,0:25:45.73,yin,,0,0,0,, 有些人可能会对此很困惑 \\N{\\fs12}Some people will be confused by that.\r\nDialogue: 0,0:25:45.73,0:25:48.90,yin,,0,0,0,, 自己的数据呢 都没了 \\N{\\fs12}You’ll think oh, what happened to all my data, it’s gone.\r\nDialogue: 0,0:25:48.92,0:25:50.46,yin,,0,0,0,, 因为它被释放了 对吧 \\N{\\fs12}Well, because it got de-allocated, all right,\r\nDialogue: 0,0:25:50.47,0:25:52.03,yin,,0,0,0,, 返回时就会进行这样的操作 \\N{\\fs12}because that’s what happens when you do back.\r\nDialogue: 0,0:25:52.30,0:25:54.49,yin,,0,0,0,, 所以如果某些数据需要继续使用 \\N{\\fs12}Okay. So if there’s any data in there that needs to stay,\r\nDialogue: 0,0:25:54.49,0:25:55.89,yin,,0,0,0,, 你就需要在某处对它进行保存 \\N{\\fs12}you need to save it somewhere.\r\nDialogue: 0,0:25:56.88,0:25:59.45,yin,,0,0,0,, 可以通过反向通信 \\N{\\fs12}Okay. And you could do it by communicating back\r\nDialogue: 0,0:25:59.63,0:26:02.71,yin,,0,0,0,, 向将你压进来的那个 MVC 发送消息来实现 \\N{\\fs12}to the MVC that pushed you onscreen,\r\nDialogue: 0,0:26:02.79,0:26:04.89,yin,,0,0,0,, 但是必须借助不可视结构化通信 \\N{\\fs12}but you have to do it with that blind structured communication.\r\nDialogue: 0,0:26:05.11,0:26:06.99,yin,,0,0,0,, 后面的课程中会讲到 \\N{\\fs12}And we’ll do that later in the quarter. Okay.\r\nDialogue: 0,0:26:07.13,0:26:09.36,yin,,0,0,0,, 反正这次作业用不到 \\N{\\fs12}You won’t have to do that for this assignment whatsoever.\r\nDialogue: 0,0:26:10.28,0:26:12.07,yin,,0,0,0,, 从根本上说 就是这样工作的 \\N{\\fs12}Okay. So, that’s basically how it works.\r\nDialogue: 0,0:26:12.44,0:26:15.27,yin,,0,0,0,, 现在我们再讲一下压入操作 \\N{\\fs12}Now, let’s talk a little bit about that pushing.\r\nDialogue: 0,0:26:15.49,0:26:19.67,yin,,0,0,0,, 如何让第二个 MVC 出现在屏幕上呢 \\N{\\fs12}How do we make a second MVC appear on screen?\r\nDialogue: 0,0:26:19.68,0:26:21.51,yin,,0,0,0,, 如何让它滑入呢 \\N{\\fs12}How do we make it do that sliding in thing?\r\nDialogue: 0,0:26:21.68,0:26:24.05,yin,,0,0,0,, 答案是使用 segue\\N{\\fs12}Well, the answer is we use what’s called a segue.\r\nDialogue: 0,0:26:24.05,0:26:26.53,yin,,0,0,0,,segue 是这节课需要理解的非常重要的内容 \\N{\\fs12}Okay. Segues are very important to understand in this class.\r\nDialogue: 0,0:26:26.66,0:26:29.71,yin,,0,0,0,,segue 是用来从一个 MVC\\N{\\fs12}A segue is just when you’re going to move or segue,\r\nDialogue: 0,0:26:29.82,0:26:31.82,yin,,0,0,0,, 移动或 segue 跳转到另一个 MVC\\N{\\fs12}from one MVC to another.\r\nDialogue: 0,0:26:32.74,0:26:34.91,yin,,0,0,0,,segue 的作用就是这样 \\N{\\fs12}Okay. That’s what a segue’s about\r\nDialogue: 0,0:26:35.15,0:26:38.54,yin,,0,0,0,,UINavigationController 中用到的 segue\\N{\\fs12}and the segue that’s involved in a UINavigationController\r\nDialogue: 0,0:26:38.55,0:26:39.90,yin,,0,0,0,, 叫做 push 类型 segue\\N{\\fs12}is called a push segue.\r\nDialogue: 0,0:26:40.20,0:26:42.71,yin,,0,0,0,, 可以把导航控制器看作是 \\N{\\fs12}We kind of think of the navigation controller as\r\nDialogue: 0,0:26:42.95,0:26:45.38,yin,,0,0,0,, 在最前面压入一个新的 MVC\\N{\\fs12}we push a new MVC into the front,\r\nDialogue: 0,0:26:45.45,0:26:46.76,yin,,0,0,0,, 可能会再压入一个 \\N{\\fs12}and maybe push another one,\r\nDialogue: 0,0:26:46.84,0:26:48.82,yin,,0,0,0,, 然后点击返回按钮后 \\N{\\fs12}and then we pop back and pop back\r\nDialogue: 0,0:26:48.83,0:26:49.88,yin,,0,0,0,, 再逐一弹出回去 \\N{\\fs12}when we hit the back button.\r\nDialogue: 0,0:26:50.22,0:26:51.55,yin,,0,0,0,, 我们用的是这个术语 \\N{\\fs12}Okay. That’s the terminology that we use.\r\nDialogue: 0,0:26:51.56,0:26:52.93,yin,,0,0,0,, 但是它叫做 push 类型 segue\\N{\\fs12}But it’s called a push segue.\r\nDialogue: 0,0:26:53.19,0:26:56.60,yin,,0,0,0,, 我们先来讲一下如何设置一个 push 类型 segue\\N{\\fs12}So, let me talk about how to set up a push segue first,\r\nDialogue: 0,0:26:56.73,0:26:59.43,yin,,0,0,0,, 然后再演示如何将全部内容 \\N{\\fs12}and then we’ll show you how to put the whole thing\r\nDialogue: 0,0:26:59.43,0:27:01.18,yin,,0,0,0,, 放入一个导航控制器中 \\N{\\fs12}into a navigation controller.\r\nDialogue: 0,0:27:01.45,0:27:03.17,yin,,0,0,0,, 所以这里分为两个步骤 \\N{\\fs12}Okay. So that’s the two-step process here.\r\nDialogue: 0,0:27:04.06,0:27:05.79,yin,,0,0,0,, 现在我们只有一个 MVC\\N{\\fs12}All right. So we’ve only had the single MVC.\r\nDialogue: 0,0:27:05.79,0:27:08.54,yin,,0,0,0,, 我再来快速演示一下 如何新建一个 MVC\\N{\\fs12}Let’s show briefly again, how you create a new one.\r\nDialogue: 0,0:27:08.65,0:27:13.51,yin,,0,0,0,, 只要从对象面板拖拽出一个 UIViewController\\N{\\fs12}I’m just going to drag a UIViewController out of the object pallet.\r\nDialogue: 0,0:27:13.64,0:27:15.43,yin,,0,0,0,, 就是这样 \\N{\\fs12}It appears like that.\r\nDialogue: 0,0:27:15.60,0:27:18.10,yin,,0,0,0,, 然后转到标识符检查器 \\N{\\fs12}Then I’m going to go up to the identity inspector,\r\nDialogue: 0,0:27:18.48,0:27:20.41,yin,,0,0,0,, 不是属性检查器 而是标识符检查器 \\N{\\fs12}not the attributes inspector, the identity inspector,\r\nDialogue: 0,0:27:20.41,0:27:21.75,yin,,0,0,0,, 将这里的类选项 \\N{\\fs12}and I’m going to set the class\r\nDialogue: 0,0:27:22.00,0:27:25.74,yin,,0,0,0,, 设置成为我之前通过新建文件创建的类 \\N{\\fs12}to be whatever class I’ve created with file, new file,\r\nDialogue: 0,0:27:25.74,0:27:27.12,yin,,0,0,0,, 或者也可能已经有那个类了 \\N{\\fs12}or I might have that class lying around,\r\nDialogue: 0,0:27:27.12,0:27:28.91,yin,,0,0,0,, 因为在 storyboard 中很有可能会出现 \\N{\\fs12}because it’s very possible in a storyboard\r\nDialogue: 0,0:27:28.92,0:27:31.85,yin,,0,0,0,, 多个场景使用同一个控制器的情况 \\N{\\fs12}to have multiple of these scenes that use the same controller,\r\nDialogue: 0,0:27:31.85,0:27:33.86,yin,,0,0,0,, 如果是在不同环境中展示相同的内容 \\N{\\fs12}if you’re displaying the same thing in different environments,\r\nDialogue: 0,0:27:33.88,0:27:35.27,yin,,0,0,0,, 都可以的 完全没问题 \\N{\\fs12}so whatever. It’s perfectly fine.\r\nDialogue: 0,0:27:35.52,0:27:38.58,yin,,0,0,0,, 很容易忘记在这里设置类 \\N{\\fs12}It’s a very common mistake to forget to do this.\r\nDialogue: 0,0:27:38.84,0:27:40.51,yin,,0,0,0,, 你可能会来问我 \\N{\\fs12}All right. You end up coming to office hours and saying\r\nDialogue: 0,0:27:40.53,0:27:42.96,yin,,0,0,0,, 我拖出了新的视图控制器 \\N{\\fs12}ah, I put this — I dragged out my new view controller,\r\nDialogue: 0,0:27:42.96,0:27:44.54,yin,,0,0,0,, 新建了视图控制器类 \\N{\\fs12}I created my new view controller class,\r\nDialogue: 0,0:27:44.54,0:27:46.57,yin,,0,0,0,, 但是我却不能连接输出口或者操作 \\N{\\fs12}but I can’t hook up any of the outlets or actions.\r\nDialogue: 0,0:27:46.58,0:27:48.12,yin,,0,0,0,, 因为你忘记设置类了 \\N{\\fs12}Well, because you forgot to set the class.\r\nDialogue: 0,0:27:48.46,0:27:51.14,yin,,0,0,0,, 操作很简单 但是也很容易忘记 \\N{\\fs12}Okay. Simple thing to do, but simple to forget as well.\r\nDialogue: 0,0:27:51.15,0:27:54.58,yin,,0,0,0,, 我敢肯定在这门课上至少会出现一次 \\N{\\fs12}I’m sure at least one time in a demo in this class in lecture,\r\nDialogue: 0,0:27:54.58,0:27:55.63,yin,,0,0,0,, 我也忘了做这个操作 \\N{\\fs12}I’ll forget to do that too,\r\nDialogue: 0,0:27:55.63,0:27:59.13,yin,,0,0,0,, 到时候就靠大家提醒我不要忘了这一步了 好吗 \\N{\\fs12}so I’m relying on you to say oh, don’t forget to set the class. Okay.\r\nDialogue: 0,0:28:00.88,0:28:02.26,yin,,0,0,0,, 设置好类之后 \\N{\\fs12}So once you’ve set the class,\r\nDialogue: 0,0:28:02.27,0:28:06.51,yin,,0,0,0,, 现在就有了这两个 MVC 控制器不同 \\N{\\fs12}now you have these two MVCs with different controllers.\r\nDialogue: 0,0:28:06.94,0:28:09.97,yin,,0,0,0,, 现在它们都没有视图 \\N{\\fs12}Okay. There’s no view in either of these right now.\r\nDialogue: 0,0:28:10.16,0:28:14.34,yin,,0,0,0,, 这个白色小长方形 我们叫做 scene 场景 \\N{\\fs12}We call this, one of these little rectangular things, a scene,\r\nDialogue: 0,0:28:14.95,0:28:16.19,yin,,0,0,0,, 是在 storyboard 中的 \\N{\\fs12}okay, in the storyboard.\r\nDialogue: 0,0:28:16.20,0:28:17.88,yin,,0,0,0,, 如果我说场景 \\N{\\fs12}If you hear me use the word scene,\r\nDialogue: 0,0:28:17.94,0:28:20.33,yin,,0,0,0,, 就表示一个控制器 \\N{\\fs12}I just mean a combination of a controller\r\nDialogue: 0,0:28:20.38,0:28:22.36,yin,,0,0,0,, 和一个特别创建的视图的组合 \\N{\\fs12}and a particular view that we’ve built.\r\nDialogue: 0,0:28:23.15,0:28:25.49,yin,,0,0,0,, 这叫做场景 \\N{\\fs12}Okay. So that’s called a scene.\r\nDialogue: 0,0:28:27.56,0:28:29.48,yin,,0,0,0,, 现在我要做的操作是 \\N{\\fs12}Okay. So, what we’re going to do now\r\nDialogue: 0,0:28:29.48,0:28:32.43,yin,,0,0,0,, 拖出一个按钮 放到左边的场景中 \\N{\\fs12}is I’m going to drag a button into the left scene,\r\nDialogue: 0,0:28:32.55,0:28:33.95,yin,,0,0,0,, 当点击那个按钮时 \\N{\\fs12}and when we click that button,\r\nDialogue: 0,0:28:33.97,0:28:37.24,yin,,0,0,0,, 它会滑进 UINavigationController 中 \\N{\\fs12}it’s going to slide it in in a UINavigationController.\r\nDialogue: 0,0:28:37.41,0:28:38.63,yin,,0,0,0,, 会压入进去 \\N{\\fs12}Okay. It’s going to push it.\r\nDialogue: 0,0:28:38.99,0:28:40.74,yin,,0,0,0,, 所以我们要把按钮放到左边 \\N{\\fs12}So we’re going to put that button in the left,\r\nDialogue: 0,0:28:40.92,0:28:43.70,yin,,0,0,0,, 然后创建一个连接到右边的 push 类型 segue\\N{\\fs12}and we’re going to create a push segue to the right.\r\nDialogue: 0,0:28:44.13,0:28:45.37,yin,,0,0,0,, 把按钮放到那里 \\N{\\fs12}So let’s put the button there.\r\nDialogue: 0,0:28:45.50,0:28:46.97,yin,,0,0,0,, 我们只要把它放在中间 \\N{\\fs12}All right. We’re just gonna drop it right in the middle there.\r\nDialogue: 0,0:28:46.97,0:28:48.91,yin,,0,0,0,, 不用编辑标题什么的 \\N{\\fs12}I’m not going to change the title or anything.\r\nDialogue: 0,0:28:49.20,0:28:52.30,yin,,0,0,0,, 创建 segue 的方法就是按住 control 键进行拖拽 \\N{\\fs12}To make it segue all I do — control drag.\r\nDialogue: 0,0:28:52.64,0:28:56.13,yin,,0,0,0,,Xcode 中就是要按住 control 键进行拖拽 \\N{\\fs12}Right. That’s what we do in Xcode, we control drag.\r\nDialogue: 0,0:28:56.31,0:29:00.43,yin,,0,0,0,, 只要从 segue 开始的地方按住 control 键 \\N{\\fs12}So you just control drag from the thing you want to start the segue\r\nDialogue: 0,0:29:00.86,0:29:03.59,yin,,0,0,0,, 拖动至想要 segue 到的视图控制器上 \\N{\\fs12}over to the view controller you want it to segue to.\r\nDialogue: 0,0:29:04.34,0:29:06.77,yin,,0,0,0,, 松开鼠标后 \\N{\\fs12}Okay. When you let go of the mouse,\r\nDialogue: 0,0:29:06.99,0:29:08.70,yin,,0,0,0,, 就会出现这个黑色的列表 \\N{\\fs12}it’s going to put this little black thing up\r\nDialogue: 0,0:29:08.94,0:29:11.72,yin,,0,0,0,, 询问你想要什么类型的 segue\\N{\\fs12}and ask what kind of segue do you want here,\r\nDialogue: 0,0:29:12.00,0:29:14.68,yin,,0,0,0,, 在当前情况下 只有三种可用 \\N{\\fs12}and in this context, there’s only three that make sense –\r\nDialogue: 0,0:29:14.68,0:29:17.24,yin,,0,0,0,,push 类型 适用于导航控制器 \\N{\\fs12}push, which would be navigation controller one.\r\nDialogue: 0,0:29:17.48,0:29:19.09,yin,,0,0,0,,modal 类型 我们稍后会讲到 \\N{\\fs12}Modal, which we’ll talk about later,\r\nDialogue: 0,0:29:19.09,0:29:21.44,yin,,0,0,0,, 这种类型的 segue 会接管屏幕 \\N{\\fs12}which is take over the screen segue.\r\nDialogue: 0,0:29:21.72,0:29:24.25,yin,,0,0,0,, 我放在后面讲 因为它有可能会被滥用 \\N{\\fs12}I teach you that late because that can be abused.\r\nDialogue: 0,0:29:24.25,0:29:25.62,yin,,0,0,0,, 我们并不想过多地使用这种类型 \\N{\\fs12}Okay. We don’t want to do that too much.\r\nDialogue: 0,0:29:25.77,0:29:27.65,yin,,0,0,0,,custom 类型允许你创建自己的 segue\\N{\\fs12}And then custom create your own segues.\r\nDialogue: 0,0:29:27.65,0:29:28.97,yin,,0,0,0,, 我们这门课上不会讲到它的 \\N{\\fs12}We’re not even going to talk about that in this class,\r\nDialogue: 0,0:29:28.97,0:29:29.83,yin,,0,0,0,, 非常少见 \\N{\\fs12}that’s so rare.\r\nDialogue: 0,0:29:30.28,0:29:31.80,yin,,0,0,0,, 点击 push 之后 \\N{\\fs12}All right. So I click push\r\nDialogue: 0,0:29:32.09,0:29:34.71,yin,,0,0,0,,MVC 之间会出现这个小图标 \\N{\\fs12}and it puts this little thing in between my MVCs.\r\nDialogue: 0,0:29:34.71,0:29:35.88,yin,,0,0,0,, 看到这个圆形图标了吗 \\N{\\fs12}You see that little round thing?\r\nDialogue: 0,0:29:36.03,0:29:36.93,yin,,0,0,0,, 它代表 segue\\N{\\fs12}That’s a segue.\r\nDialogue: 0,0:29:37.51,0:29:39.50,yin,,0,0,0,, 它是可以点击的 \\N{\\fs12}Okay. And this is a clickable thing.\r\nDialogue: 0,0:29:39.50,0:29:41.25,yin,,0,0,0,, 实际上 你也需要点击它 \\N{\\fs12}In fact, you’re going to need to click on it,\r\nDialogue: 0,0:29:41.42,0:29:42.52,yin,,0,0,0,, 因为当你点击它后 \\N{\\fs12}because when you click on it\r\nDialogue: 0,0:29:42.52,0:29:44.20,yin,,0,0,0,, 转到属性检查器 \\N{\\fs12}and you go to the attributes inspector,\r\nDialogue: 0,0:29:44.20,0:29:47.25,yin,,0,0,0,, 可以看到有两项 \\N{\\fs12}you’ll see that it has two things actually,\r\nDialogue: 0,0:29:47.27,0:29:49.05,yin,,0,0,0,, 一项是 segue 类型 这里是 push\\N{\\fs12}one is the type of segue, which is push,\r\nDialogue: 0,0:29:49.18,0:29:51.26,yin,,0,0,0,, 它的上面是标识符 \\N{\\fs12}but above that, it has this identifier.\r\nDialogue: 0,0:29:51.26,0:29:54.27,yin,,0,0,0,, 我把这个 segue 叫做 Do Something 做某事 \\N{\\fs12}Okay. And I call this segue the Do Something segue.\r\nDialogue: 0,0:29:54.75,0:29:56.97,yin,,0,0,0,, 为什么要在这里加上这个标识符 \\N{\\fs12}Now why do I need to put this identifier here?\r\nDialogue: 0,0:29:56.97,0:29:59.92,yin,,0,0,0,, 实际上 这个标识符差不多是必须设置的 \\N{\\fs12}And actually, it’s pretty much mandatory to put something here.\r\nDialogue: 0,0:30:00.30,0:30:04.42,yin,,0,0,0,, 因为我需要在代码中标识出这个 segue\\N{\\fs12}And the reason is that I need to identify this segue in my code.\r\nDialogue: 0,0:30:05.27,0:30:06.40,yin,,0,0,0,, 这是一个连接点 \\N{\\fs12}Okay. This is the link,\r\nDialogue: 0,0:30:07.15,0:30:09.09,yin,,0,0,0,, 有人可能会认为它很脆弱 \\N{\\fs12}tenuous as one might argue it is,\r\nDialogue: 0,0:30:09.31,0:30:11.13,yin,,0,0,0,, 它是 Xcode 和你的代码间 \\N{\\fs12}between Xcode and your code,\r\nDialogue: 0,0:30:11.29,0:30:12.46,yin,,0,0,0,, 关于 segue 的连接点 \\N{\\fs12}when it comes to a segue.\r\nDialogue: 0,0:30:12.46,0:30:14.52,yin,,0,0,0,, 基本上 我们都会命名 segue\\N{\\fs12}Okay. We essentially name these segues,\r\nDialogue: 0,0:30:14.52,0:30:16.08,yin,,0,0,0,, 赋予它们标识符字符串 \\N{\\fs12}we give them identifier strings\r\nDialogue: 0,0:30:16.26,0:30:17.75,yin,,0,0,0,, 然后就可以在代码中使用 \\N{\\fs12}and in our code we can refer to them.\r\nDialogue: 0,0:30:17.75,0:30:19.63,yin,,0,0,0,, 下面的一些幻灯片中 \\N{\\fs12}And you’ll see in a few slides here,\r\nDialogue: 0,0:30:20.00,0:30:22.50,yin,,0,0,0,, 将会看到在代码中什么地方用到了它们 \\N{\\fs12}where in our code we refer to this,\r\nDialogue: 0,0:30:22.51,0:30:24.21,yin,,0,0,0,, 命名 segue 是非常重要的 \\N{\\fs12}but it’s very important to do that.\r\nDialogue: 0,0:30:24.59,0:30:26.20,yin,,0,0,0,, 这是另外一件 \\N{\\fs12}Okay. Another common thing –\r\nDialogue: 0,0:30:26.21,0:30:27.32,yin,,0,0,0,, 容易忘记的事情 \\N{\\fs12}this is a common thing to forget.\r\nDialogue: 0,0:30:27.62,0:30:28.93,yin,,0,0,0,, 你创建了一个 segue\\N{\\fs12}You create a segue,\r\nDialogue: 0,0:30:29.01,0:30:30.97,yin,,0,0,0,, 转到代码才发现自己忘记命名了 \\N{\\fs12}you go to your code, and you’re like oh, oops,\r\nDialogue: 0,0:30:30.98,0:30:33.02,yin,,0,0,0,, 最后还得回到 Xcode 中对它命名 \\N{\\fs12}and then you end up having to go back to Xcode and naming it.\r\nDialogue: 0,0:30:33.09,0:30:36.55,yin,,0,0,0,, 这个操作不大可能会过了很久才发现 \\N{\\fs12}This one you’re less likely to get very far without remembering to go back,\r\nDialogue: 0,0:30:36.57,0:30:39.62,yin,,0,0,0,, 但依旧是经常会忘记的操作 \\N{\\fs12}but it’s still something that’s commonly forgotten.\r\nDialogue: 0,0:30:39.89,0:30:43.09,yin,,0,0,0,, 我们要将这个 segue 叫做 Do Something\\N{\\fs12}All right. So, we’re gonna call this segue the Do Something segue.\r\nDialogue: 0,0:30:43.30,0:30:47.01,yin,,0,0,0,, 命名时通常会选择具有描述性的标识符 \\N{\\fs12}Usually you want to pick an identifier that describes in some –\r\nDialogue: 0,0:30:47.26,0:30:50.31,yin,,0,0,0,, 就像变量名描述变量一样 \\N{\\fs12}you know, just like a variable name would describe,\r\nDialogue: 0,0:30:50.31,0:30:51.35,yin,,0,0,0,, 表明它要做什么 \\N{\\fs12}what’s going on here.\r\nDialogue: 0,0:30:51.54,0:30:53.29,yin,,0,0,0,, 这是一个通用的示例 \\N{\\fs12}So this is a generic example,\r\nDialogue: 0,0:30:53.29,0:30:55.21,yin,,0,0,0,, 点击按钮后 我们会做某事 \\N{\\fs12}so when we click that button, we’re going to do something,\r\nDialogue: 0,0:30:55.21,0:30:56.20,yin,,0,0,0,, 所以我叫它 Do Something 做某事 \\N{\\fs12}so I called it Do Something,\r\nDialogue: 0,0:30:56.21,0:30:58.78,yin,,0,0,0,, 但是你们也许会选一个更好的名字 \\N{\\fs12}but you probably want to pick a better name than Do Something.\r\nDialogue: 0,0:30:58.78,0:30:59.86,yin,,0,0,0,, 不那么通用的名字 \\N{\\fs12}That’s a little generic. Okay.\r\nDialogue: 0,0:31:01.82,0:31:03.35,yin,,0,0,0,, 但是这里有个问题 \\N{\\fs12}Okay. So, there’s a problem here though.\r\nDialogue: 0,0:31:03.35,0:31:05.48,yin,,0,0,0,, 如果现在这样运行应用 \\N{\\fs12}If I were to run my application in this state,\r\nDialogue: 0,0:31:05.48,0:31:06.38,yin,,0,0,0,, 是不会正常运行的 \\N{\\fs12}it would not work.\r\nDialogue: 0,0:31:06.73,0:31:09.46,yin,,0,0,0,, 点击那个按钮不会发生 segue 跳转 \\N{\\fs12}Okay. Clicking that button would not segue.\r\nDialogue: 0,0:31:09.82,0:31:10.67,yin,,0,0,0,, 为什么呢 \\N{\\fs12}Why is that?\r\nDialogue: 0,0:31:10.79,0:31:14.77,yin,,0,0,0,, 因为这些 MVC 需要放在导航控制器中 \\N{\\fs12}Because this whole thing has to be in a navigation controller.\r\nDialogue: 0,0:31:15.20,0:31:16.74,yin,,0,0,0,, 这有两个 MVC\\N{\\fs12}Right. These two MVCs –\r\nDialogue: 0,0:31:16.74,0:31:18.29,yin,,0,0,0,, 我需要第三个 MVC\\N{\\fs12}I need a third MVC,\r\nDialogue: 0,0:31:18.29,0:31:20.05,yin,,0,0,0,, 即它们所在的导航控制器 \\N{\\fs12}which is the navigation controller they’re in.\r\nDialogue: 0,0:31:20.36,0:31:21.88,yin,,0,0,0,, 我们讲讲如何实现 \\N{\\fs12}So, let’s talk about how to do that.\r\nDialogue: 0,0:31:22.08,0:31:23.13,yin,,0,0,0,, 非常简单 \\N{\\fs12}It’s very simple.\r\nDialogue: 0,0:31:23.15,0:31:27.97,yin,,0,0,0,, 选择想要的根视图控制器 \\N{\\fs12}You pick which one of these you want to be the root view controller,\r\nDialogue: 0,0:31:28.53,0:31:30.14,yin,,0,0,0,, 导航控制器的根视图控制器 \\N{\\fs12}all right, of the navigation controller,\r\nDialogue: 0,0:31:30.37,0:31:33.55,yin,,0,0,0,, 然后打开编辑器菜单选择嵌入导航控制器 \\N{\\fs12}and you go to the editor menu and you say embed in navigation controller.\r\nDialogue: 0,0:31:33.55,0:31:34.80,yin,,0,0,0,, 我选择了左边这个 \\N{\\fs12}So I picked the one on the left,\r\nDialogue: 0,0:31:34.81,0:31:36.94,yin,,0,0,0,, 可以看到它周围的深蓝色边框 \\N{\\fs12}you see it’s got the dark blue line around it.\r\nDialogue: 0,0:31:36.98,0:31:38.49,yin,,0,0,0,, 选择菜单中的嵌入 > 导航控制器 \\N{\\fs12}I say embed in navigation controller,\r\nDialogue: 0,0:31:38.50,0:31:40.06,yin,,0,0,0,, 这样做之后 \\N{\\fs12}and when I do that, boom,\r\nDialogue: 0,0:31:40.07,0:31:41.70,yin,,0,0,0,, 就会创建一个导航控制器 \\N{\\fs12}it’s going to create a navigation controller,\r\nDialogue: 0,0:31:41.70,0:31:44.92,yin,,0,0,0,, 所以现在 storyboard 中有三个 MVC\\N{\\fs12}so now I have three MVCs in this storyboard. Three.\r\nDialogue: 0,0:31:45.13,0:31:46.75,yin,,0,0,0,, 导航控制器在左边 \\N{\\fs12}I’ve got the navigation controller on the left,\r\nDialogue: 0,0:31:47.03,0:31:50.38,yin,,0,0,0,, 另外两个在右边 \\N{\\fs12}and then I’ve got my two other ones on the right. Okay.\r\nDialogue: 0,0:31:51.31,0:31:53.90,yin,,0,0,0,, 最左边的小箭头 \\N{\\fs12}And the little arrow on the very left,\r\nDialogue: 0,0:31:53.90,0:31:56.14,yin,,0,0,0,, 看到那个从左边指出来的箭头了吗 \\N{\\fs12}do you see that arrow that kind of points in from the left?\r\nDialogue: 0,0:31:56.59,0:32:00.95,yin,,0,0,0,, 它代表应用开始运行时 \\N{\\fs12}That is where — that’s the MVC that’s going to be onscreen\r\nDialogue: 0,0:32:00.95,0:32:02.26,yin,,0,0,0,, 将显示在屏幕上的 MVC\\N{\\fs12}when your application launches.\r\nDialogue: 0,0:32:02.86,0:32:05.63,yin,,0,0,0,, 那个小箭头其实可以被拾取和移动 \\N{\\fs12}And that little arrow can actually be picked up and moved around.\r\nDialogue: 0,0:32:06.05,0:32:08.29,yin,,0,0,0,, 只要拾取它 移动到你想要的 MVC 上 \\N{\\fs12}Just pick it up and drop it on any MVC you want.\r\nDialogue: 0,0:32:08.52,0:32:11.03,yin,,0,0,0,, 那个 MVC 就会成为应用开始运行时的第一个 MVC\\N{\\fs12}That’s going to be the MVC when you start.\r\nDialogue: 0,0:32:11.03,0:32:12.79,yin,,0,0,0,, 这个箭头原来指向的是 \\N{\\fs12}Now it used to be pointing at the MVC\r\nDialogue: 0,0:32:12.79,0:32:14.67,yin,,0,0,0,, 中间有 Button 单词的那个 MVC\\N{\\fs12}that has the word button in there in the middle,\r\nDialogue: 0,0:32:14.81,0:32:17.03,yin,,0,0,0,, 但是我将它嵌入到导航控制器中以后 \\N{\\fs12}but as soon as I embedded it in a navigation controller\r\nDialogue: 0,0:32:17.03,0:32:19.24,yin,,0,0,0,, 它就会自动移出来 指向导航控制器 \\N{\\fs12}it automatically moved it out to the navigation controller.\r\nDialogue: 0,0:32:19.48,0:32:22.25,yin,,0,0,0,, 将箭头指向导航控制器内的 MVC\\N{\\fs12}It would never make sense to have a little arrow\r\nDialogue: 0,0:32:22.44,0:32:25.79,yin,,0,0,0,, 完全没有意义 \\N{\\fs12}pointing to an MVC that’s inside a navigation controller.\r\nDialogue: 0,0:32:26.03,0:32:29.57,yin,,0,0,0,, 这样的意思不是说打开导航控制器 \\N{\\fs12}Okay. Because that doesn’t mean bring up the navigation controller\r\nDialogue: 0,0:32:29.68,0:32:31.60,yin,,0,0,0,, 让这个 MVC 成为它的根视图控制器 \\N{\\fs12}and have this be the root view controller.\r\nDialogue: 0,0:32:31.76,0:32:34.83,yin,,0,0,0,, 这样的意思很奇怪 \\N{\\fs12}That would just mean something strange.\r\nDialogue: 0,0:32:34.83,0:32:37.36,yin,,0,0,0,, 我也不知道为什么会允许这样的操作 \\N{\\fs12}I’m not even sure why it’s going to allow that,\r\nDialogue: 0,0:32:37.36,0:32:38.61,yin,,0,0,0,, 但这样是不能正常运行的 \\N{\\fs12}but it wouldn’t work.\r\nDialogue: 0,0:32:38.73,0:32:40.84,yin,,0,0,0,, 应用开始运行时不会出现导航控制器 \\N{\\fs12}When it came up there would be no navigation controller,\r\nDialogue: 0,0:32:40.84,0:32:42.74,yin,,0,0,0,, 因为你绕过了它 \\N{\\fs12}because you’d be bypassing the navigation controller.\r\nDialogue: 0,0:32:43.01,0:32:46.77,yin,,0,0,0,, 但是你可以拖动箭头 指向选项卡栏控制器 \\N{\\fs12}So — but you can drag that little arrow to a tab bar controller,\r\nDialogue: 0,0:32:46.77,0:32:50.46,yin,,0,0,0,, 有时为了测试 可以将箭头指向一个视图控制器 \\N{\\fs12}or sometimes in testing, it’s nice to move them to a view controller\r\nDialogue: 0,0:32:50.46,0:32:52.95,yin,,0,0,0,, 让应用从它开始运行 \\N{\\fs12}and just say oh, just start with this view controller,\r\nDialogue: 0,0:32:52.97,0:32:55.07,yin,,0,0,0,, 因为这些视图控制器应该是可以独立运行的 \\N{\\fs12}because remember these view controllers are supposed to stand on their own,\r\nDialogue: 0,0:32:55.88,0:32:58.11,yin,,0,0,0,, 所以可以在测试时将开始箭头指向它们 \\N{\\fs12}so you can sometimes drag it to startup for testing\r\nDialogue: 0,0:32:58.13,0:32:58.98,yin,,0,0,0,, 测试完成再移回去 \\N{\\fs12}and then drag it back.\r\nDialogue: 0,0:32:58.98,0:32:59.95,yin,,0,0,0,, 今天如果有时间的话 \\N{\\fs12}In fact, I’ll try to do that,\r\nDialogue: 0,0:32:59.97,0:33:03.01,yin,,0,0,0,, 我会演示一下 \\N{\\fs12}if we have time in the demo today. Okay.\r\nDialogue: 0,0:33:04.65,0:33:06.20,yin,,0,0,0,, 第二个小圆形图标 \\N{\\fs12}The second little thing there,\r\nDialogue: 0,0:33:06.20,0:33:08.93,yin,,0,0,0,, 看起来像是一个 segue 但其实不是 \\N{\\fs12}that looks like a segue, but it’s not actually.\r\nDialogue: 0,0:33:08.94,0:33:12.12,yin,,0,0,0,, 它只用于展示导航控制器 \\N{\\fs12}That’s actually just showing you the root view controller connection\r\nDialogue: 0,0:33:12.22,0:33:14.48,yin,,0,0,0,, 与根视图控制器之间的连接关系 \\N{\\fs12}from the navigation controller. Okay.\r\nDialogue: 0,0:33:14.74,0:33:15.74,yin,,0,0,0,, 当出现这个图标 \\N{\\fs12}When you see the little –\r\nDialogue: 0,0:33:15.82,0:33:17.82,yin,,0,0,0,, 看起来像是一条线两个点 \\N{\\fs12}kind of it looks like a line with two dots in there\r\nDialogue: 0,0:33:17.82,0:33:21.65,yin,,0,0,0,, 代表它是输出口类型的连接 而不是 segue\\N{\\fs12}that means it’s a kind of an outlet type of connection not a segue.\r\nDialogue: 0,0:33:21.65,0:33:23.86,yin,,0,0,0,, 二者很相似 但是你不能检查它 \\N{\\fs12}Looks very similar, but you can’t inspect it,\r\nDialogue: 0,0:33:23.86,0:33:25.33,yin,,0,0,0,, 不能设置它的标识符 \\N{\\fs12}you can’t set an identifier.\r\nDialogue: 0,0:33:25.33,0:33:26.73,yin,,0,0,0,, 这里都不需要 \\N{\\fs12}None of that’s necessary here.\r\nDialogue: 0,0:33:26.73,0:33:28.18,yin,,0,0,0,, 它只是用来表示这个连接 \\N{\\fs12}It’s just showing you that connection.\r\nDialogue: 0,0:33:28.43,0:33:30.36,yin,,0,0,0,, 但这个是 segue\\N{\\fs12}But this one, that is the segue,\r\nDialogue: 0,0:33:30.36,0:33:32.55,yin,,0,0,0,, 是几张幻灯片前我们按住 control 键拖拽出的 \\N{\\fs12}the thing that we control dragged a few slides ago.\r\nDialogue: 0,0:33:32.74,0:33:34.13,yin,,0,0,0,, 如果我点击它 \\N{\\fs12}If I click on that,\r\nDialogue: 0,0:33:34.14,0:33:36.44,yin,,0,0,0,, 会显示它的标识符 Do Something 等等 \\N{\\fs12}it would say identifier Do Something, etcetera,\r\nDialogue: 0,0:33:37.50,0:33:41.41,yin,,0,0,0,, 注意 所有场景 \\N{\\fs12}and notice that all — every single one of the scenes\r\nDialogue: 0,0:33:41.46,0:33:44.42,yin,,0,0,0,, 当前导航控制器中的所有场景 \\N{\\fs12}that is now inside this navigation controller –\r\nDialogue: 0,0:33:44.42,0:33:45.59,yin,,0,0,0,, 不只是根视图控制器 \\N{\\fs12}not just the root view controller,\r\nDialogue: 0,0:33:45.60,0:33:48.13,yin,,0,0,0,, 所有能过通过 push 类型 segue 导航到的场景 \\N{\\fs12}but everything it can navigate to with push segues,\r\nDialogue: 0,0:33:48.25,0:33:50.74,yin,,0,0,0,, 在 Xcode 中都在顶部添加了导航栏 \\N{\\fs12}gets a bar on the top in Xcode.\r\nDialogue: 0,0:33:50.92,0:33:53.22,yin,,0,0,0,, 这样可以方便你布局 UI\\N{\\fs12}And that’s so you can lay out your UI nicely,\r\nDialogue: 0,0:33:53.22,0:33:55.95,yin,,0,0,0,, 布局时考虑到那个导航栏始终都会出现在场景顶部 \\N{\\fs12}knowing that that bar is always going to be on top of that scene,\r\nDialogue: 0,0:33:56.05,0:33:58.08,yin,,0,0,0,, 因为它在导航控制器中 \\N{\\fs12}because this thing is inside a navigation controller.\r\nDialogue: 0,0:33:58.61,0:34:01.25,yin,,0,0,0,, 如果你要添加 toolbarItems\\N{\\fs12}Okay. And if you’re adding toolbarItems things,\r\nDialogue: 0,0:34:01.26,0:34:02.74,yin,,0,0,0,, 也会在顶部出现一栏 \\N{\\fs12}then you’ll have a bar on the bottom as well.\r\nDialogue: 0,0:34:02.81,0:34:05.24,yin,,0,0,0,, 如果这些场景都在选项卡栏控制器中 \\N{\\fs12}If this was all inside a tab bar controller,\r\nDialogue: 0,0:34:05.24,0:34:07.30,yin,,0,0,0,, 这是可以的 你们的作业中就要这么做 \\N{\\fs12}which is legal and which you’re going to be doing for your homework,\r\nDialogue: 0,0:34:07.56,0:34:10.08,yin,,0,0,0,, 这种情况会在底部出现一条选项卡栏 \\N{\\fs12}then it would also have a bar for the tab bar,\r\nDialogue: 0,0:34:10.15,0:34:11.70,yin,,0,0,0,,UI 会变短 \\N{\\fs12}and so the UI would be squinching down\r\nDialogue: 0,0:34:11.70,0:34:13.16,yin,,0,0,0,, 你需要调整 UI 以适应这种布局 \\N{\\fs12}as you have to make your UI fit.\r\nDialogue: 0,0:34:13.35,0:34:15.38,yin,,0,0,0,, 下周或者下下周 \\N{\\fs12}And again, next week or the week after,\r\nDialogue: 0,0:34:15.39,0:34:17.01,yin,,0,0,0,, 也许我们会讲到自动布局 \\N{\\fs12}I guess, we’re going to talk about autolayout,\r\nDialogue: 0,0:34:17.01,0:34:20.08,yin,,0,0,0,, 通过它 可以在这些元素 \\N{\\fs12}which is a way as these things are appearing or disappearing,\r\nDialogue: 0,0:34:20.08,0:34:21.11,yin,,0,0,0,, 这些顶部栏和底部栏出现消失时 \\N{\\fs12}these bars on the top and bottom,\r\nDialogue: 0,0:34:21.11,0:34:23.42,yin,,0,0,0,, 自动对 UI 进行调整 \\N{\\fs12}to automatically have that stuff rearrange,\r\nDialogue: 0,0:34:23.44,0:34:26.69,yin,,0,0,0,, 但是目前你需要手动调整 \\N{\\fs12}but for now you’re going to have to manually do it. Okay.\r\nDialogue: 0,0:34:27.69,0:34:31.31,yin,,0,0,0,, 如果需要 你可以在栏标题上双击 \\N{\\fs12}You can double click on the title in these bars\r\nDialogue: 0,0:34:31.31,0:34:32.78,yin,,0,0,0,, 设置标题 \\N{\\fs12}and set the title if you want,\r\nDialogue: 0,0:34:32.82,0:34:37.82,yin,,0,0,0,, 否则这里显示的就是当前场景视图控制器的标题 \\N{\\fs12}or it’ll ask the view controller that’s at that scene for its title,\r\nDialogue: 0,0:34:37.84,0:34:40.67,yin,,0,0,0,, 只要使用标题属性就可以得到 \\N{\\fs12}just using the title property,\r\nDialogue: 0,0:34:41.29,0:34:44.97,yin,,0,0,0,, 此外 如果你还想在顶部添加按钮 \\N{\\fs12}and you can also — if you wanted to add a button to the top,\r\nDialogue: 0,0:34:44.97,0:34:46.91,yin,,0,0,0,, 还记得日历顶部的按钮吗 比如搜索按钮 \\N{\\fs12}remember the calendar has like the search button,\r\nDialogue: 0,0:34:46.91,0:34:48.89,yin,,0,0,0,, 添加和编辑按钮 \\N{\\fs12}and the add button, and the edit button at the top.\r\nDialogue: 0,0:34:49.47,0:34:51.47,yin,,0,0,0,, 方法是直接拖出一个按钮放在这里 \\N{\\fs12}The way you do that is you just drag a button in,\r\nDialogue: 0,0:34:51.47,0:34:53.14,yin,,0,0,0,, 但是这里不要用 UIButton\\N{\\fs12}but don’t use UIButton here.\r\nDialogue: 0,0:34:53.73,0:34:56.12,yin,,0,0,0,, 不然你会在拖拽 UIButton 时受挫的 \\N{\\fs12}Okay. Or you’ll be frustrated if you try to drag UIButton.\r\nDialogue: 0,0:34:56.12,0:34:58.39,yin,,0,0,0,, 会疑惑 为什么 UIButton 不能放到那里呢 \\N{\\fs12}It’s like ah, how come the UIButton won’t go there?\r\nDialogue: 0,0:34:58.56,0:35:00.85,yin,,0,0,0,, 因为我们要用 UIBarButtonItem\\N{\\fs12}And that’s because we use UIBarButtonItem,\r\nDialogue: 0,0:35:00.85,0:35:02.14,yin,,0,0,0,, 它是比较轻量级的 \\N{\\fs12}which is kind of a lighter weight one.\r\nDialogue: 0,0:35:02.14,0:35:04.12,yin,,0,0,0,, 滚动到差不多面板最底部 \\N{\\fs12}You scroll down almost to the bottom of the pallet\r\nDialogue: 0,0:35:04.12,0:35:05.59,yin,,0,0,0,, 就能看到这个 Bar Button Item 栏按钮项 \\N{\\fs12}you’ll see this thing — Bar Button Item.\r\nDialogue: 0,0:35:05.88,0:35:09.14,yin,,0,0,0,, 将它拖出 可以看到它会放到那里 \\N{\\fs12}You drag that out, you’ll see that it will drop there\r\nDialogue: 0,0:35:09.36,0:35:10.31,yin,,0,0,0,, 松开鼠标之后 \\N{\\fs12}and when you let it go,\r\nDialogue: 0,0:35:10.31,0:35:12.43,yin,,0,0,0,, 就出现了一个按钮 叫做 Item\\N{\\fs12}now you have a button there called item.\r\nDialogue: 0,0:35:12.46,0:35:14.12,yin,,0,0,0,, 这个按钮只会在一种情况下出现 \\N{\\fs12}That button will only appear\r\nDialogue: 0,0:35:14.21,0:35:17.01,yin,,0,0,0,, 就是这个中间有 Button 按钮的 MVC\\N{\\fs12}when this MVC — the one that has button in the middle of it,\r\nDialogue: 0,0:35:17.21,0:35:20.34,yin,,0,0,0,, 当前在导航控制器中可见的时候 \\N{\\fs12}is the currently visible thing in the navigation controller.\r\nDialogue: 0,0:35:20.36,0:35:21.98,yin,,0,0,0,, 只有这时 Item 按钮才会出现 \\N{\\fs12}That’s the only time the item will appear.\r\nDialogue: 0,0:35:22.59,0:35:25.19,yin,,0,0,0,, 这里完全可以 \\N{\\fs12}Okay. And it is perfectly legal to,\r\nDialogue: 0,0:35:25.31,0:35:28.34,yin,,0,0,0,, 不使用从 Button 到下一个 MVC 的 segue\\N{\\fs12}instead of having our segue go from button to the next one,\r\nDialogue: 0,0:35:28.34,0:35:31.13,yin,,0,0,0,, 可以从 Item 按钮按住 control 键拖动到下一个 MVC\\N{\\fs12}we could control drag from that item to the next one.\r\nDialogue: 0,0:35:31.14,0:35:32.92,yin,,0,0,0,, 我会在示例中为大家演示 \\N{\\fs12}In fact, I’ll do that in the demo just to show you.\r\nDialogue: 0,0:35:33.69,0:35:36.06,yin,,0,0,0,, 所以顶部的这个 Item 按钮 \\N{\\fs12}Okay. So that item button at the top\r\nDialogue: 0,0:35:36.07,0:35:38.05,yin,,0,0,0,, 可以作为 segue 的起点 \\N{\\fs12}is allowed to be a source of segueing.\r\nDialogue: 0,0:35:38.05,0:35:39.53,yin,,0,0,0,, 实际上这很常见 \\N{\\fs12}In fact, it very commonly is.\r\nDialogue: 0,0:35:40.61,0:35:47.78,yin,,0,0,0,, 好了 我们讲完了如何压入 MVC\\N{\\fs12}All right. Okay. So, we talked about pushing this stuff on.\r\nDialogue: 0,0:35:47.86,0:35:49.96,yin,,0,0,0,, 让它显示在屏幕上 \\N{\\fs12}Okay. That’s how you get something to appear –\r\nDialogue: 0,0:35:49.96,0:35:51.73,yin,,0,0,0,, 方法是通过 push 类型 segue\\N{\\fs12}the segue, push segue.\r\nDialogue: 0,0:35:51.82,0:35:52.76,yin,,0,0,0,, 如何离开屏幕呢 \\N{\\fs12}How about coming off?\r\nDialogue: 0,0:35:52.78,0:35:56.25,yin,,0,0,0,, 通常情况下是通过用户点击返回按钮 \\N{\\fs12}Well normally, things are coming off by a user hitting the back button,\r\nDialogue: 0,0:35:56.52,0:35:58.15,yin,,0,0,0,, 这个时候就应该离开屏幕了 \\N{\\fs12}and that’s when you want it to happen.\r\nDialogue: 0,0:35:58.15,0:35:59.88,yin,,0,0,0,, 你希望用户能够感觉 \\N{\\fs12}You want the user to feel in control\r\nDialogue: 0,0:35:59.96,0:36:02.45,yin,,0,0,0,, 自己控制着深入细节和返回的操作 \\N{\\fs12}of their diving down for detail and coming back,\r\nDialogue: 0,0:36:03.04,0:36:04.52,yin,,0,0,0,, 所以那个返回按钮需要起作用 \\N{\\fs12}so you’ll want that back button to work.\r\nDialogue: 0,0:36:04.52,0:36:05.84,yin,,0,0,0,, 但在一些情况中 \\N{\\fs12}But there are a few times\r\nDialogue: 0,0:36:05.96,0:36:08.94,yin,,0,0,0,, 需要通过编程方式实现 \\N{\\fs12}when it makes sense to programmatically do it\r\nDialogue: 0,0:36:08.94,0:36:11.00,yin,,0,0,0,, 有一个例子是 假设 \\N{\\fs12}and one example is, let’s say,\r\nDialogue: 0,0:36:11.03,0:36:13.76,yin,,0,0,0,, 你打开详情页 显示了某条雇员记录 \\N{\\fs12}you dive down and you’re showing some employee record,\r\nDialogue: 0,0:36:13.84,0:36:16.29,yin,,0,0,0,, 里面有一个删除按钮 \\N{\\fs12}and a button in there is delete,\r\nDialogue: 0,0:36:16.44,0:36:17.94,yin,,0,0,0,, 表示删除这位雇员 \\N{\\fs12}meaning delete this employee.\r\nDialogue: 0,0:36:18.11,0:36:19.80,yin,,0,0,0,, 如果你点击了那个删除按钮 \\N{\\fs12}Well if you hit that delete button,\r\nDialogue: 0,0:36:20.00,0:36:21.96,yin,,0,0,0,, 就没有理由再留在这个页面了 \\N{\\fs12}it doesn’t make any sense to be here anymore,\r\nDialogue: 0,0:36:21.96,0:36:23.28,yin,,0,0,0,, 因为那位雇员没有了 \\N{\\fs12}because that employee is gone,\r\nDialogue: 0,0:36:23.51,0:36:24.66,yin,,0,0,0,, 所以你需要返回 \\N{\\fs12}so you want to go back.\r\nDialogue: 0,0:36:24.82,0:36:26.76,yin,,0,0,0,, 回到上一级 \\N{\\fs12}Okay. You want to go back to the previous level,\r\nDialogue: 0,0:36:26.91,0:36:29.97,yin,,0,0,0,, 所以你可以调用 UINavigationController 中的这个方法 \\N{\\fs12}and so you can call this method in UINavigationController\r\nDialogue: 0,0:36:30.10,0:36:32.86,yin,,0,0,0,, 叫做 popViewControllerAnimated\\N{\\fs12}called popViewControllerAnimated.\r\nDialogue: 0,0:36:32.95,0:36:35.20,yin,,0,0,0,, 而且动画参数几乎全部都是 YES\\N{\\fs12}We almost always specify yes, by the way, in animation.\r\nDialogue: 0,0:36:35.20,0:36:36.94,yin,,0,0,0,, 你并不希望 UI 跳来跳去 \\N{\\fs12}You don’t want your UI jumping around.\r\nDialogue: 0,0:36:36.94,0:36:40.43,yin,,0,0,0,, 你希望页面能够滑入 渐入等等 \\N{\\fs12}You want things sliding in and fading in and stuff like that,\r\nDialogue: 0,0:36:40.43,0:36:41.88,yin,,0,0,0,, 下面几周中 \\N{\\fs12}and we’re going to talk a lot about animation\r\nDialogue: 0,0:36:41.88,0:36:43.99,yin,,0,0,0,, 我们会讲到很多动画的内容 \\N{\\fs12}in the next couple weeks of your own stuff.\r\nDialogue: 0,0:36:44.45,0:36:46.83,yin,,0,0,0,, 你可能会问 \\N{\\fs12}But you might ask,\r\nDialogue: 0,0:36:47.34,0:36:49.59,yin,,0,0,0,, 如何得到当前 UINavigationController\\N{\\fs12}how do I get ahold of my UINavigationController\r\nDialogue: 0,0:36:49.60,0:36:50.84,yin,,0,0,0,, 向它发送这个消息呢 \\N{\\fs12}to send it this message\r\nDialogue: 0,0:36:51.08,0:36:54.42,yin,,0,0,0,, 这部分都是现成的 非常好用 \\N{\\fs12}and an awesome thing about this way is all set up is,\r\nDialogue: 0,0:36:54.42,0:36:55.81,yin,,0,0,0,, 如果你是一个视图控制器 \\N{\\fs12}if you are a view controller\r\nDialogue: 0,0:36:55.96,0:36:59.00,yin,,0,0,0,, 在一个导航控制器中 \\N{\\fs12}and you are inside a navigation controller –\r\nDialogue: 0,0:36:59.06,0:37:00.32,yin,,0,0,0,, 在它堆中的某个地方 \\N{\\fs12}anywhere on its stack,\r\nDialogue: 0,0:37:00.95,0:37:04.06,yin,,0,0,0,, 你可以得到自己的一个属性 \\N{\\fs12}you can get the property on yourself\r\nDialogue: 0,0:37:04.20,0:37:05.74,yin,,0,0,0,, 叫做 navigationController\\N{\\fs12}called navigationController\r\nDialogue: 0,0:37:05.74,0:37:08.00,yin,,0,0,0,, 它会返回你所在的导航控制器 \\N{\\fs12}and it will return you the navigation controller you’re in.\r\nDialogue: 0,0:37:09.27,0:37:09.96,yin,,0,0,0,, 明白吗 \\N{\\fs12}Does that make sense?\r\nDialogue: 0,0:37:09.96,0:37:11.82,yin,,0,0,0,, 如果你不在导航控制器中 \\N{\\fs12}If you’re not in a navigation controller,\r\nDialogue: 0,0:37:11.82,0:37:12.74,yin,,0,0,0,, 它就会直接返回 nil\\N{\\fs12}it’ll just return nil,\r\nDialogue: 0,0:37:13.22,0:37:15.23,yin,,0,0,0,,MVC 可以在很多环境中运行 \\N{\\fs12}and it’s perfectly reasonable to have MVCs\r\nDialogue: 0,0:37:15.23,0:37:16.92,yin,,0,0,0,, 可以在导航控制器中运行 \\N{\\fs12}that can live in a navigation controller,\r\nDialogue: 0,0:37:16.92,0:37:18.59,yin,,0,0,0,, 可以在选项卡栏控制器中运行 \\N{\\fs12}or live in a tab bar controller,\r\nDialogue: 0,0:37:18.65,0:37:21.50,yin,,0,0,0,, 或者是在选项卡栏控制器中的导航控制器中 \\N{\\fs12}or live in a navigation controller that’s inside a tab bar controller,\r\nDialogue: 0,0:37:21.51,0:37:22.66,yin,,0,0,0,, 或者是自己独立运行 \\N{\\fs12}or live on their own,\r\nDialogue: 0,0:37:22.66,0:37:24.47,yin,,0,0,0,, 或者是在模态情景下运行等等 \\N{\\fs12}or live in a modal situation, whatever.\r\nDialogue: 0,0:37:24.64,0:37:27.46,yin,,0,0,0,, 我们希望 MVC 可以运行于各种地方 \\N{\\fs12}You want to have MVCs that are flexible about where they live,\r\nDialogue: 0,0:37:28.07,0:37:29.50,yin,,0,0,0,, 所以有时这里会返回 nil\\N{\\fs12}so sometimes this’ll return nil,\r\nDialogue: 0,0:37:29.50,0:37:32.43,yin,,0,0,0,, 你可能要判断一下 如果在导航控制器中就弹出 \\N{\\fs12}and you might say, if I’m in a navigation controller then pop.\r\nDialogue: 0,0:37:32.49,0:37:34.75,yin,,0,0,0,, 如果不在 就做些别的 \\N{\\fs12}If I’m not then, you know, do something else.\r\nDialogue: 0,0:37:35.12,0:37:35.46,yin,,0,0,0,, 明白吧 \\N{\\fs12}All right.\r\nDialogue: 0,0:37:35.71,0:37:38.58,yin,,0,0,0,,self.navigationController 是控制器中很好用的属性 \\N{\\fs12}So, self dot navigationController is a good thing to know inside a controller.\r\nDialogue: 0,0:37:38.59,0:37:39.95,yin,,0,0,0,, 能告诉你当前所在的视图控制器 \\N{\\fs12}It tells you the view controller you’re in.\r\nDialogue: 0,0:37:40.07,0:37:41.83,yin,,0,0,0,, 此外还有 self.tabBarController\\N{\\fs12}There’s also self dot tabBarController.\r\nDialogue: 0,0:37:41.83,0:37:43.33,yin,,0,0,0,, 可以告诉你当前所在的选项卡栏控制器 \\N{\\fs12}You can find out the tab bar controller you’re in,\r\nDialogue: 0,0:37:43.35,0:37:44.91,yin,,0,0,0,, 但是几乎用不到 \\N{\\fs12}although you almost never need that,\r\nDialogue: 0,0:37:45.21,0:37:46.38,yin,,0,0,0,, 但 navigationController 是需要的 \\N{\\fs12}but navigationController you do,\r\nDialogue: 0,0:37:46.38,0:37:48.35,yin,,0,0,0,, 如果你要弹出或做其他操作的时候 \\N{\\fs12}if you’re going to pop or do some other things.\r\nDialogue: 0,0:37:49.85,0:37:51.49,yin,,0,0,0,, 除了 push 类型 还有什么类型的 segue 呢 \\N{\\fs12}What other segues are there besides push?\r\nDialogue: 0,0:37:51.49,0:37:53.15,yin,,0,0,0,, 我说到了 modal 和 popover\\N{\\fs12}I mentioned the modal and popover,\r\nDialogue: 0,0:37:53.16,0:37:54.42,yin,,0,0,0,, 还有一个 replace\\N{\\fs12}there’s also a replace,\r\nDialogue: 0,0:37:54.86,0:37:56.98,yin,,0,0,0,, 仅适用于 iPad 应用 \\N{\\fs12}which is an iPad only thing,\r\nDialogue: 0,0:37:56.98,0:37:58.14,yin,,0,0,0,, 还有 custom 类型 \\N{\\fs12}and there’s custom ones.\r\nDialogue: 0,0:37:58.23,0:38:01.31,yin,,0,0,0,, 后面几节课中我们会讲到 iPad 的内容 \\N{\\fs12}We’ll talk about iPad stuff in a few lectures,\r\nDialogue: 0,0:38:01.32,0:38:02.72,yin,,0,0,0,, 到时就会讲到这些类型 \\N{\\fs12}and we’ll cover all that then,\r\nDialogue: 0,0:38:02.97,0:38:04.25,yin,,0,0,0,, 再说一遍 我们要把 modal 放在后面讲解 \\N{\\fs12}and again, we’ll talk about modal later,\r\nDialogue: 0,0:38:04.27,0:38:05.75,yin,,0,0,0,, 因为它很容易被滥用 \\N{\\fs12}because it’s kind of easily abused.\r\nDialogue: 0,0:38:06.64,0:38:09.50,yin,,0,0,0,, 好的 现在我们讲一下 segue 时 \\N{\\fs12}Okay. So, now let’s talk about what happens in code\r\nDialogue: 0,0:38:09.51,0:38:10.47,yin,,0,0,0,, 代码中会发生什么 \\N{\\fs12}when a segue happens.\r\nDialogue: 0,0:38:10.55,0:38:11.96,yin,,0,0,0,, 我们已经知道屏幕上会发生什么了 \\N{\\fs12}We already know what happens on screen,\r\nDialogue: 0,0:38:11.96,0:38:13.79,yin,,0,0,0,, 也就是这个新的 MVC 滑进来 \\N{\\fs12}which is this new MVC slides in.\r\nDialogue: 0,0:38:14.16,0:38:16.46,yin,,0,0,0,, 从月份滑到日期 \\N{\\fs12}Right. Like the month slides into the day,\r\nDialogue: 0,0:38:16.46,0:38:19.90,yin,,0,0,0,, 从日期滑到事件等等 \\N{\\fs12}or the day slides into an event, you know, whatever,\r\nDialogue: 0,0:38:19.90,0:38:21.81,yin,,0,0,0,, 点击之后就滑到了新的 MVC 中 \\N{\\fs12}so they slide in as you click on them.\r\nDialogue: 0,0:38:21.83,0:38:23.05,yin,,0,0,0,, 但是代码中会发生什么呢 \\N{\\fs12}But what’s happening in your code?\r\nDialogue: 0,0:38:23.05,0:38:25.46,yin,,0,0,0,, 在新的 MVC 滑入之前 \\N{\\fs12}Well, there’s an important thing that needs to happen\r\nDialogue: 0,0:38:25.47,0:38:27.72,yin,,0,0,0,, 需要做一件很重要的事情 \\N{\\fs12}before a new MVC can slide in,\r\nDialogue: 0,0:38:27.75,0:38:29.37,yin,,0,0,0,, 就是它需要被准备好 \\N{\\fs12}which is that it needs to be prepared.\r\nDialogue: 0,0:38:29.72,0:38:31.71,yin,,0,0,0,, 我们回到日历这个例子 \\N{\\fs12}So let’s go back to the example of the calendar.\r\nDialogue: 0,0:38:31.81,0:38:33.05,yin,,0,0,0,, 当我点击–\\N{\\fs12}When I click on that –\r\nDialogue: 0,0:38:33.16,0:38:35.18,yin,,0,0,0,, 假设当前日历显示的是月视图 \\N{\\fs12}let’s say I’ve got a month’s view showing the calendar\r\nDialogue: 0,0:38:35.18,0:38:36.31,yin,,0,0,0,, 然后我选择了一天 \\N{\\fs12}and I pick on a day,\r\nDialogue: 0,0:38:36.53,0:38:38.72,yin,,0,0,0,, 日 MVC 就会滑进来 显示这一天 \\N{\\fs12}and now it’s going to slide it in to show me a day.\r\nDialogue: 0,0:38:38.92,0:38:42.43,yin,,0,0,0,, 我需要告诉那个日 MVC 当前选择了哪一天 \\N{\\fs12}I need to tell that day MVC what day.\r\nDialogue: 0,0:38:43.24,0:38:45.11,yin,,0,0,0,, 因为那个日 MVC\\N{\\fs12}Okay. Because that day MVC,\r\nDialogue: 0,0:38:46.23,0:38:48.07,yin,,0,0,0,, 也许它可以始终显示当前日期 \\N{\\fs12}I guess it could just always show today,\r\nDialogue: 0,0:38:48.07,0:38:50.50,yin,,0,0,0,, 但是日历应用中应该可以显示其他日期 \\N{\\fs12}but if you’re a calendar app you want it to be able to show other days,\r\nDialogue: 0,0:38:50.68,0:38:53.47,yin,,0,0,0,, 所以你需要为日 MVC 出现在屏幕上做准备 \\N{\\fs12}so you need to prepare that day MVC to come onscreen\r\nDialogue: 0,0:38:53.47,0:38:54.86,yin,,0,0,0,, 告诉它当前选中了哪一天 \\N{\\fs12}by telling it what day.\r\nDialogue: 0,0:38:55.24,0:38:57.86,yin,,0,0,0,, 你告诉它之后 它就可以独自运行了 \\N{\\fs12}Okay. Once you tell it what day, it’s on its own.\r\nDialogue: 0,0:38:58.15,0:38:59.44,yin,,0,0,0,, 出现在屏幕上 显示选中日期 \\N{\\fs12}It just goes off, shows the day,\r\nDialogue: 0,0:38:59.44,0:39:00.72,yin,,0,0,0,, 你可以滚动 \\N{\\fs12}you scroll around, you know,\r\nDialogue: 0,0:39:00.72,0:39:02.17,yin,,0,0,0,, 如果在上面点击某处 \\N{\\fs12}if you click on a thing,\r\nDialogue: 0,0:39:02.32,0:39:07.21,yin,,0,0,0,, 日 MVC 会将事件详情 MVC 压入显示 \\N{\\fs12}it’s the one that pushes again to push in the event detail one,\r\nDialogue: 0,0:39:07.30,0:39:08.47,yin,,0,0,0,, 但是你必须为它进行准备 \\N{\\fs12}but you’ve got to prepare it.\r\nDialogue: 0,0:39:08.69,0:39:10.60,yin,,0,0,0,,MVC 需要提前准备 \\N{\\fs12}Okay. So MVCs need to be prepared.\r\nDialogue: 0,0:39:10.60,0:39:12.23,yin,,0,0,0,, 谁来做准备工作呢 \\N{\\fs12}Well, who does the preparation?\r\nDialogue: 0,0:39:12.38,0:39:15.39,yin,,0,0,0,, 显然 是你点击的那个 MVC\\N{\\fs12}Obviously, it’s the MVC that you clicked in\r\nDialogue: 0,0:39:15.53,0:39:17.64,yin,,0,0,0,, 是它让其他 MVC 滑进来的 \\N{\\fs12}to cause this other MVC to slide in.\r\nDialogue: 0,0:39:17.64,0:39:19.32,yin,,0,0,0,, 在我们刚才做过的例子中 \\N{\\fs12}So in the example we just did,\r\nDialogue: 0,0:39:19.40,0:39:21.10,yin,,0,0,0,, 中间有按钮的那个 MVC\\N{\\fs12}the MVC that has the button in it,\r\nDialogue: 0,0:39:21.23,0:39:23.63,yin,,0,0,0,, 它应该有一个方法叫做 prepareForSegue\\N{\\fs12}it should have a method in it, prepareForSegue,\r\nDialogue: 0,0:39:24.13,0:39:26.71,yin,,0,0,0,, 为下一个 MVC 做准备 \\N{\\fs12}that prepares the next one over –\r\nDialogue: 0,0:39:26.73,0:39:28.68,yin,,0,0,0,, 为右边的 MVC 出现在屏幕上做准备 \\N{\\fs12}the one on the right to come onscreen.\r\nDialogue: 0,0:39:28.79,0:39:31.36,yin,,0,0,0,, 月 MVC 需要有一个 prepareForSegue 方法 \\N{\\fs12}The month one has to have a prepareForSegue\r\nDialogue: 0,0:39:31.36,0:39:34.03,yin,,0,0,0,, 为日视图控制器出现在屏幕上做准备 \\N{\\fs12}that prepares a day view controller for coming onscreen.\r\nDialogue: 0,0:39:34.35,0:39:36.45,yin,,0,0,0,,prepareForSegue 的代码是什么样的呢 \\N{\\fs12}So what does this prepareForSegue code look like?\r\nDialogue: 0,0:39:36.45,0:39:39.61,yin,,0,0,0,, 首先 它叫做 prepareForSegue: sender:\\N{\\fs12}Okay. First of all, it’s called prepareForSegue colon sender colon,\r\nDialogue: 0,0:39:39.87,0:39:41.46,yin,,0,0,0,, 现在不用考虑参数 sender\\N{\\fs12}don’t worry about that sender argument for now.\r\nDialogue: 0,0:39:41.46,0:39:43.48,yin,,0,0,0,, 用到它的时候 我们再讲 \\N{\\fs12}We’ll talk about when that’s useful,\r\nDialogue: 0,0:39:44.11,0:39:45.22,yin,,0,0,0,, 非常少见 \\N{\\fs12}it’s a pretty rare case.\r\nDialogue: 0,0:39:45.31,0:39:48.13,yin,,0,0,0,, 通常只需要第一个参数中的信息 \\N{\\fs12}Normally, you just need the information that’s in that first argument –\r\nDialogue: 0,0:39:48.13,0:39:49.45,yin,,0,0,0,, 也就是 UIStoryboardSegue\\N{\\fs12}the UIStoryboardSegue.\r\nDialogue: 0,0:39:49.45,0:39:50.93,yin,,0,0,0,, 看到那个 UIStoryboardSegue 了吧 \\N{\\fs12}You see that UIStoryboardSegue.\r\nDialogue: 0,0:39:50.94,0:39:52.24,yin,,0,0,0,, 如果你看一下这个类 \\N{\\fs12}If you go look at that class,\r\nDialogue: 0,0:39:52.39,0:39:54.84,yin,,0,0,0,, 就会看到两个非常有意思的属性 \\N{\\fs12}you’ll see there’s a couple of very interesting properties on it.\r\nDialogue: 0,0:39:55.08,0:39:58.32,yin,,0,0,0,, 一个是标识符 \\N{\\fs12}One of it is — one interesting property is identifier.\r\nDialogue: 0,0:39:58.89,0:40:01.88,yin,,0,0,0,, 也就是我们在 Xcode 中输入的字符串 DoSomething\\N{\\fs12}That’s that string we typed in in Xcode — DoSomething.\r\nDialogue: 0,0:40:02.32,0:40:02.90,yin,,0,0,0,, 还记得吗 \\N{\\fs12}Remember that?\r\nDialogue: 0,0:40:03.35,0:40:05.65,yin,,0,0,0,, 得到这个 preparedForSegue 时 \\N{\\fs12}So when you get this preparedForSegue,\r\nDialogue: 0,0:40:05.71,0:40:07.82,yin,,0,0,0,, 要做的第一件事就是 \\N{\\fs12}the first thing you’re going to do is\r\nDialogue: 0,0:40:07.87,0:40:10.37,yin,,0,0,0,, 查看 segue 的标识符 \\N{\\fs12}look at the identifier of the segue\r\nDialogue: 0,0:40:10.39,0:40:12.18,yin,,0,0,0,, 获得当前所说的 segue\\N{\\fs12}to see which segue we’re talking about.\r\nDialogue: 0,0:40:12.18,0:40:14.06,yin,,0,0,0,, 我们为什么要这么做呢 \\N{\\fs12}Now why do we even need to do that?\r\nDialogue: 0,0:40:14.21,0:40:17.85,yin,,0,0,0,, 答案是 我们可以有多个点触发 segue\\N{\\fs12}The answer is we can have multiple things segue,\r\nDialogue: 0,0:40:18.23,0:40:20.66,yin,,0,0,0,, 我们再回到月视图 \\N{\\fs12}so again, let’s go back to the month view.\r\nDialogue: 0,0:40:21.06,0:40:24.58,yin,,0,0,0,, 我可以点击一天 segue 到日视图 \\N{\\fs12}I can click on a day and it can segue to a day view,\r\nDialogue: 0,0:40:24.80,0:40:29.41,yin,,0,0,0,, 我也可以点击编辑之类的 \\N{\\fs12}but maybe I click on the edit, or something like that,\r\nDialogue: 0,0:40:29.42,0:40:33.11,yin,,0,0,0,, 它就可以 segue 到某个视图上 对月份进行编辑 \\N{\\fs12}and it could segue to some view that edits something about the month.\r\nDialogue: 0,0:40:33.24,0:40:35.80,yin,,0,0,0,, 比如每周从周日还是周一开始 \\N{\\fs12}Okay. Like, do they start on Sundays or do they start on Mondays,\r\nDialogue: 0,0:40:35.80,0:40:36.73,yin,,0,0,0,, 这种编辑视图 \\N{\\fs12}that kind of view.\r\nDialogue: 0,0:40:36.77,0:40:38.37,yin,,0,0,0,, 明白吗 我可以 segue 到不同的视图 \\N{\\fs12}See what I mean? So it could segue to a different one,\r\nDialogue: 0,0:40:38.38,0:40:41.88,yin,,0,0,0,, 所以月视图中有两个不同的控件 \\N{\\fs12}so you’d have two different controls inside the month view\r\nDialogue: 0,0:40:41.88,0:40:43.51,yin,,0,0,0,, 分别 segue 到不同的 MVC\\N{\\fs12}that are segueing to different MVC\r\nDialogue: 0,0:40:43.51,0:40:44.76,yin,,0,0,0,, 所以我们需要 \\N{\\fs12}so we need to know –\r\nDialogue: 0,0:40:44.98,0:40:47.10,yin,,0,0,0,, 通过标识符确认是哪个 segue\\N{\\fs12}we know which one it is by its identifier.\r\nDialogue: 0,0:40:47.73,0:40:52.53,yin,,0,0,0,, 确定目标 segue 之后–\\N{\\fs12}Okay. So, once we’ve checked to see which one we’re talking about here –\r\nDialogue: 0,0:40:52.53,0:40:53.51,yin,,0,0,0,, 我们总会执行这一步 \\N{\\fs12}and we always do that,\r\nDialogue: 0,0:40:53.51,0:40:55.07,yin,,0,0,0,, 即便只有一个 segue\\N{\\fs12}even if there’s only one segue,\r\nDialogue: 0,0:40:55.07,0:40:56.40,yin,,0,0,0,, 我们也都会检查标识符 \\N{\\fs12}we always check the identifier\r\nDialogue: 0,0:40:56.51,0:40:58.99,yin,,0,0,0,, 确保和 storyboard 中添加的是同一个 \\N{\\fs12}just to make sure we’re in sync with what we put in our storyboard,\r\nDialogue: 0,0:40:59.24,0:41:02.43,yin,,0,0,0,, 因为某天我们也许会再添加一个标识符不同的 segue\\N{\\fs12}because some day we may add another segue with a different identifier.\r\nDialogue: 0,0:41:04.39,0:41:06.03,yin,,0,0,0,, 然后 下面一步是 \\N{\\fs12}Then, the next thing we do\r\nDialogue: 0,0:41:06.04,0:41:10.23,yin,,0,0,0,, 确定要 segue 到哪个 MVC\\N{\\fs12}is we’re going to say what MVC are we segueing to?\r\nDialogue: 0,0:41:11.17,0:41:16.11,yin,,0,0,0,, 通常情况下 我们知道它的类是什么 \\N{\\fs12}Okay. Usually we are going to know what class of thing it is\r\nDialogue: 0,0:41:16.32,0:41:17.16,yin,,0,0,0,, 或者认为我们知道 \\N{\\fs12}or think we know,\r\nDialogue: 0,0:41:17.16,0:41:18.85,yin,,0,0,0,, 因为我们知道 segue 的标识符 \\N{\\fs12}because we know the identifier of the segue.\r\nDialogue: 0,0:41:18.85,0:41:20.56,yin,,0,0,0,, 如果你在月视图中 \\N{\\fs12}So it only makes sense if you’re in the month view\r\nDialogue: 0,0:41:20.68,0:41:22.03,yin,,0,0,0,, 点击了某一天 \\N{\\fs12}and you click on that day,\r\nDialogue: 0,0:41:22.47,0:41:25.14,yin,,0,0,0,, 这时候 segue 到日视图控制器才说得通 \\N{\\fs12}that thing it’s segueing to better be a day view controller,\r\nDialogue: 0,0:41:25.14,0:41:27.42,yin,,0,0,0,, 如果不是这样的话 你也不知道该做什么 对吧 \\N{\\fs12}because you don’t know what else to do if it’s not. Okay.\r\nDialogue: 0,0:41:27.47,0:41:30.13,yin,,0,0,0,, 但是即便这样 我们也会加上 \\N{\\fs12}But you still, even so, will usually do\r\nDialogue: 0,0:41:30.49,0:41:33.08,yin,,0,0,0,,segue.destinationViewController isKindOfClass\\N{\\fs12}segue.destinationViewController isKindOfClass,\r\nDialogue: 0,0:41:33.21,0:41:35.00,yin,,0,0,0,, 后面是我们想要的视图控制器 \\N{\\fs12}the view controller we expect.\r\nDialogue: 0,0:41:35.46,0:41:37.28,yin,,0,0,0,, 然后创建一个它的局部变量 \\N{\\fs12}Then we’ll make a little local variable with it,\r\nDialogue: 0,0:41:37.48,0:41:41.15,yin,,0,0,0,, 然后取局部变量 doVC 的属性值 \\N{\\fs12}and then we’re going to do doVC which is our local variable,\r\nDialogue: 0,0:41:41.23,0:41:42.90,yin,,0,0,0,,doVC.neededInfo=\\N{\\fs12}dot neededInfo equals,\r\nDialogue: 0,0:41:42.90,0:41:46.82,yin,,0,0,0,, 这算是准备日视图控制器的伪代码 \\N{\\fs12}what’s kind of pseudo code for preparing that day view controller.\r\nDialogue: 0,0:41:46.84,0:41:48.96,yin,,0,0,0,, 如果这是日视图的例子 \\N{\\fs12}So, if this were the day view example,\r\nDialogue: 0,0:41:48.97,0:41:54.54,yin,,0,0,0,, 这里可能会写成 doVC.date 等于某个 NSDate\\N{\\fs12}probably it would say doVC dot date equals some NSDate.\r\nDialogue: 0,0:41:55.08,0:41:57.06,yin,,0,0,0,, 这样我们就做好了日视图的准备工作 \\N{\\fs12}Right? And so now we’ve prepared the day thing.\r\nDialogue: 0,0:41:57.10,0:41:58.02,yin,,0,0,0,, 我们只需要做这些就行了 \\N{\\fs12}And that’s all we do here.\r\nDialogue: 0,0:41:58.29,0:41:59.71,yin,,0,0,0,, 其他操作都会神奇地自动执行 \\N{\\fs12}Everything else happens by magic.\r\nDialogue: 0,0:41:59.71,0:42:02.20,yin,,0,0,0,, 我们准备好新的 MVC 之后 \\N{\\fs12}Once we’ve prepared that new MVC,\r\nDialogue: 0,0:42:02.65,0:42:04.45,yin,,0,0,0,, 它出现在屏幕上 做它要做的事情 \\N{\\fs12}it goes onscreen, does what it does.\r\nDialogue: 0,0:42:04.64,0:42:07.01,yin,,0,0,0,, 滑动和动画都不用我们操心 \\N{\\fs12}We don’t have to do anything to make things slide or animate,\r\nDialogue: 0,0:42:07.01,0:42:08.24,yin,,0,0,0,, 都是由系统处理的 \\N{\\fs12}that’s all handled by the system.\r\nDialogue: 0,0:42:08.38,0:42:10.04,yin,,0,0,0,, 这里系统只需要你做一件事 \\N{\\fs12}All the system is asking right here is\r\nDialogue: 0,0:42:10.04,0:42:12.43,yin,,0,0,0,, 就是为 MVC 出现在屏幕上做准备 \\N{\\fs12}please prepare this MVC to come onscreen.\r\nDialogue: 0,0:42:12.61,0:42:15.39,yin,,0,0,0,, 这里需要理解一件很重要的事情 \\N{\\fs12}Now, very important thing to understand here,\r\nDialogue: 0,0:42:15.72,0:42:17.22,yin,,0,0,0,, 当调用这个方法时 \\N{\\fs12}when this is called,\r\nDialogue: 0,0:42:18.16,0:42:22.56,yin,,0,0,0,, 目标 MVC 中的输出口并没有设置好 \\N{\\fs12}your outlets are not set in the destination MVC.\r\nDialogue: 0,0:42:23.31,0:42:27.52,yin,,0,0,0,, 这个方法是在 awakeFromNib 和 viewDidLoad 之间被调用的 \\N{\\fs12}Okay. So this is between awakeFromNib and viewDidLoad.\r\nDialogue: 0,0:42:27.80,0:42:29.53,yin,,0,0,0,, 非常烦人 \\N{\\fs12}This is very annoying. Okay.\r\nDialogue: 0,0:42:29.69,0:42:30.78,yin,,0,0,0,, 我希望不是这样的 \\N{\\fs12}I wish this was different.\r\nDialogue: 0,0:42:31.02,0:42:33.77,yin,,0,0,0,, 我相信肯定有这样做的原因 \\N{\\fs12}I’m sure there must be a good reason why this is the way it is,\r\nDialogue: 0,0:42:33.77,0:42:34.80,yin,,0,0,0,, 但是这真的很烦人 \\N{\\fs12}but it’s very annoying,\r\nDialogue: 0,0:42:34.93,0:42:37.66,yin,,0,0,0,, 因为这种顺序意味着我们传递的所有信息 \\N{\\fs12}because it means that any information that you’re passing,\r\nDialogue: 0,0:42:37.66,0:42:39.52,yin,,0,0,0,, 比如传递给日视图的日期 \\N{\\fs12}like the day, to the day view,\r\nDialogue: 0,0:42:39.52,0:42:42.42,yin,,0,0,0,, 必须要等到输出口都设置好才能传递 \\N{\\fs12}it has to kind of hold on do it until all its outlets are set\r\nDialogue: 0,0:42:42.59,0:42:45.95,yin,,0,0,0,, 然后再在 viewDidLoad 中更新 UI\\N{\\fs12}and then in viewDidLoad, it can go update all its UI.\r\nDialogue: 0,0:42:47.05,0:42:48.85,yin,,0,0,0,, 我这么说明白吗 \\N{\\fs12}Does that make sense what I just said?\r\nDialogue: 0,0:42:49.90,0:42:52.24,yin,,0,0,0,, 你需要设置属性 \\N{\\fs12}Right. So you’re going to have to have properties\r\nDialogue: 0,0:42:52.24,0:42:53.79,yin,,0,0,0,, 用来保存日期 \\N{\\fs12}that are going to have to hold on to the day,\r\nDialogue: 0,0:42:53.90,0:42:56.35,yin,,0,0,0,, 然后在 viewDidLoad 执行时 它才能更新 UI\\N{\\fs12}and then when viewDidLoad happens, then it can update the UI.\r\nDialogue: 0,0:42:56.44,0:42:57.84,yin,,0,0,0,, 我会在示例中进行演示 \\N{\\fs12}And I’m going to show you in the demo,\r\nDialogue: 0,0:42:57.92,0:43:02.39,yin,,0,0,0,, 用一种大概算是样板化的方法 \\N{\\fs12}kind of a way that we might do it that’s somewhat boiler plate,\r\nDialogue: 0,0:43:02.39,0:43:03.77,yin,,0,0,0,, 或者 \\N{\\fs12}or somewhat kind of –\r\nDialogue: 0,0:43:04.23,0:43:06.39,yin,,0,0,0,, 我不知道能不能说它是最好的方法 \\N{\\fs12}I don’t know if I want to go so far as to say best practice –\r\nDialogue: 0,0:43:06.39,0:43:08.37,yin,,0,0,0,, 是简单的方法 \\N{\\fs12}simple practice for doing that –\r\nDialogue: 0,0:43:08.38,0:43:11.41,yin,,0,0,0,, 用来处理这个方法是在调用 viewDidLoad 之前 \\N{\\fs12}for dealing with the fact that this gets called before viewDidLoad,\r\nDialogue: 0,0:43:11.62,0:43:14.86,yin,,0,0,0,, 在输出口没有设好时被调用的问题 \\N{\\fs12}okay, before your outlets are set. Okay.\r\nDialogue: 0,0:43:15.38,0:43:17.71,yin,,0,0,0,,segue 是可以被阻止的 \\N{\\fs12}So it is possible to prevent a segue.\r\nDialogue: 0,0:43:17.71,0:43:19.13,yin,,0,0,0,, 对了 这里还有几张幻灯片 \\N{\\fs12}I have a few other slides, by the way,\r\nDialogue: 0,0:43:19.14,0:43:20.12,yin,,0,0,0,, 课上我就不讲了 \\N{\\fs12}that I’m not going over in lecture,\r\nDialogue: 0,0:43:20.12,0:43:21.76,yin,,0,0,0,, 大家可以下载到 \\N{\\fs12}but they’re on what you downloaded,\r\nDialogue: 0,0:43:21.77,0:43:23.27,yin,,0,0,0,, 通读一遍 \\N{\\fs12}so you can kind of read through them\r\nDialogue: 0,0:43:23.43,0:43:24.71,yin,,0,0,0,, 查看相关文档 就可以理解了 \\N{\\fs12}and look at the documentation to figure it out.\r\nDialogue: 0,0:43:24.72,0:43:27.18,yin,,0,0,0,, 这里我要再讲一些 segue 的内容 \\N{\\fs12}But I’m going to talk about a couple of segue things here.\r\nDialogue: 0,0:43:27.20,0:43:29.65,yin,,0,0,0,, 一是你可以阻止 segue 跳转 \\N{\\fs12}One is you can prevent a segue from happening\r\nDialogue: 0,0:43:29.66,0:43:33.59,yin,,0,0,0,, 方法是 shouldPerformsegueWithIdentifier: sender:\\N{\\fs12}by doing this shouldPerformsegueWithIdentifier colon sender colon,\r\nDialogue: 0,0:43:33.98,0:43:35.61,yin,,0,0,0,, 方法名就是它的含义 \\N{\\fs12}and that’s exactly what it says.\r\nDialogue: 0,0:43:35.61,0:43:38.19,yin,,0,0,0,, 返回 YES 或 NO 来表示是否允许某个 segue 跳转 \\N{\\fs12}You return yes or no whether you want that segue to happen.\r\nDialogue: 0,0:43:38.25,0:43:40.86,yin,,0,0,0,, 为什么我们不想允许 segue 跳转呢 \\N{\\fs12}Why would you never want — why would you not want this to happen?\r\nDialogue: 0,0:43:40.96,0:43:42.88,yin,,0,0,0,, 比如说你有一个按钮 \\N{\\fs12}Let’s say you have a button\r\nDialogue: 0,0:43:42.88,0:43:45.03,yin,,0,0,0,, 通常情况下 点击按钮之后就会进行 segue 跳转 \\N{\\fs12}and you click on it and it normally segues,\r\nDialogue: 0,0:43:45.03,0:43:46.64,yin,,0,0,0,, 但是因为某些原因 你不能进行 segue\\N{\\fs12}but for some reason you can’t segue.\r\nDialogue: 0,0:43:46.95,0:43:48.75,yin,,0,0,0,, 也许你没有权限 \\N{\\fs12}Okay. Maybe you don’t have permission,\r\nDialogue: 0,0:43:48.75,0:43:50.84,yin,,0,0,0,, 找不到日期了等等 \\N{\\fs12}or it can’t find the date, or whatever,\r\nDialogue: 0,0:43:50.84,0:43:52.77,yin,,0,0,0,, 所以这时你希望弹出一个警告 \\N{\\fs12}so instead you want to put up an alert\r\nDialogue: 0,0:43:52.90,0:43:56.52,yin,,0,0,0,, 说无法提供信息等等 \\N{\\fs12}that says could not, you know, provide the information, or whatever.\r\nDialogue: 0,0:43:56.74,0:44:01.12,yin,,0,0,0,, 不能直接用按钮上的目标操作 \\N{\\fs12}You can’t just have a target action from that button\r\nDialogue: 0,0:44:01.12,0:44:02.48,yin,,0,0,0,, 来弹出警告 \\N{\\fs12}that puts up the alert.\r\nDialogue: 0,0:44:02.69,0:44:05.04,yin,,0,0,0,, 你需要阻止 segue 跳转的发生 \\N{\\fs12}Okay. You need to prevent the segue from happening\r\nDialogue: 0,0:44:05.05,0:44:05.87,yin,,0,0,0,, 并弹出警告 \\N{\\fs12}and put up the alert.\r\nDialogue: 0,0:44:05.88,0:44:07.38,yin,,0,0,0,, 所以你需要用这个方法来阻止 segue\\N{\\fs12}So you prevent the segue with this\r\nDialogue: 0,0:44:07.97,0:44:09.41,yin,,0,0,0,, 然后再通过按钮的目标操作 \\N{\\fs12}and then you have target action from your button\r\nDialogue: 0,0:44:09.41,0:44:10.90,yin,,0,0,0,, 弹出警告 \\N{\\fs12}that puts up the altet.\r\nDialogue: 0,0:44:11.24,0:44:13.79,yin,,0,0,0,, 你显然不想同时弹出警告和进行 segue 跳转 \\N{\\fs12}Okay. That obviously, you wouldn’t want to put up the alert and segue,\r\nDialogue: 0,0:44:13.80,0:44:16.22,yin,,0,0,0,, 二者只能执行一项 \\N{\\fs12}so it — they want to be mutually exclusive,\r\nDialogue: 0,0:44:16.24,0:44:19.89,yin,,0,0,0,, 这就是阻止 segue 跳转的方法 \\N{\\fs12}but this is how you can prevent a segue. Okay.\r\nDialogue: 0,0:44:20.51,0:44:22.29,yin,,0,0,0,, 进入演示之前 \\N{\\fs12}Any questions before I dive into a demo\r\nDialogue: 0,0:44:22.29,0:44:23.98,yin,,0,0,0,, 有什么问题吗 \\N{\\fs12}to show you all this in action?\r\nDialogue: 0,0:44:25.22,0:44:26.86,yin,,0,0,0,, 好的 我来演示一下 \\N{\\fs12}All right. Here we go.\r\nDialogue: 0,0:44:27.91,0:44:29.34,yin,,0,0,0,, 这里我们要做的是 \\N{\\fs12}So what we’re going to do here\r\nDialogue: 0,0:44:30.10,0:44:37.05,yin,,0,0,0,, 回到 Attributor\\N{\\fs12}is we are going to go back to Attributor. Right?\r\nDialogue: 0,0:44:37.06,0:44:39.45,yin,,0,0,0,, 不用 Matchismo 了 我们这回用 Attributor 来演示 \\N{\\fs12}Instead of Matchismo, we’re going to do this in Attributor.\r\nDialogue: 0,0:44:40.73,0:44:42.97,yin,,0,0,0,, 好了 隐藏其他内容 \\N{\\fs12}All right. Let’s hide others here.\r\nDialogue: 0,0:44:43.58,0:44:45.29,yin,,0,0,0,,Attributor 就是这个样子的 \\N{\\fs12}So this is what Attributor looks like,\r\nDialogue: 0,0:44:46.15,0:44:48.11,yin,,0,0,0,, 两天前的例子 希望大家还记得 \\N{\\fs12}if you’ll remember, hopefully, from just two days ago.\r\nDialogue: 0,0:44:48.51,0:44:51.66,yin,,0,0,0,, 我们要做的是添加第二个 MVC\\N{\\fs12}And what we’re going to do is we’re going to add a second MVC,\r\nDialogue: 0,0:44:51.95,0:44:55.31,yin,,0,0,0,, 而这个 MVC 要做的是 \\N{\\fs12}and what this MVC is going to do is to analyze –\r\nDialogue: 0,0:44:55.31,0:44:57.19,yin,,0,0,0,, 分析某些文本 \\N{\\fs12}it’s going to analyze some text\r\nDialogue: 0,0:44:57.39,0:44:59.86,yin,,0,0,0,, 统计彩色字符有多少个 \\N{\\fs12}and say how many colored characters in there,\r\nDialogue: 0,0:44:59.86,0:45:02.08,yin,,0,0,0,, 带有轮廓的字符有多少个等等 \\N{\\fs12}how many outlined characters in there, etcetera.\r\nDialogue: 0,0:45:02.09,0:45:04.01,yin,,0,0,0,, 所以它会进行统计 \\N{\\fs12}Right. So it’s kind of a stat.\r\nDialogue: 0,0:45:04.04,0:45:06.49,yin,,0,0,0,, 告诉你某些文本的统计数据 \\N{\\fs12}It’s giving you statistics about some texts.\r\nDialogue: 0,0:45:06.51,0:45:08.56,yin,,0,0,0,, 现在我要把这个 MVC 移到一旁 \\N{\\fs12}Now, I’m going to put this aside\r\nDialogue: 0,0:45:08.77,0:45:12.39,yin,,0,0,0,, 单独做这个新的 MVC\\N{\\fs12}and do this new MVC completely independently.\r\nDialogue: 0,0:45:12.69,0:45:15.78,yin,,0,0,0,, 换句话说 我现在甚至不会考虑这个 MVC\\N{\\fs12}In other words, I’m not even going to think about this right now.\r\nDialogue: 0,0:45:15.86,0:45:19.33,yin,,0,0,0,, 我要创建第二个 MVC\\N{\\fs12}I’m going to build the second MVC that does this thing\r\nDialogue: 0,0:45:19.34,0:45:21.29,yin,,0,0,0,, 用来分析文本 得出统计结果 \\N{\\fs12}which is analyze text and give you result,\r\nDialogue: 0,0:45:22.32,0:45:23.29,yin,,0,0,0,, 然后我们会用到它 \\N{\\fs12}then we’ll use it.\r\nDialogue: 0,0:45:23.29,0:45:24.93,yin,,0,0,0,, 我只是想通过这样做 \\N{\\fs12}And I just want to do that to emphasize\r\nDialogue: 0,0:45:24.93,0:45:27.13,yin,,0,0,0,, 强调 MVC 的独立性 \\N{\\fs12}how we want MVCs to be independent.\r\nDialogue: 0,0:45:27.94,0:45:29.91,yin,,0,0,0,, 我们来设计那个 MVC\\N{\\fs12}Okay. So let’s design that MVC.\r\nDialogue: 0,0:45:29.96,0:45:32.25,yin,,0,0,0,, 先拖出一个视图控制器 \\N{\\fs12}We start by dragging out a view controller,\r\nDialogue: 0,0:45:32.70,0:45:33.43,yin,,0,0,0,, 像这样 \\N{\\fs12}just like this.\r\nDialogue: 0,0:45:34.16,0:45:36.61,yin,,0,0,0,, 然后为它新建一个类 \\N{\\fs12}Okay. We’re going to create a new class for it.\r\nDialogue: 0,0:45:37.74,0:45:39.70,yin,,0,0,0,, 我要叫它 \\N{\\fs12}Okay. And I’m going to call this thing –\r\nDialogue: 0,0:45:40.13,0:45:42.75,yin,,0,0,0,, 它是一个 UIViewController\\N{\\fs12}it’s going to be a UIViewController,\r\nDialogue: 0,0:45:43.16,0:45:44.51,yin,,0,0,0,, 我要叫它 \\N{\\fs12}and I’m going to call it –\r\nDialogue: 0,0:45:45.66,0:45:49.88,yin,,0,0,0,, 我们就叫它 TextStatsViewController\\N{\\fs12}let’s call it TextStatsViewController.\r\nDialogue: 0,0:45:49.90,0:45:52.75,yin,,0,0,0,, 我用的应该是这个名字 我看一下 没错 \\N{\\fs12}I think that’s the name I used. Make sure I did it. Yeah.\r\nDialogue: 0,0:45:53.64,0:45:54.77,yin,,0,0,0,,TextStatsViewController\\N{\\fs12}TextStatsViewController.\r\nDialogue: 0,0:45:54.77,0:45:57.22,yin,,0,0,0,, 也可以叫它 AnalyzeTextViewController 等等 \\N{\\fs12}We could call it AnalyzeTextViewController, something like that,\r\nDialogue: 0,0:45:57.24,0:46:00.38,yin,,0,0,0,, 但我认为 TextStatsViewController 虽然很难读 \\N{\\fs12}but I think TextStatsViewController — although it’s mouthful,\r\nDialogue: 0,0:46:00.53,0:46:01.53,yin,,0,0,0,, 但是具有很好的描述性 \\N{\\fs12}is pretty descriptive.\r\nDialogue: 0,0:46:02.17,0:46:04.19,yin,,0,0,0,, 保存在同一目录下 \\N{\\fs12}And so we’re going to put it at the same top level there,\r\nDialogue: 0,0:46:04.19,0:46:06.08,yin,,0,0,0,, 我们当然也可以将视图控制器进行分组 \\N{\\fs12}and we can of course group our view controllers too.\r\nDialogue: 0,0:46:06.55,0:46:09.93,yin,,0,0,0,, 这是 TextStatsViewController 的代码 \\N{\\fs12}Here’s the code for our TextStatsViewController.\r\nDialogue: 0,0:46:09.93,0:46:10.85,yin,,0,0,0,, 这里同样可以看到 \\N{\\fs12}You can see again,\r\nDialogue: 0,0:46:10.98,0:46:14.56,yin,,0,0,0,, 自动生成了这个指定初始化方法 我们不需要 \\N{\\fs12}we’ve got this nice designated initializer which we don’t want,\r\nDialogue: 0,0:46:14.68,0:46:16.62,yin,,0,0,0,, 还有一些视图控制器生命周期的代码 \\N{\\fs12}and we’ve got some view controller lifecycle,\r\nDialogue: 0,0:46:16.62,0:46:17.75,yin,,0,0,0,, 我们也不需要 \\N{\\fs12}we don’t want any of that. Okay.\r\nDialogue: 0,0:46:18.28,0:46:20.82,yin,,0,0,0,, 这个 TextStatsViewController\\N{\\fs12}So, this TextStatsViewController,\r\nDialogue: 0,0:46:21.94,0:46:24.30,yin,,0,0,0,, 本质上说 它是可重用的 \\N{\\fs12}it is essentially a reusable thing.\r\nDialogue: 0,0:46:24.30,0:46:25.70,yin,,0,0,0,, 需要一个公有 API\\N{\\fs12}It needs a public API.\r\nDialogue: 0,0:46:26.46,0:46:29.34,yin,,0,0,0,, 就像设计卡牌配对游戏时一样 \\N{\\fs12}Okay. And just like we did when we designed the card matching game\r\nDialogue: 0,0:46:29.34,0:46:33.67,yin,,0,0,0,, 我们想要先设置一个公有 API\\N{\\fs12}and we kind of tried to come up with a public API first\r\nDialogue: 0,0:46:33.76,0:46:35.78,yin,,0,0,0,, 然后才能考虑如何使用我们的元素 \\N{\\fs12}so we could think of how our thing is going to be used,\r\nDialogue: 0,0:46:35.83,0:46:37.43,yin,,0,0,0,, 这里我们要做完全一样的操作 \\N{\\fs12}we’re going to do exact same thing here.\r\nDialogue: 0,0:46:37.62,0:46:39.79,yin,,0,0,0,, 转到它的公有接口 \\N{\\fs12}So, I’m going to go to the public interface of this.\r\nDialogue: 0,0:46:39.81,0:46:42.78,yin,,0,0,0,, 这是 TextStatsViewController 的公有接口 \\N{\\fs12}this is the public interface for TextStatsViewController,\r\nDialogue: 0,0:46:42.96,0:46:44.83,yin,,0,0,0,, 我要增加一个属性 \\N{\\fs12}and I’m going to add a property,\r\nDialogue: 0,0:46:45.35,0:46:49.15,yin,,0,0,0,,nonatomic strong 是一个 NSAttributedString\\N{\\fs12}nonatomic strong, which is a NSAttributedString,\r\nDialogue: 0,0:46:49.56,0:46:52.00,yin,,0,0,0,, 叫做 textToAnalyze 待分析文本 \\N{\\fs12}which is the textToAnalyze.\r\nDialogue: 0,0:46:52.65,0:46:55.37,yin,,0,0,0,, 这个 MVC 的工作方式就是 \\N{\\fs12}Okay. So the way this MVC is going to work\r\nDialogue: 0,0:46:55.38,0:46:58.27,yin,,0,0,0,, 你为它设置一个 textToAnalyze\\N{\\fs12}is you set it a textToAnalyze\r\nDialogue: 0,0:46:58.27,0:46:59.55,yin,,0,0,0,, 是一个属性化字符串 \\N{\\fs12}which is an attributed string,\r\nDialogue: 0,0:46:59.55,0:47:00.95,yin,,0,0,0,, 然后它会对其进行分析 \\N{\\fs12}and it’s going to analyze it.\r\nDialogue: 0,0:47:01.82,0:47:04.11,yin,,0,0,0,, 就是这样 它就是这个功能 \\N{\\fs12}Okay. That’s it. That’s what it does.\r\nDialogue: 0,0:47:04.90,0:47:08.02,yin,,0,0,0,, 这就是它存在的意义 \\N{\\fs12}Okay. That’s its entire reason for being. Okay.\r\nDialogue: 0,0:47:08.03,0:47:09.66,yin,,0,0,0,, 但它是一个完整的 MVC\\N{\\fs12}But it’s an entire MVC,\r\nDialogue: 0,0:47:09.92,0:47:11.67,yin,,0,0,0,, 所以要有相应 UI 等 \\N{\\fs12}so it’s going to have the UI to do that,\r\nDialogue: 0,0:47:11.69,0:47:14.02,yin,,0,0,0,, 来实现这个功能 \\N{\\fs12}all that stuff to do that.\r\nDialogue: 0,0:47:14.40,0:47:16.95,yin,,0,0,0,, 那么如何实现呢 \\N{\\fs12}So, how are we going to implement something like this?\r\nDialogue: 0,0:47:18.44,0:47:21.06,yin,,0,0,0,, 我要先思考一下 \\N{\\fs12}Well, I’m going to start by thinking about\r\nDialogue: 0,0:47:21.52,0:47:25.81,yin,,0,0,0,, 如果我是这个 MVC\\N{\\fs12}how I want to react if I’m this MVC\r\nDialogue: 0,0:47:25.81,0:47:27.96,yin,,0,0,0,, 有人设置了 textToAnalyze 我要如何反应 \\N{\\fs12}when people set my textToAnalyze.\r\nDialogue: 0,0:47:28.25,0:47:31.29,yin,,0,0,0,, 显然 如果有人设置了 textToAnalyze\\N{\\fs12}And obviously, if someone sets my textToAnalyze,\r\nDialogue: 0,0:47:31.29,0:47:34.30,yin,,0,0,0,, 使用 setTextToAnalyze 这个公有方法 \\N{\\fs12}using setTextToAnalyze, right, the public method.\r\nDialogue: 0,0:47:34.78,0:47:37.33,yin,,0,0,0,, 显然 我需要在这里设置变量 \\N{\\fs12}Obviously, I want to set my variable here,\r\nDialogue: 0,0:47:37.40,0:47:39.62,yin,,0,0,0,, 我还要更新我的 UI\\N{\\fs12}but I’m also going to update my UI.\r\nDialogue: 0,0:47:40.67,0:47:43.72,yin,,0,0,0,, 只要有人设置了要分析的文本 \\N{\\fs12}Okay. So anytime someone sets the text to analyze,\r\nDialogue: 0,0:47:43.74,0:47:45.31,yin,,0,0,0,, 我就要更新 UI\\N{\\fs12}I’m going to update my UI.\r\nDialogue: 0,0:47:45.66,0:47:49.06,yin,,0,0,0,, 所以 我并不希望我的 UI\\N{\\fs12}So, I don’t want to allow my UI to ever get out of sync\r\nDialogue: 0,0:47:49.06,0:47:51.73,yin,,0,0,0,, 和我的模型不同步 \\N{\\fs12}with what is essentially my model.\r\nDialogue: 0,0:47:52.16,0:47:54.81,yin,,0,0,0,, 从本质上说 它就是这个 MVC 的模型 \\N{\\fs12}Okay. This is essentially the model for this MVC,\r\nDialogue: 0,0:47:54.92,0:47:56.36,yin,,0,0,0,, 就是要分析的文本 \\N{\\fs12}is the text to analyze.\r\nDialogue: 0,0:47:56.82,0:48:00.48,yin,,0,0,0,, 当然 我们还要加上 updateUI\\N{\\fs12}So, of course, we’re going to want nice updateUI,\r\nDialogue: 0,0:48:00.54,0:48:02.17,yin,,0,0,0,, 和另一个 MVC 中的很类似 \\N{\\fs12}very similar to that we had in the other one,\r\nDialogue: 0,0:48:02.19,0:48:04.20,yin,,0,0,0,, 我们一会实现它 \\N{\\fs12}and we’ll do that in a minute. Okay.\r\nDialogue: 0,0:48:05.76,0:48:11.10,yin,,0,0,0,, 还有一个时间点可能需要更新 UI\\N{\\fs12}But, there’s another time here when I might want to update my UI,\r\nDialogue: 0,0:48:11.92,0:48:14.79,yin,,0,0,0,, 就是在 viewWillAppear 视图将要出现时 \\N{\\fs12}and that is in viewWillAppear.\r\nDialogue: 0,0:48:15.59,0:48:18.50,yin,,0,0,0,, 这又回到了我们以前讲过的内容 \\N{\\fs12}And that’s back to what we were talking about before,\r\nDialogue: 0,0:48:18.74,0:48:24.90,yin,,0,0,0,, 如果我不在屏幕上的时候 textToAnalyze 被设置了怎么办 \\N{\\fs12}which is that if this textToAnalyze gets set when I’m not onscreen,\r\nDialogue: 0,0:48:24.91,0:48:26.90,yin,,0,0,0,, 也许是在输出口没有设置好的时候 \\N{\\fs12}maybe before my outlets are set,\r\nDialogue: 0,0:48:27.34,0:48:30.34,yin,,0,0,0,, 我希望视图将要出现时同步数据 \\N{\\fs12}okay, I want to come along when view will appear\r\nDialogue: 0,0:48:30.42,0:48:32.52,yin,,0,0,0,, 确保 UI 同步 \\N{\\fs12}and make sure my UI is in sync.\r\nDialogue: 0,0:48:32.97,0:48:36.72,yin,,0,0,0,, 因为显然 这个 updateUI 要向我的视图发送消息 \\N{\\fs12}Okay. Because this updateUI is obviously going to be taking to my view\r\nDialogue: 0,0:48:36.72,0:48:39.74,yin,,0,0,0,, 如果输出口没有设好 它不会做任何操作的 \\N{\\fs12}and if my outlets aren’t set, it won’t do anything. Okay.\r\nDialogue: 0,0:48:39.89,0:48:43.21,yin,,0,0,0,, 这个方法显然马上会在 prepareForSegue 中被调用 \\N{\\fs12}So this is obviously gonna get called in prepareForSegue in a moment,\r\nDialogue: 0,0:48:43.47,0:48:44.58,yin,,0,0,0,, 所以我要这样做 \\N{\\fs12}so that’s why I’m doing this,\r\nDialogue: 0,0:48:44.58,0:48:49.62,yin,,0,0,0,, 一般来说 在这两个地方都更新 UI\\N{\\fs12}but this is also kind of a generically good thing to update UI there,\r\nDialogue: 0,0:48:49.63,0:48:50.66,yin,,0,0,0,, 是比较好的做法 \\N{\\fs12}and update it here.\r\nDialogue: 0,0:48:50.79,0:48:52.83,yin,,0,0,0,, 有人可能会认为 真浪费 \\N{\\fs12}Now you might argue oh, what a waste.\r\nDialogue: 0,0:48:52.83,0:48:55.07,yin,,0,0,0,, 如果调用它的时候 输出口设好了呢 \\N{\\fs12}What if this is called and your outlets are set?\r\nDialogue: 0,0:48:55.41,0:48:58.70,yin,,0,0,0,, 你在这里更新了 UI 然后出现时又更新了一遍 \\N{\\fs12}You updated UI and then you appeared and you updated UI again.\r\nDialogue: 0,0:48:59.02,0:49:01.94,yin,,0,0,0,, 所以有人可能会认为这样做比较好 \\N{\\fs12}So, one might argue that it’s a good thing to do this.\r\nDialogue: 0,0:49:03.56,0:49:10.43,yin,,0,0,0,,self.view.window 是当前视图所在窗口 \\N{\\fs12}Okay. Self dot view dot window is the window that your view is in,\r\nDialogue: 0,0:49:10.49,0:49:13.12,yin,,0,0,0,,view 指的是你的 MVC 的顶级视图 \\N{\\fs12}view is the top level view of your MVC,\r\nDialogue: 0,0:49:13.12,0:49:15.67,yin,,0,0,0,, 如果它是 nil 那么你现在不在屏幕上 \\N{\\fs12}and if that’s nil, then you’re not onscreen right now.\r\nDialogue: 0,0:49:16.41,0:49:17.70,yin,,0,0,0,, 所以这样写的意思是 \\N{\\fs12}So what this says is,\r\nDialogue: 0,0:49:17.70,0:49:21.24,yin,,0,0,0,, 如果有人设置了待分析的文本 而且我在屏幕上 \\N{\\fs12}if someone sets the text I’m supposed to analyze and I’m onscreen,\r\nDialogue: 0,0:49:21.25,0:49:22.85,yin,,0,0,0,, 那么我最好更新我的 UI\\N{\\fs12}then I’d better update my UI.\r\nDialogue: 0,0:49:23.18,0:49:26.18,yin,,0,0,0,, 否则就让 viewWillAppear 替我执行 \\N{\\fs12}Otherwise, I’ll let viewWillAppear do it for me,\r\nDialogue: 0,0:49:26.76,0:49:29.08,yin,,0,0,0,, 因为我现在不在屏幕上 但最终会出现在屏幕上 \\N{\\fs12}because I’m not onscreen and I’m eventually going to come onscreen.\r\nDialogue: 0,0:49:29.09,0:49:32.26,yin,,0,0,0,, 实际上 除非我出现在屏幕上 否则我不会分析文本的 \\N{\\fs12}In fact, I’ll never analyze my text unless I get put onscreen,\r\nDialogue: 0,0:49:32.27,0:49:33.60,yin,,0,0,0,, 这样的性能也很好 \\N{\\fs12}so it’s kind of good performance too,\r\nDialogue: 0,0:49:33.61,0:49:36.59,yin,,0,0,0,, 尽管分析文本会变得不太重要 \\N{\\fs12}although analyzing text is going to be trivial. Okay.\r\nDialogue: 0,0:49:36.93,0:49:39.12,yin,,0,0,0,, 这是一种常用的模式 \\N{\\fs12}So this is kind of a common pattern\r\nDialogue: 0,0:49:39.32,0:49:41.42,yin,,0,0,0,, 设置输出口 \\N{\\fs12}to have outlets that you set\r\nDialogue: 0,0:49:41.57,0:49:43.96,yin,,0,0,0,, 如果你在屏幕上的话就更新 \\N{\\fs12}that if you’re onscreen will update,\r\nDialogue: 0,0:49:43.96,0:49:46.38,yin,,0,0,0,, 否则就等着让 viewWillAppear 来做 \\N{\\fs12}otherwise, you wait and let viewWillAppear do it.\r\nDialogue: 0,0:49:47.02,0:49:48.64,yin,,0,0,0,, 明白吧 好的 \\N{\\fs12}Okay. All right.\r\nDialogue: 0,0:49:48.66,0:49:51.02,yin,,0,0,0,, 我们讲讲如何更新 UI\\N{\\fs12}So let’s talk about update UI and how that’s going to work.\r\nDialogue: 0,0:49:51.02,0:49:52.91,yin,,0,0,0,, 先创建视图 \\N{\\fs12}Well, let’s build our view\r\nDialogue: 0,0:49:52.96,0:49:56.24,yin,,0,0,0,, 方便大家知道我们要创建的 UI 是怎样的 \\N{\\fs12}so you know what our UI is that we want to build here.\r\nDialogue: 0,0:49:56.24,0:49:58.32,yin,,0,0,0,,UI 会非常非常简单 \\N{\\fs12}So, I’m going to make this really, really simple,\r\nDialogue: 0,0:49:58.32,0:50:00.23,yin,,0,0,0,, 只是添加两个标签 \\N{\\fs12}so I’m just going to have a couple of labels here.\r\nDialogue: 0,0:50:00.89,0:50:04.95,yin,,0,0,0,, 这里写上 0 个彩色字符 \\N{\\fs12}I’m going to say zero colorful characters.\r\nDialogue: 0,0:50:06.18,0:50:08.66,yin,,0,0,0,, 我们会用在 Matchismo 中用过的 \\N{\\fs12}Okay. And then we’re going to do the same thing we did\r\nDialogue: 0,0:50:08.75,0:50:11.99,yin,,0,0,0,, 处理分数的方法 \\N{\\fs12}with the score in Matchismo\r\nDialogue: 0,0:50:12.00,0:50:13.91,yin,,0,0,0,, 用打印函数来修改标签 \\N{\\fs12}to change that with the printf thing,\r\nDialogue: 0,0:50:14.08,0:50:17.20,yin,,0,0,0,, 再添加一条带有轮廓字符的统计信息 \\N{\\fs12}and then we’ll also keep track of outlined characters,\r\nDialogue: 0,0:50:17.50,0:50:19.45,yin,,0,0,0,, 这个文本分析器中 \\N{\\fs12}but you could imagine that this text analyzer\r\nDialogue: 0,0:50:19.45,0:50:20.73,yin,,0,0,0,, 应该还有很多其他数据 \\N{\\fs12}would have a whole bunch of other lines,\r\nDialogue: 0,0:50:20.73,0:50:24.50,yin,,0,0,0,, 分析随机属性化文本的其他数据 \\N{\\fs12}where it’d analyze other thing that was in random attributed text.\r\nDialogue: 0,0:50:24.73,0:50:27.73,yin,,0,0,0,, 字体 加粗 斜体等等 \\N{\\fs12}Okay. Font, bold, italic, etcetera,\r\nDialogue: 0,0:50:27.73,0:50:29.25,yin,,0,0,0,, 但是这里我们就简化一下 \\N{\\fs12}but again, we’re going to make this simple.\r\nDialogue: 0,0:50:30.01,0:50:32.84,yin,,0,0,0,, 我需要更新这两条数据 \\N{\\fs12}So I need to update these two things with –\r\nDialogue: 0,0:50:33.30,0:50:38.31,yin,,0,0,0,, 通过分析模型 这里的这个模型 \\N{\\fs12}by analyzing whatever my model, this model right here,\r\nDialogue: 0,0:50:38.67,0:50:40.32,yin,,0,0,0,, 分析它的属性化字符串的内容情况 \\N{\\fs12}contains in terms of attributed strings.\r\nDialogue: 0,0:50:40.33,0:50:41.12,yin,,0,0,0,, 我要怎么实现呢 \\N{\\fs12}So how am I going to do that?\r\nDialogue: 0,0:50:41.13,0:50:45.51,yin,,0,0,0,, 我要为大家展示 \\N{\\fs12}Well, I’m going to do that in a way that shows off a little bit\r\nDialogue: 0,0:50:45.66,0:50:48.46,yin,,0,0,0,, 如何分析属性化字符串 \\N{\\fs12}how we analyze attributed strings.\r\nDialogue: 0,0:50:48.59,0:50:50.73,yin,,0,0,0,, 我会快速输入代码 \\N{\\fs12}Okay. I’m going to type this code in pretty quick\r\nDialogue: 0,0:50:50.73,0:50:52.36,yin,,0,0,0,, 因为显然我们时间不够了 \\N{\\fs12}because we’re time constrained, obviously,\r\nDialogue: 0,0:50:52.50,0:50:54.22,yin,,0,0,0,, 但大家要确保自己理解了这段代码 \\N{\\fs12}but you should make sure you understand this code.\r\nDialogue: 0,0:50:54.22,0:50:55.75,yin,,0,0,0,, 非常简单和直接 \\N{\\fs12}It’s very simple and straightforward,\r\nDialogue: 0,0:50:55.90,0:50:58.64,yin,,0,0,0,, 但是真的需要你理解属性化字符串 \\N{\\fs12}but it really requires that you understand attributed strings,\r\nDialogue: 0,0:50:58.64,0:50:59.84,yin,,0,0,0,, 所以这也同时检查了 \\N{\\fs12}so it’s a little bit of a double check\r\nDialogue: 0,0:50:59.85,0:51:02.39,yin,,0,0,0,, 大家对于属性化字符串的理解 \\N{\\fs12}of your attributed string understanding.\r\nDialogue: 0,0:51:02.74,0:51:03.88,yin,,0,0,0,, 我要做的是 \\N{\\fs12}So what I’m going to do is\r\nDialogue: 0,0:51:03.88,0:51:08.53,yin,,0,0,0,, 添加一个方法 叫做 charactersMatching–\\N{\\fs12}I’m going to have a method called charactersMatching –\r\nDialogue: 0,0:51:09.46,0:51:11.06,yin,,0,0,0,, 不如我们用这个吧 \\N{\\fs12}or we’ll just use this one like\r\nDialogue: 0,0:51:11.06,0:51:17.62,yin,,0,0,0,,charactersWithAttribute: (NSString )attributeName\\N{\\fs12}charactersWithAttribute NSString attributeName. Okay.\r\nDialogue: 0,0:51:17.83,0:51:19.58,yin,,0,0,0,, 这个方法要做的是 \\N{\\fs12}So what this is going to do is\r\nDialogue: 0,0:51:19.59,0:51:21.73,yin,,0,0,0,, 对 textToAnalyze 进行查找 \\N{\\fs12}it’s going to look in my textToAnalyze\r\nDialogue: 0,0:51:21.99,0:51:24.45,yin,,0,0,0,, 看有哪些字符具有这个属性 \\N{\\fs12}for any characters that have this attribute,\r\nDialogue: 0,0:51:24.47,0:51:29.30,yin,,0,0,0,, 比如 NSForegroundColor 和 strokeWidth 等 \\N{\\fs12}like NSForegroundColor attribute or in strokeWidth, or something like that,\r\nDialogue: 0,0:51:29.49,0:51:31.33,yin,,0,0,0,, 这个方法会返回一个字符串 \\N{\\fs12}and it’s going to return a string\r\nDialogue: 0,0:51:31.33,0:51:33.81,yin,,0,0,0,, 复制了所有符合条件的字符 \\N{\\fs12}that has all those characters cloned onto it.\r\nDialogue: 0,0:51:34.20,0:51:36.04,yin,,0,0,0,, 然后在 UI 中 \\N{\\fs12}And then in my UI,\r\nDialogue: 0,0:51:36.09,0:51:39.60,yin,,0,0,0,, 我只要知道长度就可以得到字符的数量 \\N{\\fs12}I’ll just specify how many of them there are by checking the length,\r\nDialogue: 0,0:51:40.50,0:51:41.93,yin,,0,0,0,, 通过字符串的长度 \\N{\\fs12}okay, of that string.\r\nDialogue: 0,0:51:42.17,0:51:44.56,yin,,0,0,0,, 有人可能会问 为什么要这么麻烦地收集字符 \\N{\\fs12}And you might ask why am I going to all the troubles to collect them up,\r\nDialogue: 0,0:51:44.77,0:51:45.81,yin,,0,0,0,, 等下就知道了 \\N{\\fs12}and you’ll see that later.\r\nDialogue: 0,0:51:46.44,0:51:48.61,yin,,0,0,0,, 如何把字符收集起来呢 \\N{\\fs12}Okay. So, how would I collect this up?\r\nDialogue: 0,0:51:48.61,0:51:51.33,yin,,0,0,0,, 我这样做是想为大家演示它是如何作用的 \\N{\\fs12}I’m doing it mostly because I want to show you how that would work.\r\nDialogue: 0,0:51:51.50,0:51:54.85,yin,,0,0,0,, 我要创建一个可变属性化字符串 用来收集字符 \\N{\\fs12}So I’m gonna create a mutable attributed string to collect all this into.\r\nDialogue: 0,0:51:54.85,0:51:56.03,yin,,0,0,0,, 叫它 characters\\N{\\fs12}I’ll call it characters,\r\nDialogue: 0,0:51:56.19,0:51:59.35,yin,,0,0,0,, 把两边的面板隐藏 腾出更大空间 \\N{\\fs12}and let’s make more space here on both sides.\r\nDialogue: 0,0:52:00.45,0:52:00.95,yin,,0,0,0,, 好的 \\N{\\fs12}Okay.\r\nDialogue: 0,0:52:01.68,0:52:04.86,yin,,0,0,0,, 然后是 [NSMutableAttributedString alloc] init\\N{\\fs12}So I’m just going to say NSMutableAttributedString alloc init,\r\nDialogue: 0,0:52:04.86,0:52:06.25,yin,,0,0,0,, 现在这是一个空的可变字符串 \\N{\\fs12}so here’s an empty mutable string\r\nDialogue: 0,0:52:06.27,0:52:10.44,yin,,0,0,0,, 我要在其中添加字符 然后返回字符串 \\N{\\fs12}that I’m going to put the characters in and return. Okay.\r\nDialogue: 0,0:52:10.55,0:52:13.59,yin,,0,0,0,, 所以在中间我需要收集符合条件的字符 \\N{\\fs12}So, in here I need to collect all this stuff.\r\nDialogue: 0,0:52:14.00,0:52:15.23,yin,,0,0,0,, 我要做什么呢 \\N{\\fs12}So what am I going to do?\r\nDialogue: 0,0:52:15.32,0:52:17.09,yin,,0,0,0,, 实际上 我要做的是 \\N{\\fs12}I’m actually just going to\r\nDialogue: 0,0:52:17.35,0:52:19.90,yin,,0,0,0,, 创建一个 while 循环 依次检查字符 \\N{\\fs12}do a while loop that goes through and looks at every character.\r\nDialogue: 0,0:52:20.45,0:52:21.57,yin,,0,0,0,, 再简单不过了 \\N{\\fs12}Okay. Couldn’t be simpler.\r\nDialogue: 0,0:52:21.78,0:52:25.14,yin,,0,0,0,, 这里写 int index=0\\N{\\fs12}So I’ll say int index equals zero\r\nDialogue: 0,0:52:26.38,0:52:33.88,yin,,0,0,0,, 当 index 小于 self.textToAnalyze 的长度时 \\N{\\fs12}while this index is less than the self textToAnalyze length,\r\nDialogue: 0,0:52:34.85,0:52:36.06,yin,,0,0,0,,while (index<[self.textToAnalyze lenth])\\N{\\fs12}oops, length.\r\nDialogue: 0,0:52:37.25,0:52:40.76,yin,,0,0,0,, 我就会收集字符 \\N{\\fs12}Then I’m going to collect the characters. Okay.\r\nDialogue: 0,0:52:40.77,0:52:43.35,yin,,0,0,0,, 这里多了一个方括号 \\N{\\fs12}Too many square brackets there. Okay.\r\nDialogue: 0,0:52:44.57,0:52:46.83,yin,,0,0,0,, 到这里大家都明白吧 \\N{\\fs12}So everyone understands this part so far, right?\r\nDialogue: 0,0:52:47.17,0:52:49.81,yin,,0,0,0,, 这部分最简单了 \\N{\\fs12}This part couldn’t be simpler.\r\nDialogue: 0,0:52:51.25,0:52:54.08,yin,,0,0,0,, 我们继续 \\N{\\fs12}So, now let’s go ahead\r\nDialogue: 0,0:52:54.09,0:52:57.59,yin,,0,0,0,, 获取这个属性的值 \\N{\\fs12}and get the value of this attribute\r\nDialogue: 0,0:52:57.86,0:52:59.48,yin,,0,0,0,, 这个位置的字符的属性值 \\N{\\fs12}at this character.\r\nDialogue: 0,0:53:00.08,0:53:03.06,yin,,0,0,0,, 叫做 value 它在这里是一个 ID 类型 \\N{\\fs12}So that’s value, and the value’s an ID here,\r\nDialogue: 0,0:53:03.40,0:53:07.19,yin,,0,0,0,, 因为它有可能是一种颜色 一种字体 对吧 \\N{\\fs12}because it could be a color, it could be a font. Right?\r\nDialogue: 0,0:53:07.22,0:53:09.40,yin,,0,0,0,, 可能是一个 NSNumber\\N{\\fs12}It could be NSNumber, so I’m –\r\nDialogue: 0,0:53:09.40,0:53:11.82,yin,,0,0,0,, 这样 ID 类型就派上用场了 \\N{\\fs12}this is where ID comes in handy dandy.\r\nDialogue: 0,0:53:12.13,0:53:21.51,yin,,0,0,0,, 然后是 self.textToAnalyze attribute:attributeName\\N{\\fs12}So let’s say self dot textToAnalyze attribute colon attributeName\r\nDialogue: 0,0:53:22.84,0:53:26.93,yin,,0,0,0,,atIndex: index effectiveRange\\N{\\fs12}atIndex: index effectiveRange. Okay.\r\nDialogue: 0,0:53:26.99,0:53:28.66,yin,,0,0,0,, 还记得这个 effectiveRange 吧 \\N{\\fs12}So this effectiveRange, remember I told you,\r\nDialogue: 0,0:53:28.66,0:53:32.49,yin,,0,0,0,, 它会返回具有相同属性的字符范围 \\N{\\fs12}is gonna return the range that this attribute is the same for.\r\nDialogue: 0,0:53:32.98,0:53:35.42,yin,,0,0,0,, 如果连续 12 个字符都具有这个属性 \\N{\\fs12}Right. So if this attribute is there for 12 characters in a row,\r\nDialogue: 0,0:53:35.42,0:53:37.25,yin,,0,0,0,, 它就会返回连续 12 个这样的范围 \\N{\\fs12}it’s going to return this range 12 in a row,\r\nDialogue: 0,0:53:37.25,0:53:38.80,yin,,0,0,0,, 我要得到这个范围 \\N{\\fs12}so I’m going to capture that range,\r\nDialogue: 0,0:53:38.80,0:53:40.08,yin,,0,0,0,, 你们会看到我为什么要这样做 \\N{\\fs12}and you’ll see why I want that.\r\nDialogue: 0,0:53:40.50,0:53:42.43,yin,,0,0,0,, 我最好新建一个局部变量 \\N{\\fs12}Okay. So I better create a local variable\r\nDialogue: 0,0:53:42.44,0:53:48.58,yin,,0,0,0,,NSRange range\\N{\\fs12}NSRanger, no, NSRange. Oh, hello, range, range.\r\nDialogue: 0,0:53:48.78,0:53:51.17,yin,,0,0,0,, 这只是这个结构体的局部变量 range\\N{\\fs12}So this is just a local variable range for this struct\r\nDialogue: 0,0:53:51.52,0:53:53.21,yin,,0,0,0,, 我要传递一个指针给它 \\N{\\fs12}and I’m just going to pass a pointer to it,\r\nDialogue: 0,0:53:53.21,0:53:56.24,yin,,0,0,0,,effectiveRange 把结构体填满 \\N{\\fs12}so that it fills that struct out with the effectiveRange.\r\nDialogue: 0,0:53:57.07,0:53:58.12,yin,,0,0,0,, 有问题吗 \\N{\\fs12}Got any questions there?\r\nDialogue: 0,0:53:58.94,0:53:59.48,yin,,0,0,0,, 好的 \\N{\\fs12}All right.\r\nDialogue: 0,0:53:59.49,0:54:02.16,yin,,0,0,0,, 如果 value 不为空 \\N{\\fs12}So, if the value is set,\r\nDialogue: 0,0:54:02.85,0:54:04.70,yin,,0,0,0,, 那就是我想要的 \\N{\\fs12}okay, that’s what I’m looking for.\r\nDialogue: 0,0:54:04.74,0:54:07.68,yin,,0,0,0,, 我要找那些设置了这个属性的字符 \\N{\\fs12}I’m looking for characters where this attribute is set.\r\nDialogue: 0,0:54:08.23,0:54:09.86,yin,,0,0,0,, 如果我查看的属性是前景色 \\N{\\fs12}Okay. So, if I’m looking at foreground color,\r\nDialogue: 0,0:54:09.86,0:54:11.12,yin,,0,0,0,, 那这就是带颜色的字符 \\N{\\fs12}this would be colored characters.\r\nDialogue: 0,0:54:11.36,0:54:12.24,yin,,0,0,0,, 如果我查看的是描边宽度 \\N{\\fs12}If I’m looking at stroke width,\r\nDialogue: 0,0:54:12.24,0:54:13.51,yin,,0,0,0,, 那就是带有轮廓的字符 \\N{\\fs12}it would be outlined characters.\r\nDialogue: 0,0:54:13.82,0:54:15.07,yin,,0,0,0,, 所以如果 value 不为空 \\N{\\fs12}So if the value is set,\r\nDialogue: 0,0:54:15.56,0:54:20.50,yin,,0,0,0,, 我就要将它加到 characters 中 \\N{\\fs12}then I’m going to take the characters and append onto it\r\nDialogue: 0,0:54:21.09,0:54:26.04,yin,,0,0,0,,textToAnalyze attributedSubstringFromRange\\N{\\fs12}the textToAnalyze attributedSubstringFromRange,\r\nDialogue: 0,0:54:26.05,0:54:27.42,yin,,0,0,0,, 然后是我得到的范围 range\\N{\\fs12}that range I just got back.\r\nDialogue: 0,0:54:29.59,0:54:30.68,yin,,0,0,0,, 大家都明白吗 \\N{\\fs12}Everyone make sense there?\r\nDialogue: 0,0:54:30.68,0:54:34.26,yin,,0,0,0,, 这里我收集了符合属性条件的字符 \\N{\\fs12}So I just collected those characters that matched that attribute,\r\nDialogue: 0,0:54:34.42,0:54:36.99,yin,,0,0,0,, 我还想加上 \\N{\\fs12}and I also want to say –\r\nDialogue: 0,0:54:37.00,0:54:40.44,yin,,0,0,0,, 这里可以用 index++ 进入下一个 index\\N{\\fs12}I could say index plus plus and just go to the next index,\r\nDialogue: 0,0:54:40.53,0:54:43.67,yin,,0,0,0,, 但是实际上 我们知道字符范围 \\N{\\fs12}but actually know that this range of character\r\nDialogue: 0,0:54:43.69,0:54:48.71,yin,,0,0,0,, 结束的位置是 range.location+range.length\\N{\\fs12}ends at range dot location plus range dot length.\r\nDialogue: 0,0:54:49.38,0:54:51.22,yin,,0,0,0,, 所以不需要逐一检查 \\N{\\fs12}Right. So there’s no need to check –\r\nDialogue: 0,0:54:51.22,0:54:52.82,yin,,0,0,0,, 我已经得到了这个范围 \\N{\\fs12}I already grabbed this range,\r\nDialogue: 0,0:54:52.82,0:54:54.84,yin,,0,0,0,, 只要直接跳到这个范围的末尾就可以了 \\N{\\fs12}so I need now to jump to the end of this range.\r\nDialogue: 0,0:54:55.47,0:54:57.93,yin,,0,0,0,, 如果这个字符没有设置这个属性 \\N{\\fs12}If the attribute is not set on this character,\r\nDialogue: 0,0:54:57.93,0:55:00.93,yin,,0,0,0,, 那我确实需要移到下一个 index\\N{\\fs12}then I do need to move to the next thing.\r\nDialogue: 0,0:55:01.42,0:55:03.03,yin,,0,0,0,, 移到下一个字符 \\N{\\fs12}Okay. To the next character,\r\nDialogue: 0,0:55:03.25,0:55:04.62,yin,,0,0,0,, 因为我是在这个 while 循环中 \\N{\\fs12}because I’m in this while loop right here,\r\nDialogue: 0,0:55:04.62,0:55:05.81,yin,,0,0,0,, 需要循环执行 \\N{\\fs12}I need to go round and round.\r\nDialogue: 0,0:55:06.58,0:55:07.73,yin,,0,0,0,, 好的 就是这样 \\N{\\fs12}Okay. So that’s it.\r\nDialogue: 0,0:55:08.13,0:55:10.52,yin,,0,0,0,, 希望大家都理解了这段代码 \\N{\\fs12}Hopefully, you all understand this code.\r\nDialogue: 0,0:55:11.42,0:55:13.79,yin,,0,0,0,, 如果没有 下面再看看 \\N{\\fs12}If you don’t, you definitely want to offline,\r\nDialogue: 0,0:55:14.17,0:55:15.97,yin,,0,0,0,, 确保自己理解了这部分的工作原理 \\N{\\fs12}make sure you understand how this works\r\nDialogue: 0,0:55:15.97,0:55:17.47,yin,,0,0,0,, 理解了可变字符串 \\N{\\fs12}so that you understand mutable strings\r\nDialogue: 0,0:55:17.48,0:55:20.33,yin,,0,0,0,, 理解了属性化字符串 \\N{\\fs12}or attributed strings. Okay.\r\nDialogue: 0,0:55:20.51,0:55:24.12,yin,,0,0,0,, 注意这里返回的是一个不可变属性化字符串 \\N{\\fs12}So now, notice that I’m returning a non-mutable attributed string here\r\nDialogue: 0,0:55:24.21,0:55:26.63,yin,,0,0,0,, 而它显然是一个可变属性化字符串 \\N{\\fs12}and this is clearly a mutable attributed string,\r\nDialogue: 0,0:55:26.63,0:55:27.77,yin,,0,0,0,, 这样完全没问题 \\N{\\fs12}and that’s perfectly fine.\r\nDialogue: 0,0:55:28.33,0:55:30.94,yin,,0,0,0,, 这样意味着 不管是谁调用这个方法 \\N{\\fs12}What that says is whoever’s calling this,\r\nDialogue: 0,0:55:30.94,0:55:32.77,yin,,0,0,0,, 都不应该认为它是可变的 \\N{\\fs12}shouldn’t rely on this being mutable.\r\nDialogue: 0,0:55:33.15,0:55:34.71,yin,,0,0,0,, 应该假设它是不可变的 \\N{\\fs12}They should assume it’s not mutable.\r\nDialogue: 0,0:55:34.78,0:55:37.29,yin,,0,0,0,,updateUI 会调用这个方法 \\N{\\fs12}And so, updateUI is going to call this\r\nDialogue: 0,0:55:37.29,0:55:41.59,yin,,0,0,0,, 它不应该尝试改变这些字符 \\N{\\fs12}and it should be sure not to try and change these characters,\r\nDialogue: 0,0:55:41.59,0:55:44.07,yin,,0,0,0,, 如果不进行类型转换 这也是不允许的 \\N{\\fs12}and it won’t be allowed to either without doing some sort of casting\r\nDialogue: 0,0:55:44.08,0:55:47.58,yin,,0,0,0,, 因为编译器不允许赋值给可变字符串 \\N{\\fs12}because the compiler is not gonna let you assign this to a mutable string.\r\nDialogue: 0,0:55:47.59,0:55:50.16,yin,,0,0,0,, 我把这个方法移到上面这里 \\N{\\fs12}I’m going to move this up here like this,\r\nDialogue: 0,0:55:50.46,0:55:52.17,yin,,0,0,0,, 我们继续 用下面这行代码 \\N{\\fs12}and so let’s go ahead and use this.\r\nDialogue: 0,0:55:53.46,0:55:55.44,yin,,0,0,0,, 可能看起来很长 \\N{\\fs12}This might seem like a really long line of code,\r\nDialogue: 0,0:55:55.44,0:55:57.17,yin,,0,0,0,, 但也很简单 \\N{\\fs12}but it’s pretty straightforward,\r\nDialogue: 0,0:55:57.34,0:56:02.96,yin,,0,0,0,, 我们需要添加一些指向它们的输出口 \\N{\\fs12}so we need to have some outlets that point to these things.\r\nDialogue: 0,0:56:03.33,0:56:05.80,yin,,0,0,0,, 指向这两个标签 我们做一下 \\N{\\fs12}Right. These little guys right here, so let’s do that.\r\nDialogue: 0,0:56:09.39,0:56:13.79,yin,,0,0,0,, 这正好是我刚才说过的内容的例子 \\N{\\fs12}Okay. So, here’s an example of exactly what I was talking about.\r\nDialogue: 0,0:56:13.90,0:56:15.56,yin,,0,0,0,, 我想在这里创建一个输出口 \\N{\\fs12}I want to create an outlet here\r\nDialogue: 0,0:56:15.80,0:56:17.89,yin,,0,0,0,, 怎么回事 \\N{\\fs12}and what’s going on?\r\nDialogue: 0,0:56:17.90,0:56:19.37,yin,,0,0,0,, 为什么不能创建这个输出口呢 \\N{\\fs12}How come I can’t create this outlet?\r\nDialogue: 0,0:56:19.77,0:56:22.04,yin,,0,0,0,, 是自动没错 \\N{\\fs12}Okay. This is on automatic.\r\nDialogue: 0,0:56:22.49,0:56:23.63,yin,,0,0,0,, 怎么回事呢 \\N{\\fs12}What’s going on here?\r\nDialogue: 0,0:56:23.63,0:56:27.02,yin,,0,0,0,, 答案是 它还是一个 UIViewController\\N{\\fs12}Well the answer is, this is still UIViewController,\r\nDialogue: 0,0:56:27.41,0:56:28.77,yin,,0,0,0,, 所以我需要转到这里 \\N{\\fs12}so I need to go over here,\r\nDialogue: 0,0:56:29.27,0:56:30.28,yin,,0,0,0,, 打开标识符检查器 \\N{\\fs12}go to here,\r\nDialogue: 0,0:56:30.41,0:56:33.02,yin,,0,0,0,, 这里现在是 UIViewController\\N{\\fs12}and instead of having UIViewController here,\r\nDialogue: 0,0:56:33.02,0:56:35.29,yin,,0,0,0,, 我要改成 TextStatsViewController\\N{\\fs12}I need TextStatsViewController.\r\nDialogue: 0,0:56:35.66,0:56:37.24,yin,,0,0,0,, 看看发生了什么 \\N{\\fs12}Okay. Now look what happened.\r\nDialogue: 0,0:56:37.34,0:56:39.00,yin,,0,0,0,, 系统自动更新了代码 \\N{\\fs12}It automatically updated this.\r\nDialogue: 0,0:56:39.74,0:56:42.33,yin,,0,0,0,, 自动模式发挥了它的作用 \\N{\\fs12}Okay. The automatic did its automatic job.\r\nDialogue: 0,0:56:42.78,0:56:46.76,yin,,0,0,0,, 现在我就可以在这里按住 control 键拖动到这里了 \\N{\\fs12}Okay. So now I can control drag from here to here –\r\nDialogue: 0,0:56:46.77,0:56:50.58,yin,,0,0,0,, 我们叫它 colorfulCharactersLabel 彩色字符标签 \\N{\\fs12}we’ll call this colorfulCharactersLabel,\r\nDialogue: 0,0:56:51.32,0:56:53.81,yin,,0,0,0,, 我还要从这里拖动到这里 \\N{\\fs12}and I’ll also drag from here to here\r\nDialogue: 0,0:56:53.82,0:56:58.72,yin,,0,0,0,, 我要叫它 outlinedCharactersLabel 带有轮廓字符标签 \\N{\\fs12}and we’ll call this outlinedCharactersLabel. Okay.\r\nDialogue: 0,0:56:59.55,0:57:00.44,yin,,0,0,0,, 看懂了吗 \\N{\\fs12}Everyone see that?\r\nDialogue: 0,0:57:01.91,0:57:03.67,yin,,0,0,0,, 剩下要做的 \\N{\\fs12}All right. So all we have left to do here\r\nDialogue: 0,0:57:03.68,0:57:05.68,yin,,0,0,0,, 就是实现 updateUI 方法 \\N{\\fs12}is implement our updateUI\r\nDialogue: 0,0:57:05.69,0:57:08.50,yin,,0,0,0,, 让这两个标签 \\N{\\fs12}to make these two labels here\r\nDialogue: 0,0:57:08.82,0:57:10.71,yin,,0,0,0,, 能够正确显示字符串长度 \\N{\\fs12}properly display the length of the characters\r\nDialogue: 0,0:57:10.72,0:57:14.16,yin,,0,0,0,, 而长度是通过下面的 charactersWithAttribute 计算出的 \\N{\\fs12}that we calculated with this charactersWithAttribute down here.\r\nDialogue: 0,0:57:14.42,0:57:16.64,yin,,0,0,0,, 腾出更大空间 \\N{\\fs12}So let’s make a lot more space.\r\nDialogue: 0,0:57:16.64,0:57:19.60,yin,,0,0,0,, 转到这里 只显示视图控制器 \\N{\\fs12}Let’s go over here, just showing our view controller.\r\nDialogue: 0,0:57:20.67,0:57:24.36,yin,,0,0,0,, 实际上 updateUI 方法中要做的是 \\N{\\fs12}And in updateUI all we really need to do\r\nDialogue: 0,0:57:24.37,0:57:26.59,yin,,0,0,0,, 得到具有指定属性的字符 \\N{\\fs12}is get the characters with the given attribute,\r\nDialogue: 0,0:57:26.59,0:57:29.56,yin,,0,0,0,, 无论属性是颜色还是轮廓 \\N{\\fs12}whether it be color or the outline\r\nDialogue: 0,0:57:29.72,0:57:31.49,yin,,0,0,0,, 然后计算字符个数 \\N{\\fs12}and count how many characters in there.\r\nDialogue: 0,0:57:31.50,0:57:34.96,yin,,0,0,0,, 我们用 self–\\N{\\fs12}So let’s do self dot –\r\nDialogue: 0,0:57:35.99,0:57:39.05,yin,,0,0,0,, 先用 self.charactersWithAttribute\\N{\\fs12}sorry, let’s do self dot charactersWithAttribute first.\r\nDialogue: 0,0:57:39.06,0:57:42.73,yin,,0,0,0,, 我们先看颜色属性的情况 \\N{\\fs12}And let’s do the color ones first,\r\nDialogue: 0,0:57:42.73,0:57:47.01,yin,,0,0,0,, 对应属性是 NSForegroundColorAttributeName\\N{\\fs12}which the attribute there would be the ForegroundColorAttributeName.\r\nDialogue: 0,0:57:47.28,0:57:49.04,yin,,0,0,0,, 现在我们得到了这些字符 \\N{\\fs12}So now we’ve got these characters.\r\nDialogue: 0,0:57:49.54,0:57:51.33,yin,,0,0,0,, 看一下 \\N{\\fs12}And let’s see.\r\nDialogue: 0,0:57:51.33,0:57:54.96,yin,,0,0,0,, 得到字符后 就可以计算字符个数了 \\N{\\fs12}Now that we have them, we can count them.\r\nDialogue: 0,0:57:55.20,0:57:59.43,yin,,0,0,0,, 方法是发送字符串的长度 \\N{\\fs12}So let’s do that by sending length of the string.\r\nDialogue: 0,0:57:59.44,0:58:01.25,yin,,0,0,0,, 现在我们就知道这里有多少个字符了 \\N{\\fs12}So now we know how many characters there are here.\r\nDialogue: 0,0:58:01.40,0:58:04.53,yin,,0,0,0,, 现在我们就可以更新那个字段了 \\N{\\fs12}So now we can update that field,\r\nDialogue: 0,0:58:04.58,0:58:09.43,yin,,0,0,0,, 也就是 self.colorfulCharactersLabel.text\\N{\\fs12}which is our self dot colorfulCharactersLabel text.\r\nDialogue: 0,0:58:09.76,0:58:14.02,yin,,0,0,0,, 然后是 NSString stringWithFormat:\\N{\\fs12}And we’ll do that by saying NSString stringWithFormat,\r\nDialogue: 0,0:58:14.92,0:58:20.85,yin,,0,0,0,,@”%d colorful characters”\\N{\\fs12}percent D colorful characters,\r\nDialogue: 0,0:58:22.30,0:58:25.16,yin,,0,0,0,, 参数就是刚才写好的这个计算结果 \\N{\\fs12}and the argument is this thing we just calculated right here.\r\nDialogue: 0,0:58:26.53,0:58:27.73,yin,,0,0,0,, 这个写好了 \\N{\\fs12}Okay? So we got that.\r\nDialogue: 0,0:58:27.73,0:58:29.40,yin,,0,0,0,, 再做一次 \\N{\\fs12}And let’s do the exact same thing here\r\nDialogue: 0,0:58:29.66,0:58:33.25,yin,,0,0,0,, 带有轮廓字符的情况 \\N{\\fs12}with the outlined characters.\r\nDialogue: 0,0:58:33.46,0:58:36.80,yin,,0,0,0,, 这里改成 outlined characters\\N{\\fs12}And these are outlined characters.\r\nDialogue: 0,0:58:36.82,0:58:42.56,yin,,0,0,0,, 这里改成 NSStrokeWidthAttributeName\\N{\\fs12}And this is the NSStrokeWidthAttributeName.\r\nDialogue: 0,0:58:43.86,0:58:47.58,yin,,0,0,0,, 我们找到了具有该属性的字符 \\N{\\fs12}Okay? So we’ve went and found the characters that have that attribute,\r\nDialogue: 0,0:58:47.66,0:58:49.13,yin,,0,0,0,, 计算了它们的数量 \\N{\\fs12}found out how many there are,\r\nDialogue: 0,0:58:49.88,0:58:52.35,yin,,0,0,0,, 然后创建了一个格式化字符串 \\N{\\fs12}and then we created a string with format\r\nDialogue: 0,0:58:52.40,0:58:54.18,yin,,0,0,0,, 显示在标签上 \\N{\\fs12}that displayed that into the label.\r\nDialogue: 0,0:58:55.48,0:58:57.46,yin,,0,0,0,, 这样并不是完全正确的 \\N{\\fs12}Okay. This is not 100% correct,\r\nDialogue: 0,0:58:57.46,0:59:01.51,yin,,0,0,0,, 如果设置的颜色是黑色呢 \\N{\\fs12}because what if the color set on something is black?\r\nDialogue: 0,0:59:02.12,0:59:03.67,yin,,0,0,0,, 并不是彩色的字符 \\N{\\fs12}It’s not a very colorful character.\r\nDialogue: 0,0:59:03.78,0:59:06.31,yin,,0,0,0,, 或者如果设置了描边宽度 \\N{\\fs12}Or what if the stroke width is set,\r\nDialogue: 0,0:59:06.31,0:59:07.42,yin,,0,0,0,, 但是宽度设为 0 呢 \\N{\\fs12}but it’s set to zero,\r\nDialogue: 0,0:59:07.44,0:59:12.47,yin,,0,0,0,, 所以这并不是一个很好的实现方法 但是很简单 \\N{\\fs12}so this is not a great implementation, but it’s simple.\r\nDialogue: 0,0:59:12.53,0:59:13.50,yin,,0,0,0,, 能够给你一种思路 \\N{\\fs12}It gives you the idea.\r\nDialogue: 0,0:59:14.38,0:59:18.43,yin,,0,0,0,, 有时 我喜欢在新建 MVC 时测试一下 \\N{\\fs12}Now one thing I like to do when I build a new MVC sometimes is test it.\r\nDialogue: 0,0:59:18.91,0:59:23.09,yin,,0,0,0,, 测试的方法是添加一个简单的 viewDidLoad 方法 \\N{\\fs12}Okay. So I’m going to test this by adding a little viewDidLoad.\r\nDialogue: 0,0:59:24.02,0:59:26.51,yin,,0,0,0,, 这是 viewDidLoad\\N{\\fs12}Okay. So here’s viewDidLoad,\r\nDialogue: 0,0:59:28.41,0:59:32.72,yin,,0,0,0,, 这里要写的是 self.textToAnalyze=\\N{\\fs12}and what I’m going to do is self dot textToAnalyze equals\r\nDialogue: 0,0:59:32.97,0:59:40.80,yin,,0,0,0,,[NSAttributedString alloc] initWithString:@”test” attributes:\\N{\\fs12}NSAttributedString alloc initWithString test attributes,\r\nDialogue: 0,0:59:40.82,0:59:42.36,yin,,0,0,0,, 后面我要加上某些测试属性 \\N{\\fs12}and I’m going to put some test attributes in here\r\nDialogue: 0,0:59:42.36,0:59:45.72,yin,,0,0,0,, 比如前景色为绿色 \\N{\\fs12}like NSForegroundColor, green,\r\nDialogue: 0,0:59:47.33,0:59:49.88,yin,,0,0,0,, 再加上描边宽度属性 \\N{\\fs12}and also let’s put NSStrokeWidth –\r\nDialogue: 0,0:59:51.18,0:59:53.75,yin,,0,0,0,, 比如 -3 之类的 \\N{\\fs12}call it minus three, or something like that.\r\nDialogue: 0,0:59:55.24,0:59:56.61,yin,,0,0,0,, 好了 我写好了 \\N{\\fs12}Right. So I have this.\r\nDialogue: 0,0:59:56.61,0:59:59.62,yin,,0,0,0,, 现在 当这个 MVC 出现时 \\N{\\fs12}So now, when this MVC appears,\r\nDialogue: 0,0:59:59.63,1:00:01.67,yin,,0,0,0,, 它的 viewDidLoad 方法会设置它的模型 \\N{\\fs12}its viewDidLoad is going to set its own model,\r\nDialogue: 0,1:00:02.19,1:00:03.65,yin,,0,0,0,, 是一种很好的测试方法 \\N{\\fs12}which is kind of a good testing thing,\r\nDialogue: 0,1:00:04.05,1:00:05.68,yin,,0,0,0,, 我们回去做一下 \\N{\\fs12}so let’s go back and do that.\r\nDialogue: 0,1:00:05.83,1:00:06.95,yin,,0,0,0,, 我们如何做这个测试呢 \\N{\\fs12}And how would we do that test?\r\nDialogue: 0,1:00:06.95,1:00:08.39,yin,,0,0,0,, 这里是我们的 storyboard\\N{\\fs12}So we got our storyboard here,\r\nDialogue: 0,1:00:08.39,1:00:11.26,yin,,0,0,0,, 我们直接把这个箭头移到这里 \\N{\\fs12}what if we just pick this guy up and put it over here?\r\nDialogue: 0,1:00:12.33,1:00:13.55,yin,,0,0,0,, 现在我再运行这个应用 \\N{\\fs12}Now when I run this app,\r\nDialogue: 0,1:00:13.55,1:00:16.48,yin,,0,0,0,, 就会直接来到这个 MVC 跳过左边这个 \\N{\\fs12}it’s going to go straight to this MVC and just bypass –\r\nDialogue: 0,1:00:16.49,1:00:18.70,yin,,0,0,0,, 不会用到左边这个 \\N{\\fs12}this is not even going to be used right now,\r\nDialogue: 0,1:00:18.70,1:00:19.88,yin,,0,0,0,, 因为我只是测试右边这个 MVC\\N{\\fs12}because I’m just going to test this guy.\r\nDialogue: 0,1:00:19.88,1:00:21.39,yin,,0,0,0,, 我们试试 \\N{\\fs12}So let’s try that.\r\nDialogue: 0,1:00:21.39,1:00:22.73,yin,,0,0,0,, 看看我有没有忘记什么 \\N{\\fs12}See if I forgot anything.\r\nDialogue: 0,1:00:28.15,1:00:31.52,yin,,0,0,0,, 不是模拟器 我换一下 \\N{\\fs12}Oops, simulator. I’ll do this on the –\r\nDialogue: 0,1:00:35.57,1:00:37.33,yin,,0,0,0,, 我们在设备上运行 \\N{\\fs12}Let’s go put it on the device.\r\nDialogue: 0,1:00:44.48,1:00:47.46,yin,,0,0,0,,test 这个词中有四个字符 \\N{\\fs12}Okay. So the word test has four characters in it,\r\nDialogue: 0,1:00:47.46,1:00:48.83,yin,,0,0,0,, 希望运行出来显示的是 \\N{\\fs12}so hopefully this is going to come up and say\r\nDialogue: 0,1:00:48.83,1:00:50.92,yin,,0,0,0,,4 个彩色字符 4 个带有轮廓字符 \\N{\\fs12}four colorful characters and four outline characters,\r\nDialogue: 0,1:00:51.09,1:00:51.81,yin,,0,0,0,, 是运行正常的 \\N{\\fs12}so it’s working.\r\nDialogue: 0,1:00:52.17,1:00:55.03,yin,,0,0,0,, 我可以删掉一个属性 \\N{\\fs12}And I could go delete one of those attributes,\r\nDialogue: 0,1:00:55.03,1:00:56.18,yin,,0,0,0,, 检查数量是否显示为 0\\N{\\fs12}make sure it says zero.\r\nDialogue: 0,1:00:56.18,1:00:57.90,yin,,0,0,0,, 还可以换一个比 test 长的单词 \\N{\\fs12}I could change the word to be longer than test\r\nDialogue: 0,1:00:57.90,1:00:58.97,yin,,0,0,0,, 检查显示数量是否大于 4\\N{\\fs12}to make sure it says more than four.\r\nDialogue: 0,1:00:58.97,1:00:59.56,yin,,0,0,0,, 明白吗 \\N{\\fs12}You see what I mean?\r\nDialogue: 0,1:00:59.56,1:01:01.79,yin,,0,0,0,, 明白我是如何测试这个 MVC 检查它是否正常运行的吗 \\N{\\fs12}See how I can kind of test this MVC to make sure it’s working?\r\nDialogue: 0,1:01:02.17,1:01:04.14,yin,,0,0,0,, 但我们现在就相信它 \\N{\\fs12}So, we’re going to take our word for it though\r\nDialogue: 0,1:01:04.14,1:01:06.06,yin,,0,0,0,, 这样测试就够了 它运行正常 \\N{\\fs12}that’s enough testing and that it’s working,\r\nDialogue: 0,1:01:06.47,1:01:08.22,yin,,0,0,0,, 删掉 viewDidLoad\\N{\\fs12}so I’m going to get rid of viewDidLoad.\r\nDialogue: 0,1:01:08.39,1:01:10.01,yin,,0,0,0,, 这些也可以放到 \\N{\\fs12}This is something you might put this in\r\nDialogue: 0,1:01:10.01,1:01:12.88,yin,,0,0,0,,ifdef 之类的测试中 \\N{\\fs12}some sort of ifdef testing or something like that.\r\nDialogue: 0,1:01:12.88,1:01:13.91,yin,,0,0,0,, 大家都知道怎么做 \\N{\\fs12}You know how to do all that,\r\nDialogue: 0,1:01:14.39,1:01:15.45,yin,,0,0,0,, 也可以那样做 \\N{\\fs12}so you could do that as well,\r\nDialogue: 0,1:01:15.45,1:01:17.46,yin,,0,0,0,, 我就直接删掉 viewDidLoad 了 \\N{\\fs12}but I’m just going to delete viewDidLoad,\r\nDialogue: 0,1:01:18.23,1:01:21.94,yin,,0,0,0,, 现在这里我有了一个非常好用的 MVC\\N{\\fs12}but I have a really nice working MVC right here\r\nDialogue: 0,1:01:22.05,1:01:25.23,yin,,0,0,0,, 能告诉我某段给定文本中 \\N{\\fs12}that tells how many characters are colored and outlined\r\nDialogue: 0,1:01:25.25,1:01:26.20,yin,,0,0,0,, 有多少彩色和带有轮廓的字符 \\N{\\fs12}in a given piece of text.\r\nDialogue: 0,1:01:26.20,1:01:28.95,yin,,0,0,0,, 显然 现在应用可以从这里开始了 \\N{\\fs12}Well now, obviously, I could use if from this guy –\r\nDialogue: 0,1:01:28.95,1:01:30.14,yin,,0,0,0,, 我们把箭头移回去 \\N{\\fs12}let’s move this guy back.\r\nDialogue: 0,1:01:30.54,1:01:35.89,yin,,0,0,0,, 我要把它们放到一个导航控制器中 \\N{\\fs12}And I’m going to put these inside of a navigation controller,\r\nDialogue: 0,1:01:36.05,1:01:37.53,yin,,0,0,0,, 我还要在导航控制器顶栏上 \\N{\\fs12}and I’m going to actually add a button\r\nDialogue: 0,1:01:37.53,1:01:39.47,yin,,0,0,0,, 添加一个按钮 \\N{\\fs12}to the navigation controller’s bar,\r\nDialogue: 0,1:01:39.69,1:01:41.03,yin,,0,0,0,, 在这个 MVC 显示时出现 \\N{\\fs12}when this one’s visible,\r\nDialogue: 0,1:01:41.15,1:01:43.46,yin,,0,0,0,, 用来 segue 到这个 MVC\\N{\\fs12}that will segue over to this guy.\r\nDialogue: 0,1:01:43.90,1:01:44.77,yin,,0,0,0,, 我们做一下 \\N{\\fs12}Okay. So let’s do that.\r\nDialogue: 0,1:01:44.77,1:01:46.65,yin,,0,0,0,, 先把它加到导航控制器中 \\N{\\fs12}Let’s put it in navigation controller first.\r\nDialogue: 0,1:01:47.16,1:01:48.25,yin,,0,0,0,, 腾出更大空间 \\N{\\fs12}More space here.\r\nDialogue: 0,1:01:48.46,1:01:51.81,yin,,0,0,0,, 我只要选择嵌入导航控制器 \\N{\\fs12}so I’m just going to embed in navigation controller. Right.\r\nDialogue: 0,1:01:52.45,1:01:54.69,yin,,0,0,0,, 放进去了 上面自动添加了一栏 \\N{\\fs12}Boom, puts it in. Okay. It got a bar.\r\nDialogue: 0,1:01:54.75,1:01:56.43,yin,,0,0,0,, 注意这个 MVC 并没有顶栏 \\N{\\fs12}Notice that this one did not get a bar.\r\nDialogue: 0,1:01:56.80,1:01:59.58,yin,,0,0,0,, 为什么 因为还没有元素能够 segue 到它这里 \\N{\\fs12}Why? Because there’s nothing that segues to this yet,\r\nDialogue: 0,1:01:59.70,1:02:01.44,yin,,0,0,0,, 导航控制器中没有 \\N{\\fs12}that’s inside this navigation controller.\r\nDialogue: 0,1:02:01.90,1:02:03.55,yin,,0,0,0,, 还发生了一件不太好的事 \\N{\\fs12}Another bad thing happened though.\r\nDialogue: 0,1:02:03.58,1:02:06.02,yin,,0,0,0,,CS193p Rocks 不见了 \\N{\\fs12}I lost my CS193P rocks.\r\nDialogue: 0,1:02:06.43,1:02:09.08,yin,,0,0,0,, 我们知道 CS193p 确实很棒 \\N{\\fs12}Okay. And we know that CS193P does rock,\r\nDialogue: 0,1:02:09.08,1:02:11.47,yin,,0,0,0,, 所以我们不希望这句话被遮掉 \\N{\\fs12}so we do not want it blocked like that,\r\nDialogue: 0,1:02:11.74,1:02:14.78,yin,,0,0,0,, 如果某个元素像这样被遮掉了 \\N{\\fs12}so one thing you can do is if something gets blocked like this,\r\nDialogue: 0,1:02:14.78,1:02:16.74,yin,,0,0,0,, 你想着 我得把它改好 \\N{\\fs12}you know like, oh no, I’ve got to go fix that,\r\nDialogue: 0,1:02:16.80,1:02:19.20,yin,,0,0,0,, 你可以直接删除导航控制器 \\N{\\fs12}you can just delete the navigation controller\r\nDialogue: 0,1:02:19.21,1:02:20.40,yin,,0,0,0,, 就会回到之前的状态 \\N{\\fs12}and you’ll be back where you were,\r\nDialogue: 0,1:02:20.40,1:02:21.43,yin,,0,0,0,, 或者点击撤消 \\N{\\fs12}or you can hit undo.\r\nDialogue: 0,1:02:21.66,1:02:23.70,yin,,0,0,0,, 实际上 我要删掉它 \\N{\\fs12}So I’m actually going to get rid of this\r\nDialogue: 0,1:02:23.70,1:02:26.18,yin,,0,0,0,, 将它放到灰栏上 \\N{\\fs12}and put it in that gray bar instead.\r\nDialogue: 0,1:02:26.51,1:02:28.88,yin,,0,0,0,, 放在那里很合适 \\N{\\fs12}It’s a perfectly reasonable place for it to go.\r\nDialogue: 0,1:02:28.88,1:02:30.06,yin,,0,0,0,, 也许我应该把上边界降低一点 \\N{\\fs12}Maybe I’ll move this down a little bit\r\nDialogue: 0,1:02:30.06,1:02:31.82,yin,,0,0,0,, 确保等下大小合适 \\N{\\fs12}to make sure it fits on there.\r\nDialogue: 0,1:02:31.87,1:02:34.81,yin,,0,0,0,, 现在再选中它 \\N{\\fs12}So now let’s go back and select this again\r\nDialogue: 0,1:02:35.15,1:02:36.38,yin,,0,0,0,, 选择嵌入 \\N{\\fs12}and embed it.\r\nDialogue: 0,1:02:38.33,1:02:39.99,yin,,0,0,0,, 现在又回到了导航控制器中 \\N{\\fs12}Okay. So now we’re back in here.\r\nDialogue: 0,1:02:40.25,1:02:44.82,yin,,0,0,0,, 现在我可以把 CS193p Rocks 放在这里 \\N{\\fs12}All right. And now I can put my CS193p rocks here.\r\nDialogue: 0,1:02:45.66,1:02:47.55,yin,,0,0,0,, 放在这里很合适 \\N{\\fs12}Okay. Perfectly reasonable place to put it.\r\nDialogue: 0,1:02:48.04,1:02:48.92,yin,,0,0,0,, 得到了这个界面 \\N{\\fs12}And I’ve got this.\r\nDialogue: 0,1:02:48.92,1:02:51.27,yin,,0,0,0,, 还可以往上拉一点 \\N{\\fs12}Maybe I would line that up there or there,\r\nDialogue: 0,1:02:51.74,1:02:53.60,yin,,0,0,0,, 根据蓝线的指引 \\N{\\fs12}depends on where the blue lines say. Okay.\r\nDialogue: 0,1:02:53.73,1:02:54.48,yin,,0,0,0,, 得到了这个界面 \\N{\\fs12}So I got that.\r\nDialogue: 0,1:02:54.79,1:02:56.94,yin,,0,0,0,, 现在我想在这里添加一个小按钮 \\N{\\fs12}Now I want to put a little button right here,\r\nDialogue: 0,1:02:57.00,1:02:58.65,yin,,0,0,0,, 都还记得怎么做吧 \\N{\\fs12}so if everyone remembers how to do that.\r\nDialogue: 0,1:02:58.65,1:03:01.02,yin,,0,0,0,, 滚动到下面 \\N{\\fs12}We go all the way down to the bottom here\r\nDialogue: 0,1:03:01.91,1:03:04.35,yin,,0,0,0,, 找到 Bar Button Item 栏按钮项 在这里 \\N{\\fs12}and we find bar button item, which is right here,\r\nDialogue: 0,1:03:04.45,1:03:05.34,yin,,0,0,0,, 将它拖出 \\N{\\fs12}and we drag it up.\r\nDialogue: 0,1:03:05.52,1:03:06.51,yin,,0,0,0,, 放在这里 \\N{\\fs12}We put it right there.\r\nDialogue: 0,1:03:06.70,1:03:08.13,yin,,0,0,0,, 它是用来显示统计数据的 \\N{\\fs12}This is going to show the stats,\r\nDialogue: 0,1:03:08.13,1:03:09.51,yin,,0,0,0,, 我就叫它 Stats\\N{\\fs12}so I’m going to call this Stats.\r\nDialogue: 0,1:03:10.04,1:03:10.38,yin,,0,0,0,, 好的 \\N{\\fs12}All right.\r\nDialogue: 0,1:03:11.04,1:03:13.05,yin,,0,0,0,, 每次点击 Stats 时 \\N{\\fs12}And now, every time I click on stats,\r\nDialogue: 0,1:03:13.11,1:03:17.24,yin,,0,0,0,, 我想让这个 MVC 滑进来 替换掉左边的 MVC\\N{\\fs12}I want this MVC to slide in here and replace this one,\r\nDialogue: 0,1:03:17.25,1:03:20.01,yin,,0,0,0,, 在 Stats 上按住 control 键拖动到这里 \\N{\\fs12}so I’m going to control drag to here.\r\nDialogue: 0,1:03:20.47,1:03:23.57,yin,,0,0,0,, 导航控制器中的 segue 类型都是 push\\N{\\fs12}Okay. Inside of navigation controller it’s always push.\r\nDialogue: 0,1:03:24.23,1:03:26.00,yin,,0,0,0,, 这里出现了一个 segue\\N{\\fs12}Okay. There’s a segue right here.\r\nDialogue: 0,1:03:26.06,1:03:29.17,yin,,0,0,0,, 如果我们点击这个 segue 转到属性检查器 \\N{\\fs12}If we click on this segue and go to the attributes inspector\r\nDialogue: 0,1:03:29.34,1:03:30.79,yin,,0,0,0,, 可以看到它是一个 push 类型 segue\\N{\\fs12}and see that it’s a push segue,\r\nDialogue: 0,1:03:31.01,1:03:34.06,yin,,0,0,0,, 我们要叫它 Show Stats 显示统计数据 \\N{\\fs12}and we’re going to call this show stats\r\nDialogue: 0,1:03:34.14,1:03:37.76,yin,,0,0,0,, 或者换个更好的 Analyze Text 分析文本 \\N{\\fs12}or even maybe better, Analyze Text.\r\nDialogue: 0,1:03:38.44,1:03:39.98,yin,,0,0,0,, 标识符最好选择一个 \\N{\\fs12}Okay. So, we want to have something in there\r\nDialogue: 0,1:03:39.98,1:03:41.94,yin,,0,0,0,, 能够清楚说明 segue 作用的名称 \\N{\\fs12}that makes it clear what this segue does.\r\nDialogue: 0,1:03:42.03,1:03:43.80,yin,,0,0,0,, 在这里 它的作用是分析文本 \\N{\\fs12}It analyzes the text in this case.\r\nDialogue: 0,1:03:44.39,1:03:45.94,yin,,0,0,0,, 我们要做的最后一件事是 \\N{\\fs12}Okay. Now the last thing we need to do\r\nDialogue: 0,1:03:45.94,1:03:48.55,yin,,0,0,0,, 为这个 MVC 出现在屏幕上做准备 \\N{\\fs12}is prepare this MVC to come onscreen,\r\nDialogue: 0,1:03:48.59,1:03:52.36,yin,,0,0,0,, 也就是将模型设置为这个文本视图中的文本 \\N{\\fs12}basically, by setting its model to be the text that’s in this text view.\r\nDialogue: 0,1:03:52.60,1:03:54.73,yin,,0,0,0,, 要在这里实现 \\N{\\fs12}Right. So we do that in here.\r\nDialogue: 0,1:03:54.98,1:03:57.88,yin,,0,0,0,, 让右边 MVC 出现在屏幕上的准备工作是由它完成的 \\N{\\fs12}The preparation for this to come onscreen is done by this guy,\r\nDialogue: 0,1:03:57.88,1:04:02.41,yin,,0,0,0,, 因为 segue 是由它发出的 \\N{\\fs12}because this guy’s the guy causing the segue.\r\nDialogue: 0,1:04:02.74,1:04:03.65,yin,,0,0,0,, 我们转到这里 \\N{\\fs12}So let’s go here.\r\nDialogue: 0,1:04:03.65,1:04:05.20,yin,,0,0,0,, 我们是在自动模式下 \\N{\\fs12}As we do this we’re on automatic,\r\nDialogue: 0,1:04:05.20,1:04:07.57,yin,,0,0,0,, 所以我们可以看到它的代码 在这里 \\N{\\fs12}so we’re going to see this guy’s code. Here it is.\r\nDialogue: 0,1:04:07.84,1:04:10.06,yin,,0,0,0,, 希望大家还记得上次的代码 \\N{\\fs12}Okay. Hopefully, you remember this code from last time,\r\nDialogue: 0,1:04:10.55,1:04:12.71,yin,,0,0,0,, 我们来添加 prepareForSegue 方法 \\N{\\fs12}and let’s go ahead and put the prepareForSegue.\r\nDialogue: 0,1:04:12.72,1:04:15.18,yin,,0,0,0,, 放在上面 这样我更顺手 \\N{\\fs12}We’ll put it at the top because it works nicer for me.\r\nDialogue: 0,1:04:15.75,1:04:16.93,yin,,0,0,0,,prepareForSegue\\N{\\fs12}prepareForSegue.\r\nDialogue: 0,1:04:18.45,1:04:21.04,yin,,0,0,0,, 在这个 prepareForSegue 方法中 \\N{\\fs12}All right. And all we have to do inside this prepareForSegue\r\nDialogue: 0,1:04:21.12,1:04:23.32,yin,,0,0,0,, 我们只要为这个 segue 做准备 \\N{\\fs12}is prepare for this particular segue.\r\nDialogue: 0,1:04:23.32,1:04:24.52,yin,,0,0,0,, 我们只有这一个 segue\\N{\\fs12}It’s the only segue we have,\r\nDialogue: 0,1:04:24.93,1:04:27.17,yin,,0,0,0,, 把代码区拉大一点 \\N{\\fs12}so I’m going to make more space here,\r\nDialogue: 0,1:04:28.43,1:04:32.74,yin,,0,0,0,, 往这边滚动一下 这样在我们编写代码的时候 \\N{\\fs12}actually let’s scroll over so you can see the segue in your mind,\r\nDialogue: 0,1:04:32.76,1:04:33.84,yin,,0,0,0,, 大家能看到这个 segue\\N{\\fs12}while we’re working on this.\r\nDialogue: 0,1:04:34.96,1:04:37.60,yin,,0,0,0,, 再选中它 好了 \\N{\\fs12}Just click this back again. There we go.\r\nDialogue: 0,1:04:38.09,1:04:40.15,yin,,0,0,0,, 那么在 prepareForSegue 中我们做什么呢 \\N{\\fs12}Okay. So in prepareForSegue what do we do?\r\nDialogue: 0,1:04:40.15,1:04:41.82,yin,,0,0,0,, 就像我刚才说过的 我们要做的第一件事 \\N{\\fs12}Well, like I said, the first thing we’re going to do\r\nDialogue: 0,1:04:41.98,1:04:48.46,yin,,0,0,0,, 就是确保目标 segue 就是这个特定的 segue\\N{\\fs12}is we’re going to make sure we’re talking about this particular segue,\r\nDialogue: 0,1:04:48.48,1:04:53.94,yin,,0,0,0,, 也就是 Analyze Text\\N{\\fs12}which is the Analyze Text one.\r\nDialogue: 0,1:04:53.96,1:04:56.49,yin,,0,0,0,, 当然 如果你在这里输错了 \\N{\\fs12}Now, of course, if you mistype this here,\r\nDialogue: 0,1:04:56.92,1:04:59.12,yin,,0,0,0,, 不会得到任何警告之类的 \\N{\\fs12}you’re not going to get any warning or anything like that,\r\nDialogue: 0,1:04:59.13,1:05:01.66,yin,,0,0,0,, 如果这里输错了 它只是不会正常运行 \\N{\\fs12}or if you mistype it over there, and it’s just not going to work,\r\nDialogue: 0,1:05:01.85,1:05:04.46,yin,,0,0,0,, 因为不能正确准备那个 MVC\\N{\\fs12}because it’s not going to prepare that MVC properly,\r\nDialogue: 0,1:05:04.47,1:05:07.91,yin,,0,0,0,, 我觉得系统功能在这里有点缺陷 \\N{\\fs12}so it’s a little bit of a weakness I think of the way this system works,\r\nDialogue: 0,1:05:07.91,1:05:09.85,yin,,0,0,0,, 只要增加一个调试操作 \\N{\\fs12}but it’s just a debugging thing\r\nDialogue: 0,1:05:09.85,1:05:12.96,yin,,0,0,0,, 就能检查这里的文本是否与 segue 标识符一致 \\N{\\fs12}to make sure your text here matches the text there.\r\nDialogue: 0,1:05:14.12,1:05:18.09,yin,,0,0,0,, 我知道 当我在这里进行 segue 跳转时 \\N{\\fs12}All right. So I know that when I’m segueing here,\r\nDialogue: 0,1:05:18.17,1:05:22.59,yin,,0,0,0,, 需要用到这个 TextStatsViewController\\N{\\fs12}I need to use this TextStatsViewController.\r\nDialogue: 0,1:05:23.44,1:05:30.14,yin,,0,0,0,, 我可以在这里导入目标 MVC 的类 \\N{\\fs12}Okay. So it’s okay for me to import that MVC’s class in here,\r\nDialogue: 0,1:05:30.15,1:05:32.91,yin,,0,0,0,, 因为它基本算是我的视图的一部分 \\N{\\fs12}because it’s part of my view almost,\r\nDialogue: 0,1:05:33.02,1:05:34.18,yin,,0,0,0,, 所以你可以认为 \\N{\\fs12}so you can kind of think of it –\r\nDialogue: 0,1:05:34.18,1:05:36.19,yin,,0,0,0,, 统计 MVC 是另一个 MVC 视图的一部分 \\N{\\fs12}the stats as being part of the view of this other one,\r\nDialogue: 0,1:05:36.22,1:05:38.52,yin,,0,0,0,, 是下一级 \\N{\\fs12}because it’s sub — you know, a sub thing,\r\nDialogue: 0,1:05:38.54,1:05:40.05,yin,,0,0,0,, 所以可以这样做 \\N{\\fs12}so it’s okay to do that,\r\nDialogue: 0,1:05:40.06,1:05:43.52,yin,,0,0,0,, 但是我最好再确认一下我们要 segue 去的 \\N{\\fs12}but I better make sure that the destination view controller\r\nDialogue: 0,1:05:43.71,1:05:49.49,yin,,0,0,0,, 目标视图控制器属于 TextStatsViewController 类 \\N{\\fs12}that we’re gonna be segueing to is kind of TextStatsViewController.\r\nDialogue: 0,1:05:50.67,1:05:54.01,yin,,0,0,0,, 如果是的话 我就在这里创建一个局部变量 \\N{\\fs12}Okay. But if it is, then I’ll create a little local variable here,\r\nDialogue: 0,1:05:54.01,1:05:57.61,yin,,0,0,0,,tsvc=(TextStatsViewController *)\\N{\\fs12}text stats view controller equals TextStatsViewController.\r\nDialogue: 0,1:05:57.63,1:05:59.45,yin,,0,0,0,, 这个操作 \\N{\\fs12}This is actually not necessary,\r\nDialogue: 0,1:05:59.71,1:06:01.07,yin,,0,0,0,, 并不是强制要求 \\N{\\fs12}this one I’m doing right here,\r\nDialogue: 0,1:06:01.34,1:06:02.93,yin,,0,0,0,, 但是我个人喜欢这样做 \\N{\\fs12}but I personally like to do it,\r\nDialogue: 0,1:06:04.48,1:06:08.27,yin,,0,0,0,, 因为我喜欢创建一个局部变量 \\N{\\fs12}just because I like to have, you know, a local variable\r\nDialogue: 0,1:06:08.28,1:06:12.33,yin,,0,0,0,, 这样能够直接用 tsvc.textToAnalyze=\\N{\\fs12}that I can do things like tsvc dot textToAnalyze equals.\r\nDialogue: 0,1:06:12.81,1:06:14.48,yin,,0,0,0,, 现在我是在为它做准备 \\N{\\fs12}Okay. So here I’m preparing it.\r\nDialogue: 0,1:06:15.04,1:06:16.31,yin,,0,0,0,, 它需要什么呢 \\N{\\fs12}Okay. What does it need?\r\nDialogue: 0,1:06:16.31,1:06:18.98,yin,,0,0,0,, 需要我的正文文本 \\N{\\fs12}It needs my body text.\r\nDialogue: 0,1:06:20.86,1:06:22.34,yin,,0,0,0,, 还记得上次讲过的内容吗 \\N{\\fs12}Okay. Remember from last time?\r\nDialogue: 0,1:06:22.54,1:06:25.01,yin,,0,0,0,, 这个文本视图是 self.body\\N{\\fs12}This text view right here is self dot body,\r\nDialogue: 0,1:06:25.17,1:06:28.12,yin,,0,0,0,,textStorage 是一个 NSMutableAttributedString\\N{\\fs12}and the textStorage is the NSMutableAttributedString.\r\nDialogue: 0,1:06:28.23,1:06:30.09,yin,,0,0,0,, 这是一个 NSAttributedString\\N{\\fs12}This is an NSAttributedString,\r\nDialogue: 0,1:06:30.09,1:06:31.62,yin,,0,0,0,, 但是可以这样赋值 \\N{\\fs12}but it’s okay to assign that,\r\nDialogue: 0,1:06:31.62,1:06:35.05,yin,,0,0,0,, 因为可变字符串也属于属性化字符串 \\N{\\fs12}because a mutable string is a regular attributed string,\r\nDialogue: 0,1:06:35.42,1:06:36.73,yin,,0,0,0,, 所以这样是完全没问题的 \\N{\\fs12}so this is perfectly legal,\r\nDialogue: 0,1:06:37.06,1:06:38.00,yin,,0,0,0,, 就是这样了 \\N{\\fs12}and so that’s it.\r\nDialogue: 0,1:06:38.23,1:06:40.05,yin,,0,0,0,, 我们需要做的就是这些 \\N{\\fs12}That’s all that’s necessary for us to do.\r\nDialogue: 0,1:06:40.05,1:06:41.01,yin,,0,0,0,, 现在再运行一下 \\N{\\fs12}And now if we run,\r\nDialogue: 0,1:06:42.16,1:06:43.01,yin,,0,0,0,, 大家会看到 \\N{\\fs12}you will see\r\nDialogue: 0,1:06:46.37,1:06:50.61,yin,,0,0,0,, 首先 我们出现在一个导航控制器中 \\N{\\fs12}that first of all, we come up inside of a navigation controller.\r\nDialogue: 0,1:06:50.62,1:06:52.79,yin,,0,0,0,, 之前的页面还在这里 \\N{\\fs12}Okay. We still have our thing here.\r\nDialogue: 0,1:06:52.81,1:06:54.15,yin,,0,0,0,, 依旧可以选择文本 \\N{\\fs12}We can still select text.\r\nDialogue: 0,1:06:54.78,1:06:57.60,yin,,0,0,0,, 如果打开统计页面 显示的是 0 个彩色字符 \\N{\\fs12}If we bring up the stats, there’s zero colorful characters.\r\nDialogue: 0,1:06:57.60,1:06:58.90,yin,,0,0,0,, 我还没有设置颜色 \\N{\\fs12}I didn’t color anything.\r\nDialogue: 0,1:06:58.93,1:07:02.91,yin,,0,0,0,, 点击返回之后 系统释放了那个文本分析 MVC\\N{\\fs12}When I hit back, it just dealloc that text analyze.\r\nDialogue: 0,1:07:03.11,1:07:04.75,yin,,0,0,0,, 我们重新设置一下 \\N{\\fs12}Let’s go ahead and make a new one here.\r\nDialogue: 0,1:07:04.75,1:07:09.42,yin,,0,0,0,, 变为橙色 加上轮廓 加点紫色 \\N{\\fs12}Orange and maybe some outline, and maybe some purple,\r\nDialogue: 0,1:07:09.55,1:07:12.63,yin,,0,0,0,, 再看统计结果 14 个彩色字符 7 个带有轮廓字符 \\N{\\fs12}and now stats — 14 colorful, seven outlined,\r\nDialogue: 0,1:07:12.63,1:07:13.80,yin,,0,0,0,, 非常好用 \\N{\\fs12}okay, working like a charm.\r\nDialogue: 0,1:07:14.04,1:07:16.54,yin,,0,0,0,, 我们也许可以为一串字符添加轮廓 \\N{\\fs12}Maybe we’ll make a whole bunch of outlined here.\r\nDialogue: 0,1:07:16.82,1:07:18.88,yin,,0,0,0,, 再看统计结果 250 个 \\N{\\fs12}Okay. Stats — 250.\r\nDialogue: 0,1:07:19.17,1:07:20.74,yin,,0,0,0,, 就是这样 \\N{\\fs12}Okay. So that’s it.\r\nDialogue: 0,1:07:21.56,1:07:22.32,yin,,0,0,0,, 都明白了吗 \\N{\\fs12}Everyone got that?\r\nDialogue: 0,1:07:22.32,1:07:25.16,yin,,0,0,0,, 你们要在作业中完成这部分 \\N{\\fs12}So you will be doing this on your homework.\r\nDialogue: 0,1:07:25.17,1:07:26.61,yin,,0,0,0,, 实际上 你们需要将它们 \\N{\\fs12}In fact, you’ll be taking this\r\nDialogue: 0,1:07:26.69,1:07:29.98,yin,,0,0,0,, 放入一个选项卡栏控制器中 \\N{\\fs12}and putting it inside of a tab bar controller,\r\nDialogue: 0,1:07:29.98,1:07:31.18,yin,,0,0,0,, 所以你们要实现两项内容 \\N{\\fs12}so you’ll be doing double duty.\r\nDialogue: 0,1:07:31.18,1:07:31.98,yin,,0,0,0,, 剩下五分钟 \\N{\\fs12}So let’s talk about tab bar controller\r\nDialogue: 0,1:07:31.98,1:07:34.25,yin,,0,0,0,, 我们来讲一下选项卡栏控制器 \\N{\\fs12}in the last five minutes that we have here.\r\nDialogue: 0,1:07:37.59,1:07:40.13,yin,,0,0,0,, 在此之前还有什么问题吗 \\N{\\fs12}Any questions about that before I go on to tab bar controller?\r\nDialogue: 0,1:07:41.48,1:07:43.94,yin,,0,0,0,, 看了演示就能明白了吧 \\N{\\fs12}It all makes sense once you see it. Right?\r\nDialogue: 0,1:07:44.46,1:07:46.66,yin,,0,0,0,, 有许多组成部分 但是能够组合在一起 \\N{\\fs12}There’s a number of components to it, but they kind of fit together.\r\nDialogue: 0,1:07:47.65,1:07:49.30,yin,,0,0,0,, 好的 接着讲选项卡栏控制器 \\N{\\fs12}All right. Tab bar controller.\r\nDialogue: 0,1:07:50.05,1:07:54.40,yin,,0,0,0,, 这是我最喜欢的选项卡栏控制器应用示例 \\N{\\fs12}Here is my favorite tab bar controller application example,\r\nDialogue: 0,1:07:54.40,1:07:56.41,yin,,0,0,0,,iOS7 的时钟应用 \\N{\\fs12}which is the clock app on iOS seven.\r\nDialogue: 0,1:07:56.41,1:07:59.43,yin,,0,0,0,, 可以看到底部有一个选项卡栏 上面有四个选项卡 \\N{\\fs12}You can see it has a tab bar across the bottom there and four tabs.\r\nDialogue: 0,1:07:59.44,1:08:02.22,yin,,0,0,0,, 相互之间完全独立 \\N{\\fs12}Each of these four tabs is completely independent of the other\r\nDialogue: 0,1:08:02.44,1:08:05.94,yin,,0,0,0,, 选项卡栏中的 MVC 就应该是这样 \\N{\\fs12}and that’s the way MVCs inside a tab bar controller should be,\r\nDialogue: 0,1:08:06.12,1:08:07.64,yin,,0,0,0,, 相互完全独立 \\N{\\fs12}completely independent of each other.\r\nDialogue: 0,1:08:07.74,1:08:10.55,yin,,0,0,0,, 如果 MVC 间是相关的 你也许就需要用导航控制器了 \\N{\\fs12}If they’re dependent, you probably want a navigation controller.\r\nDialogue: 0,1:08:10.95,1:08:12.12,yin,,0,0,0,, 或者如果是在 iPad 上 \\N{\\fs12}Okay. Or if they’re in an iPad,\r\nDialogue: 0,1:08:12.13,1:08:14.17,yin,,0,0,0,, 也许可以用弹出窗口之类的 \\N{\\fs12}you might want to a popover, or something like that,\r\nDialogue: 0,1:08:14.17,1:08:19.02,yin,,0,0,0,, 但是 iPhone 应用中需要的是导航控制器 \\N{\\fs12}but on an iPhone you probably want a navigation controller\r\nDialogue: 0,1:08:19.03,1:08:20.17,yin,,0,0,0,, 如果 MVC 间有依赖关系的话 \\N{\\fs12}if you have a dependency.\r\nDialogue: 0,1:08:21.05,1:08:23.32,yin,,0,0,0,, 选项卡栏控制器是怎样工作的呢 \\N{\\fs12}All right. So how does tab bar controller work?\r\nDialogue: 0,1:08:23.65,1:08:25.13,yin,,0,0,0,, 它是非常简单的控制器 \\N{\\fs12}Very, very simply controller,\r\nDialogue: 0,1:08:25.13,1:08:27.82,yin,,0,0,0,, 有一个属性叫做 viewControllers\\N{\\fs12}it has a property called viewControllers,\r\nDialogue: 0,1:08:28.11,1:08:32.29,yin,,0,0,0,, 是一个 MVC 的数组 UIViewController 的数组 \\N{\\fs12}which is an array of MVCs — UIViewControllers,\r\nDialogue: 0,1:08:32.30,1:08:34.11,yin,,0,0,0,,MVC 的控制器组成的数组 \\N{\\fs12}basically, the controllers of the MVCs.\r\nDialogue: 0,1:08:34.31,1:08:36.09,yin,,0,0,0,, 数组中有多少个控制器 \\N{\\fs12}And how ever many you have,\r\nDialogue: 0,1:08:36.25,1:08:38.85,yin,,0,0,0,, 底部就有多少个小选项卡 \\N{\\fs12}that’s how many little tabs you’ll have on the bottom.\r\nDialogue: 0,1:08:39.35,1:08:43.52,yin,,0,0,0,, 而在 storyboard 中创建连接的方法 \\N{\\fs12}Okay. And this — to create these connections in your storyboard –\r\nDialogue: 0,1:08:43.52,1:08:45.03,yin,,0,0,0,, 同样是按住 control 键进行拖拽 \\N{\\fs12}surprise, control drag.\r\nDialogue: 0,1:08:45.64,1:08:48.72,yin,,0,0,0,, 你只要拖出一个 UITabBarController\\N{\\fs12}Okay. So you just drag a UITabBarController out\r\nDialogue: 0,1:08:48.85,1:08:51.30,yin,,0,0,0,, 然后按住 control 键拖动到 \\N{\\fs12}and then just control drag to all the controllers\r\nDialogue: 0,1:08:51.30,1:08:52.81,yin,,0,0,0,, 各选项卡对应的控制器上 \\N{\\fs12}that you want to be the various tabs.\r\nDialogue: 0,1:08:53.09,1:08:57.29,yin,,0,0,0,,Timer 和小图标是如何出现在上面的呢 \\N{\\fs12}Now, how does the word timer and the little icon there appear.\r\nDialogue: 0,1:08:57.44,1:09:01.37,yin,,0,0,0,,Timer 是 UIViewController 的标题 \\N{\\fs12}Well, the timer is going to be the UIViewController’s title,\r\nDialogue: 0,1:09:01.38,1:09:04.95,yin,,0,0,0,, 和分屏视图控制器顶部显示的一样 \\N{\\fs12}the same thing that will appear in the top of a split view controller,\r\nDialogue: 0,1:09:05.11,1:09:07.52,yin,,0,0,0,, 而图标呢 \\N{\\fs12}and the icon,\r\nDialogue: 0,1:09:07.52,1:09:12.01,yin,,0,0,0,,UIViewController 有一个属性叫做 tabBarItem\\N{\\fs12}there’s actually a UIViewController property called tabBarItem,\r\nDialogue: 0,1:09:12.11,1:09:14.14,yin,,0,0,0,, 里面有图标 \\N{\\fs12}and inside there is the icon\r\nDialogue: 0,1:09:14.14,1:09:15.78,yin,,0,0,0,, 还有其他元素 比如小气泡 \\N{\\fs12}and a few other things like the badge,\r\nDialogue: 0,1:09:15.87,1:09:18.67,yin,,0,0,0,, 就是一个小圆圈 里面有数字或字母 \\N{\\fs12}which is a little round circle with a number or a letter in it,\r\nDialogue: 0,1:09:18.69,1:09:20.44,yin,,0,0,0,, 可以显示在上面 \\N{\\fs12}which you can put on there.\r\nDialogue: 0,1:09:20.58,1:09:22.48,yin,,0,0,0,, 这就是设置这些元素的方法 \\N{\\fs12}So that’s how these things get set,\r\nDialogue: 0,1:09:22.58,1:09:24.11,yin,,0,0,0,, 但是在这里我就不演示了 \\N{\\fs12}but I’m not even showing you that here,\r\nDialogue: 0,1:09:24.11,1:09:25.71,yin,,0,0,0,, 因为通常是在 storyboard 中进行设置 \\N{\\fs12}because usually you set them in the storyboard.\r\nDialogue: 0,1:09:26.11,1:09:28.82,yin,,0,0,0,, 在 storyboard 中设置图标和文字 \\N{\\fs12}Okay. You set this icon and this text in the storyboard.\r\nDialogue: 0,1:09:29.04,1:09:31.19,yin,,0,0,0,, 最好在那里设置 \\N{\\fs12}That’s the best place to set these things.\r\nDialogue: 0,1:09:31.38,1:09:33.52,yin,,0,0,0,, 如果你有四个以上控制器呢 \\N{\\fs12}Now, what if you have more than four controllers\r\nDialogue: 0,1:09:33.53,1:09:34.86,yin,,0,0,0,, 五个以上呢 \\N{\\fs12}or more than five, actually?\r\nDialogue: 0,1:09:35.58,1:09:36.67,yin,,0,0,0,, 会发生什么 \\N{\\fs12}Then what happens?\r\nDialogue: 0,1:09:36.81,1:09:40.15,yin,,0,0,0,, 会出现一个 More 更多的选项卡 \\N{\\fs12}Then a little more tab is going to appear.\r\nDialogue: 0,1:09:40.56,1:09:41.76,yin,,0,0,0,, 在右下角 看到了吗 \\N{\\fs12}See it down there in the corner,\r\nDialogue: 0,1:09:41.81,1:09:42.74,yin,,0,0,0,, 点击它之后 \\N{\\fs12}and when you click that\r\nDialogue: 0,1:09:42.74,1:09:46.24,yin,,0,0,0,, 会出现一个界面显示全部控制器 \\N{\\fs12}there’s going to be this UI that’s presented that allows you to –\r\nDialogue: 0,1:09:46.28,1:09:48.71,yin,,0,0,0,, 用户可以从中选择四个显示在底部 \\N{\\fs12}the user to pick which four they want down there.\r\nDialogue: 0,1:09:49.05,1:09:50.21,yin,,0,0,0,, 可以来回交换 \\N{\\fs12}Swap them back and forth,\r\nDialogue: 0,1:09:50.47,1:09:51.53,yin,,0,0,0,, 挺好用的 \\N{\\fs12}okay, which is kind of cool.\r\nDialogue: 0,1:09:51.60,1:09:53.89,yin,,0,0,0,, 这都是自动完成的 \\N{\\fs12}And that happens automatically.\r\nDialogue: 0,1:09:53.89,1:09:55.52,yin,,0,0,0,, 将更多按钮放在那里 系统会自动执行 \\N{\\fs12}You put that more button on there, it just does it.\r\nDialogue: 0,1:09:55.52,1:09:56.34,yin,,0,0,0,, 替你完成相关操作 \\N{\\fs12}It does it for you.\r\nDialogue: 0,1:09:56.69,1:09:57.29,yin,,0,0,0,, 非常好用 \\N{\\fs12}So that’s really cool.\r\nDialogue: 0,1:09:57.95,1:10:02.49,yin,,0,0,0,, 我其实不推荐 UI 上的选项卡多于五个 \\N{\\fs12}Okay. So I actually don’t recommend UIs that have more than five tabs.\r\nDialogue: 0,1:10:02.73,1:10:05.45,yin,,0,0,0,, 我认为这样对用户来说很麻烦 \\N{\\fs12}I think this is a little cumbersome for users,\r\nDialogue: 0,1:10:05.56,1:10:07.64,yin,,0,0,0,, 但有些地方需要这样做 \\N{\\fs12}but there are some places it would make sense.\r\nDialogue: 0,1:10:08.07,1:10:10.21,yin,,0,0,0,, 这个应用就还不错 比较合理 \\N{\\fs12}In this app, it’s not bad. It kind of makes sense.\r\nDialogue: 0,1:10:10.21,1:10:13.91,yin,,0,0,0,, 这是 iPod 应用之类的 音乐应用 \\N{\\fs12}This is the iPod app, or whatever, your music app.\r\nDialogue: 0,1:10:14.13,1:10:15.91,yin,,0,0,0,, 所以这样做是有道理的 \\N{\\fs12}So it kind of makes some sense here.\r\nDialogue: 0,1:10:16.61,1:10:19.89,yin,,0,0,0,, 不管怎样 如果你确实需要五个以上 那就是这样用的 \\N{\\fs12}But anyway, if you do need to do that, that’s how it works.\r\nDialogue: 0,1:10:20.03,1:10:22.43,yin,,0,0,0,, 最后几分钟 \\N{\\fs12}So let’s, in the last couple of minutes here,\r\nDialogue: 0,1:10:22.45,1:10:26.84,yin,,0,0,0,, 我们看看在 Xcode 中如何创建选项卡栏控制器 \\N{\\fs12}look in Xcode and see what it looks like to make a tab bar controller.\r\nDialogue: 0,1:10:26.85,1:10:29.55,yin,,0,0,0,, 和几张幻灯片之前展示的一样 \\N{\\fs12}So this is the same thing I was just showing a few slides earlier.\r\nDialogue: 0,1:10:29.55,1:10:33.19,yin,,0,0,0,, 可以看到导航控制器中那个中间有按钮的 MVC\\N{\\fs12}You see the navigation controller with the MVC that has the button\r\nDialogue: 0,1:10:33.27,1:10:36.13,yin,,0,0,0,, 然后从它 segue 到下一个 MVC\\N{\\fs12}and then it just — you know, it segues to the next one,\r\nDialogue: 0,1:10:36.25,1:10:39.43,yin,,0,0,0,, 我要把它放在一个选项卡栏控制器中 \\N{\\fs12}so I’m actually going to put this in a tab bar controller,\r\nDialogue: 0,1:10:39.43,1:10:40.75,yin,,0,0,0,, 所以它会是一个选项卡 \\N{\\fs12}so it’s going to be one of the tabs,\r\nDialogue: 0,1:10:40.88,1:10:43.08,yin,,0,0,0,, 然后让另一个空白视图作为另一个选项卡 \\N{\\fs12}and then I’m just going to have like a blank view be the other one.\r\nDialogue: 0,1:10:43.12,1:10:45.27,yin,,0,0,0,, 看见右下的选项卡栏控制器了吗 \\N{\\fs12}Okay. So, see the tab bar controller there?\r\nDialogue: 0,1:10:45.28,1:10:46.65,yin,,0,0,0,, 将它拖出 \\N{\\fs12}I’m dragging it out.\r\nDialogue: 0,1:10:46.84,1:10:47.82,yin,,0,0,0,, 拖出它时 \\N{\\fs12}When you drag it out,\r\nDialogue: 0,1:10:47.82,1:10:51.11,yin,,0,0,0,, 它会自带两个空白场景 \\N{\\fs12}it’s going to come along with two blank ones, okay,\r\nDialogue: 0,1:10:51.72,1:10:53.22,yin,,0,0,0,, 两个空白无物的 \\N{\\fs12}two empty blank ones,\r\nDialogue: 0,1:10:53.35,1:10:55.99,yin,,0,0,0,, 大部分情况下 你并不需要 \\N{\\fs12}which very much of the time you don’t want.\r\nDialogue: 0,1:10:56.33,1:10:58.41,yin,,0,0,0,, 这里我会留下一个 删掉另一个 \\N{\\fs12}In this case, I’m going to keep one of them, get rid of the other one,\r\nDialogue: 0,1:10:58.41,1:10:59.63,yin,,0,0,0,, 只是为了给大家示范如何实现 \\N{\\fs12}just to show you how that’s done.\r\nDialogue: 0,1:10:59.63,1:11:03.39,yin,,0,0,0,, 当你放下它时 可能会遮挡其他 MVC\\N{\\fs12}So when you drop it, it might overlap other ones.\r\nDialogue: 0,1:11:03.45,1:11:04.61,yin,,0,0,0,, 当然 在 storyboard 中 \\N{\\fs12}Obviously, in the storyboard,\r\nDialogue: 0,1:11:04.61,1:11:07.43,yin,,0,0,0,, 为了显示效果 你可以随意移动 MVC\\N{\\fs12}you can drag these MVCs anyway you want to make them look nice.\r\nDialogue: 0,1:11:07.44,1:11:10.27,yin,,0,0,0,, 如果它们之间有 segue 等连线 \\N{\\fs12}If they happen to be connected by a segue or something,\r\nDialogue: 0,1:11:10.32,1:11:12.94,yin,,0,0,0,, 在移动时 系统会自动重绘连接线 \\N{\\fs12}it’ll automatically redraw that line for you as you move it.\r\nDialogue: 0,1:11:12.99,1:11:14.68,yin,,0,0,0,, 这是很好的 \\N{\\fs12}It’s really quite nice in that way.\r\nDialogue: 0,1:11:15.05,1:11:17.73,yin,,0,0,0,, 可以想象 storyboard 可以变得非常庞大 \\N{\\fs12}You can imagine that these storyboards get very large.\r\nDialogue: 0,1:11:17.73,1:11:20.12,yin,,0,0,0,, 比如有 100 个 storyboard 怎么操作呢 \\N{\\fs12}With 100 storyboards in there how does it even work.\r\nDialogue: 0,1:11:20.15,1:11:24.17,yin,,0,0,0,, 如果你看右下角 \\N{\\fs12}Well, if you look down in the lower right corner there,\r\nDialogue: 0,1:11:24.21,1:11:25.67,yin,,0,0,0,, 可以看到一个放大镜 \\N{\\fs12}you’ll see there’s a magnifying glass,\r\nDialogue: 0,1:11:25.67,1:11:26.87,yin,,0,0,0,, 可以用它放大或缩小 \\N{\\fs12}you can zoom in and out.\r\nDialogue: 0,1:11:27.12,1:11:28.15,yin,,0,0,0,, 可以大幅度缩小 \\N{\\fs12}Okay. Zoom way out.\r\nDialogue: 0,1:11:28.15,1:11:30.37,yin,,0,0,0,, 如果你有 100 个 MVC 可以缩小到一屏上 \\N{\\fs12}If you have 100, you can see all 100 at the same time.\r\nDialogue: 0,1:11:30.37,1:11:33.86,yin,,0,0,0,, 放大到显示某个视图控制器 \\N{\\fs12}Zoom in all the way to zooming in all the way in on one view controller\r\nDialogue: 0,1:11:33.87,1:11:35.10,yin,,0,0,0,, 然后你就可以编辑那个视图控制器 \\N{\\fs12}and then you can edit that view controller.\r\nDialogue: 0,1:11:35.10,1:11:36.70,yin,,0,0,0,, 只有将某个视图控制器放大 \\N{\\fs12}You can’t edit a view controller itself\r\nDialogue: 0,1:11:36.70,1:11:38.49,yin,,0,0,0,, 你才能对它进行编辑 \\N{\\fs12}unless you’ve zoomed in all the way. Okay.\r\nDialogue: 0,1:11:39.49,1:11:41.02,yin,,0,0,0,, 现在我有两个空白场景 \\N{\\fs12}So here I’ve got two blank ones.\r\nDialogue: 0,1:11:41.02,1:11:41.94,yin,,0,0,0,, 我并不是都想要 \\N{\\fs12}I don’t want them both,\r\nDialogue: 0,1:11:42.10,1:11:45.01,yin,,0,0,0,, 所以我只要选中其中一个 \\N{\\fs12}so I’m just going to select one of them,\r\nDialogue: 0,1:11:45.03,1:11:45.86,yin,,0,0,0,, 变为蓝色 \\N{\\fs12}make it blue,\r\nDialogue: 0,1:11:46.20,1:11:47.25,yin,,0,0,0,, 和之前讲过的一样 \\N{\\fs12}as we talked about before,\r\nDialogue: 0,1:11:47.31,1:11:48.80,yin,,0,0,0,, 点击删除 它就消失了 \\N{\\fs12}and hit delete, and it’s gone.\r\nDialogue: 0,1:11:48.80,1:11:50.60,yin,,0,0,0,, 剩下另外一个 \\N{\\fs12}So I’ve still got the other one. Okay.\r\nDialogue: 0,1:11:50.89,1:11:53.74,yin,,0,0,0,, 现在我要用 control 拖拽 \\N{\\fs12}And now I’m gonna hook that navigation controller in there\r\nDialogue: 0,1:11:53.74,1:11:55.79,yin,,0,0,0,, 将导航控制器连接起来 \\N{\\fs12}by control dragging.\r\nDialogue: 0,1:11:55.82,1:11:57.86,yin,,0,0,0,, 按住 control 键从选项卡栏控制器 \\N{\\fs12}So I’m control dragging from the tab bar controller\r\nDialogue: 0,1:11:57.86,1:11:58.77,yin,,0,0,0,, 拖动到导航控制器 \\N{\\fs12}to the navigation controller,\r\nDialogue: 0,1:11:59.14,1:12:01.92,yin,,0,0,0,, 进行 control 拖拽时 \\N{\\fs12}and when you do this control drag,\r\nDialogue: 0,1:12:01.92,1:12:03.98,yin,,0,0,0,, 会弹出这个 segue 列表 \\N{\\fs12}it’s going to put up this little segue thing,\r\nDialogue: 0,1:12:04.08,1:12:05.69,yin,,0,0,0,, 如果是一个选项卡栏控制器 \\N{\\fs12}but when it’s a tab bar controller,\r\nDialogue: 0,1:12:05.71,1:12:07.72,yin,,0,0,0,, 那这里就只能选择视图控制器 \\N{\\fs12}it only makes sense for this to be view controller.\r\nDialogue: 0,1:12:07.72,1:12:10.21,yin,,0,0,0,,Xcode 不能自动选择好 我真的很惊讶 \\N{\\fs12}And I’m really surprised the Xcode just doesn’t automatically do this.\r\nDialogue: 0,1:12:10.21,1:12:12.34,yin,,0,0,0,, 我也不知道为什么 \\N{\\fs12}I’m not sure exactly why, because you –\r\nDialogue: 0,1:12:12.45,1:12:13.96,yin,,0,0,0,, 这里选择 push 类型完全说不通 \\N{\\fs12}it would make no sense to pick push here,\r\nDialogue: 0,1:12:13.96,1:12:15.66,yin,,0,0,0,, 那为什么还要给出这个选项 我不知道 \\N{\\fs12}so why even offer that. I don’t know.\r\nDialogue: 0,1:12:16.22,1:12:17.55,yin,,0,0,0,, 总之选项卡栏控制器的 segue\\N{\\fs12}Anyway, you always want to one on the bottom\r\nDialogue: 0,1:12:17.55,1:12:18.62,yin,,0,0,0,, 要选择最下面的视图控制器 \\N{\\fs12}when it’s a tab bar controller,\r\nDialogue: 0,1:12:18.62,1:12:21.56,yin,,0,0,0,, 表示将它连接到视图控制器列表中 \\N{\\fs12}which means wire this up to the list of view controllers.\r\nDialogue: 0,1:12:22.00,1:12:25.78,yin,,0,0,0,, 这样做之后就会得到这样一条线 \\N{\\fs12}Okay. You do that and now it’s going to have this line drawn over there.\r\nDialogue: 0,1:12:25.79,1:12:28.26,yin,,0,0,0,, 这些小圆圈不是 segue\\N{\\fs12}Again, these little round circles are not segues,\r\nDialogue: 0,1:12:28.33,1:12:31.33,yin,,0,0,0,, 视图控制器中 \\N{\\fs12}they’re showing the outlet view controllers,\r\nDialogue: 0,1:12:31.33,1:12:32.84,yin,,0,0,0,, 它们是用来显示多个输出口视图控制器的 \\N{\\fs12}plural in the view controller case.\r\nDialogue: 0,1:12:32.85,1:12:35.58,yin,,0,0,0,, 在分屏视图或者导航视图控制器中 \\N{\\fs12}It’s root view controller in the split view\r\nDialogue: 0,1:12:35.59,1:12:37.76,yin,,0,0,0,, 这个位置显示的是根视图控制器 \\N{\\fs12}or the navigation view controller space over there.\r\nDialogue: 0,1:12:38.89,1:12:40.64,yin,,0,0,0,, 我将它们连好了 \\N{\\fs12}So I got these things wired up.\r\nDialogue: 0,1:12:41.69,1:12:46.44,yin,,0,0,0,, 注意 所有可能出现在这个选项卡栏中的场景 \\N{\\fs12}Note that on all of the scenes that might appear in this tab bar,\r\nDialogue: 0,1:12:46.44,1:12:47.14,yin,,0,0,0,, 即使它们 \\N{\\fs12}even if they’re –\r\nDialogue: 0,1:12:47.29,1:12:49.31,yin,,0,0,0,, 是通过导航控制器出现的 \\N{\\fs12}that’s happening through a navigation controller,\r\nDialogue: 0,1:12:49.31,1:12:51.37,yin,,0,0,0,, 都会在底部留出这一栏的位置 \\N{\\fs12}they’re all getting room for this little bar on the bottom.\r\nDialogue: 0,1:12:51.93,1:12:52.32,yin,,0,0,0,, 看到了吗 \\N{\\fs12}You see that?\r\nDialogue: 0,1:12:52.68,1:12:54.07,yin,,0,0,0,, 底部的那条栏所占的空间 \\N{\\fs12}Little bar space on the bottom,\r\nDialogue: 0,1:12:54.07,1:12:54.83,yin,,0,0,0,, 都会是这样 \\N{\\fs12}so that’s going to be true.\r\nDialogue: 0,1:12:54.83,1:12:56.03,yin,,0,0,0,, 所以聪明的做法是 \\N{\\fs12}So it’s smart about knowing\r\nDialogue: 0,1:12:56.04,1:12:57.60,yin,,0,0,0,, 确定某个场景是否最终出现在选项卡栏中 \\N{\\fs12}oh, this could eventually be in this tab bar,\r\nDialogue: 0,1:12:57.62,1:12:59.24,yin,,0,0,0,, 然后提前在底部留出空间 \\N{\\fs12}so I’m going to make that space down there.\r\nDialogue: 0,1:12:59.36,1:13:02.92,yin,,0,0,0,, 你同样需要调整 UI 以适应较小的空间 \\N{\\fs12}And again, you have to adjust your UI to fit in the smaller space, whatever.\r\nDialogue: 0,1:13:04.31,1:13:07.79,yin,,0,0,0,, 注意 我们这里是将导航控制器放入选项卡栏控制器中 \\N{\\fs12}Notice we have a navigation controller inside a tab bar controller,\r\nDialogue: 0,1:13:07.79,1:13:08.63,yin,,0,0,0,, 这是合法的 \\N{\\fs12}that’s legal,\r\nDialogue: 0,1:13:08.70,1:13:11.12,yin,,0,0,0,, 反过来就不是了 \\N{\\fs12}other way around, not so much. Okay.\r\nDialogue: 0,1:13:11.13,1:13:13.62,yin,,0,0,0,, 不要将选项卡栏控制器放入导航控制器中 \\N{\\fs12}Don’t be putting a tab bar controller inside a navigation controller.\r\nDialogue: 0,1:13:13.62,1:13:14.04,yin,,0,0,0,, 请讲 \\N{\\fs12}Yeah?\r\nDialogue: 0,1:13:14.90,1:13:17.96,yin,,0,0,0,, 怎么知道哪个选项卡会出现在左边呢 \\N{\\fs12}How do you know which one shows up on the left?\r\nDialogue: 0,1:13:18.72,1:13:20.94,yin,,0,0,0,, 选项卡栏控制器 \\N{\\fs12}Well, the tab bar controller –\r\nDialogue: 0,1:13:20.99,1:13:23.34,yin,,0,0,0,, 选项卡栏控制器所指向的 MVC\\N{\\fs12}the things that the tab bar controller points to,\r\nDialogue: 0,1:13:23.34,1:13:25.83,yin,,0,0,0,, 会出现在各个选项卡中 \\N{\\fs12}those are going to show up in each tab. Okay.\r\nDialogue: 0,1:13:25.99,1:13:28.47,yin,,0,0,0,, 如果你将导航控制器连接到 \\N{\\fs12}If you wired from the navigation controller\r\nDialogue: 0,1:13:28.57,1:13:31.31,yin,,0,0,0,, 某个有选项卡栏控制器的场景中 \\N{\\fs12}to any scene that had a tab bar controller in it,\r\nDialogue: 0,1:13:31.31,1:13:32.14,yin,,0,0,0,, 就不对了 \\N{\\fs12}that would be bad.\r\nDialogue: 0,1:13:32.26,1:13:33.51,yin,,0,0,0,, 所以基本上 选项卡栏控制器 \\N{\\fs12}So basically, the tab bar controller\r\nDialogue: 0,1:13:33.51,1:13:37.01,yin,,0,0,0,, 不应该出现在导航控制器的下游 \\N{\\fs12}should not be anywhere downstream of a navigation controller.\r\nDialogue: 0,1:13:37.65,1:13:39.17,yin,,0,0,0,, 但我的意思是…\\N{\\fs12}Oh but, what I meant is…\r\nDialogue: 0,1:13:39.58,1:13:42.39,yin,,0,0,0,, 问题是选项卡的顺序是什么 \\N{\\fs12}Oh, so the question is what’s the order of the tabs?\r\nDialogue: 0,1:13:43.03,1:13:45.05,yin,,0,0,0,, 这是可以在 Xcode 中修改的 \\N{\\fs12}That can actually be changed in Xcode.\r\nDialogue: 0,1:13:45.24,1:13:47.86,yin,,0,0,0,, 选项卡栏控制器底部会显示出各个选项卡 \\N{\\fs12}If you see where the tabs are in the bottom of the tab bar controller,\r\nDialogue: 0,1:13:47.87,1:13:49.86,yin,,0,0,0,, 你可以拾取然后移动 \\N{\\fs12}you can pick those up and move them. Okay.\r\nDialogue: 0,1:13:51.44,1:13:52.97,yin,,0,0,0,, 现在我们有了这两个选项卡 \\N{\\fs12}So anyway, so we have these two tabs.\r\nDialogue: 0,1:13:53.77,1:13:55.39,yin,,0,0,0,, 我需要选择运行开始的位置 \\N{\\fs12}I’m going to make the launch point.\r\nDialogue: 0,1:13:55.39,1:13:57.85,yin,,0,0,0,, 我要将箭头从导航控制器 \\N{\\fs12}I’m moving it from being the navigation controller\r\nDialogue: 0,1:13:57.94,1:13:59.66,yin,,0,0,0,, 移到选项卡栏控制器上 \\N{\\fs12}over to be the tab bar controller. Right.\r\nDialogue: 0,1:13:59.66,1:14:02.69,yin,,0,0,0,, 显然 我想在运行应用时让选项卡栏控制器 \\N{\\fs12}Obviously, I want the tab bar controller to be showing onscreen\r\nDialogue: 0,1:14:02.86,1:14:04.23,yin,,0,0,0,, 首先出现在屏幕上 \\N{\\fs12}when it first launches,\r\nDialogue: 0,1:14:04.64,1:14:08.85,yin,,0,0,0,, 可以在视图控制器底部双击 \\N{\\fs12}and I can double click down on a view controller\r\nDialogue: 0,1:14:08.86,1:14:11.09,yin,,0,0,0,, 在那里修改标题文本 \\N{\\fs12}and change the text, right there.\r\nDialogue: 0,1:14:11.53,1:14:13.13,yin,,0,0,0,, 看到所指的地方了吗 在那里双击 \\N{\\fs12}See where I am there? Double click.\r\nDialogue: 0,1:14:13.23,1:14:16.01,yin,,0,0,0,, 还可以在右边设置图像 \\N{\\fs12}And I can also set the image over here on the right.\r\nDialogue: 0,1:14:16.22,1:14:18.77,yin,,0,0,0,, 可以设置为资产库中的一张图像 \\N{\\fs12}You can set it to an image that’s in your assets library.\r\nDialogue: 0,1:14:18.89,1:14:22.90,yin,,0,0,0,, 图像要求是 3030 像素的 Alpha 通道 \\N{\\fs12}These images need to be 30 by 30 pixels, all alpha. Okay.\r\nDialogue: 0,1:14:23.02,1:14:25.22,yin,,0,0,0,, 也就是说 在 30*30 的图标中 \\N{\\fs12}In other words, your tint color is going to\r\nDialogue: 0,1:14:25.24,1:14:29.08,yin,,0,0,0,, 你的色调颜色要通过 Alpha 通道显示出来 \\N{\\fs12}show through the alpha in that 30 by 30 icon.\r\nDialogue: 0,1:14:29.53,1:14:30.68,yin,,0,0,0,, 就是这么简单 \\N{\\fs12}Okay. It’s as simple as that.\r\nDialogue: 0,1:14:31.35,1:14:32.74,yin,,0,0,0,, 颜色要通过 Alpha 通道显示出来 \\N{\\fs12}It’s going to show through the alpha.\r\nDialogue: 0,1:14:32.75,1:14:35.52,yin,,0,0,0,, 如果图标除了 Alpha 之外还有别的通道 \\N{\\fs12}So if that icon has anything but alpha in it,\r\nDialogue: 0,1:14:36.66,1:14:39.16,yin,,0,0,0,, 比如不透明度 是不会显示出来的 \\N{\\fs12}you know, opaque and alpha, it’s not going to show. Okay.\r\nDialogue: 0,1:14:41.03,1:14:43.17,yin,,0,0,0,, 就是这样了 就是这些 \\N{\\fs12}So that’s that. That’s it.\r\nDialogue: 0,1:14:43.41,1:14:46.82,yin,,0,0,0,, 希望今天的内容能够帮助大家实现两种控制器 \\N{\\fs12}Hopefully that’s enough for you to do both kinds of controllers.\r\nDialogue: 0,1:14:47.27,1:14:49.26,yin,,0,0,0,, 周五没有课外辅导 \\N{\\fs12}Friday, no section.\r\nDialogue: 0,1:14:49.53,1:14:52.62,yin,,0,0,0,, 下周五帮助大家在设备上运行应用 \\N{\\fs12}Next Friday we’ll get you up and running on your devices.\r\nDialogue: 0,1:14:52.62,1:14:53.91,yin,,0,0,0,, 周一没课 \\N{\\fs12}Monday, no lecture.\r\nDialogue: 0,1:14:53.91,1:14:56.24,yin,,0,0,0,, 作业截止日期是周三 很方便 \\N{\\fs12}Your homework’s due on Wednesday, which is convenient,\r\nDialogue: 0,1:14:56.37,1:14:58.52,yin,,0,0,0,, 从下周三开始 \\N{\\fs12}and then starting next week, next Wednesday\r\nDialogue: 0,1:14:58.53,1:14:59.85,yin,,0,0,0,, 以及之后的两周 \\N{\\fs12}and for the two weeks after that,\r\nDialogue: 0,1:14:59.85,1:15:02.92,yin,,0,0,0,, 我们会讲到绘制 手势 自动布局 动画 \\N{\\fs12}we’ll be doing drawing and gestures and autolayout animation.\r\nDialogue: 0,1:15:02.92,1:15:04.47,yin,,0,0,0,, 很多有意思的内容 \\N{\\fs12}Lots and lots of fun stuff.\r\nDialogue: 0,1:15:05.01,1:15:06.57,yin,,0,0,0,, 好的 非常感谢 \\N{\\fs12}Okay. Thank you very much.\r\nDialogue: 0,1:15:08.95,1:15:12.38,yin,,0,0,0,, 更多内容 请访问斯坦福网站 \\N{\\fs12}For more, please visit us at stanford.edu."
  },
  {
    "path": "Subtitles/7. Views and Gestures.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.1.3\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\nLast Style Storage: Default\r\nAegisub Scroll Position: 0\r\nAegisub Active Line: 8\r\nAegisub Video Zoom Percent: 1.000000\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.04,0:00:06.35,yin,,0,0,0,,斯坦福大学\\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:08.59,0:00:10.90,yin,,0,0,0,,欢迎来到2013至2014秋季学期\\N{\\fs12}Well, welcome everyone to lecture number seven\r\nDialogue: 0,0:00:10.90,0:00:14.64,yin,,0,0,0,,CS193P第七讲\\N{\\fs12}of CS1973P fall of 2013-14.\r\nDialogue: 0,0:00:14.97,0:00:17.83,yin,,0,0,0,,今天我们会讲一下输入输出\\N{\\fs12}Today we are going to talk about input and output.\r\nDialogue: 0,0:00:17.98,0:00:19.97,yin,,0,0,0,,涉及到屏幕上\\N{\\fs12}Okay? It's about views\r\nDialogue: 0,0:00:19.98,0:00:22.67,yin,,0,0,0,,矩形区域的视图\\N{\\fs12}which you're rectangular areas on the screen\r\nDialogue: 0,0:00:22.68,0:00:25.94,yin,,0,0,0,,可以在其中绘制自定义内容\\N{\\fs12}that you can use both to draw custom stuff\r\nDialogue: 0,0:00:26.09,0:00:28.06,yin,,0,0,0,,以及从用户触控手势 多点触控中\\N{\\fs12}and to get gestures in\r\nDialogue: 0,0:00:28.68,0:00:30.95,yin,,0,0,0,,获取手势\\N{\\fs12}from user touch gestures, multi-touch.\r\nDialogue: 0,0:00:31.63,0:00:34.17,yin,,0,0,0,,我会用一个示例演示这些内容\\N{\\fs12}I'm going to have a demo that's going to show you all that.\r\nDialogue: 0,0:00:34.19,0:00:35.43,yin,,0,0,0,,我们会创建一个自定义视图\\N{\\fs12}We're going to build a custom view,\r\nDialogue: 0,0:00:35.44,0:00:39.20,yin,,0,0,0,,它有自己的自定义手势等等\\N{\\fs12}it's going to have its own custom gestures and all that stuff.\r\nDialogue: 0,0:00:39.21,0:00:42.74,yin,,0,0,0,,基本上 它会绘制...\\N{\\fs12}It's basically going to draw the--\r\nDialogue: 0,0:00:42.75,0:00:44.92,yin,,0,0,0,,我们在Machismo中使用的卡牌\\N{\\fs12}you know, the cards that we used in Machismo\r\nDialogue: 0,0:00:44.93,0:00:47.19,yin,,0,0,0,,都不太好看 比如梅花A\\N{\\fs12}were just really bad, like A clubs.\r\nDialogue: 0,0:00:47.19,0:00:48.34,yin,,0,0,0,,看起来并不像扑克牌\\N{\\fs12}They didn't look like cards,\r\nDialogue: 0,0:00:48.36,0:00:51.07,yin,,0,0,0,,所以我们会创建一个自定义视图\\N{\\fs12}so we're going to actually have a custom view\r\nDialogue: 0,0:00:51.24,0:00:54.18,yin,,0,0,0,,顶角有数字和花色 还有人头牌\\N{\\fs12}Right? Has the things in the corner, and face cards,\r\nDialogue: 0,0:00:54.20,0:00:55.79,yin,,0,0,0,,这些全套的东西\\N{\\fs12}all that-- that whole business.\r\nDialogue: 0,0:00:57.44,0:01:00.98,yin,,0,0,0,,视图是iOS中至关重要的一部分\\N{\\fs12}All right, so a view is of critical importance in iOS.\r\nDialogue: 0,0:01:00.98,0:01:03.50,yin,,0,0,0,,它是所有绘制操作的核心\\N{\\fs12}It's right at the heart of all the drawing we do.\r\nDialogue: 0,0:01:03.61,0:01:05.57,yin,,0,0,0,,大家已经用过非常多的视图了\\N{\\fs12}You've used a ton of views already.\r\nDialogue: 0,0:01:05.58,0:01:06.42,yin,,0,0,0,,按钮是视图\\N{\\fs12}Buttons are views.\r\nDialogue: 0,0:01:06.43,0:01:07.89,yin,,0,0,0,,标签是视图\\N{\\fs12}Labels are views. Okay?\r\nDialogue: 0,0:01:08.80,0:01:12.32,yin,,0,0,0,,基本上 它是构造块\\N{\\fs12}It's basically the building block\r\nDialogue: 0,0:01:12.32,0:01:14.98,yin,,0,0,0,,代表屏幕上的一块矩形区域\\N{\\fs12}that represents a rectangular area on screen.\r\nDialogue: 0,0:01:14.98,0:01:16.89,yin,,0,0,0,,定义了一个坐标空间\\N{\\fs12}It defines a coordinate space.\r\nDialogue: 0,0:01:17.06,0:01:18.58,yin,,0,0,0,,在这个坐标空间中 你可以进行绘制\\N{\\fs12}Okay? A coordinate space you can draw in.\r\nDialogue: 0,0:01:18.59,0:01:20.56,yin,,0,0,0,,可以在其中添加触控事件\\N{\\fs12}And a coordinate space that you can get touch events in\r\nDialogue: 0,0:01:20.56,0:01:22.01,yin,,0,0,0,,掌握它们的位置\\N{\\fs12}and understand where they are.\r\nDialogue: 0,0:01:23.36,0:01:24.96,yin,,0,0,0,,它是分层级的\\N{\\fs12}It's hierarchical.\r\nDialogue: 0,0:01:25.09,0:01:26.95,yin,,0,0,0,,可以在视图中嵌套视图\\N{\\fs12}Right? So you can have view inside views,\r\nDialogue: 0,0:01:26.97,0:01:28.97,yin,,0,0,0,,层层嵌套 明白吗\\N{\\fs12}inside views, all right?\r\nDialogue: 0,0:01:29.94,0:01:32.34,yin,,0,0,0,,每个视图只有一个父视图\\N{\\fs12}Every view only has one superview.\r\nDialogue: 0,0:01:32.63,0:01:35.53,yin,,0,0,0,,但是一个特定视图可以有很多子视图\\N{\\fs12}But a given view could have many subviews\r\nDialogue: 0,0:01:35.55,0:01:36.96,yin,,0,0,0,,而这些子视图就是一个个矩形\\N{\\fs12}and those sub view are just rectangles.\r\nDialogue: 0,0:01:36.97,0:01:38.94,yin,,0,0,0,,相互之间可以重叠等等\\N{\\fs12}They can overlap, whatever.\r\nDialogue: 0,0:01:39.72,0:01:43.20,yin,,0,0,0,,不要求它们平铺或相互独立\\N{\\fs12}You know they're not required to somehow be tiled or separate.\r\nDialogue: 0,0:01:43.21,0:01:46.89,yin,,0,0,0,,特定视图的子视图是完全自由的\\N{\\fs12}They're complete free form subviews of a given view.\r\nDialogue: 0,0:01:48.06,0:01:51.46,yin,,0,0,0,,一个视图可以有任意多个子视图\\N{\\fs12}You can have any number of subview you want for a given view.\r\nDialogue: 0,0:01:51.74,0:01:53.63,yin,,0,0,0,,子视图的顺序很重要\\N{\\fs12}The order of the subviews does matter,\r\nDialogue: 0,0:01:53.63,0:01:55.13,yin,,0,0,0,,因为它们可以是透明的\\N{\\fs12}because they can be transparent.\r\nDialogue: 0,0:01:55.14,0:01:56.13,yin,,0,0,0,,我们会讲到这部分\\N{\\fs12}We'll talk about that.\r\nDialogue: 0,0:01:56.44,0:01:59.41,yin,,0,0,0,,还有一点有时会令人困惑就是\\N{\\fs12}And one thing that's sometimes a little confusing is\r\nDialogue: 0,0:01:59.86,0:02:01.86,yin,,0,0,0,,视图是这个矩形区域\\N{\\fs12}you have this rectangular area that you're view,\r\nDialogue: 0,0:02:01.86,0:02:04.27,yin,,0,0,0,,但其实可以在区域外进行绘制\\N{\\fs12}but you can actually draw outside that area.\r\nDialogue: 0,0:02:04.31,0:02:05.40,yin,,0,0,0,,完全合法\\N{\\fs12}Perfectly legal.\r\nDialogue: 0,0:02:05.89,0:02:08.16,yin,,0,0,0,,Xcode中有一个开关\\N{\\fs12}There is a little switch you can turn on in Xcode\r\nDialogue: 0,0:02:08.17,0:02:11.01,yin,,0,0,0,,或者说是UIView的一个属性\\N{\\fs12}or obviously a property in UIView\r\nDialogue: 0,0:02:11.02,0:02:12.48,yin,,0,0,0,,代表\"裁剪子视图\"\\N{\\fs12}that says \"Clips my subviews.\"\r\nDialogue: 0,0:02:12.48,0:02:15.22,yin,,0,0,0,,换句话说就是不要让我的子视图\\N{\\fs12}In other words, don't let my subviews go outside my\r\nDialogue: 0,0:02:15.94,0:02:17.18,yin,,0,0,0,,超出视图边界\\N{\\fs12}my view's bound. Right?\r\nDialogue: 0,0:02:17.19,0:02:19.41,yin,,0,0,0,,可以按照自己意愿将绘制内容控制在一定范围内\\N{\\fs12}So you can kind of keep things contained if you want, but...\r\nDialogue: 0,0:02:20.46,0:02:22.69,yin,,0,0,0,,通常这并不是默认值 我们一般也不需要\\N{\\fs12}General that's not the default and generally we don't.\r\nDialogue: 0,0:02:23.34,0:02:25.43,yin,,0,0,0,,有一个UIWindow类\\N{\\fs12}There is a UIWindow class.\r\nDialogue: 0,0:02:25.61,0:02:27.16,yin,,0,0,0,,在iOS中并不重要\\N{\\fs12}Very unimportant in iOS.\r\nDialogue: 0,0:02:27.16,0:02:29.33,yin,,0,0,0,,如果要学习Mac UIWindow就很重要了\\N{\\fs12}If we're on the Mac, UIWindow would matter.\r\nDialogue: 0,0:02:29.33,0:02:31.73,yin,,0,0,0,,可以在桌面上放置多个窗口\\N{\\fs12}You got a lot of windows on a desktop.\r\nDialogue: 0,0:02:31.95,0:02:33.54,yin,,0,0,0,,但在iOS中 视图就是主要内容了\\N{\\fs12}But in iOS, it's all about views.\r\nDialogue: 0,0:02:33.55,0:02:34.92,yin,,0,0,0,,只有一个UIWindow\\N{\\fs12}There's only one UIWindow.\r\nDialogue: 0,0:02:34.93,0:02:37.56,yin,,0,0,0,,它包括了当前出现在屏幕上的\\N{\\fs12}It's the one that's containing all the views\r\nDialogue: 0,0:02:37.57,0:02:38.56,yin,,0,0,0,,全部视图\\N{\\fs12}that are currently on screen.\r\nDialogue: 0,0:02:38.57,0:02:40.89,yin,,0,0,0,,这也就是为什么在上一个示例中 我可以说\\N{\\fs12}That's why in the last demo I was able to say\r\nDialogue: 0,0:02:41.02,0:02:44.24,yin,,0,0,0,,如果self.view.window不为空 我就知道我正显示在屏幕上\\N{\\fs12}if self.View.Window, then I knew I was on screen.\r\nDialogue: 0,0:02:44.25,0:02:45.97,yin,,0,0,0,,因为只有这一个窗口\\N{\\fs12}Right? Because that's the only window there is\r\nDialogue: 0,0:02:45.98,0:02:48.60,yin,,0,0,0,,如果我在窗口中 那么我就是在屏幕上\\N{\\fs12}and so if I am in it then I'm on screen.\r\nDialogue: 0,0:02:48.89,0:02:50.68,yin,,0,0,0,,所以UIWindow无关紧要\\N{\\fs12}So UIWindow very unimportant,\r\nDialogue: 0,0:02:51.23,0:02:52.26,yin,,0,0,0,,你甚至用不着\\N{\\fs12}you don't even aver had to\r\nDialogue: 0,0:02:52.27,0:02:54.04,yin,,0,0,0,,查看UIWindow的文档\\N{\\fs12}look at the documentation for UIWindow.\r\nDialogue: 0,0:02:54.80,0:02:56.33,yin,,0,0,0,,UIView就是我们需要的全部内容\\N{\\fs12}UIViews are what it's all about.\r\nDialogue: 0,0:02:57.29,0:02:58.82,yin,,0,0,0,,视图的这种层级结构\\N{\\fs12}So this hierarchy of views.\r\nDialogue: 0,0:02:58.82,0:03:02.26,yin,,0,0,0,,视图嵌套视图 通常是在Xcode中完成的\\N{\\fs12}View inside views is most often built in Xcode,\r\nDialogue: 0,0:03:02.27,0:03:03.77,yin,,0,0,0,,只要将视图拖入即可\\N{\\fs12}just by dragging views in.\r\nDialogue: 0,0:03:03.78,0:03:05.42,yin,,0,0,0,,我们目前还没有做过很多\\N{\\fs12}Now we haven't done a lot of\r\nDialogue: 0,0:03:05.43,0:03:07.12,yin,,0,0,0,,将视图拖拽到另一个视图中的操作\\N{\\fs12}dragging views inside other views,\r\nDialogue: 0,0:03:07.13,0:03:08.52,yin,,0,0,0,,但是这样做是完全合法的\\N{\\fs12}but it's perfectly legal to do that\r\nDialogue: 0,0:03:08.53,0:03:10.14,yin,,0,0,0,,你有时会在Xcode中遇到这种情况\\N{\\fs12}and you'll see in Xcode sometimes\r\nDialogue: 0,0:03:10.15,0:03:12.47,yin,,0,0,0,,当你拖拽时 系统会想要将它放到另一个视图中\\N{\\fs12}when you drag, it try to drop it in another view.\r\nDialogue: 0,0:03:12.47,0:03:14.61,yin,,0,0,0,,你也许并不想这样做 但是系统会尝试这样做\\N{\\fs12}You might even don't want it to, but it tries to.\r\nDialogue: 0,0:03:15.62,0:03:17.15,yin,,0,0,0,,所以很多情况下都会用图形化的方式来创建\\N{\\fs12}So a lot of it would build graphically.\r\nDialogue: 0,0:03:17.16,0:03:19.03,yin,,0,0,0,,我们还可以通过代码创建\\N{\\fs12}However, we could also build it in code\r\nDialogue: 0,0:03:19.05,0:03:20.17,yin,,0,0,0,,当我们使用代码\\N{\\fs12}and when we build it in code,\r\nDialogue: 0,0:03:20.36,0:03:22.64,yin,,0,0,0,,创建和拆解这个新的层级结构时\\N{\\fs12}build and tear down this new hierarchy in code\r\nDialogue: 0,0:03:22.65,0:03:24.63,yin,,0,0,0,,需要这两个方法 addSubView\\N{\\fs12}with these two methods, addSubView.\r\nDialogue: 0,0:03:25.19,0:03:26.33,yin,,0,0,0,,和大家想的完全一样\\N{\\fs12}Exactly what you would think.\r\nDialogue: 0,0:03:26.34,0:03:27.45,yin,,0,0,0,,它得到一个视图\\N{\\fs12}It just takes a view\r\nDialogue: 0,0:03:27.46,0:03:29.44,yin,,0,0,0,,将它作为子视图添加到另一个视图上\\N{\\fs12}and adds it as a subview of some other view.\r\nDialogue: 0,0:03:29.44,0:03:31.41,yin,,0,0,0,,将这个方法发送给\\N{\\fs12}You send that to the view\r\nDialogue: 0,0:03:31.54,0:03:33.33,yin,,0,0,0,,目标父视图\\N{\\fs12}that you want to be the parent view, right.\r\nDialogue: 0,0:03:33.68,0:03:36.40,yin,,0,0,0,,也就是你想要向其添加子视图的那个视图\\N{\\fs12}That's the view to which you are adding the subview.\r\nDialogue: 0,0:03:37.16,0:03:38.24,yin,,0,0,0,,相反的操作\\N{\\fs12}On the opposite side,\r\nDialogue: 0,0:03:38.24,0:03:40.33,yin,,0,0,0,,如果想要将视图从视图层级中移除\\N{\\fs12}to get a view out of the view hierarchy\r\nDialogue: 0,0:03:40.34,0:03:44.35,yin,,0,0,0,,就要向想要移除的那个视图发送removeFromSuperview\\N{\\fs12}you send removeFromSuperview to the view you want to remove.\r\nDialogue: 0,0:03:44.67,0:03:45.86,yin,,0,0,0,,而不是发送给它的父视图\\N{\\fs12}Not to it's parent.\r\nDialogue: 0,0:03:46.00,0:03:49.35,yin,,0,0,0,,所以不能用removeFromSuperview:view\\N{\\fs12}So you don't say removeFromSuperview:view.\r\nDialogue: 0,0:03:49.36,0:03:51.49,yin,,0,0,0,,只需要对你想要移除的那个视图说\\N{\\fs12}You just say to a view that you want out of there,\r\nDialogue: 0,0:03:51.54,0:03:53.10,yin,,0,0,0,,从父视图中移除你自己\\N{\\fs12}remove yourself from superview.\r\nDialogue: 0,0:03:53.72,0:03:55.78,yin,,0,0,0,,所以添加和移除操作中发送方法的对象\\N{\\fs12}Okay, so it's a little different adding and removing\r\nDialogue: 0,0:03:55.78,0:03:57.96,yin,,0,0,0,,不太一样\\N{\\fs12}who you ask to do it.\r\nDialogue: 0,0:03:59.17,0:04:02.31,yin,,0,0,0,,这是MVC 所有肯定有视图\\N{\\fs12}You're MVCs, of course have a view.\r\nDialogue: 0,0:04:02.67,0:04:06.47,yin,,0,0,0,,而MVC的视图层级结构中\\N{\\fs12}And that top level view that contains all the views\r\nDialogue: 0,0:04:06.47,0:04:08.72,yin,,0,0,0,,包含全部视图的那个顶级视图\\N{\\fs12}in the view hierarchy for your MVC\r\nDialogue: 0,0:04:09.02,0:04:12.67,yin,,0,0,0,,就是视图控制器中的view视图属性\\N{\\fs12}is the property view in view controller.\r\nDialogue: 0,0:04:13.07,0:04:14.73,yin,,0,0,0,,所以如果你查看UIViewController\\N{\\fs12}So if you look in UIViewController,\r\nDialogue: 0,0:04:14.74,0:04:15.77,yin,,0,0,0,,它有一个属性叫做view\\N{\\fs12}there's a property called view.\r\nDialogue: 0,0:04:15.77,0:04:16.94,yin,,0,0,0,,它是UIView\\N{\\fs12}It's a UIView.\r\nDialogue: 0,0:04:17.48,0:04:21.68,yin,,0,0,0,,如果你打开Xcode 在控制器上单击右键\\N{\\fs12}And if you go in Xcode and right click on your controller\r\nDialogue: 0,0:04:21.68,0:04:24.73,yin,,0,0,0,,或者在MVC的视图背景上单击右键\\N{\\fs12}or right click on the background of your MVC's view,\r\nDialogue: 0,0:04:24.85,0:04:27.04,yin,,0,0,0,,你会看到一个输出口\\N{\\fs12}you'll see an outlet basically.\r\nDialogue: 0,0:04:27.04,0:04:29.80,yin,,0,0,0,,因为这个view属性确实就是个输出口\\N{\\fs12}Because it's really is an outlet, this view property.\r\nDialogue: 0,0:04:30.02,0:04:32.36,yin,,0,0,0,,输出口指向顶级视图\\N{\\fs12}And it points to that top level view.\r\nDialogue: 0,0:04:32.64,0:04:34.20,yin,,0,0,0,,所以如果你想用代码\\N{\\fs12}So that's a good place to start\r\nDialogue: 0,0:04:34.21,0:04:37.03,yin,,0,0,0,,向视图层级结构中添加视图\\N{\\fs12}if you want to start adding views in code\r\nDialogue: 0,0:04:37.30,0:04:38.07,yin,,0,0,0,,这是一个很好的出发点\\N{\\fs12}to your view hierarchy.\r\nDialogue: 0,0:04:38.07,0:04:40.02,yin,,0,0,0,,当然 当你在Xcode中拖出它们时\\N{\\fs12}And of course when you drag them out in Xcode\r\nDialogue: 0,0:04:40.03,0:04:40.64,yin,,0,0,0,,你就是这样做的\\N{\\fs12}that's what you're doing.\r\nDialogue: 0,0:04:40.64,0:04:41.65,yin,,0,0,0,,是将它们放在了...\\N{\\fs12}You're dropping them in--\r\nDialogue: 0,0:04:42.27,0:04:44.22,yin,,0,0,0,,除非你是将它们拖拽到另一个视图上\\N{\\fs12}Unless you're dropping them in on top of another view,\r\nDialogue: 0,0:04:44.23,0:04:46.79,yin,,0,0,0,,否则你就是将视图放到了背景中 self.view中\\N{\\fs12}you're dropping into that background, the self.view.\r\nDialogue: 0,0:04:47.02,0:04:47.93,yin,,0,0,0,,self.view\\N{\\fs12}Okay, self.View.\r\nDialogue: 0,0:04:47.94,0:04:50.32,yin,,0,0,0,,我们用self.view来表示 将视图放在self.view中\\N{\\fs12}We use that phrase self.view, it puts in self.view.\r\nDialogue: 0,0:04:50.55,0:04:55.85,yin,,0,0,0,,self.view是UIViewController的顶级UIView\\N{\\fs12}Self.View is that top level UIView in UIViewController.\r\nDialogue: 0,0:04:55.86,0:04:57.17,yin,,0,0,0,,它只是一个普通的UIView\\N{\\fs12}It's just a plain UIView.\r\nDialogue: 0,0:04:57.18,0:04:58.12,yin,,0,0,0,,并不是子类\\N{\\fs12}It's not a subclass version.\r\nDialogue: 0,0:04:58.13,0:04:59.59,yin,,0,0,0,,我们永远都不会子类化这个视图\\N{\\fs12}You never subclass that view.\r\nDialogue: 0,0:04:59.59,0:05:01.34,yin,,0,0,0,,它就像是一个大的容器视图\\N{\\fs12}It's just kind of a big container view.\r\nDialogue: 0,0:05:01.56,0:05:02.98,yin,,0,0,0,,这是另外一件需要知道的关于视图的事情\\N{\\fs12}And that's another thing to know about views,\r\nDialogue: 0,0:05:03.00,0:05:05.90,yin,,0,0,0,,绘制或处理触控事件时并不经常需要对其进行子类化\\N{\\fs12}you don't always subclass them to draw or do touch events.\r\nDialogue: 0,0:05:05.92,0:05:07.86,yin,,0,0,0,,有时它们只是边界\\N{\\fs12}Sometimes they're just boundaries. Right?\r\nDialogue: 0,0:05:07.87,0:05:09.97,yin,,0,0,0,,只是用来定义一个坐标空间\\N{\\fs12}Just a view you want to define a coordinate space\r\nDialogue: 0,0:05:09.98,0:05:11.59,yin,,0,0,0,,在其中增加其他视图\\N{\\fs12}and you want to put some other views inside of it.\r\nDialogue: 0,0:05:11.94,0:05:13.65,yin,,0,0,0,,完全没问题 可以这样做\\N{\\fs12}Perfectly fine, we do that.\r\nDialogue: 0,0:05:15.60,0:05:17.60,yin,,0,0,0,,初始化UIView\\N{\\fs12}So initializing a UIView.\r\nDialogue: 0,0:05:17.75,0:05:20.84,yin,,0,0,0,,更常见的是\\N{\\fs12}A little more common to want to\r\nDialogue: 0,0:05:20.90,0:05:23.68,yin,,0,0,0,,在子类中 重写UIView的\\N{\\fs12}override the designated initializer of a UIView\r\nDialogue: 0,0:05:23.69,0:05:24.37,yin,,0,0,0,,指定初始化方法\\N{\\fs12}in a subclass.\r\nDialogue: 0,0:05:24.37,0:05:26.95,yin,,0,0,0,,还记得吗 在UIViewController中我们说\\N{\\fs12}Remember in UIViewController we kind of said,\r\nDialogue: 0,0:05:27.07,0:05:28.45,yin,,0,0,0,,我们几乎从来不会这样做\\N{\\fs12}we almost never do that\r\nDialogue: 0,0:05:28.46,0:05:31.34,yin,,0,0,0,,因为UIViewController通常都会从storyboard中创建\\N{\\fs12}because UIViewController are almost always coming out of storyboards.\r\nDialogue: 0,0:05:31.53,0:05:34.42,yin,,0,0,0,,所以指定初始化方法永远都不会被调用\\N{\\fs12}So the designated initializer never gets called in anyway.\r\nDialogue: 0,0:05:34.61,0:05:36.16,yin,,0,0,0,,我们只要用awakeFromNib方法\\N{\\fs12}So we just do awakeFromNib.\r\nDialogue: 0,0:05:36.68,0:05:40.58,yin,,0,0,0,,而不用initWithNibName bundle\\N{\\fs12}Okay? And we never do that initWithNibName bundle thing.\r\nDialogue: 0,0:05:41.16,0:05:42.52,yin,,0,0,0,,UIView中并不是这样的\\N{\\fs12}That's not true in UIView.\r\nDialogue: 0,0:05:42.53,0:05:46.95,yin,,0,0,0,,在UIView中 你不仅需要\\N{\\fs12}In UIView you do more often both need to do something\r\nDialogue: 0,0:05:46.95,0:05:50.78,yin,,0,0,0,,在初始化方法中做些操作\\N{\\fs12}in your initializer and just want to, you know,\r\nDialogue: 0,0:05:50.79,0:05:53.76,yin,,0,0,0,,需要初始化方法 并在其中添加代码\\N{\\fs12}have your initializer around and code in there.\r\nDialogue: 0,0:05:54.05,0:05:57.96,yin,,0,0,0,,但当你这样做时 你仍需要awakeFromNib\\N{\\fs12}So but when you do it, you want to also do awakeFromNib.\r\nDialogue: 0,0:05:58.51,0:06:03.09,yin,,0,0,0,,因为创建UIView的两种方法是同等的\\N{\\fs12}Okay? That's because UIViews are equally created--\r\nDialogue: 0,0:06:03.09,0:06:05.96,yin,,0,0,0,,也不是完全同等 但至少是两种常用的方法\\N{\\fs12}well, not equally, but at least they're commonly created\r\nDialogue: 0,0:06:05.99,0:06:08.74,yin,,0,0,0,,一种是将它们拖进storyboard中\\N{\\fs12}both by dragging them into a storyboard,\r\nDialogue: 0,0:06:08.76,0:06:11.32,yin,,0,0,0,,对应的就是awakeFromNib初始化\\N{\\fs12}so that would be the awakeFromNib initialization\r\nDialogue: 0,0:06:11.47,0:06:13.34,yin,,0,0,0,,另外一种是向它们发送alloc/init\\N{\\fs12}and by sending alloc and init to them.\r\nDialogue: 0,0:06:13.70,0:06:15.97,yin,,0,0,0,,也就是说在代码中创建一个视图\\N{\\fs12}In other words, in your code creating a view.\r\nDialogue: 0,0:06:15.98,0:06:18.04,yin,,0,0,0,,比如 在作业中\\N{\\fs12}So for example, in your homework you're going to\r\nDialogue: 0,0:06:18.05,0:06:21.21,yin,,0,0,0,,大家需要实现设置卡牌和真正的扑克牌\\N{\\fs12}have to do set cards and playing cards for real,\r\nDialogue: 0,0:06:21.27,0:06:23.24,yin,,0,0,0,,不再是按钮 而是真正地绘制出来\\N{\\fs12}not as buttons, but actually drawing them\r\nDialogue: 0,0:06:23.44,0:06:27.17,yin,,0,0,0,,几乎可以肯定 你会用allco/init来初始化这些视图\\N{\\fs12}and you will almost certainly be allocating those views\r\nDialogue: 0,0:06:27.29,0:06:30.26,yin,,0,0,0,,因为视图数量不确定\\N{\\fs12}because there can be-- there's not a fixed number of them\r\nDialogue: 0,0:06:30.26,0:06:31.81,yin,,0,0,0,,所以你并不能完全用在Xcode中拖出来实现\\N{\\fs12}so you can't really drag them out in Xcode\r\nDialogue: 0,0:06:31.81,0:06:33.15,yin,,0,0,0,,因为它们需要出现和消失\\N{\\fs12}because they have to come and go.\r\nDialogue: 0,0:06:33.96,0:06:34.70,yin,,0,0,0,,大家要实现这部分内容\\N{\\fs12}So you'll be doing that.\r\nDialogue: 0,0:06:34.70,0:06:37.48,yin,,0,0,0,,这和我们对UIViewController做过的操作类似\\N{\\fs12}So we do the same kind of thing we did with UIViewController.\r\nDialogue: 0,0:06:37.48,0:06:39.35,yin,,0,0,0,,添加一个setup方法\\N{\\fs12}Right? Where we have some kind of setup method.\r\nDialogue: 0,0:06:39.35,0:06:41.21,yin,,0,0,0,,方法名可以是setup或者其他的\\N{\\fs12}You can call it setup thing or whatever you want.\r\nDialogue: 0,0:06:41.43,0:06:43.21,yin,,0,0,0,,然后在awakeFromNib中调用它\\N{\\fs12}And then you call it from awakeFromNib\r\nDialogue: 0,0:06:43.31,0:06:47.70,yin,,0,0,0,,还要从UIView的指定初始化方法中调用它\\N{\\fs12}and then you also call it from UIView's designated initializer\r\nDialogue: 0,0:06:47.70,0:06:49.54,yin,,0,0,0,,指定初始化方法叫做initWithFrame\\N{\\fs12}which is called initWithFrame.\r\nDialogue: 0,0:06:49.98,0:06:52.54,yin,,0,0,0,,Frame框架指定了该视图\\N{\\fs12}And that frame specifies where this view is\r\nDialogue: 0,0:06:52.55,0:06:54.54,yin,,0,0,0,,在其父视图坐标系中的位置\\N{\\fs12}in its superview's coordinate system.\r\nDialogue: 0,0:06:54.70,0:06:56.85,yin,,0,0,0,,是该视图的位置信息\\N{\\fs12}It's the positioning of this view.\r\nDialogue: 0,0:06:57.46,0:07:00.41,yin,,0,0,0,,代码就是这个样子的\\N{\\fs12}Okay? So that's what the code would look like.\r\nDialogue: 0,0:07:00.43,0:07:01.00,yin,,0,0,0,,就像这样\\N{\\fs12}Just like that.\r\nDialogue: 0,0:07:01.11,0:07:02.87,yin,,0,0,0,,加上初始化代码\\N{\\fs12}Put your initialization codes inside.\r\nDialogue: 0,0:07:02.88,0:07:04.76,yin,,0,0,0,,我们会在示例中进行演示\\N{\\fs12}And we'll do that in the demo just so you see that.\r\nDialogue: 0,0:07:05.10,0:07:07.33,yin,,0,0,0,,在继续讲解UIView的\\N{\\fs12}Now before I can talk more about UIView\r\nDialogue: 0,0:07:07.34,0:07:09.22,yin,,0,0,0,,绘制和获取事件之前\\N{\\fs12}and drawing there and getting events,\r\nDialogue: 0,0:07:09.23,0:07:11.51,yin,,0,0,0,,我们需要先定义几个类型\\N{\\fs12}we got to define a few types here.\r\nDialogue: 0,0:07:11.64,0:07:13.03,yin,,0,0,0,,一个是CGFloat\\N{\\fs12}One is CGFloat.\r\nDialogue: 0,0:07:13.08,0:07:14.56,yin,,0,0,0,,它是一个浮点数\\N{\\fs12}It's a floating point number.\r\nDialogue: 0,0:07:14.97,0:07:17.48,yin,,0,0,0,,在屏幕上绘制图形 获取触控事件等\\N{\\fs12}All floating point numbers that have to do with\r\nDialogue: 0,0:07:17.49,0:07:20.10,yin,,0,0,0,,所用到的全部浮点数\\N{\\fs12}drawing on the screen or getting touch events or whatever\r\nDialogue: 0,0:07:20.38,0:07:21.58,yin,,0,0,0,,都是CGFloat\\N{\\fs12}are CGFloats.\r\nDialogue: 0,0:07:21.77,0:07:23.47,yin,,0,0,0,,它可能是一个double类型\\N{\\fs12}This might be a double.\r\nDialogue: 0,0:07:23.47,0:07:25.37,yin,,0,0,0,,可能只是一个普通的浮点数\\N{\\fs12}It might be just a regular floating point number.\r\nDialogue: 0,0:07:25.37,0:07:27.52,yin,,0,0,0,,可能是32位 64位\\N{\\fs12}It might be 32 bits, 64 bits.\r\nDialogue: 0,0:07:27.52,0:07:29.03,yin,,0,0,0,,我们不知道 也不在意\\N{\\fs12}You don't know and you don't care\r\nDialogue: 0,0:07:29.10,0:07:30.94,yin,,0,0,0,,但你始终需要使用CGFloat\\N{\\fs12}but you always have to use CGFloat.\r\nDialogue: 0,0:07:31.06,0:07:34.85,yin,,0,0,0,,不只是用CGFloat来指定屏幕上的位置等\\N{\\fs12}Not only using CGFloat to specify positions on screen and all the things\r\nDialogue: 0,0:07:35.01,0:07:37.97,yin,,0,0,0,,如果你要对屏幕上的数字\\N{\\fs12}but if you're going to be multiplying or adding numbers\r\nDialogue: 0,0:07:37.98,0:07:39.73,yin,,0,0,0,,做乘法或加法\\N{\\fs12}to things that are on screen\r\nDialogue: 0,0:07:39.90,0:07:42.61,yin,,0,0,0,,重新计算得到新值\\N{\\fs12}to recalculate new things, all--\r\nDialogue: 0,0:07:42.61,0:07:45.14,yin,,0,0,0,,这些都要用CGFloat\\N{\\fs12}you want to do all that in the CGFloat domain.\r\nDialogue: 0,0:07:45.15,0:07:45.98,yin,,0,0,0,,所以处理屏幕事件时\\N{\\fs12}So you're going to have a lot of\r\nDialogue: 0,0:07:46.02,0:07:48.91,yin,,0,0,0,,很多属性和局部变量\\N{\\fs12}properties and local variables that are CGFloats\r\nDialogue: 0,0:07:48.98,0:07:50.76,yin,,0,0,0,,都是CGFloat类型\\N{\\fs12}when you're doing screen stuff. Okay?\r\nDialogue: 0,0:07:51.37,0:07:53.85,yin,,0,0,0,,还有一个C结构体叫做CGPoint\\N{\\fs12}Then there's a c-struct called CGPoint.\r\nDialogue: 0,0:07:54.00,0:07:56.18,yin,,0,0,0,,其中有两个元素 x和y\\N{\\fs12}That has just got two elements in it. X and y.\r\nDialogue: 0,0:07:56.19,0:07:57.60,yin,,0,0,0,,分别代表X轴和Y轴的位置\\N{\\fs12}That's an X and Y position.\r\nDialogue: 0,0:07:57.82,0:07:59.70,yin,,0,0,0,,在绘制范围内\\N{\\fs12}Okay? In the drawing world.\r\nDialogue: 0,0:08:00.00,0:08:02.50,yin,,0,0,0,,还有一个结构体叫做CGSize\\N{\\fs12}And there's CGSize which is just a struct\r\nDialogue: 0,0:08:02.51,0:08:05.46,yin,,0,0,0,,包含宽度和高度 也都是CGFloat\\N{\\fs12}with width and height which are both CGFloats also.\r\nDialogue: 0,0:08:05.47,0:08:07.56,yin,,0,0,0,,指定了宽度和高度\\N{\\fs12}And that's just specifying a width and height.\r\nDialogue: 0,0:08:07.79,0:08:09.21,yin,,0,0,0,,还有CGRect\\N{\\fs12}And then there's CGRect\r\nDialogue: 0,0:08:09.32,0:08:13.39,yin,,0,0,0,,这个C结构体包含了另外两个CG结构体\\N{\\fs12}which is c-struct with those other two CG structs in them.\r\nDialogue: 0,0:08:13.40,0:08:14.65,yin,,0,0,0,,CGPoint和CGSize\\N{\\fs12}CGPoint and CGSize.\r\nDialogue: 0,0:08:14.65,0:08:16.56,yin,,0,0,0,,指定了一个矩形的原点\\N{\\fs12}That specifies an origin\r\nDialogue: 0,0:08:16.75,0:08:18.68,yin,,0,0,0,,以及宽度和高度\\N{\\fs12}and a width and height for a rectangle.\r\nDialogue: 0,0:08:18.94,0:08:20.35,yin,,0,0,0,,大家要知道这四个结构体\\N{\\fs12}Okay? So you've got to know these four.\r\nDialogue: 0,0:08:20.49,0:08:22.30,yin,,0,0,0,,当我们在屏幕上进行绘制时\\N{\\fs12}I'm going to refer these left, right and center\r\nDialogue: 0,0:08:22.37,0:08:23.65,yin,,0,0,0,,我会用到左 右 中间\\N{\\fs12}whenever we're drawing on screen,\r\nDialogue: 0,0:08:23.68,0:08:24.71,yin,,0,0,0,,说的就是这些结构体\\N{\\fs12}this is what we're talking about.\r\nDialogue: 0,0:08:25.70,0:08:29.08,yin,,0,0,0,,绘制或处理事件所用的视图坐标系中\\N{\\fs12}Okay? The origin of a views coordinate system\r\nDialogue: 0,0:08:29.09,0:08:32.80,yin,,0,0,0,,原点是左上角\\N{\\fs12}for drawing or for handling events is upper left.\r\nDialogue: 0,0:08:33.11,0:08:33.98,yin,,0,0,0,,不是左下角\\N{\\fs12}Now lower left.\r\nDialogue: 0,0:08:34.00,0:08:35.59,yin,,0,0,0,,与笛卡儿坐标系不同\\N{\\fs12}Not like Cartesian coordinates. Okay?\r\nDialogue: 0,0:08:35.61,0:08:38.26,yin,,0,0,0,,这里是从左上角开始绘制\\N{\\fs12}This is drawing from the upper left.\r\nDialogue: 0,0:08:38.27,0:08:41.28,yin,,0,0,0,,所以Y值越大 屏幕上的位置越靠下\\N{\\fs12}So positive Y values are down the screen.\r\nDialogue: 0,0:08:42.02,0:08:45.84,yin,,0,0,0,,大家可以看到 我在那里放的那个点是(400,35)\\N{\\fs12}Okay? So you can see I put that point up there 400,35.\r\nDialogue: 0,0:08:45.84,0:08:50.05,yin,,0,0,0,,就是X和Y轴的值 X是向右400\\N{\\fs12}That's X and Y. X is 400 way over to the right\r\nDialogue: 0,0:08:50.33,0:08:52.71,yin,,0,0,0,,Y是正数35\\N{\\fs12}and 35 is Y and positive\r\nDialogue: 0,0:08:52.72,0:08:55.79,yin,,0,0,0,,所以是从左上角原点向下\\N{\\fs12}so it's down from that origin on the upper left. Okay?\r\nDialogue: 0,0:08:56.94,0:09:01.18,yin,,0,0,0,,绘制的单位都是点 而非像素点\\N{\\fs12}The units in all this drawing are points, not pixels.\r\nDialogue: 0,0:09:01.85,0:09:05.05,yin,,0,0,0,,原因可能大家已经明白了\\N{\\fs12}Okay? Probably you already understand why this is，\r\nDialogue: 0,0:09:05.06,0:09:07.89,yin,,0,0,0,,因为有些设备的像素很高\\N{\\fs12}because some devices have lots of pixels.\r\nDialogue: 0,0:09:07.90,0:09:10.79,yin,,0,0,0,,像素点排列非常密集\\N{\\fs12}Right? I mean it's very high density pixeled\r\nDialogue: 0,0:09:10.79,0:09:12.05,yin,,0,0,0,,比如Retina显示屏\\N{\\fs12}like these retina displays.\r\nDialogue: 0,0:09:12.24,0:09:15.67,yin,,0,0,0,,而有些设备 比如iPad和旧款的iPhone\\N{\\fs12}Other ones like some of the iPads, older iPhones,\r\nDialogue: 0,0:09:15.96,0:09:18.19,yin,,0,0,0,,它们的像素点没有那么多和密集\\N{\\fs12}they don't have as many-- they're not as dense of pixels.\r\nDialogue: 0,0:09:18.20,0:09:21.19,yin,,0,0,0,,如果不用点来作为单位 而是用像素点\\N{\\fs12}Well if we didn't use points, if we used pixels\r\nDialogue: 0,0:09:21.20,0:09:23.53,yin,,0,0,0,,那么像素点小的时候\\N{\\fs12}then things we drew would be really small\r\nDialogue: 0,0:09:23.54,0:09:24.55,yin,,0,0,0,,我们绘制的内容就会很小\\N{\\fs12}if the pixels were small\r\nDialogue: 0,0:09:24.56,0:09:25.98,yin,,0,0,0,,如果像素点大 绘制的内容就会很大\\N{\\fs12}and really big if the pixels were big.\r\nDialogue: 0,0:09:25.99,0:09:28.66,yin,,0,0,0,,所以我们简化一下 使用点来作为绘制单位\\N{\\fs12}So we abstract that away by using points.\r\nDialogue: 0,0:09:28.82,0:09:31.95,yin,,0,0,0,,要知道你的视图所在的显示器上\\N{\\fs12}Okay? How many pixels per point are\r\nDialogue: 0,0:09:31.96,0:09:33.84,yin,,0,0,0,,每个点中有多少像素点\\N{\\fs12}on the display that your view is in.\r\nDialogue: 0,0:09:33.92,0:09:37.13,yin,,0,0,0,,可以通过UIView的这个属性\\N{\\fs12}You can find out by using this UIView property\r\nDialogue: 0,0:09:37.14,0:09:38.41,yin,,0,0,0,,contentScaleFactor来获得\\N{\\fs12}contentScaleFactor.\r\nDialogue: 0,0:09:38.42,0:09:40.92,yin,,0,0,0,,如果是Retina显示屏 返回值为2\\N{\\fs12}So it returned two for example on a retina display\r\nDialogue: 0,0:09:40.93,0:09:43.18,yin,,0,0,0,,因为Retina显示屏上每点包括两个像素点\\N{\\fs12}because there are two pixels per point on a retina display.\r\nDialogue: 0,0:09:43.19,0:09:46.23,yin,,0,0,0,,而在非Retina屏的iPad上则返回1\\N{\\fs12}One on a non-retina iPad for example.\r\nDialogue: 0,0:09:48.38,0:09:50.87,yin,,0,0,0,,在我们这门课上 这个学期中\\N{\\fs12}You know, probably not going to need to use that property\r\nDialogue: 0,0:09:50.87,0:09:52.50,yin,,0,0,0,,我们可能用不到这个属性\\N{\\fs12}in this class, this quarter.\r\nDialogue: 0,0:09:52.71,0:09:54.27,yin,,0,0,0,,上个学期我们用到了它\\N{\\fs12}Previous quarter we played around with it,\r\nDialogue: 0,0:09:54.28,0:09:55.00,yin,,0,0,0,,但是这个学期不需要了\\N{\\fs12}but not this quarter.\r\nDialogue: 0,0:09:55.78,0:09:57.74,yin,,0,0,0,,更重要的是 这些属性\\N{\\fs12}But more importantly, there are these properties\r\nDialogue: 0,0:09:57.75,0:10:02.56,yin,,0,0,0,,说明了绘制系统的位置和范围\\N{\\fs12}that talk about the position and extent of your drawing system.\r\nDialogue: 0,0:10:02.72,0:10:03.05,yin,,0,0,0,,明白吗\\N{\\fs12}Okay?\r\nDialogue: 0,0:10:03.26,0:10:04.97,yin,,0,0,0,,理解这些属性间的不同\\N{\\fs12}It's really important to understand the difference\r\nDialogue: 0,0:10:04.98,0:10:06.13,yin,,0,0,0,,是非常重要的\\N{\\fs12}between these properties.\r\nDialogue: 0,0:10:06.42,0:10:09.32,yin,,0,0,0,,首先是这个CGRect属性bounds\\N{\\fs12}First you have this CGRect property bounds.\r\nDialogue: 0,0:10:09.60,0:10:13.99,yin,,0,0,0,,这是你的坐标系中绘制区域的原点\\N{\\fs12}That is the origin and width and height of the drawing area\r\nDialogue: 0,0:10:14.20,0:10:16.02,yin,,0,0,0,,以及宽度和高度\\N{\\fs12}in your own coordinate system.\r\nDialogue: 0,0:10:17.05,0:10:18.08,yin,,0,0,0,,你自己的坐标系\\N{\\fs12}Your own coordinate system.\r\nDialogue: 0,0:10:18.08,0:10:21.06,yin,,0,0,0,,在其中绘制和处理触控事件\\N{\\fs12}A system you are drawing in and handling touch events in.\r\nDialogue: 0,0:10:21.34,0:10:24.93,yin,,0,0,0,,底下的CGRect frame\\N{\\fs12}Okay? CGRect frame at the bottom there,\r\nDialogue: 0,0:10:25.21,0:10:28.88,yin,,0,0,0,,指的是你的父视图坐标系中的一个矩形\\N{\\fs12}that is a rectangle that completely contains you\r\nDialogue: 0,0:10:29.01,0:10:30.88,yin,,0,0,0,,这个矩形完全包含了你的绘制区域\\N{\\fs12}in your superview's coordinate system.\r\nDialogue: 0,0:10:31.61,0:10:33.47,yin,,0,0,0,,可以看到它是如何定位你的\\N{\\fs12}So you can see how that positions you.\r\nDialogue: 0,0:10:33.85,0:10:35.87,yin,,0,0,0,,因为它在你的父视图坐标系中\\N{\\fs12}Right? Because that's in your superview's coordinate system.\r\nDialogue: 0,0:10:35.87,0:10:37.06,yin,,0,0,0,,也就是你所在的位置\\N{\\fs12}That's where you are.\r\nDialogue: 0,0:10:37.45,0:10:40.40,yin,,0,0,0,,center代表你在父视图坐标系中\\N{\\fs12}Okay? Center is just the center of where you are\r\nDialogue: 0,0:10:40.59,0:10:42.18,yin,,0,0,0,,所在位置的中心\\N{\\fs12}in your superview's coordinate system.\r\nDialogue: 0,0:10:42.21,0:10:44.37,yin,,0,0,0,,没有属性能够得到\\N{\\fs12}There's no property to get your center\r\nDialogue: 0,0:10:44.38,0:10:45.50,yin,,0,0,0,,你在自己的坐标系中的中心位置\\N{\\fs12}in your own coordinate system.\r\nDialogue: 0,0:10:45.50,0:10:46.71,yin,,0,0,0,,只要得到bounds\\N{\\fs12}You just take your bounds out\r\nDialogue: 0,0:10:46.71,0:10:48.71,yin,,0,0,0,,宽度和高度分别除以二\\N{\\fs12}width divide it by two and height divide it by two\r\nDialogue: 0,0:10:48.71,0:10:49.98,yin,,0,0,0,,就可以得到中心位置了\\N{\\fs12}and boom you're in the middle.\r\nDialogue: 0,0:10:50.53,0:10:53.55,yin,,0,0,0,,你可能会认为frame和bounds\\N{\\fs12}Okay? Now you might think frame and bounds\r\nDialogue: 0,0:10:53.56,0:10:55.37,yin,,0,0,0,,是完全一样的\\N{\\fs12}are going to be exactly the same,\r\nDialogue: 0,0:10:55.39,0:10:57.37,yin,,0,0,0,,除了一点不同\\N{\\fs12}except for that the frame is going to be\r\nDialogue: 0,0:10:57.38,0:10:58.71,yin,,0,0,0,,frame是在父视图坐标系中的\\N{\\fs12}in the superview's coordinate system,\r\nDialogue: 0,0:10:58.71,0:11:00.09,yin,,0,0,0,,所以二者的原点可能不同\\N{\\fs12}so the origins might be different.\r\nDialogue: 0,0:11:00.29,0:11:01.24,yin,,0,0,0,,但并不是这样的\\N{\\fs12}But that's not true.\r\nDialogue: 0,0:11:01.37,0:11:05.51,yin,,0,0,0,,因为视图可以旋转\\N{\\fs12}Okay? And the reason for that is that views can be rotated.\r\nDialogue: 0,0:11:06.39,0:11:09.86,yin,,0,0,0,,视图旋转后 可以看到\\N{\\fs12}Okay? And if a view is rotated you can see that\r\nDialogue: 0,0:11:09.86,0:11:12.62,yin,,0,0,0,,包含它的那个矩形会变大很多\\N{\\fs12}the rectangle that contains it might be much bigger.\r\nDialogue: 0,0:11:13.04,0:11:15.61,yin,,0,0,0,,因为要包含的是一个菱形\\N{\\fs12}Right? Because it's a diamond shape that it has to contain.\r\nDialogue: 0,0:11:16.44,0:11:19.80,yin,,0,0,0,,幻灯片中这里还有些具体数据\\N{\\fs12}Okay? So there's details on here in this slide.\r\nDialogue: 0,0:11:19.80,0:11:21.03,yin,,0,0,0,,大家有空可以看一下\\N{\\fs12}You can look at them at your leisure,\r\nDialogue: 0,0:11:21.04,0:11:22.74,yin,,0,0,0,,但是至少要理解\\N{\\fs12}but bottom line is understand\r\nDialogue: 0,0:11:22.74,0:11:25.15,yin,,0,0,0,,frame是在你的父视图坐标系中\\N{\\fs12}that frame is a rectangle containing you\r\nDialogue: 0,0:11:25.17,0:11:26.71,yin,,0,0,0,,包含你的一个矩形\\N{\\fs12}in your superview's coordinate system,\r\nDialogue: 0,0:11:26.90,0:11:29.97,yin,,0,0,0,,bounds是你在自己的视图中\\N{\\fs12}bounds is the rectangle you use to draw\r\nDialogue: 0,0:11:29.98,0:11:32.43,yin,,0,0,0,,用自己的代码进行绘制时使用的矩形\\N{\\fs12}when you're drawing in your own code in your view.\r\nDialogue: 0,0:11:32.54,0:11:33.57,yin,,0,0,0,,是在你自己的坐标系中\\N{\\fs12}It's your coordinate system.\r\nDialogue: 0,0:11:33.71,0:11:34.01,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,0:11:34.34,0:11:37.95,yin,,0,0,0,,bounds的原点何时不为(0,0)呢\\N{\\fs12}When would the origins of bounds not be zero zero?\r\nDialogue: 0,0:11:38.27,0:11:40.47,yin,,0,0,0,,bounds的原点什么时候不是(0,0)呢\\N{\\fs12}When did the origins of bounds not be zero zero?\r\nDialogue: 0,0:11:40.47,0:11:41.67,yin,,0,0,0,,非常棒的问题\\N{\\fs12}That's an excellent question.\r\nDialogue: 0,0:11:41.75,0:11:43.05,yin,,0,0,0,,因为是你自己的坐标系\\N{\\fs12}The origin of the bounds,\r\nDialogue: 0,0:11:43.05,0:11:44.69,yin,,0,0,0,,所以bounds的原点\\N{\\fs12}since it's your own coordinate system\r\nDialogue: 0,0:11:44.70,0:11:46.47,yin,,0,0,0,,取决于你的解释\\N{\\fs12}is up to your own interpretation.\r\nDialogue: 0,0:11:46.95,0:11:50.11,yin,,0,0,0,,比如滚动视图中的原点\\N{\\fs12}So for example scroll view uses the origin to say\r\nDialogue: 0,0:11:50.11,0:11:52.93,yin,,0,0,0,,代表滚动目标的位置\\N{\\fs12}where am I looking in the thing I'm scrolling on?\r\nDialogue: 0,0:11:53.09,0:11:54.95,yin,,0,0,0,,它就是这样定义原点的\\N{\\fs12}That's just the way it defines origin.\r\nDialogue: 0,0:11:55.14,0:11:58.24,yin,,0,0,0,,你可以根据需要 定义原点的含义\\N{\\fs12}You can define what you want origin to mean.\r\nDialogue: 0,0:11:58.53,0:12:01.00,yin,,0,0,0,,因为要求你进行绘制\\N{\\fs12}Okay? Because you're going to be asked to draw\r\nDialogue: 0,0:12:01.01,0:12:02.60,yin,,0,0,0,,而你知道自己的坐标系\\N{\\fs12}and you know your own coordinate systems.\r\nDialogue: 0,0:12:02.60,0:12:04.92,yin,,0,0,0,,无论要求你绘制什么 你都要绘制出来\\N{\\fs12}You're gonna draw whatever you're asked to draw.\r\nDialogue: 0,0:12:05.31,0:12:06.44,yin,,0,0,0,,所以基本取决于你\\N{\\fs12}So it's kind of up to you.\r\nDialogue: 0,0:12:06.45,0:12:09.04,yin,,0,0,0,,99%的情况下 原点都是(0,0)\\N{\\fs12}99% of the time, your origin is zero zero.\r\nDialogue: 0,0:12:09.21,0:12:10.55,yin,,0,0,0,,因为它对你来说没有什么意义\\N{\\fs12}Because it doesn't mean anything for you.\r\nDialogue: 0,0:12:10.55,0:12:12.03,yin,,0,0,0,,宽度和高度才是重要的\\N{\\fs12}It's just the width and height that matter.\r\nDialogue: 0,0:12:12.16,0:12:13.19,yin,,0,0,0,,这个问题非常好\\N{\\fs12}But that's a great question.\r\nDialogue: 0,0:12:14.18,0:12:18.11,yin,,0,0,0,,大家可以再看看幻灯片 获取细节内容\\N{\\fs12}Okay? So again, you can look at the slide for more detail\r\nDialogue: 0,0:12:18.11,0:12:20.23,yin,,0,0,0,,但是一定要理解frame和bounds\\N{\\fs12}but frame and bounds just make sure you understand that.\r\nDialogue: 0,0:12:21.64,0:12:25.16,yin,,0,0,0,,创建视图的方法\\N{\\fs12}So most often you create views\r\nDialogue: 0,0:12:25.17,0:12:27.36,yin,,0,0,0,,通常是从Xcode的面板中拖出\\N{\\fs12}by dragging them out of the palette in Xcode\r\nDialogue: 0,0:12:27.37,0:12:29.45,yin,,0,0,0,,方法和拖出标签\\N{\\fs12}and that's like when you're dragging out labels,\r\nDialogue: 0,0:12:29.47,0:12:32.14,yin,,0,0,0,,按钮 滚动视图和文本视图一样\\N{\\fs12}and buttons, and scroll views, and text views.\r\nDialogue: 0,0:12:32.14,0:12:33.10,yin,,0,0,0,,它们都是视图\\N{\\fs12}Those are all views.\r\nDialogue: 0,0:12:33.10,0:12:34.56,yin,,0,0,0,,直接拖出它们就可以进行创建\\N{\\fs12}So you just create them by dragging out\r\nDialogue: 0,0:12:34.65,0:12:37.49,yin,,0,0,0,,甚至还可以拖出你的自定义视图\\N{\\fs12}and you could even drag out your own custom views.\r\nDialogue: 0,0:12:37.50,0:12:40.65,yin,,0,0,0,,但是方法是先拖出一个通用视图\\N{\\fs12}But the way you do that is you drag out a generic view,\r\nDialogue: 0,0:12:40.79,0:12:44.06,yin,,0,0,0,,然后转到标识符检查器 修改它的类\\N{\\fs12}and then go to the identity inspector and change its class.\r\nDialogue: 0,0:12:44.07,0:12:46.99,yin,,0,0,0,,和拖出视图控制器的方法一样\\N{\\fs12}Exactly like how we drag out a view controller.\r\nDialogue: 0,0:12:47.11,0:12:50.35,yin,,0,0,0,,我们需要把它的类修改为某个自定义类\\N{\\fs12}We have to go change its class to be one of our custom classes. Right?\r\nDialogue: 0,0:12:50.49,0:12:53.46,yin,,0,0,0,,因为Xcode显然不知道我们的自定义类\\N{\\fs12}Because Xcode obviously doesn't know our custom classes.\r\nDialogue: 0,0:12:53.73,0:12:56.05,yin,,0,0,0,,至少在storyboard中运行时\\N{\\fs12}At least doesn't know in the kind of runtime way\r\nDialogue: 0,0:12:56.06,0:12:57.40,yin,,0,0,0,,它不知道\\N{\\fs12}that's happening in the storyboard,\r\nDialogue: 0,0:12:57.77,0:12:59.34,yin,,0,0,0,,所以我们需要手动设置\\N{\\fs12}so we have to set the things.\r\nDialogue: 0,0:12:59.35,0:13:02.05,yin,,0,0,0,,和设置视图控制器是完全一样的\\N{\\fs12}It works exactly the same as setting view controllers.\r\nDialogue: 0,0:13:03.53,0:13:04.85,yin,,0,0,0,,在代码中创建视图\\N{\\fs12}Creating a view in code,\r\nDialogue: 0,0:13:04.85,0:13:07.62,yin,,0,0,0,,也就是说不直接将其拖至storyboard中\\N{\\fs12}in other words not dragging it in to a storyboard.\r\nDialogue: 0,0:13:07.63,0:13:10.42,yin,,0,0,0,,可以直接用alloc/initWithFrame 或者alloc/init\\N{\\fs12}You just use alloc and initWithFrame or just alloc and init.\r\nDialogue: 0,0:13:10.44,0:13:11.63,yin,,0,0,0,,如果用alloc/init\\N{\\fs12}It you do alloc and init,\r\nDialogue: 0,0:13:11.67,0:13:15.32,yin,,0,0,0,,等同于alloc initWithFrame: CGRectZero\\N{\\fs12}that's the same as alloc and initWithFrame CGRectZero,\r\nDialogue: 0,0:13:15.33,0:13:17.13,yin,,0,0,0,,CGRectZero是一个原点为0\\N{\\fs12}which is a rectangle with origin zero,\r\nDialogue: 0,0:13:17.24,0:13:19.56,yin,,0,0,0,,宽度和高度为0的矩形\\N{\\fs12}width and height of zero. Okay?\r\nDialogue: 0,0:13:20.03,0:13:21.30,yin,,0,0,0,,可以任选其一\\N{\\fs12}So you can do either one.\r\nDialogue: 0,0:13:21.41,0:13:22.72,yin,,0,0,0,,如果要用alloc/init\\N{\\fs12}If you do alloc and init\r\nDialogue: 0,0:13:23.20,0:13:25.88,yin,,0,0,0,,最好为frame赋值\\N{\\fs12}presumably you better set the frame to something\r\nDialogue: 0,0:13:25.89,0:13:27.19,yin,,0,0,0,,这样当它被放入父视图中时\\N{\\fs12}so that it knows where to be\r\nDialogue: 0,0:13:27.20,0:13:29.32,yin,,0,0,0,,才能知道自己要出现在哪里\\N{\\fs12}when it's put into its superview.\r\nDialogue: 0,0:13:31.31,0:13:34.56,yin,,0,0,0,,这个示例是用代码创建UILabel\\N{\\fs12}So here's an example of creating a UILabel in code.\r\nDialogue: 0,0:13:34.71,0:13:36.94,yin,,0,0,0,,我这里用的是UILabel initWithFrame\\N{\\fs12}You see I said UILabel initWithFrame.\r\nDialogue: 0,0:13:36.96,0:13:38.67,yin,,0,0,0,,我向它传递了一个矩形\\N{\\fs12}I gave it a rectangle.\r\nDialogue: 0,0:13:38.67,0:13:40.56,yin,,0,0,0,,是在父视图坐标系中的\\N{\\fs12}That's in the superview coordinate system.\r\nDialogue: 0,0:13:40.77,0:13:44.70,yin,,0,0,0,,然后我用addSubview将那个标签添加为self.view的子视图\\N{\\fs12}And then I addSubview that label to self.view\r\nDialogue: 0,0:13:44.71,0:13:47.39,yin,,0,0,0,,self.view是我的视图控制器中的顶级视图\\N{\\fs12}which is that top level view in my view controller.\r\nDialogue: 0,0:13:47.52,0:13:51.02,yin,,0,0,0,,所以在我的MVC视图中 它显示在(20,20)的位置\\N{\\fs12}And so it ended up at 20, 20, 20 X and 20 Y,\r\nDialogue: 0,0:13:51.03,0:13:56.97,yin,,0,0,0,,宽度为50 高度为30\\N{\\fs12}and its 50 wide and 30 high in my MVC's view. Right?\r\nDialogue: 0,0:13:57.63,0:14:00.03,yin,,0,0,0,,你可能不会这样创建标签\\N{\\fs12}Now you probably wouldn't ever create a label like this\r\nDialogue: 0,0:14:00.04,0:14:00.92,yin,,0,0,0,,因为可以直接拖出标签\\N{\\fs12}because you drag them out.\r\nDialogue: 0,0:14:00.95,0:14:04.07,yin,,0,0,0,,但是你可能会这样创建自己的自定义视图\\N{\\fs12}But you might create your own custom view like this. Right?\r\nDialogue: 0,0:14:05.76,0:14:09.12,yin,,0,0,0,,什么时候需要创建自定义视图呢\\N{\\fs12}Okay, so when do I want to create my own custom views?\r\nDialogue: 0,0:14:09.17,0:14:11.15,yin,,0,0,0,,显然是当我想绘制一些自定义内容的时候\\N{\\fs12}Obviously, when I want to draw something custom.\r\nDialogue: 0,0:14:11.15,0:14:13.54,yin,,0,0,0,,按钮或标签无法绘制出的内容\\N{\\fs12}Not something that a button or a label can draw for me.\r\nDialogue: 0,0:14:13.72,0:14:16.20,yin,,0,0,0,,或者是当我要处理特殊触控事件时\\N{\\fs12}Or when I want to handle special touch events.\r\nDialogue: 0,0:14:16.26,0:14:18.29,yin,,0,0,0,,滑动 捏合之类的\\N{\\fs12}Swipes, or pinches, or something like that.\r\nDialogue: 0,0:14:19.14,0:14:21.42,yin,,0,0,0,,我们先介绍绘制部分\\N{\\fs12}So the drawing side of this which we'll talk about first\r\nDialogue: 0,0:14:21.43,0:14:22.52,yin,,0,0,0,,这部分非常简单\\N{\\fs12}is really easy.\r\nDialogue: 0,0:14:22.71,0:14:26.09,yin,,0,0,0,,UIView中有一个方法叫做drawRect\\N{\\fs12}There's one method in UIView called drawRect\r\nDialogue: 0,0:14:26.30,0:14:29.75,yin,,0,0,0,,你只要实现这个方法\\N{\\fs12}and all you have to do is implement that method\r\nDialogue: 0,0:14:29.95,0:14:31.08,yin,,0,0,0,,就可以绘制想要的内容\\N{\\fs12}to draw what you want.\r\nDialogue: 0,0:14:31.43,0:14:32.72,yin,,0,0,0,,只要这一个方法就够了\\N{\\fs12}Okay? One method, that's it.\r\nDialogue: 0,0:14:33.33,0:14:34.97,yin,,0,0,0,,实现这个方法来绘制想要的内容\\N{\\fs12}Implement this method to draw what you want.\r\nDialogue: 0,0:14:35.13,0:14:36.86,yin,,0,0,0,,它有一个参数\\N{\\fs12}Now it has that argument there,\r\nDialogue: 0,0:14:36.96,0:14:38.65,yin,,0,0,0,,是一项性能优化\\N{\\fs12}that's a performance optimization.\r\nDialogue: 0,0:14:39.23,0:14:41.22,yin,,0,0,0,,代表一个矩形说\\N{\\fs12}That's basically a rectangle that says,\r\nDialogue: 0,0:14:41.33,0:14:44.89,yin,,0,0,0,,你绘制吧 但是我只需要坐标系中\\N{\\fs12}well, please draw yourself but really I only need the stuff\r\nDialogue: 0,0:14:44.90,0:14:47.20,yin,,0,0,0,,这个矩形范围内的内容\\N{\\fs12}that's in the rectangle in your coordinate system.\r\nDialogue: 0,0:14:47.45,0:14:48.84,yin,,0,0,0,,但如果你不想管这个矩形\\N{\\fs12}But if you want to ignore this rectangle\r\nDialogue: 0,0:14:48.85,0:14:50.95,yin,,0,0,0,,想随意绘制 我觉得没问题\\N{\\fs12}and draw all over yourself, that's fine by me.\r\nDialogue: 0,0:14:51.17,0:14:53.17,yin,,0,0,0,,它只是为了优化性能\\N{\\fs12}Okay? So it's purely performance thing.\r\nDialogue: 0,0:14:53.29,0:14:55.42,yin,,0,0,0,,对于某些视图 只考虑这个矩形是有意义的\\N{\\fs12}Some views it'll make sense to look at that rectangle\r\nDialogue: 0,0:14:55.42,0:14:56.57,yin,,0,0,0,,会非常有效率\\N{\\fs12}and be really efficient.\r\nDialogue: 0,0:14:56.84,0:14:59.29,yin,,0,0,0,,几年前 这门课布置过一个作业\\N{\\fs12}Like we had an assignment a couple years ago in this class\r\nDialogue: 0,0:14:59.29,0:15:00.71,yin,,0,0,0,,需要绘制一条曲线\\N{\\fs12}where you're drawing a graph.\r\nDialogue: 0,0:15:00.87,0:15:01.91,yin,,0,0,0,,如果你是在绘制曲线\\N{\\fs12}Well, if you're drawing a graph\r\nDialogue: 0,0:15:01.93,0:15:03.36,yin,,0,0,0,,需要计算每一个点\\N{\\fs12}and you're having to calculate every point\r\nDialogue: 0,0:15:03.39,0:15:05.34,yin,,0,0,0,,如果只需要计算曲线某一段上的点\\N{\\fs12}it's kind of nice to only have to calculate the points\r\nDialogue: 0,0:15:05.36,0:15:06.49,yin,,0,0,0,,而不是每次都绘制全部曲线\\N{\\fs12}in some part of the graph\r\nDialogue: 0,0:15:06.52,0:15:07.95,yin,,0,0,0,,是很好的\\N{\\fs12}instead of drawing the whole thing every time.\r\nDialogue: 0,0:15:08.22,0:15:09.85,yin,,0,0,0,,但是如果你要绘制的是扑克牌\\N{\\fs12}But if you're drawing a playing card,\r\nDialogue: 0,0:15:10.19,0:15:11.98,yin,,0,0,0,,只需要很少的资源\\N{\\fs12}it's so light weight to draw it,\r\nDialogue: 0,0:15:11.99,0:15:13.21,yin,,0,0,0,,可以全部都绘制出来\\N{\\fs12}so you can just draw all the parts of it.\r\nDialogue: 0,0:15:13.21,0:15:14.82,yin,,0,0,0,,不需要使用这个矩形\\N{\\fs12}You don't have to use the rectangle.\r\nDialogue: 0,0:15:15.20,0:15:17.01,yin,,0,0,0,,如果在矩形外面绘制\\N{\\fs12}If you draw outside of the rectangle\r\nDialogue: 0,0:15:17.03,0:15:18.28,yin,,0,0,0,,会显示出来吗\\N{\\fs12}does that stuff show up?\r\nDialogue: 0,0:15:18.53,0:15:20.21,yin,,0,0,0,,问题是 如果在矩形外面绘制\\N{\\fs12}The question is if you draw outside the rectangle\r\nDialogue: 0,0:15:20.21,0:15:20.99,yin,,0,0,0,,会显示出来吗\\N{\\fs12}does that show up?\r\nDialogue: 0,0:15:21.48,0:15:24.38,yin,,0,0,0,,记住 所有绘制内容都会显示出来\\N{\\fs12}Remember that everything you draw shows up\r\nDialogue: 0,0:15:24.51,0:15:26.71,yin,,0,0,0,,除非用了之前讲到的裁剪\\N{\\fs12}unless you have one of these clipping things I talked about\r\nDialogue: 0,0:15:26.72,0:15:28.99,yin,,0,0,0,,父视图对你进行了裁剪\\N{\\fs12}where your superview is clipping you\r\nDialogue: 0,0:15:29.00,0:15:31.80,yin,,0,0,0,,或者绘制的一部分是裁剪矩形\\N{\\fs12}or you have a clip rect as part of what you draw.\r\nDialogue: 0,0:15:32.05,0:15:34.91,yin,,0,0,0,,答案是 这个矩形和裁剪毫无关系\\N{\\fs12}So the answer is that rectangle has nothing to do with clipping.\r\nDialogue: 0,0:15:35.85,0:15:38.65,yin,,0,0,0,,无论这个矩形是什么\\N{\\fs12}Okay? No matter what that rectangle is,\r\nDialogue: 0,0:15:39.15,0:15:40.90,yin,,0,0,0,,是否裁剪都是不受影响的\\N{\\fs12}clipping or not is unaffected.\r\nDialogue: 0,0:15:41.45,0:15:42.43,yin,,0,0,0,,只是为了性能优化\\N{\\fs12}It's purely performance--\r\nDialogue: 0,0:15:42.45,0:15:44.59,yin,,0,0,0,,提示你什么内容需要重新绘制\\N{\\fs12}giving you a hint of what needs to be redrawn.\r\nDialogue: 0,0:15:44.84,0:15:45.51,yin,,0,0,0,,就是这样\\N{\\fs12}That's all it is.\r\nDialogue: 0,0:15:45.98,0:15:49.90,yin,,0,0,0,,非常重要的一点是 绝不要调用drawRect\\N{\\fs12}So really important, never call drawRect.\r\nDialogue: 0,0:15:49.91,0:15:52.02,yin,,0,0,0,,如果你在作业中调用了drawRect\\N{\\fs12}If you called drawRect in a homework assignment in this class\r\nDialogue: 0,0:15:52.03,0:15:53.34,yin,,0,0,0,,就等着挨批吧\\N{\\fs12}you are going to get dinged.\r\nDialogue: 0,0:15:53.40,0:15:56.05,yin,,0,0,0,,因为我在这里用红色字体写了 绝对不要\\N{\\fs12}Because I'm putting it in red, never red.\r\nDialogue: 0,0:15:56.26,0:15:58.38,yin,,0,0,0,,绝对不要调用drawRect\\N{\\fs12}And I'm telling you don't ever call drawRect.\r\nDialogue: 0,0:15:58.41,0:16:00.56,yin,,0,0,0,,drawRect是由系统来调用的\\N{\\fs12}DrawRect is for the system to call.\r\nDialogue: 0,0:16:00.72,0:16:03.43,yin,,0,0,0,,如果你想要重绘视图\\N{\\fs12}Okay? If you want your view redrawn\r\nDialogue: 0,0:16:03.57,0:16:05.98,yin,,0,0,0,,就调用setNeedsDisplay\\N{\\fs12}you call the method setNeedsDisplay.\r\nDialogue: 0,0:16:06.48,0:16:09.57,yin,,0,0,0,,它会告诉系统 这个视图需要被重绘\\N{\\fs12}That tells the system this view needs to be redrawn,\r\nDialogue: 0,0:16:10.02,0:16:11.82,yin,,0,0,0,,然后系统会在合适的时间\\N{\\fs12}and then the system will call drawRect\r\nDialogue: 0,0:16:11.82,0:16:13.24,yin,,0,0,0,,调用drawRect\\N{\\fs12}at an appropriate time.\r\nDialogue: 0,0:16:13.59,0:16:16.04,yin,,0,0,0,,系统知道在什么时间\\N{\\fs12}Okay? The system knows when it's an appropriate time\r\nDialogue: 0,0:16:16.29,0:16:19.29,yin,,0,0,0,,调用drawRect 更新屏外缓冲器\\N{\\fs12}to call drawRect, update offscreen buffers,\r\nDialogue: 0,0:16:19.31,0:16:21.31,yin,,0,0,0,,完成全部所需操作\\N{\\fs12}whatever the heck it has to do.\r\nDialogue: 0,0:16:21.52,0:16:22.73,yin,,0,0,0,,它来负责\\N{\\fs12}It's in control of that.\r\nDialogue: 0,0:16:22.94,0:16:23.95,yin,,0,0,0,,不要自己调用drawRect\\N{\\fs12}Don't ever call drawRect.\r\nDialogue: 0,0:16:23.97,0:16:26.28,yin,,0,0,0,,调用drawRect是不会起作用的\\N{\\fs12}It just will not work to call drawRect. Okay?\r\nDialogue: 0,0:16:27.48,0:16:28.57,yin,,0,0,0,,要调用setNeedsDisplay\\N{\\fs12}SetNeedsDisplay.\r\nDialogue: 0,0:16:28.64,0:16:30.09,yin,,0,0,0,,你可以调用setNeedsDisplayInRect\\N{\\fs12}And you can do setNeedsDisplayInRect,\r\nDialogue: 0,0:16:30.11,0:16:32.57,yin,,0,0,0,,传给它那个优化矩形\\N{\\fs12}that's giving the little optimization rect. Okay?\r\nDialogue: 0,0:16:32.88,0:16:35.68,yin,,0,0,0,,要调用setNeedsDisplay来实现\\N{\\fs12}But setNeedsDisplay is how you do that. Okay?\r\nDialogue: 0,0:16:38.23,0:16:40.99,yin,,0,0,0,,那么如何实现drawRect呢\\N{\\fs12}All right so, how do I implement this drawRect thing?\r\nDialogue: 0,0:16:41.23,0:16:42.39,yin,,0,0,0,,我有这个drawRect方法\\N{\\fs12}Okay, I got this drawRect method.\r\nDialogue: 0,0:16:42.39,0:16:43.75,yin,,0,0,0,,想要绘制一些内容\\N{\\fs12}I want to draw something.\r\nDialogue: 0,0:16:43.75,0:16:46.59,yin,,0,0,0,,方法是使用这个Quartz库\\N{\\fs12}Well, the answer is you use this library, the Quartz library\r\nDialogue: 0,0:16:46.59,0:16:48.21,yin,,0,0,0,,叫做Core Graphics\\N{\\fs12}that's called Core Graphics.\r\nDialogue: 0,0:16:48.70,0:16:49.81,yin,,0,0,0,,Core Graphics\\N{\\fs12}Core Graphics.\r\nDialogue: 0,0:16:50.26,0:16:51.99,yin,,0,0,0,,其中有很多C函数\\N{\\fs12}It has a ton of C functions\r\nDialogue: 0,0:16:52.00,0:16:54.21,yin,,0,0,0,,函数名以Core Graphics的缩写CG开头\\N{\\fs12}that all start with CG, Core Graphics.\r\nDialogue: 0,0:16:55.09,0:16:57.25,yin,,0,0,0,,几乎全部都以context上下文作为第一个参数\\N{\\fs12}They almost all take in context as the first argument.\r\nDialogue: 0,0:16:57.25,0:16:58.23,yin,,0,0,0,,我们会讲到的\\N{\\fs12}We'll talk about that.\r\nDialogue: 0,0:16:58.46,0:17:02.02,yin,,0,0,0,,还可以用这个类 UIBezierPath\\N{\\fs12}Or you can use this nice class called the UIBezierPath.\r\nDialogue: 0,0:17:02.26,0:17:05.90,yin,,0,0,0,,UIBezierPath可以将各种复杂形状\\N{\\fs12}UIBezierPath let's you build all these complicated shapes\r\nDialogue: 0,0:17:06.12,0:17:07.31,yin,,0,0,0,,组成一个大的路径\\N{\\fs12}into a big path,\r\nDialogue: 0,0:17:07.32,0:17:09.68,yin,,0,0,0,,然后你可以在屏幕上对其进行描边或填充\\N{\\fs12}and then you can stroke it or fill it on screen.\r\nDialogue: 0,0:17:10.39,0:17:11.94,yin,,0,0,0,,我们详细讲一下\\N{\\fs12}Okay, so let's look into these.\r\nDialogue: 0,0:17:12.69,0:17:14.50,yin,,0,0,0,,想要理解这些内容 我们需要先理解一下\\N{\\fs12}To understand these we need to understand a little bit\r\nDialogue: 0,0:17:14.51,0:17:16.44,yin,,0,0,0,,Core Graphics的工作思路\\N{\\fs12}about how Core Graphics thinks\r\nDialogue: 0,0:17:16.60,0:17:18.94,yin,,0,0,0,,它是按照下面四步进行的\\N{\\fs12}and it thinks in the following four step process.\r\nDialogue: 0,0:17:19.12,0:17:21.08,yin,,0,0,0,,你需要有一个绘制的上下文\\N{\\fs12}You got to have a context to draw in.\r\nDialogue: 0,0:17:21.85,0:17:24.99,yin,,0,0,0,,你需要创建路径 三角形 正方形\\N{\\fs12}You got to create paths: triangle, squares, whatever,\r\nDialogue: 0,0:17:24.99,0:17:26.92,yin,,0,0,0,,圆角矩形等等\\N{\\fs12}rounded rect, whatever it might be.\r\nDialogue: 0,0:17:27.21,0:17:30.57,yin,,0,0,0,,然后设置你想要的颜色 字体\\N{\\fs12}Then you set the colors and the fonts you want to use,\r\nDialogue: 0,0:17:30.57,0:17:32.37,yin,,0,0,0,,线宽等等\\N{\\fs12}and line widths and all that stuff.\r\nDialogue: 0,0:17:32.60,0:17:36.60,yin,,0,0,0,,然后对刚才创建的路径进行描边或填充\\N{\\fs12}And then you stroke or fill the paths that you created.\r\nDialogue: 0,0:17:36.92,0:17:39.37,yin,,0,0,0,,这是Core Graphics的基本流程\\N{\\fs12}This is the fundamental way Core Graphics goes.\r\nDialogue: 0,0:17:40.03,0:17:42.10,yin,,0,0,0,,我们具体讲一下这些内容\\N{\\fs12}Okay? So let's talk about all those things.\r\nDialogue: 0,0:17:42.37,0:17:44.86,yin,,0,0,0,,UIBezierPath封装了\\N{\\fs12}UIBezierPath by the way encapsulates all --\r\nDialogue: 0,0:17:44.86,0:17:46.01,yin,,0,0,0,,全部上述操作\\N{\\fs12}doing all of that.\r\nDialogue: 0,0:17:46.56,0:17:48.16,yin,,0,0,0,,帮你处理好了上下文\\N{\\fs12}It takes care of the context for you.\r\nDialogue: 0,0:17:48.16,0:17:49.79,yin,,0,0,0,,你不用费心去想它\\N{\\fs12}So you don't even have to think about that.\r\nDialogue: 0,0:17:49.87,0:17:52.49,yin,,0,0,0,,创建路径的方法就是\\N{\\fs12}You create paths by sending messages to the UA--\r\nDialogue: 0,0:17:52.49,0:17:54.62,yin,,0,0,0,,向UIBezierPath实例发送消息\\N{\\fs12}to a UIBezierPath instance.\r\nDialogue: 0,0:17:54.68,0:17:57.29,yin,,0,0,0,,它允许你设置颜色 线宽等等\\N{\\fs12}It let's you set colors and line widths and all that\r\nDialogue: 0,0:17:57.41,0:17:59.44,yin,,0,0,0,,然后调用它的方法进行描边和填充\\N{\\fs12}and then it has methods to stroke and fill.\r\nDialogue: 0,0:17:59.44,0:18:00.96,yin,,0,0,0,,它封装了全部上述机制\\N{\\fs12}So it encapsulates all that mechanism.\r\nDialogue: 0,0:18:01.36,0:18:02.69,yin,,0,0,0,,我们来讲讲上下文\\N{\\fs12}So let's talk about the context.\r\nDialogue: 0,0:18:02.85,0:18:04.53,yin,,0,0,0,,通常情况下 你不用考虑上下文\\N{\\fs12}Mostly you don't have to worry about context\r\nDialogue: 0,0:18:04.54,0:18:06.25,yin,,0,0,0,,因为要用UIBezierPath\\N{\\fs12}because you're going to use UIBezierPath.\r\nDialogue: 0,0:18:06.50,0:18:08.99,yin,,0,0,0,,我会演示一个方法 可以使用CG函数\\N{\\fs12}I'll show you a way if you're using the CG functions\r\nDialogue: 0,0:18:08.99,0:18:10.97,yin,,0,0,0,,获取在屏幕上绘制的上下文\\N{\\fs12}to get the context to draw on screen.\r\nDialogue: 0,0:18:11.12,0:18:14.77,yin,,0,0,0,,上下文代表的是绘制的位置\\N{\\fs12}But a context means where am I drawing in terms of--\r\nDialogue: 0,0:18:15.01,0:18:16.68,yin,,0,0,0,,我现在是在屏幕上绘制吗\\N{\\fs12}am I drawing on screen right now?\r\nDialogue: 0,0:18:16.74,0:18:18.83,yin,,0,0,0,,还是绘制在屏外位图上呢\\N{\\fs12}Am I drawing off screen, in some bitmap?\r\nDialogue: 0,0:18:18.92,0:18:21.83,yin,,0,0,0,,绘制的内容创建为PDF文件吗\\N{\\fs12}Am I creating a PDF file out of what I'm drawing?\r\nDialogue: 0,0:18:21.86,0:18:22.97,yin,,0,0,0,,是否绘制输出至打印机呢\\N{\\fs12}Am I drawing to a printer?\r\nDialogue: 0,0:18:22.97,0:18:24.82,yin,,0,0,0,,iOS可以很好地支持打印机操作\\N{\\fs12}iOS has great printing support\r\nDialogue: 0,0:18:24.84,0:18:27.19,yin,,0,0,0,,所以你可以将绘制的图像\\N{\\fs12}so you could be drawing to print a page\r\nDialogue: 0,0:18:27.21,0:18:29.39,yin,,0,0,0,,通过Air Print打印机之类的打印出来\\N{\\fs12}on an Air Print printer or something like that.\r\nDialogue: 0,0:18:29.55,0:18:31.01,yin,,0,0,0,,这就是context上下文\\N{\\fs12}So that's the context part of it.\r\nDialogue: 0,0:18:31.92,0:18:35.97,yin,,0,0,0,,对于一般绘制 UIKit会在调用drawRect前\\N{\\fs12}For normal drawing, UIKit sets this context up for you\r\nDialogue: 0,0:18:36.24,0:18:37.73,yin,,0,0,0,,替你设置这个上下文\\N{\\fs12}before it calls drawRect.\r\nDialogue: 0,0:18:38.35,0:18:41.30,yin,,0,0,0,,当执行drawRect时 上下文就可以使用了\\N{\\fs12}And then once you're in drawRect, context is ready to go.\r\nDialogue: 0,0:18:41.36,0:18:43.19,yin,,0,0,0,,UIBezierPath知道它是什么\\N{\\fs12}UIBezierPath knows what it is,\r\nDialogue: 0,0:18:43.38,0:18:45.45,yin,,0,0,0,,如果你想调用CG函数\\N{\\fs12}and if you want to call the CG functions\r\nDialogue: 0,0:18:45.50,0:18:49.05,yin,,0,0,0,,就调用这个方法UIGraphicsGetCurrentContext\\N{\\fs12}you call this method UIGraphicsGetCurrentContext.\r\nDialogue: 0,0:18:49.06,0:18:50.78,yin,,0,0,0,,如果在drawRect中调用这个方法\\N{\\fs12}If you call this inside your drawRect\r\nDialogue: 0,0:18:50.90,0:18:52.09,yin,,0,0,0,,你会得到一个cookie\\N{\\fs12}you'll get a little cookie\r\nDialogue: 0,0:18:52.35,0:18:54.40,yin,,0,0,0,,将它作为第一个参数\\N{\\fs12}that you can hand off as the first argument\r\nDialogue: 0,0:18:54.41,0:18:58.87,yin,,0,0,0,,传递给Core Graphic函数\\N{\\fs12}to all these CG, you know, Core Graphic functions. Okay?\r\nDialogue: 0,0:18:59.12,0:19:01.29,yin,,0,0,0,,这些CG函数并不常用\\N{\\fs12}And you're not gonna need those CG functions very much.\r\nDialogue: 0,0:19:01.29,0:19:04.31,yin,,0,0,0,,只有当UIBezierPath无法实现目标功能时才会用到\\N{\\fs12}Only when UIBezierPath won't do what you want,\r\nDialogue: 0,0:19:04.58,0:19:05.48,yin,,0,0,0,,非常少见\\N{\\fs12}which is pretty rare.\r\nDialogue: 0,0:19:06.15,0:19:07.87,yin,,0,0,0,,这是个神奇的东西\\N{\\fs12}Okay? So this is the magic thing.\r\nDialogue: 0,0:19:07.88,0:19:10.51,yin,,0,0,0,,CGContextRef是一个无类型指针\\N{\\fs12}That context ref is just a void star.\r\nDialogue: 0,0:19:10.51,0:19:11.50,yin,,0,0,0,,你不知道它是什么\\N{\\fs12}You don't know what it is.\r\nDialogue: 0,0:19:11.50,0:19:12.45,yin,,0,0,0,,它是不透明的\\N{\\fs12}It's opaque.\r\nDialogue: 0,0:19:13.43,0:19:18.39,yin,,0,0,0,,每次调用drawRect时都会新建它\\N{\\fs12}And this thing is new every time your drawRect is called,\r\nDialogue: 0,0:19:18.39,0:19:20.02,yin,,0,0,0,,所以不要一直保存着它\\N{\\fs12}so never keep that thing around.\r\nDialogue: 0,0:19:20.04,0:19:22.76,yin,,0,0,0,,它只在drawRect调用期间有效\\N{\\fs12}It's only good from the start of your drawRect to the end.\r\nDialogue: 0,0:19:22.90,0:19:25.17,yin,,0,0,0,,不要把它保存在属性等始终有效的元素内\\N{\\fs12}Don't keep it in a property or anything that's going to live.\r\nDialogue: 0,0:19:25.27,0:19:28.26,yin,,0,0,0,,每次使用drawRect时\\N{\\fs12}Okay? Call the UIGraphicsGetCurrentContext\r\nDialogue: 0,0:19:28.28,0:19:29.85,yin,,0,0,0,,调用UIGraphicsGetCurrentContext\\N{\\fs12}each time you start a drawRect.\r\nDialogue: 0,0:19:31.31,0:19:33.01,yin,,0,0,0,,如何定义路径呢\\N{\\fs12}Okay, so how do we define a path?\r\nDialogue: 0,0:19:33.02,0:19:35.99,yin,,0,0,0,,假设我们想用UIBezierPath绘制三角形\\N{\\fs12}So let's say we wanted to do a triangle with UIBezierPath.\r\nDialogue: 0,0:19:36.16,0:19:38.97,yin,,0,0,0,,我们这样对UIBezierPath进行分配和初始化\\N{\\fs12}We alloc and init UIBezierPath like this.\r\nDialogue: 0,0:19:39.15,0:19:41.36,yin,,0,0,0,,移动至起始点\\N{\\fs12}We move to where our starting point is.\r\nDialogue: 0,0:19:41.36,0:19:43.88,yin,,0,0,0,,我要移动到上面的那个点\\N{\\fs12}So I'm going to move to the top there.\r\nDialogue: 0,0:19:44.35,0:19:46.26,yin,,0,0,0,,向右75 向下10\\N{\\fs12}75 across and 10 down.\r\nDialogue: 0,0:19:46.40,0:19:49.94,yin,,0,0,0,,然后添加一条直线至下面这个点\\N{\\fs12}Then I'm going to add a line to that point\r\nDialogue: 0,0:19:50.05,0:19:52.85,yin,,0,0,0,,向右160 向下150\\N{\\fs12}going down to over to 160 down to 150.\r\nDialogue: 0,0:19:52.93,0:19:57.35,yin,,0,0,0,,再添加一条线到左边(10,150)这点\\N{\\fs12}I'll add another line to come back to 10, 150.\r\nDialogue: 0,0:19:57.46,0:20:01.30,yin,,0,0,0,,然后调用closePath方法封闭路径\\N{\\fs12}And then I'm going to close this path, by calling closePath--\r\nDialogue: 0,0:20:01.71,0:20:05.05,yin,,0,0,0,,再添加一条线回到起始点\\N{\\fs12}that goes back to where we-- draws a line where we started.\r\nDialogue: 0,0:20:05.61,0:20:07.00,yin,,0,0,0,,得到了一个好看的三角形\\N{\\fs12}So I have a nice triangle there.\r\nDialogue: 0,0:20:07.16,0:20:08.35,yin,,0,0,0,,我这样讲有点误导大家\\N{\\fs12}Now I'm kind of misleading you,\r\nDialogue: 0,0:20:08.35,0:20:11.92,yin,,0,0,0,,因为在调用UIBezierPath的这些方法时\\N{\\fs12}because as I'm making all those calls in UIBezierPath,\r\nDialogue: 0,0:20:12.02,0:20:13.40,yin,,0,0,0,,实际上什么都不会发生\\N{\\fs12}nothing is actually happening.\r\nDialogue: 0,0:20:13.64,0:20:15.29,yin,,0,0,0,,屏幕是空的\\N{\\fs12}Okay? The screen is blank.\r\nDialogue: 0,0:20:15.83,0:20:18.47,yin,,0,0,0,,我刚才的这些操作只是在UIBezierPath中\\N{\\fs12}Okay? Because all I'm doing here is building that path up\r\nDialogue: 0,0:20:18.47,0:20:19.73,yin,,0,0,0,,创建绘制路径\\N{\\fs12}in that UIBezierPath.\r\nDialogue: 0,0:20:19.75,0:20:21.18,yin,,0,0,0,,我还没有真正进行绘制\\N{\\fs12}I haven't actually draw it yet.\r\nDialogue: 0,0:20:21.45,0:20:23.07,yin,,0,0,0,,当真正要绘制时\\N{\\fs12}When I want to actually draw it\r\nDialogue: 0,0:20:23.42,0:20:26.16,yin,,0,0,0,,需要设置填充颜色和描边颜色\\N{\\fs12}I have to set my fill color and stroke color\r\nDialogue: 0,0:20:26.21,0:20:27.57,yin,,0,0,0,,方法是调用...\\N{\\fs12}and you can do that by calling--\r\nDialogue: 0,0:20:27.58,0:20:30.71,yin,,0,0,0,,向一个UIColor发送setFill和setStroke\\N{\\fs12}sending setFill and setStroke to a UIColor.\r\nDialogue: 0,0:20:31.14,0:20:34.76,yin,,0,0,0,,获取UIColor的方法和属性化字符串那里的操作一样\\N{\\fs12}Just get a UIColor like you did for attributed string, whatever.\r\nDialogue: 0,0:20:34.77,0:20:35.81,yin,,0,0,0,,一样的\\N{\\fs12}UIColor, Same thing.\r\nDialogue: 0,0:20:36.08,0:20:37.31,yin,,0,0,0,,调用setFill和setStroke\\N{\\fs12}Call setFill or setStroke.\r\nDialogue: 0,0:20:37.31,0:20:38.66,yin,,0,0,0,,甚至可以直接用set\\N{\\fs12}You can even just say set\r\nDialogue: 0,0:20:38.67,0:20:40.05,yin,,0,0,0,,它会将填充颜色和描边颜色\\N{\\fs12}and it'll set the fill and the stroke\r\nDialogue: 0,0:20:40.06,0:20:41.51,yin,,0,0,0,,都设为你选定的颜色\\N{\\fs12}to be whatever color you're sent it to.\r\nDialogue: 0,0:20:41.76,0:20:44.92,yin,,0,0,0,,设置好填充和描边颜色之后\\N{\\fs12}And once you have your color for fill and stroke set\r\nDialogue: 0,0:20:44.99,0:20:47.76,yin,,0,0,0,,向路径发送一条fill填充消息\\N{\\fs12}you send a message to the path saying fill\r\nDialogue: 0,0:20:47.95,0:20:50.05,yin,,0,0,0,,或者发送一条stroke描边消息\\N{\\fs12}and or message to the path saying stroke.\r\nDialogue: 0,0:20:50.05,0:20:51.79,yin,,0,0,0,,这时它才会真正进行绘制\\N{\\fs12}And now it will actually draw.\r\nDialogue: 0,0:20:52.04,0:20:54.25,yin,,0,0,0,,最后的fill和stroke这两个调用\\N{\\fs12}So those last two calls there, fill and stroke.\r\nDialogue: 0,0:20:54.25,0:20:55.99,yin,,0,0,0,,才是真正开始绘制\\N{\\fs12}Those are the things that cause drawing to happen.\r\nDialogue: 0,0:20:56.77,0:20:58.73,yin,,0,0,0,,之前其他操作都类似于准备工作\\N{\\fs12}Okay? Everything else is just like setup.\r\nDialogue: 0,0:20:59.79,0:21:00.35,yin,,0,0,0,,明白吗\\N{\\fs12}Make sense?\r\nDialogue: 0,0:21:01.56,0:21:04.99,yin,,0,0,0,,这些看起来好像很简单 三角形\\N{\\fs12}Okay. Now this might all seem like whoa, triangle great\r\nDialogue: 0,0:21:04.99,0:21:06.48,yin,,0,0,0,,我可以绘制一个三角形\\N{\\fs12}and I can draw a triangle.\r\nDialogue: 0,0:21:06.71,0:21:07.61,yin,,0,0,0,,听起来很容易\\N{\\fs12}Sounds easy.\r\nDialogue: 0,0:21:07.72,0:21:10.46,yin,,0,0,0,,但是实际上 UIBezierPath可以实现很多操作\\N{\\fs12}But there's actually a lot the UIBezierPath can do\r\nDialogue: 0,0:21:10.47,0:21:12.76,yin,,0,0,0,,比这复杂得多\\N{\\fs12}that's really much more sophisticated than that.\r\nDialogue: 0,0:21:12.89,0:21:15.28,yin,,0,0,0,,你还可以设置线宽等等\\N{\\fs12}You can set your line widths and things like that\r\nDialogue: 0,0:21:15.37,0:21:17.31,yin,,0,0,0,,让你的图像...\\N{\\fs12}to make your drawing, you know,\r\nDialogue: 0,0:21:17.60,0:21:20.08,yin,,0,0,0,,可以设置图案等等\\N{\\fs12}you can set patterns and all kinds of that\r\nDialogue: 0,0:21:20.09,0:21:21.18,yin,,0,0,0,,让绘制图像更加有趣\\N{\\fs12}to make them more interesting.\r\nDialogue: 0,0:21:21.28,0:21:23.84,yin,,0,0,0,,UIBezierPath还有很多很棒的函数\\N{\\fs12}And also UIBezierPath has a lot of cool functions\r\nDialogue: 0,0:21:23.85,0:21:27.31,yin,,0,0,0,,比如bezierPathWithRoundedRect cornerRadius\\N{\\fs12}like bezierPathWithRoundedRect cornerRadius.\r\nDialogue: 0,0:21:27.56,0:21:29.36,yin,,0,0,0,,它会给你一个路径\\N{\\fs12}Okay? And that will give you a path,\r\nDialogue: 0,0:21:29.37,0:21:31.33,yin,,0,0,0,,是一个圆角矩形\\N{\\fs12}which is a rounded rectangle\r\nDialogue: 0,0:21:31.77,0:21:34.17,yin,,0,0,0,,在特定的bounds内\\N{\\fs12}in its... inside of a certain bounds.\r\nDialogue: 0,0:21:34.55,0:21:37.05,yin,,0,0,0,,还有很多类似的函数\\N{\\fs12}Okay? And it has a bunch of other ones similar to that.\r\nDialogue: 0,0:21:37.47,0:21:39.69,yin,,0,0,0,,这样你就可以构建更复杂的图形\\N{\\fs12}So that you can build more complicated things\r\nDialogue: 0,0:21:39.69,0:21:41.31,yin,,0,0,0,,不再只是一条条直线连接起来\\N{\\fs12}than line to line to line to.\r\nDialogue: 0,0:21:41.31,0:21:42.89,yin,,0,0,0,,我演示刚才的例子 只是因为它比较简单\\N{\\fs12}Okay? I just show you that because it's simple.\r\nDialogue: 0,0:21:43.22,0:21:45.51,yin,,0,0,0,,下面这是创建椭圆形的示例\\N{\\fs12}Right? So that's how you would for example create an oval.\r\nDialogue: 0,0:21:47.57,0:21:50.66,yin,,0,0,0,,你还可以用UIBezierPath来裁剪绘图\\N{\\fs12}You can also use UIBezierPath to clip your drawing.\r\nDialogue: 0,0:21:50.66,0:21:51.70,yin,,0,0,0,,这非常重要\\N{\\fs12}This is super important.\r\nDialogue: 0,0:21:51.70,0:21:53.62,yin,,0,0,0,,你们的作业需要用到它\\N{\\fs12}You will need this for your homework I think.\r\nDialogue: 0,0:21:53.90,0:21:55.77,yin,,0,0,0,,我觉得应该有不用它完成作业的方法\\N{\\fs12}I supposed there's a way to do the homework without this\r\nDialogue: 0,0:21:55.77,0:21:57.31,yin,,0,0,0,,但是我想不出来\\N{\\fs12}but I can't think of a way.\r\nDialogue: 0,0:21:58.73,0:22:01.33,yin,,0,0,0,,我可以 但是会非常冗长乏味\\N{\\fs12}Well, I can but it would be extremely tedious.\r\nDialogue: 0,0:22:01.66,0:22:03.83,yin,,0,0,0,,比如圆角矩形\\N{\\fs12}Rounded rect for example\r\nDialogue: 0,0:22:03.84,0:22:05.89,yin,,0,0,0,,就可以用来裁剪绘图\\N{\\fs12}could be used to clip your drawing.\r\nDialogue: 0,0:22:05.89,0:22:07.65,yin,,0,0,0,,所以如果你想绘制某种图案\\N{\\fs12}So if you wanted to draw some kind of pattern\r\nDialogue: 0,0:22:07.65,0:22:10.00,yin,,0,0,0,,但是想让它出现在一个圆角矩形内\\N{\\fs12}but you wanted it to be inside a rounded rect\r\nDialogue: 0,0:22:10.13,0:22:11.84,yin,,0,0,0,,你只要生成一个圆角矩形\\N{\\fs12}you just get a rounded rect,\r\nDialogue: 0,0:22:11.85,0:22:13.31,yin,,0,0,0,,就像幻灯片上面的示例那样\\N{\\fs12}just like earlier in the slide there\r\nDialogue: 0,0:22:13.37,0:22:14.62,yin,,0,0,0,,然后用addClip\\N{\\fs12}and say addClip.\r\nDialogue: 0,0:22:15.13,0:22:16.84,yin,,0,0,0,,从这里开始\\N{\\fs12}And at that point-- from that point on\r\nDialogue: 0,0:22:16.93,0:22:18.45,yin,,0,0,0,,你的所有绘图都会被裁剪\\N{\\fs12}all your drawing will be clipped\r\nDialogue: 0,0:22:18.57,0:22:20.64,yin,,0,0,0,,出现在那个圆角矩形路径内\\N{\\fs12}to be inside that Bezier path.\r\nDialogue: 0,0:22:21.74,0:22:24.00,yin,,0,0,0,,还可以添加更多裁剪区域\\N{\\fs12}Okay? And there's ways to add more clipping on,\r\nDialogue: 0,0:22:24.18,0:22:26.19,yin,,0,0,0,,取消裁剪等等\\N{\\fs12}to turn off your clipping, you know, that kind of thing.\r\nDialogue: 0,0:22:26.36,0:22:29.76,yin,,0,0,0,,所以裁剪也是UIBezierPath中重要的一部分\\N{\\fs12}So clipping is important piece of UIBezierPath as well.\r\nDialogue: 0,0:22:31.43,0:22:34.27,yin,,0,0,0,,再讲一下如何利用UIView的透明度进行绘制\\N{\\fs12}Okay, let's talk about drawing with transparency in UIView.\r\nDialogue: 0,0:22:34.57,0:22:37.36,yin,,0,0,0,,默认情况下 UIView是不透明的\\N{\\fs12}Okay, UIViews by default are opaque.\r\nDialogue: 0,0:22:37.53,0:22:40.24,yin,,0,0,0,,它们有背景色 默认是白色\\N{\\fs12}They have a background color, by default it's white.\r\nDialogue: 0,0:22:40.55,0:22:43.35,yin,,0,0,0,,所以如果你在屏幕上放一个视图 然后运行\\N{\\fs12}So if you put a view on screen and just run\r\nDialogue: 0,0:22:43.42,0:22:44.93,yin,,0,0,0,,会出现一个白色的矩形\\N{\\fs12}it'll come out as a white rectangle.\r\nDialogue: 0,0:22:45.52,0:22:48.27,yin,,0,0,0,,我们并不总是需要这样\\N{\\fs12}Okay? So that's not always what you want.\r\nDialogue: 0,0:22:48.28,0:22:51.90,yin,,0,0,0,,如果是扑克牌 我想要圆角矩形的\\N{\\fs12}So for example in a playing card I want it to have rounded rects\r\nDialogue: 0,0:22:51.97,0:22:54.31,yin,,0,0,0,,我希望顶角部分是透明的\\N{\\fs12}and I want those corners to show through.\r\nDialogue: 0,0:22:54.66,0:22:58.27,yin,,0,0,0,,也许牌桌上有其他牌\\N{\\fs12}Maybe there's a card behind or something on the playing table\r\nDialogue: 0,0:22:58.27,0:22:59.84,yin,,0,0,0,,被这张牌盖住了之类的\\N{\\fs12}that the card is on or something.\r\nDialogue: 0,0:22:59.85,0:23:01.63,yin,,0,0,0,,所以我不希望它是不透明的\\N{\\fs12}So I don't want it to be opaque.\r\nDialogue: 0,0:23:01.64,0:23:03.83,yin,,0,0,0,,在示例中大家会看到\\N{\\fs12}So you're going to see in our demo\r\nDialogue: 0,0:23:03.84,0:23:06.07,yin,,0,0,0,,我们要关掉这个不透明性\\N{\\fs12}we're going to have to turn this opaqueness off.\r\nDialogue: 0,0:23:07.17,0:23:08.61,yin,,0,0,0,,实现方法是\\N{\\fs12}The way you turn the opaqueness off\r\nDialogue: 0,0:23:08.63,0:23:12.46,yin,,0,0,0,,将UIView的属性opaque设置为NO\\N{\\fs12}is you have to set this property opaque in UIView to no.\r\nDialogue: 0,0:23:12.68,0:23:14.32,yin,,0,0,0,,也就是说 你要告诉系统\\N{\\fs12}In other words you have to tell the system\r\nDialogue: 0,0:23:14.45,0:23:15.63,yin,,0,0,0,,这个视图不是不透明的\\N{\\fs12}this view is not opaque.\r\nDialogue: 0,0:23:15.66,0:23:19.20,yin,,0,0,0,,即便你将背景色设为了nil\\N{\\fs12}Even if you set the background color to nil.\r\nDialogue: 0,0:23:19.65,0:23:21.66,yin,,0,0,0,,表示不需要背景色\\N{\\fs12}Okay? Which means I don't want a background color.\r\nDialogue: 0,0:23:21.70,0:23:25.71,yin,,0,0,0,,因为有这个属性 它依旧不会是透明的\\N{\\fs12}It still won't be transparent because of this.\r\nDialogue: 0,0:23:25.82,0:23:28.25,yin,,0,0,0,,这个opaque不是一项性能优化\\N{\\fs12}This opaque isn't a performance optimization\r\nDialogue: 0,0:23:28.34,0:23:29.69,yin,,0,0,0,,但却是必要的优化\\N{\\fs12}but it's a hard optimization,\r\nDialogue: 0,0:23:29.70,0:23:31.60,yin,,0,0,0,,如果设置不正确\\N{\\fs12}meaning it just won't work\r\nDialogue: 0,0:23:31.60,0:23:32.94,yin,,0,0,0,,它就无法正常工作\\N{\\fs12}if you don't set it to the right thing.\r\nDialogue: 0,0:23:32.96,0:23:34.55,yin,,0,0,0,,所以如果你想让视图变为透明的\\N{\\fs12}So if you want your view to be transparent\r\nDialogue: 0,0:23:34.56,0:23:35.79,yin,,0,0,0,,就要把opaque设置为NO\\N{\\fs12}you have to set opaque to no.\r\nDialogue: 0,0:23:35.89,0:23:38.09,yin,,0,0,0,,同时还要把背景色设为nil\\N{\\fs12}You're also going to want to set your background color to nil\r\nDialogue: 0,0:23:38.11,0:23:39.94,yin,,0,0,0,,避免填充背景色\\N{\\fs12}so that it's not filling with a background color.\r\nDialogue: 0,0:23:40.33,0:23:44.61,yin,,0,0,0,,还可以将整个视图变为透明的\\N{\\fs12}It is also possible to make your entire view transparent\r\nDialogue: 0,0:23:44.95,0:23:45.82,yin,,0,0,0,,用alpha属性\\N{\\fs12}with alpha.\r\nDialogue: 0,0:23:46.56,0:23:49.27,yin,,0,0,0,,UIView有一个属性叫做alpha\\N{\\fs12}Okay? So UIView has a property called alpha.\r\nDialogue: 0,0:23:49.28,0:23:50.60,yin,,0,0,0,,如果你将它设为50%\\N{\\fs12}If you set it to 50%\r\nDialogue: 0,0:23:50.61,0:23:53.97,yin,,0,0,0,,那么视图中全部元素都会透出50%\\N{\\fs12}then everything in your view will be 50% see through.\r\nDialogue: 0,0:23:54.26,0:23:55.74,yin,,0,0,0,,透明度为50%\\N{\\fs12}Right? 50% transparent.\r\nDialogue: 0,0:23:55.75,0:23:57.63,yin,,0,0,0,,或者20%等等 看你需要\\N{\\fs12}20% or whatever percent you want.\r\nDialogue: 0,0:23:57.64,0:23:58.45,yin,,0,0,0,,是整个视图\\N{\\fs12}That's the entire view.\r\nDialogue: 0,0:23:58.45,0:24:00.22,yin,,0,0,0,,不管里面是什么\\N{\\fs12}No matter what's going on inside.\r\nDialogue: 0,0:24:00.65,0:24:02.92,yin,,0,0,0,,当然 还有透明颜色\\N{\\fs12}And of course, you have transparent colors\r\nDialogue: 0,0:24:03.01,0:24:05.94,yin,,0,0,0,,可以用来绘制 填充 描边等等\\N{\\fs12}that you could draw with, fill with, stroke with, whatever.\r\nDialogue: 0,0:24:06.11,0:24:08.36,yin,,0,0,0,,绘制出来也是透明的\\N{\\fs12}To draw transparently that way as well.\r\nDialogue: 0,0:24:08.36,0:24:11.46,yin,,0,0,0,,所以有很多方法可以在视图中进行透明绘制\\N{\\fs12}So there's a lot of ways to draw transparently in your view.\r\nDialogue: 0,0:24:11.68,0:24:15.41,yin,,0,0,0,,如果透明绘制的视图重叠了会怎样呢\\N{\\fs12}What happens if you've draw transparently and views overlap?\r\nDialogue: 0,0:24:15.68,0:24:17.88,yin,,0,0,0,,它们会互相透过来显示\\N{\\fs12}Well, they show through to each other.\r\nDialogue: 0,0:24:18.31,0:24:20.06,yin,,0,0,0,,我刚才讲过的\\N{\\fs12}Okay? And I told you that the order\r\nDialogue: 0,0:24:20.06,0:24:22.34,yin,,0,0,0,,添加子视图的顺序很重要\\N{\\fs12}in which you add the subviews matters.\r\nDialogue: 0,0:24:22.49,0:24:27.40,yin,,0,0,0,,所有视图都有属性subviews 是一个NSArray\\N{\\fs12}Okay? Every view has a property, an NSArray called subviews.\r\nDialogue: 0,0:24:27.40,0:24:30.11,yin,,0,0,0,,是视图的列表 顺序很重要\\N{\\fs12}It's the list of views and the order matters.\r\nDialogue: 0,0:24:30.16,0:24:32.64,yin,,0,0,0,,数组中靠前的视图\\N{\\fs12}The lower one in the array, okay,\r\nDialogue: 0,0:24:32.65,0:24:35.65,yin,,0,0,0,,比如位置0的视图在后面\\N{\\fs12}the ones that-- like zero are in the back\r\nDialogue: 0,0:24:35.92,0:24:38.19,yin,,0,0,0,,数组中靠后的视图在前面\\N{\\fs12}and the ones down at the end are in the front.\r\nDialogue: 0,0:24:38.31,0:24:38.60,yin,,0,0,0,,明白吗\\N{\\fs12}All right?\r\nDialogue: 0,0:24:38.60,0:24:40.46,yin,,0,0,0,,所以是按照subviews数组中的顺序由后至前\\N{\\fs12}So the subviews array is from back to front.\r\nDialogue: 0,0:24:40.88,0:24:43.21,yin,,0,0,0,,视图间可以重叠 压在其他视图上面\\N{\\fs12}Okay? And things can overlap and be on top of the others\r\nDialogue: 0,0:24:43.22,0:24:44.47,yin,,0,0,0,,它们可以透过上面的视图显示出来\\N{\\fs12}and they will show through.\r\nDialogue: 0,0:24:44.71,0:24:46.27,yin,,0,0,0,,如果中间有一个不透明视图\\N{\\fs12}If you have an opaque on in the middle,\r\nDialogue: 0,0:24:46.29,0:24:48.40,yin,,0,0,0,,就会遮挡住后面的全部视图\\N{\\fs12}it would block all the ones in the back.\r\nDialogue: 0,0:24:48.63,0:24:49.91,yin,,0,0,0,,明白吗\\N{\\fs12}See what I mean?\r\nDialogue: 0,0:24:50.37,0:24:51.46,yin,,0,0,0,,就是这么简单\\N{\\fs12}So it's as simple as that.\r\nDialogue: 0,0:24:51.76,0:24:54.92,yin,,0,0,0,,实现透明的开销并不少\\N{\\fs12}Now having transparent views is not cheap.\r\nDialogue: 0,0:24:55.04,0:24:56.72,yin,,0,0,0,,关于性能优化\\N{\\fs12}We talk about performance optimization,\r\nDialogue: 0,0:24:56.72,0:24:58.04,yin,,0,0,0,,我认为计算机科学的学生\\N{\\fs12}one of the biggest mistakes I think\r\nDialogue: 0,0:24:58.07,0:24:59.36,yin,,0,0,0,,最容易犯的错误\\N{\\fs12}computer science students make\r\nDialogue: 0,0:24:59.51,0:25:00.70,yin,,0,0,0,,就是过早优化\\N{\\fs12}is premature optimization.\r\nDialogue: 0,0:25:00.70,0:25:03.58,yin,,0,0,0,,优化了无关紧要的内容\\N{\\fs12}You're in there optimizing stuff that just doesn't matter.\r\nDialogue: 0,0:25:03.72,0:25:04.52,yin,,0,0,0,,而这个很重要\\N{\\fs12}This matters.\r\nDialogue: 0,0:25:04.74,0:25:06.67,yin,,0,0,0,,如果你用了很多透明视图\\N{\\fs12}If you have a lot of transparency,\r\nDialogue: 0,0:25:06.78,0:25:08.13,yin,,0,0,0,,会占用大量性能资源\\N{\\fs12}it's going to be a performance hit\r\nDialogue: 0,0:25:08.14,0:25:10.56,yin,,0,0,0,,因为你要根据透明度\\N{\\fs12}because you're talking about having to composite those view\r\nDialogue: 0,0:25:10.57,0:25:12.01,yin,,0,0,0,,一层层地合成这些视图\\N{\\fs12}on top of each other with alpha.\r\nDialogue: 0,0:25:12.06,0:25:15.18,yin,,0,0,0,,比直接改变比特值的开销大多了\\N{\\fs12}Way more expensive than just blasting the bits in there.\r\nDialogue: 0,0:25:15.44,0:25:18.02,yin,,0,0,0,,学过图形学的同学知道我在说什么\\N{\\fs12}Okay? Anyone taking graphics knows that I'm talking about.\r\nDialogue: 0,0:25:18.42,0:25:20.11,yin,,0,0,0,,所以这是要注意的地方\\N{\\fs12}So this is something you're gonna be a little careful with.\r\nDialogue: 0,0:25:20.12,0:25:21.74,yin,,0,0,0,,你要将opaque属性设为NO\\N{\\fs12}You're going to set that opaque to no.\r\nDialogue: 0,0:25:21.93,0:25:24.60,yin,,0,0,0,,明白这里涉及一个性能开销的问题\\N{\\fs12}Understand there's a performance cost there.\r\nDialogue: 0,0:25:24.92,0:25:26.12,yin,,0,0,0,,这就是我刚说的\\N{\\fs12}Yeah, there's what I am saying.\r\nDialogue: 0,0:25:27.32,0:25:29.67,yin,,0,0,0,,你还可以隐藏整个视图\\N{\\fs12}You can also hide a view entirely.\r\nDialogue: 0,0:25:29.88,0:25:33.11,yin,,0,0,0,,可以把它想成是alpha为0的情况\\N{\\fs12}Okay? So it's just like think of it as alpha of zero,\r\nDialogue: 0,0:25:33.11,0:25:34.08,yin,,0,0,0,,什么都看不到\\N{\\fs12}like you can't see anything.\r\nDialogue: 0,0:25:34.08,0:25:36.00,yin,,0,0,0,,但是它同时也无法获取任何手势\\N{\\fs12}But it also won't get any gestures.\r\nDialogue: 0,0:25:36.11,0:25:38.62,yin,,0,0,0,,很像是将视图从视图层级中移除了\\N{\\fs12}It's almost like removing from the view hierarchy,\r\nDialogue: 0,0:25:38.62,0:25:39.54,yin,,0,0,0,,但是你把它留下了\\N{\\fs12}but you're leaving it,\r\nDialogue: 0,0:25:39.56,0:25:42.84,yin,,0,0,0,,所以它还在子视图列表中\\N{\\fs12}so it has its space in the subviews list.\r\nDialogue: 0,0:25:43.35,0:25:45.85,yin,,0,0,0,,还有它的位置 但是并不显示出来\\N{\\fs12}It gets to keep that, but otherwise it doesn't appear.\r\nDialogue: 0,0:25:45.85,0:25:47.96,yin,,0,0,0,,不进行绘制 无法获取事件\\N{\\fs12}It doesn't draw, it doesn't get events.\r\nDialogue: 0,0:25:48.09,0:25:49.46,yin,,0,0,0,,就像没在屏幕上一样\\N{\\fs12}It's like it's not even there.\r\nDialogue: 0,0:25:49.71,0:25:50.79,yin,,0,0,0,,为什么要这样呢\\N{\\fs12}Why do you want that?\r\nDialogue: 0,0:25:50.80,0:25:51.92,yin,,0,0,0,,因为有时你只是想将某个视图\\N{\\fs12}Well, because sometimes you just want to\r\nDialogue: 0,0:25:51.93,0:25:55.00,yin,,0,0,0,,暂时从层级中移出\\N{\\fs12}temporarily remove a view from the hierarchy\r\nDialogue: 0,0:25:55.00,0:25:56.15,yin,,0,0,0,,再把它重新放回来\\N{\\fs12}and put it right back in.\r\nDialogue: 0,0:25:56.23,0:25:59.07,yin,,0,0,0,,或者过一小段时间后再放回来\\N{\\fs12}So you said-- or put it back in some short time later.\r\nDialogue: 0,0:25:59.18,0:26:00.58,yin,,0,0,0,,写上hidden=YES\\N{\\fs12}So you say hidden equals yes.\r\nDialogue: 0,0:26:00.69,0:26:01.34,yin,,0,0,0,,它就不见了\\N{\\fs12}It's gone.\r\nDialogue: 0,0:26:01.54,0:26:03.61,yin,,0,0,0,,写上hidden=NO 它就重新出现了\\N{\\fs12}You say hidden equals no, oh it reappears.\r\nDialogue: 0,0:26:03.92,0:26:07.98,yin,,0,0,0,,这比设置为透明更好\\N{\\fs12}Okay? So that's better than setting the transparency.\r\nDialogue: 0,0:26:07.98,0:26:12.10,yin,,0,0,0,,大部分情况下 UIKit可能会将alpha=0\\N{\\fs12}Although I think mostly the UIKit probably optimizes alpha equals zero\r\nDialogue: 0,0:26:12.11,0:26:15.02,yin,,0,0,0,,优化为hidden 这是我的猜测\\N{\\fs12}to be the same as hidden as my guess. Okay.\r\nDialogue: 0,0:26:17.16,0:26:19.45,yin,,0,0,0,,我想作业中可能不需要用到\\N{\\fs12}Probably won't have to do that in homework as my guess.\r\nDialogue: 0,0:26:19.95,0:26:20.63,yin,,0,0,0,,也可能会用到\\N{\\fs12}But you might.\r\nDialogue: 0,0:26:20.64,0:26:22.38,yin,,0,0,0,,取决于你的UI的复杂度\\N{\\fs12}Depends on what kind of sophisticated UI you build.\r\nDialogue: 0,0:26:23.45,0:26:24.92,yin,,0,0,0,,这张幻灯片我就不详细讲了\\N{\\fs12}I'm not going to go through this slide\r\nDialogue: 0,0:26:24.93,0:26:26.39,yin,,0,0,0,,但是可以想象一下\\N{\\fs12}but you can imagine that\r\nDialogue: 0,0:26:26.40,0:26:28.53,yin,,0,0,0,,如果你在子程序中\\N{\\fs12}if you're setting up fill colors and clipping\r\nDialogue: 0,0:26:28.54,0:26:30.48,yin,,0,0,0,,设置了填充颜色 裁剪等等\\N{\\fs12}and all that stuff in a subroutine,\r\nDialogue: 0,0:26:30.77,0:26:32.34,yin,,0,0,0,,当你从子程序中返回时\\N{\\fs12}when you come back from the subroutine,\r\nDialogue: 0,0:26:32.35,0:26:33.76,yin,,0,0,0,,这些属性值不变\\N{\\fs12}all those things might still be set.\r\nDialogue: 0,0:26:33.77,0:26:34.73,yin,,0,0,0,,这样就不好了\\N{\\fs12}And that would be bad.\r\nDialogue: 0,0:26:34.89,0:26:38.69,yin,,0,0,0,,所以最好能压入和取出你的状态\\N{\\fs12}Okay? So you want to be able to push and pop your state.\r\nDialogue: 0,0:26:38.71,0:26:41.13,yin,,0,0,0,,也就是保存当前图形上下文\\N{\\fs12}Basically save the current graphics context\r\nDialogue: 0,0:26:41.28,0:26:42.53,yin,,0,0,0,,然后再恢复它\\N{\\fs12}and then restore it.\r\nDialogue: 0,0:26:42.65,0:26:44.00,yin,,0,0,0,,也就是这两个函数的功能\\N{\\fs12}And that what these functions do,\r\nDialogue: 0,0:26:44.02,0:26:48.00,yin,,0,0,0,,CGContextSaveGState和CGContextRestoreGState\\N{\\fs12}CGContextSaveGState and CGContextRestoreGState.\r\nDialogue: 0,0:26:48.11,0:26:48.93,yin,,0,0,0,,把各种设置都保存起来\\N{\\fs12}We'll save everything,\r\nDialogue: 0,0:26:48.93,0:26:51.08,yin,,0,0,0,,填充颜色 裁剪区域\\N{\\fs12}all the fill colors and clipping regions.\r\nDialogue: 0,0:26:51.23,0:26:52.38,yin,,0,0,0,,执行一些操作\\N{\\fs12}You go do a bunch of stuff.\r\nDialogue: 0,0:26:52.54,0:26:54.18,yin,,0,0,0,,裁剪 填充等等\\N{\\fs12}You know, clip and fill and everything\r\nDialogue: 0,0:26:54.19,0:26:56.01,yin,,0,0,0,,然后恢复一下 就回到了之前的状态\\N{\\fs12}and then you restore and you're back the way you were.\r\nDialogue: 0,0:26:56.16,0:26:57.43,yin,,0,0,0,,这样如果你有drawRect方法\\N{\\fs12}So that if you have your drawRect\r\nDialogue: 0,0:26:57.43,0:27:00.31,yin,,0,0,0,,它调用了这个drawGreenCircle\\N{\\fs12}and it calls this drawGreenCircle thing,\r\nDialogue: 0,0:27:00.47,0:27:01.85,yin,,0,0,0,,不会在你回到drawRect之后\\N{\\fs12}it won't come back to your drawRect\r\nDialogue: 0,0:27:01.86,0:27:03.44,yin,,0,0,0,,所有绘制图形都变成绿色\\N{\\fs12}and now everything is drawn in green.\r\nDialogue: 0,0:27:04.15,0:27:07.34,yin,,0,0,0,,这就是压入和取出状态\\N{\\fs12}Okay? So that's push and pop basically the state.\r\nDialogue: 0,0:27:08.45,0:27:09.51,yin,,0,0,0,,下面是绘制文本\\N{\\fs12}All right, drawing text.\r\nDialogue: 0,0:27:09.51,0:27:11.30,yin,,0,0,0,,绘制三角形\\N{\\fs12}Okay, it's all great drawing triangles\r\nDialogue: 0,0:27:11.30,0:27:12.26,yin,,0,0,0,,填充颜色都可以了\\N{\\fs12}and filling them with colors.\r\nDialogue: 0,0:27:12.26,0:27:15.20,yin,,0,0,0,,怎样在视图中绘制文本呢\\N{\\fs12}What if you want to draw text inside your view?\r\nDialogue: 0,0:27:15.30,0:27:17.25,yin,,0,0,0,,当然 绝大多数情况下 在UIKit中\\N{\\fs12}Well, of course we use UILabel to draw\r\nDialogue: 0,0:27:17.26,0:27:20.00,yin,,0,0,0,,我们使用UILabel绘制文本\\N{\\fs12}the vast majority of text on the screen in UIKit.\r\nDialogue: 0,0:27:20.22,0:27:22.24,yin,,0,0,0,,但是你可以用NSAttributedString\\N{\\fs12}But you can use NSAttributedString\r\nDialogue: 0,0:27:22.41,0:27:23.86,yin,,0,0,0,,绘制任意想要的文本\\N{\\fs12}to draw any text you want.\r\nDialogue: 0,0:27:24.41,0:27:25.68,yin,,0,0,0,,非常简单\\N{\\fs12}And it could not be simpler.\r\nDialogue: 0,0:27:25.72,0:27:27.19,yin,,0,0,0,,创建属性化字符串\\N{\\fs12}You create the attributes string\r\nDialogue: 0,0:27:27.19,0:27:28.57,yin,,0,0,0,,添加所需属性\\N{\\fs12}with all the attributes you want.\r\nDialogue: 0,0:27:28.58,0:27:31.18,yin,,0,0,0,,没有限制 和上次作业中做的\\N{\\fs12}No restrictions, exactly like you learned to do\r\nDialogue: 0,0:27:31.37,0:27:32.73,yin,,0,0,0,,是一样的\\N{\\fs12}in this last homework assignment\r\nDialogue: 0,0:27:32.85,0:27:33.94,yin,,0,0,0,,然后只要向那个属性化字符串\\N{\\fs12}and then you just send a message\r\nDialogue: 0,0:27:33.94,0:27:36.68,yin,,0,0,0,,发送消息drawAtPoint\\N{\\fs12}to that attributed string, drawAtPoint.\r\nDialogue: 0,0:27:36.79,0:27:37.44,yin,,0,0,0,,这个点\\N{\\fs12}This point.\r\nDialogue: 0,0:27:37.45,0:27:40.65,yin,,0,0,0,,这个点是一个矩形的左上角\\N{\\fs12}And that will be the upper left corner of a rectangle\r\nDialogue: 0,0:27:40.66,0:27:43.93,yin,,0,0,0,,矩形包括了全部属性化文本\\N{\\fs12}that includes all that attributed text.\r\nDialogue: 0,0:27:44.60,0:27:47.38,yin,,0,0,0,,再简单不过了\\N{\\fs12}Okay? It's-- could not be any simpler.\r\nDialogue: 0,0:27:48.11,0:27:51.04,yin,,0,0,0,,你还可以得到文本大小\\N{\\fs12}You can also find out how big that text is going to take.\r\nDialogue: 0,0:27:51.04,0:27:52.89,yin,,0,0,0,,文本所占空间大小\\N{\\fs12}How much space that thing is going to take\r\nDialogue: 0,0:27:53.08,0:27:56.38,yin,,0,0,0,,方法是向属性化字符串发送size\\N{\\fs12}by sending size to the attributed string\r\nDialogue: 0,0:27:56.39,0:27:57.87,yin,,0,0,0,,它会返回文本空间大小\\N{\\fs12}and it'll tell you how big it is.\r\nDialogue: 0,0:27:57.87,0:28:00.06,yin,,0,0,0,,你可能会对这部分内容有点困扰\\N{\\fs12}Now you might be a little disturbed by this and like whoa,\r\nDialogue: 0,0:28:00.06,0:28:02.35,yin,,0,0,0,,属性化字符串并不是UIKit的内容\\N{\\fs12}attributed string is not really a UIKit thing.\r\nDialogue: 0,0:28:02.35,0:28:04.22,yin,,0,0,0,,它的属性一般都是\\N{\\fs12}All the properties inside usually are,\r\nDialogue: 0,0:28:04.22,0:28:06.15,yin,,0,0,0,,但它本身并不是\\N{\\fs12}but it itself is not.\r\nDialogue: 0,0:28:06.26,0:28:07.23,yin,,0,0,0,,是这样的\\N{\\fs12}And that's true.\r\nDialogue: 0,0:28:07.58,0:28:09.81,yin,,0,0,0,,UIKit实际上是添加了这些方法\\N{\\fs12}UIKit actually adds these methods\r\nDialogue: 0,0:28:09.82,0:28:12.35,yin,,0,0,0,,drawAtPoint size等\\N{\\fs12}drawAtPoint and size and there's a few other ones.\r\nDialogue: 0,0:28:12.44,0:28:13.90,yin,,0,0,0,,即便是在完全不同的框架中\\N{\\fs12}It adds them even though\r\nDialogue: 0,0:28:13.91,0:28:15.28,yin,,0,0,0,,也可以添加方法\\N{\\fs12}it's in a completely different framework\r\nDialogue: 0,0:28:15.35,0:28:17.02,yin,,0,0,0,,使用了Objective C中的一项机制\\N{\\fs12}using a mechanism in Objective C\r\nDialogue: 0,0:28:17.03,0:28:18.76,yin,,0,0,0,,可以直接向类中添加方法\\N{\\fs12}where you can add methods to classes\r\nDialogue: 0,0:28:18.76,0:28:20.11,yin,,0,0,0,,而不用对它们进行子类化\\N{\\fs12}without subclassing them.\r\nDialogue: 0,0:28:20.92,0:28:24.54,yin,,0,0,0,,叫做Category类别 不好控制\\N{\\fs12}Okay? It's called categories, talk about Wild West.\r\nDialogue: 0,0:28:24.54,0:28:26.73,yin,,0,0,0,,这就是为什么我要到学期下半部分才讲\\N{\\fs12}That's why I don't show you until the halfway through\r\nDialogue: 0,0:28:26.74,0:28:29.30,yin,,0,0,0,,因为这项机制可能会被滥用\\N{\\fs12}because it can be abused, this mechanism.\r\nDialogue: 0,0:28:30.02,0:28:31.29,yin,,0,0,0,,对这部分感到困惑的同学\\N{\\fs12}But that's how this is working\r\nDialogue: 0,0:28:31.38,0:28:33.29,yin,,0,0,0,,这就是它的工作方式\\N{\\fs12}for those of you who are wondering.\r\nDialogue: 0,0:28:34.50,0:28:36.64,yin,,0,0,0,,绘制图像差不多是一样的\\N{\\fs12}Drawing images is almost the same.\r\nDialogue: 0,0:28:36.72,0:28:39.67,yin,,0,0,0,,但是不用NSAttributedString 而是UIImage\\N{\\fs12}But instead of an NSAttributedString, you get a UIImage.\r\nDialogue: 0,0:28:39.67,0:28:40.59,yin,,0,0,0,,大家知道如何用图像名\\N{\\fs12}So you know how to get one\r\nDialogue: 0,0:28:40.59,0:28:42.82,yin,,0,0,0,,从图像资产库中得到图像\\N{\\fs12}out of the image assets library with image name.\r\nDialogue: 0,0:28:43.03,0:28:44.88,yin,,0,0,0,,还可以从文件中创建\\N{\\fs12}There are other ways you can create them from a file.\r\nDialogue: 0,0:28:44.88,0:28:46.88,yin,,0,0,0,,甚至还可以通过绘至屏外位图\\N{\\fs12}You can even draw into an offscreen bitmap\r\nDialogue: 0,0:28:46.89,0:28:47.93,yin,,0,0,0,,创建UIImage\\N{\\fs12}to create a UIImage.\r\nDialogue: 0,0:28:48.10,0:28:50.01,yin,,0,0,0,,有了UIImage之后\\N{\\fs12}Once you have a UIImage in your hand,\r\nDialogue: 0,0:28:50.14,0:28:52.62,yin,,0,0,0,,只要向它发送drawAtPoint\\N{\\fs12}you just send it drawAtPoint,\r\nDialogue: 0,0:28:52.68,0:28:54.71,yin,,0,0,0,,就会绘制那幅图像\\N{\\fs12}which will draw that image\r\nDialogue: 0,0:28:54.72,0:28:57.58,yin,,0,0,0,,左上角位于你所指定的那个点\\N{\\fs12}with its upper left hand corner at the point you specified.\r\nDialogue: 0,0:28:57.67,0:29:00.55,yin,,0,0,0,,或者用drawInRect 这样会缩放图像\\N{\\fs12}Or drawInRect which will scale the image\r\nDialogue: 0,0:29:00.76,0:29:02.92,yin,,0,0,0,,以适合你所指定的矩形大小\\N{\\fs12}to fit in the rectangle you specify.\r\nDialogue: 0,0:29:02.97,0:29:04.59,yin,,0,0,0,,这是通过缩放实现的\\N{\\fs12}Okay? This is a scaling one.\r\nDialogue: 0,0:29:04.85,0:29:08.55,yin,,0,0,0,,drawAsPatternInRect会平铺图像\\N{\\fs12}Or drawAsPatternInRect which will like tile the image.\r\nDialogue: 0,0:29:08.64,0:29:09.70,yin,,0,0,0,,重复绘制图像\\N{\\fs12}You know, repeat the image\r\nDialogue: 0,0:29:09.71,0:29:11.77,yin,,0,0,0,,以填满你指定的矩形\\N{\\fs12}to fill the rectangle that you specified.\r\nDialogue: 0,0:29:12.52,0:29:16.45,yin,,0,0,0,,还可以得到其他表示法\\N{\\fs12}Okay? And you can get other representations,\r\nDialogue: 0,0:29:16.48,0:29:18.65,yin,,0,0,0,,绘制内容的PNG表示\\N{\\fs12}PNG representations of things you've drawn\r\nDialogue: 0,0:29:18.66,0:29:19.22,yin,,0,0,0,,这类的操作\\N{\\fs12}and all these things.\r\nDialogue: 0,0:29:19.22,0:29:20.59,yin,,0,0,0,,我只是想让大家知道有这个功能\\N{\\fs12}So I just wanted to let you know that's in there.\r\nDialogue: 0,0:29:20.59,0:29:22.68,yin,,0,0,0,,作业中不需要\\N{\\fs12}You don't need it for your homework but anyway.\r\nDialogue: 0,0:29:22.69,0:29:24.91,yin,,0,0,0,,所以绘制文本和图像非常简单\\N{\\fs12}So the drawing text and images really easy.\r\nDialogue: 0,0:29:24.92,0:29:26.80,yin,,0,0,0,,只是用到属性化字符串 UIImage\\N{\\fs12}It's just attributed string and UIImage,\r\nDialogue: 0,0:29:26.90,0:29:29.24,yin,,0,0,0,,drawAtPoint和drawInRect\\N{\\fs12}drawAtPoint, drawInRect. Okay?\r\nDialogue: 0,0:29:30.56,0:29:32.94,yin,,0,0,0,,如果bounds变化了会怎样呢\\N{\\fs12}What about when your bounds change? Okay?\r\nDialogue: 0,0:29:33.05,0:29:36.15,yin,,0,0,0,,当你添加导航栏控制器\\N{\\fs12}You notice when you did the navigation controller\r\nDialogue: 0,0:29:36.15,0:29:37.29,yin,,0,0,0,,或者选项卡栏控制器时\\N{\\fs12}or the tab bar, you know,\r\nDialogue: 0,0:29:37.30,0:29:40.54,yin,,0,0,0,,视图的bounds会缩短\\N{\\fs12}your bounds of your view got shrunk down\r\nDialogue: 0,0:29:40.55,0:29:41.65,yin,,0,0,0,,以适应底部的选项卡栏\\N{\\fs12}to fit the thing at the bottom\r\nDialogue: 0,0:29:41.65,0:29:42.95,yin,,0,0,0,,或者顶部的导航栏\\N{\\fs12}or fit the thing at the top.\r\nDialogue: 0,0:29:43.27,0:29:45.00,yin,,0,0,0,,还有在你旋转设备的时候\\N{\\fs12}And also if you rotate your device\r\nDialogue: 0,0:29:45.01,0:29:46.48,yin,,0,0,0,,显然bounds也会改变\\N{\\fs12}obviously the bounds are going to change.\r\nDialogue: 0,0:29:46.48,0:29:47.93,yin,,0,0,0,,bounds发生变化了会怎样呢\\N{\\fs12}What happens when your bounds change?\r\nDialogue: 0,0:29:47.93,0:29:52.20,yin,,0,0,0,,默认情况下 视图的比特值...\\N{\\fs12}Well, by default the bits of your view, the--\r\nDialogue: 0,0:29:52.21,0:29:55.21,yin,,0,0,0,,最后绘制的内容会被拉伸\\N{\\fs12}that were last draw will get stretched.\r\nDialogue: 0,0:29:55.64,0:29:58.93,yin,,0,0,0,,并不是我们想要的效果\\N{\\fs12}Okay? Which really is almost never what you want.\r\nDialogue: 0,0:29:58.94,0:30:02.54,yin,,0,0,0,,大部分内容都希望是被绘制出来的\\N{\\fs12}Okay? I mean most content wants to be drawn\r\nDialogue: 0,0:30:02.67,0:30:04.97,yin,,0,0,0,,这样分辨率高 看起来比较好看\\N{\\fs12}to get high resolution to look nice.\r\nDialogue: 0,0:30:05.15,0:30:08.52,yin,,0,0,0,,默认是拉伸 因为这样比重新绘制的\\N{\\fs12}So the default is that because it's way high performance\r\nDialogue: 0,0:30:08.53,0:30:10.04,yin,,0,0,0,,性能更高\\N{\\fs12}than asking you to draw again.\r\nDialogue: 0,0:30:10.50,0:30:13.07,yin,,0,0,0,,但是UIView中有一个属性\\N{\\fs12}But there's a property in UIView.\r\nDialogue: 0,0:30:13.07,0:30:15.24,yin,,0,0,0,,大家需要知道 叫做contentMode\\N{\\fs12}You really want to know called contentMode.\r\nDialogue: 0,0:30:15.47,0:30:18.05,yin,,0,0,0,,它代表bounds变化时会发生什么\\N{\\fs12}And it says what happens when your bounds change.\r\nDialogue: 0,0:30:18.19,0:30:22.65,yin,,0,0,0,,底下还有一个UIViewContentModeRedraw\\N{\\fs12}And the one down at the bottom there UIViewContentModeRedraw\r\nDialogue: 0,0:30:22.97,0:30:24.53,yin,,0,0,0,,如你所想\\N{\\fs12}is doing what you imagine,\r\nDialogue: 0,0:30:24.54,0:30:28.43,yin,,0,0,0,,是要你在bounds变化时 用drawRect\\N{\\fs12}which is it asks you to redraw your whole view with drawRect\r\nDialogue: 0,0:30:28.81,0:30:30.23,yin,,0,0,0,,重绘整个视图\\N{\\fs12}whenever your bounds change.\r\nDialogue: 0,0:30:30.85,0:30:33.59,yin,,0,0,0,,在演示中 我们会设置为重新绘制\\N{\\fs12}Okay? So in our demo we're going to set it to redraw\r\nDialogue: 0,0:30:33.59,0:30:37.24,yin,,0,0,0,,因为如果卡牌bounds发生变化 我们希望能重绘\\N{\\fs12}because if our cards bounds ever change we want to redraw\r\nDialogue: 0,0:30:37.24,0:30:39.53,yin,,0,0,0,,这样人头牌面会比较清晰\\N{\\fs12}so we get a nice sharp face card image\r\nDialogue: 0,0:30:39.55,0:30:43.32,yin,,0,0,0,,右边有小花色符号和文字等等\\N{\\fs12}or the right side little pips on there and text and all that.\r\nDialogue: 0,0:30:43.32,0:30:45.48,yin,,0,0,0,,你可能也想要这样做\\N{\\fs12}So you might want to do that as well.\r\nDialogue: 0,0:30:45.62,0:30:48.17,yin,,0,0,0,,UIViewContentModeScaleToFill是默认值\\N{\\fs12}Okay, UIViewContentModeScaleToFill is the default.\r\nDialogue: 0,0:30:48.17,0:30:49.50,yin,,0,0,0,,绘制内容会被拉伸\\N{\\fs12}That's the bit stretcher.\r\nDialogue: 0,0:30:51.47,0:30:54.49,yin,,0,0,0,,以上是绘制部分的内容\\N{\\fs12}Okay, so that's the drawing side of things.\r\nDialogue: 0,0:30:54.50,0:30:56.57,yin,,0,0,0,,我们来讲一下输入部分\\N{\\fs12}Now let's talk about the input side.\r\nDialogue: 0,0:30:56.58,0:30:58.47,yin,,0,0,0,,手势识别\\N{\\fs12}Okay, the recognizing gestures.\r\nDialogue: 0,0:30:59.17,0:31:01.54,yin,,0,0,0,,手指触摸屏幕的原始数据\\N{\\fs12}It is possible to get the raw data\r\nDialogue: 0,0:31:01.55,0:31:03.40,yin,,0,0,0,,是可以得到的\\N{\\fs12}about fingers touching the screen.\r\nDialogue: 0,0:31:03.42,0:31:06.42,yin,,0,0,0,,触摸的数量 手指的位置和移动\\N{\\fs12}How many they're touching, where the fingers are, when they move.\r\nDialogue: 0,0:31:06.43,0:31:07.84,yin,,0,0,0,,以前\\N{\\fs12}But-- and it used to be that\r\nDialogue: 0,0:31:07.86,0:31:09.61,yin,,0,0,0,,真的需要自己查看这些数据\\N{\\fs12}you actually had to look at all that data\r\nDialogue: 0,0:31:09.63,0:31:11.76,yin,,0,0,0,,判断用户在做什么\\N{\\fs12}to figure out what the heck the user was doing.\r\nDialogue: 0,0:31:11.76,0:31:13.10,yin,,0,0,0,,滑动还是捏合\\N{\\fs12}Swiping or pinching?\r\nDialogue: 0,0:31:13.11,0:31:14.24,yin,,0,0,0,,真是个噩梦\\N{\\fs12}It was a nightmare.\r\nDialogue: 0,0:31:14.24,0:31:16.23,yin,,0,0,0,,无法相信有人真的这样做了\\N{\\fs12}I mean I can't believe people actually did it.\r\nDialogue: 0,0:31:16.23,0:31:18.25,yin,,0,0,0,,代码非常难懂\\N{\\fs12}It was quite esoteric code.\r\nDialogue: 0,0:31:18.57,0:31:22.46,yin,,0,0,0,,最近发布的几个iOS版本解决了这个问题\\N{\\fs12}But the last few iOS releases have had the right way to do it\r\nDialogue: 0,0:31:22.47,0:31:24.85,yin,,0,0,0,,添加了手势识别器功能\\N{\\fs12}which is gesture recognizers. Okay?\r\nDialogue: 0,0:31:25.12,0:31:27.59,yin,,0,0,0,,所以我们理解用户操作的方法是\\N{\\fs12}So the way we're gonna understand what the user is doing is\r\nDialogue: 0,0:31:27.64,0:31:30.85,yin,,0,0,0,,系统会替我们识别特定手势\\N{\\fs12}this system is gonna recognize certain gestures for us\r\nDialogue: 0,0:31:30.86,0:31:32.62,yin,,0,0,0,,在手势发生时告诉我们\\N{\\fs12}and tell us when those gestures are happening.\r\nDialogue: 0,0:31:32.86,0:31:35.21,yin,,0,0,0,,显然我们想要用这种方式\\N{\\fs12}Okay? Obviously you want to do this.\r\nDialogue: 0,0:31:36.34,0:31:38.88,yin,,0,0,0,,有一个类\\N{\\fs12}The class that is the base\r\nDialogue: 0,0:31:38.88,0:31:40.92,yin,,0,0,0,,是这些手势识别的基础\\N{\\fs12}for all these recognizing gestures\r\nDialogue: 0,0:31:40.94,0:31:42.77,yin,,0,0,0,,叫做UIGestureRecognizer\\N{\\fs12}is called UIGestureRecognizer.\r\nDialogue: 0,0:31:42.78,0:31:44.35,yin,,0,0,0,,它是一个抽象类\\N{\\fs12}It's an abstract class.\r\nDialogue: 0,0:31:44.36,0:31:45.92,yin,,0,0,0,,不允许对它进行实例化\\N{\\fs12}Okay, you never instantiate it.\r\nDialogue: 0,0:31:46.08,0:31:48.59,yin,,0,0,0,,但它有很多具体子类\\N{\\fs12}But it has a lot of concrete subclasses\r\nDialogue: 0,0:31:48.61,0:31:50.97,yin,,0,0,0,,比如捏合手势 点击手势等\\N{\\fs12}like pinch gesture, tap gesture, all that.\r\nDialogue: 0,0:31:51.33,0:31:52.19,yin,,0,0,0,,这些具体子类\\N{\\fs12}And those are the things\r\nDialogue: 0,0:31:52.20,0:31:54.60,yin,,0,0,0,,能够真正识别手势\\N{\\fs12}that does the actual recognition of a gesture\r\nDialogue: 0,0:31:54.61,0:31:56.96,yin,,0,0,0,,并在手势发生时与你通信\\N{\\fs12}and communicating with you when it does.\r\nDialogue: 0,0:31:57.47,0:32:00.04,yin,,0,0,0,,使用手势识别器有两步\\N{\\fs12}There's two parts to using a gesture recognizer.\r\nDialogue: 0,0:32:00.05,0:32:04.40,yin,,0,0,0,,先要创建手势识别器 添加到视图中\\N{\\fs12}You have to create a gesture recognizer and add it to a view.\r\nDialogue: 0,0:32:04.58,0:32:06.88,yin,,0,0,0,,只能将识别器添加到视图中\\N{\\fs12}You can only add a recognizer to a view.\r\nDialogue: 0,0:32:07.00,0:32:09.12,yin,,0,0,0,,因为只有视图具有坐标系\\N{\\fs12}Because views are the only ones that have a coordinate system\r\nDialogue: 0,0:32:09.14,0:32:11.47,yin,,0,0,0,,能够知道触发手势的\\N{\\fs12}to know where the touches were\r\nDialogue: 0,0:32:11.67,0:32:13.10,yin,,0,0,0,,触摸的位置\\N{\\fs12}that cause the gesture to happen.\r\nDialogue: 0,0:32:13.39,0:32:15.92,yin,,0,0,0,,第二步是你需要提供一个处理器\\N{\\fs12}And then number two is you've got to provide the handler,\r\nDialogue: 0,0:32:15.93,0:32:18.42,yin,,0,0,0,,当手势发生时要调用的一个方法\\N{\\fs12}a method to call when the gesture happens\r\nDialogue: 0,0:32:18.42,0:32:19.37,yin,,0,0,0,,或者是手势正在发生时\\N{\\fs12}or is happening.\r\nDialogue: 0,0:32:19.43,0:32:21.55,yin,,0,0,0,,如果是捏合手势\\N{\\fs12}If it's like a pinch it's, you know,\r\nDialogue: 0,0:32:21.55,0:32:23.91,yin,,0,0,0,,手势处理器会随着来回缩放\\N{\\fs12}that gesture handle is going to get called a lot\r\nDialogue: 0,0:32:23.97,0:32:25.29,yin,,0,0,0,,多次被调用\\N{\\fs12}as the pinch goes out and in.\r\nDialogue: 0,0:32:25.29,0:32:26.42,yin,,0,0,0,,拖动手势也是这样\\N{\\fs12}Or if it's a pan.\r\nDialogue: 0,0:32:26.66,0:32:28.70,yin,,0,0,0,,但如果是滑动或点击\\N{\\fs12}Okay? But if it's a swipe or a tap\r\nDialogue: 0,0:32:28.71,0:32:30.04,yin,,0,0,0,,就只会调用一次\\N{\\fs12}you're just going to get called once.\r\nDialogue: 0,0:32:30.71,0:32:31.31,yin,,0,0,0,,明白吗\\N{\\fs12}Make sense?\r\nDialogue: 0,0:32:32.02,0:32:33.75,yin,,0,0,0,,这就是需要做的两步操作\\N{\\fs12}So those are the two things that you need to do.\r\nDialogue: 0,0:32:33.93,0:32:36.53,yin,,0,0,0,,第一步一般由控制器完成\\N{\\fs12}Usually number one is done by controller,\r\nDialogue: 0,0:32:36.53,0:32:38.96,yin,,0,0,0,,但有时是视图自己完成\\N{\\fs12}although it's sometimes views do it to themselves\r\nDialogue: 0,0:32:38.96,0:32:41.57,yin,,0,0,0,,为自己添加一个手势识别器\\N{\\fs12}where they add a gesture recognizer to themselves.\r\nDialogue: 0,0:32:41.72,0:32:44.05,yin,,0,0,0,,而步骤二通常由视图提供\\N{\\fs12}And number two is often provided by the view.\r\nDialogue: 0,0:32:44.05,0:32:45.14,yin,,0,0,0,,也就是说 处理器\\N{\\fs12}In other words the handler,\r\nDialogue: 0,0:32:45.15,0:32:48.80,yin,,0,0,0,,手势发生时或发生后要做的事情\\N{\\fs12}the thing to do when the gesture is happening or happened,\r\nDialogue: 0,0:32:48.81,0:32:51.27,yin,,0,0,0,,很多时候 是视图实现了那个方法\\N{\\fs12}a lot of times the view implements that method.\r\nDialogue: 0,0:32:51.55,0:32:53.06,yin,,0,0,0,,所以即便可能是由控制器\\N{\\fs12}So even though the controller\r\nDialogue: 0,0:32:53.07,0:32:55.63,yin,,0,0,0,,向视图添加了手势识别器\\N{\\fs12}might add the gesture recognizer to the view,\r\nDialogue: 0,0:32:55.79,0:32:58.07,yin,,0,0,0,,当它添加时 它会告诉系统\\N{\\fs12}when it adds it, it tells the system\r\nDialogue: 0,0:32:58.08,0:33:01.25,yin,,0,0,0,,如果你识别出手势 让视图来处理\\N{\\fs12}and when you recognize the gesture, let the view handle it.\r\nDialogue: 0,0:33:01.75,0:33:03.30,yin,,0,0,0,,但是控制器可以自行处理\\N{\\fs12}But the controller can handle it itself.\r\nDialogue: 0,0:33:03.30,0:33:04.78,yin,,0,0,0,,两种方式我们都会演示\\N{\\fs12}So we'll do both in the demo.\r\nDialogue: 0,0:33:04.78,0:33:05.96,yin,,0,0,0,,让控制器来处理\\N{\\fs12}We'll have the controller handle it.\r\nDialogue: 0,0:33:05.96,0:33:07.16,yin,,0,0,0,,和让视图来处理\\N{\\fs12}We'll have the view handle it.\r\nDialogue: 0,0:33:07.17,0:33:07.94,yin,,0,0,0,,都演示一下\\N{\\fs12}The whole deal.\r\nDialogue: 0,0:33:10.33,0:33:11.64,yin,,0,0,0,,我们来看一下代码\\N{\\fs12}So let's take a look at the code.\r\nDialogue: 0,0:33:11.64,0:33:12.83,yin,,0,0,0,,向视图添加手势识别器的\\N{\\fs12}What the code would look like\r\nDialogue: 0,0:33:12.99,0:33:16.33,yin,,0,0,0,,代码是怎样的\\N{\\fs12}to add a gesture recognizer to a view.\r\nDialogue: 0,0:33:16.34,0:33:18.78,yin,,0,0,0,,在控制器中向视图添加手势识别器\\N{\\fs12}A gesture recognizer to a view in a controller.\r\nDialogue: 0,0:33:18.78,0:33:21.23,yin,,0,0,0,,所以这段示例代码是在控制器中的\\N{\\fs12}So this code that I'm trying right here is in a controller.\r\nDialogue: 0,0:33:21.37,0:33:26.20,yin,,0,0,0,,它是视图输出口panableView的setter\\N{\\fs12}It's the setter of an outlet for a view called pannableView.\r\nDialogue: 0,0:33:26.88,0:33:28.75,yin,,0,0,0,,输出口叫做pannableView\\N{\\fs12}Okay? That's the name of the outlet, pannableView.\r\nDialogue: 0,0:33:29.06,0:33:31.19,yin,,0,0,0,,按住control键进行拖动\\N{\\fs12}So this would just control drag.\r\nDialogue: 0,0:33:31.33,0:33:33.54,yin,,0,0,0,,连接起来就创建了输出口\\N{\\fs12}Wire it up and now as an outlet\r\nDialogue: 0,0:33:33.54,0:33:34.74,yin,,0,0,0,,这是输出口的setter\\N{\\fs12}and now we're in the setter.\r\nDialogue: 0,0:33:34.91,0:33:36.23,yin,,0,0,0,,而在setter中要做的是\\N{\\fs12}And in the setter what we're going to do is\r\nDialogue: 0,0:33:36.23,0:33:38.64,yin,,0,0,0,,当控制器中的视图设好以后\\N{\\fs12}when that view is set in our controller,\r\nDialogue: 0,0:33:38.65,0:33:40.93,yin,,0,0,0,,我们要向那个视图添加手势识别器\\N{\\fs12}we're going to add a gesture recognizer to that view.\r\nDialogue: 0,0:33:41.43,0:33:44.73,yin,,0,0,0,,这样视图就可以识别拖动手势了\\N{\\fs12}So that that view starts recognizing the pan gesture.\r\nDialogue: 0,0:33:44.74,0:33:46.88,yin,,0,0,0,,拖动是指用手指触摸着屏幕来回移动\\N{\\fs12}Pan is put your finger down and move around.\r\nDialogue: 0,0:33:47.23,0:33:48.10,yin,,0,0,0,,这叫拖动\\N{\\fs12}That's called panning.\r\nDialogue: 0,0:33:49.49,0:33:50.62,yin,,0,0,0,,非常简单\\N{\\fs12}So it's very simple.\r\nDialogue: 0,0:33:50.80,0:33:51.41,yin,,0,0,0,,可以看到\\N{\\fs12}You can see that\r\nDialogue: 0,0:33:51.42,0:33:54.76,yin,,0,0,0,,我们创建了一个UIGestureRecognizer的具体子类\\N{\\fs12}we create a concrete subclass of gesture recognizer\r\nDialogue: 0,0:33:54.78,0:33:56.37,yin,,0,0,0,,叫做UIPanGestureRecognizer\\N{\\fs12}called UIPanGestureRecognizer.\r\nDialogue: 0,0:33:56.37,0:33:57.94,yin,,0,0,0,,就是黄色气泡显示的那条代码\\N{\\fs12}You see that there in the yellow bubble.\r\nDialogue: 0,0:33:58.29,0:34:02.03,yin,,0,0,0,,可以看到创建时的指定初始化方法\\N{\\fs12}And when we create it you can see its designated initializer.\r\nDialogue: 0,0:34:02.03,0:34:05.64,yin,,0,0,0,,所有实体类的指定初始化方法\\N{\\fs12}All the concrete classes' designate initializer\r\nDialogue: 0,0:34:05.81,0:34:06.80,yin,,0,0,0,,都需要两个参数\\N{\\fs12}take two arguments.\r\nDialogue: 0,0:34:06.81,0:34:08.13,yin,,0,0,0,,一个是target目标\\N{\\fs12}One is the target.\r\nDialogue: 0,0:34:08.16,0:34:10.90,yin,,0,0,0,,也就是手势发生时 谁来处理\\N{\\fs12}That's who's going to handle this gesture when it happens.\r\nDialogue: 0,0:34:11.15,0:34:14.43,yin,,0,0,0,,第二个参数是该对象中要调用的方法\\N{\\fs12}And the second thing is the method to call in that object.\r\nDialogue: 0,0:34:15.01,0:34:17.84,yin,,0,0,0,,所以这里pan要被发送到那个视图\\N{\\fs12}So here pan is going to be sent to the view itself.\r\nDialogue: 0,0:34:18.45,0:34:19.54,yin,,0,0,0,,也就是我们要为其添加手势识别器的\\N{\\fs12}The same view that we're gonna\r\nDialogue: 0,0:34:19.55,0:34:21.22,yin,,0,0,0,,那个视图\\N{\\fs12}add this gesture recognizer to.\r\nDialogue: 0,0:34:21.76,0:34:23.21,yin,,0,0,0,,下面一步就只要\\N{\\fs12}And then we just do the step\r\nDialogue: 0,0:34:23.22,0:34:25.45,yin,,0,0,0,,将手势识别器添加到视图\\N{\\fs12}of adding the gesture recognizer to the view.\r\nDialogue: 0,0:34:25.54,0:34:27.31,yin,,0,0,0,,addGestureRecognizer方法\\N{\\fs12}The method addGestureRecognizer\r\nDialogue: 0,0:34:27.32,0:34:29.37,yin,,0,0,0,,只能由UIView实现\\N{\\fs12}is only implemented by UIView.\r\nDialogue: 0,0:34:29.84,0:34:32.38,yin,,0,0,0,,控制器无法识别手势\\N{\\fs12}So a controller can't recognize a gesture.\r\nDialogue: 0,0:34:32.38,0:34:34.69,yin,,0,0,0,,它没有坐标系 任何方法都无法完成\\N{\\fs12}It was no coordinate system to do that in any way.\r\nDialogue: 0,0:34:34.80,0:34:37.29,yin,,0,0,0,,所以某些视图需要处理手势\\N{\\fs12}So some view has to be handling this gesture\r\nDialogue: 0,0:34:37.31,0:34:40.53,yin,,0,0,0,,当然可以用self.view识别手势\\N{\\fs12}and yes you can have self.view recognize gestures.\r\nDialogue: 0,0:34:40.53,0:34:41.48,yin,,0,0,0,,用整个视图\\N{\\fs12}Right? The whole view.\r\nDialogue: 0,0:34:41.49,0:34:42.60,yin,,0,0,0,,完全没问题\\N{\\fs12}That's perfectly fine.\r\nDialogue: 0,0:34:43.03,0:34:46.44,yin,,0,0,0,,操作中的目标target可以是控制器\\N{\\fs12}And yes, the target in action could be the controller.\r\nDialogue: 0,0:34:46.44,0:34:47.53,yin,,0,0,0,,控制器中的方法\\N{\\fs12}A method in the controller.\r\nDialogue: 0,0:34:47.54,0:34:49.16,yin,,0,0,0,,不一定是视图\\N{\\fs12}It doesn't have to be a view.\r\nDialogue: 0,0:34:49.63,0:34:51.43,yin,,0,0,0,,可以是任意对象\\N{\\fs12}Okay? That can be any object.\r\nDialogue: 0,0:34:54.29,0:34:58.17,yin,,0,0,0,,那我们如何实现目标呢 那个拖动调用\\N{\\fs12}So how do we implement that target, that pan calling. Right?\r\nDialogue: 0,0:34:58.34,0:35:00.74,yin,,0,0,0,,我在拖动 在捏合\\N{\\fs12}So I'm panning, I'm pinching\r\nDialogue: 0,0:35:00.83,0:35:03.93,yin,,0,0,0,,在拖动时发送拖动调用\\N{\\fs12}and I'm getting sent pan calling when I'm panning.\r\nDialogue: 0,0:35:04.09,0:35:05.85,yin,,0,0,0,,我要在那个方法中做什么呢\\N{\\fs12}What do I do inside that method?\r\nDialogue: 0,0:35:06.24,0:35:09.49,yin,,0,0,0,,答案是 UIGestureRecognizer的所有具体子类\\N{\\fs12}And the answer is that each concrete subclass\r\nDialogue: 0,0:35:09.49,0:35:13.25,yin,,0,0,0,,都会提供一些方法来辅助你\\N{\\fs12}of UIGestureRecognizer will provide some methods to help you.\r\nDialogue: 0,0:35:13.47,0:35:16.06,yin,,0,0,0,,例如 UIPanGestureRecognizer\\N{\\fs12}Okay? So for example the pan gesture recognizer\r\nDialogue: 0,0:35:16.19,0:35:17.67,yin,,0,0,0,,提供这三个方法\\N{\\fs12}provides these three methods.\r\nDialogue: 0,0:35:17.68,0:35:22.91,yin,,0,0,0,,translationInView代表触摸移动距离\\N{\\fs12}TranslationInView, that's how far the touch moved\r\nDialogue: 0,0:35:23.02,0:35:27.09,yin,,0,0,0,,从上次重置之后的移动距离\\N{\\fs12}since it's-- since basically it was last reset.\r\nDialogue: 0,0:35:27.45,0:35:31.03,yin,,0,0,0,,手指触摸到屏幕时 系统进行重置\\N{\\fs12}Okay? It starts off reset when the touch goes down.\r\nDialogue: 0,0:35:31.03,0:35:32.99,yin,,0,0,0,,在移动过程中 你可以重置\\N{\\fs12}So as you move unless you reset it\r\nDialogue: 0,0:35:32.99,0:35:34.58,yin,,0,0,0,,可以在识别器中实现\\N{\\fs12}which you can do in your recognizer.\r\nDialogue: 0,0:35:34.58,0:35:35.38,yin,,0,0,0,,稍后会演示\\N{\\fs12}We'll show you that.\r\nDialogue: 0,0:35:36.12,0:35:39.91,yin,,0,0,0,,这个方法会告诉你从起点开始的\\N{\\fs12}It's going to tell you the cumulative translation distance\r\nDialogue: 0,0:35:39.91,0:35:40.86,yin,,0,0,0,,累计移动距离\\N{\\fs12}from where you started.\r\nDialogue: 0,0:35:41.20,0:35:43.26,yin,,0,0,0,,这就是translationView\\N{\\fs12}Okay? So that's translationView.\r\nDialogue: 0,0:35:43.32,0:35:47.25,yin,,0,0,0,,velocityInView代表移动速度\\N{\\fs12}velocityInView is how fast it's moving.\r\nDialogue: 0,0:35:47.48,0:35:48.97,yin,,0,0,0,,手指移动速度是不是很快\\N{\\fs12}Is your finger moving quickly\r\nDialogue: 0,0:35:49.07,0:35:50.93,yin,,0,0,0,,好像滑动之类的\\N{\\fs12}like it's almost like a swipe or something?\r\nDialogue: 0,0:35:50.93,0:35:52.51,yin,,0,0,0,,还是移动得很慢\\N{\\fs12}Or is it moving really slow?\r\nDialogue: 0,0:35:52.51,0:35:55.22,yin,,0,0,0,,用户是想做些精细操作吗\\N{\\fs12}Is the user trying to really do some detail work?\r\nDialogue: 0,0:35:55.22,0:35:56.70,yin,,0,0,0,,这个方法可以提供速度信息\\N{\\fs12}So this is telling the velocity.\r\nDialogue: 0,0:35:56.94,0:35:58.83,yin,,0,0,0,,最后一个setTranslation inView\\N{\\fs12}And then setTranslation inView\r\nDialogue: 0,0:35:58.85,0:36:00.93,yin,,0,0,0,,允许你对移动距离进行重置\\N{\\fs12}allows you to reset the translation.\r\nDialogue: 0,0:36:01.75,0:36:02.97,yin,,0,0,0,,我刚才讲了\\N{\\fs12}Okay? Because I told you\r\nDialogue: 0,0:36:02.98,0:36:05.09,yin,,0,0,0,,translationInView代表上次重置之后的距离\\N{\\fs12}translationInView is since the last reset.\r\nDialogue: 0,0:36:05.37,0:36:07.92,yin,,0,0,0,,setTranslation可以将其重置至某点\\N{\\fs12}SetTranslation will let you to reset it to some point.\r\nDialogue: 0,0:36:08.32,0:36:10.23,yin,,0,0,0,,然后下次拖动被调用时\\N{\\fs12}And then the next pan calling in you get,\r\nDialogue: 0,0:36:10.24,0:36:11.39,yin,,0,0,0,,下次手指移动时\\N{\\fs12}the next finger movement,\r\nDialogue: 0,0:36:11.59,0:36:12.63,yin,,0,0,0,,移动距离就会是\\N{\\fs12}the translation will be\r\nDialogue: 0,0:36:12.64,0:36:14.83,yin,,0,0,0,,从重置的那个点到最后位置的距离\\N{\\fs12}from the place you just reset to the last time.\r\nDialogue: 0,0:36:17.79,0:36:22.62,yin,,0,0,0,,这就是UIPanGestureRecognizer提供的方法\\N{\\fs12}So those are given to you by pan gesture recognizer\r\nDialogue: 0,0:36:22.62,0:36:24.10,yin,,0,0,0,,你还继承了...\\N{\\fs12}and you also inherit --\r\nDialogue: 0,0:36:24.34,0:36:28.59,yin,,0,0,0,,UIPanGestureRecognizer还从UIGestureRecognizer\\N{\\fs12}pan gesture also inherits a very important property\r\nDialogue: 0,0:36:28.73,0:36:31.18,yin,,0,0,0,,从这个抽象超类继承了一个非常重要的属性\\N{\\fs12}from UIGestureRecognizer, the abstract superclass\r\nDialogue: 0,0:36:31.20,0:36:32.09,yin,,0,0,0,,叫做state状态\\N{\\fs12}called state.\r\nDialogue: 0,0:36:32.49,0:36:35.13,yin,,0,0,0,,状态有很多种不同的情况\\N{\\fs12}Now state can be a lot of different things.\r\nDialogue: 0,0:36:35.13,0:36:36.90,yin,,0,0,0,,这里是比较有趣的几个状态\\N{\\fs12}Here are some of the more interesting ones.\r\nDialogue: 0,0:36:37.45,0:36:41.32,yin,,0,0,0,,UIGestureRecognizerStateBegan表示\\N{\\fs12}UIGestureRecognizerStateBegan means\r\nDialogue: 0,0:36:41.43,0:36:45.02,yin,,0,0,0,,这是一个连续运动的手势\\N{\\fs12}this is a continuous motion kind of thing\r\nDialogue: 0,0:36:45.03,0:36:46.64,yin,,0,0,0,,比如拖动或捏合\\N{\\fs12}like a pan or a pinch\r\nDialogue: 0,0:36:47.06,0:36:48.09,yin,,0,0,0,,而它刚刚开始\\N{\\fs12}and it just started.\r\nDialogue: 0,0:36:48.55,0:36:49.55,yin,,0,0,0,,手指刚触碰到屏幕\\N{\\fs12}Finger just went down.\r\nDialogue: 0,0:36:50.02,0:36:54.05,yin,,0,0,0,,UIGestureRecognizerStateChanged表示\\N{\\fs12}Okay? Then UIGestureRecognizerStateChanged means\r\nDialogue: 0,0:36:54.06,0:36:56.24,yin,,0,0,0,,这是一个连续运动手势 并且它变化了\\N{\\fs12}it's one of those continuous things and it changed.\r\nDialogue: 0,0:36:56.35,0:36:57.09,yin,,0,0,0,,手指移动了\\N{\\fs12}The fingers moved.\r\nDialogue: 0,0:36:57.63,0:36:58.92,yin,,0,0,0,,Changed代表手指移动了\\N{\\fs12}Okay? Changed means it moved.\r\nDialogue: 0,0:36:59.03,0:37:01.70,yin,,0,0,0,,还有UIGestureRecognizerStateEnded\\N{\\fs12}And then there's UIGestureRecognizerStateEnded.\r\nDialogue: 0,0:37:02.24,0:37:03.07,yin,,0,0,0,,手指抬离屏幕了\\N{\\fs12}Finger went up.\r\nDialogue: 0,0:37:03.70,0:37:04.92,yin,,0,0,0,,和大家可能想到的一样\\N{\\fs12}Okay? Exactly what you would think.\r\nDialogue: 0,0:37:05.21,0:37:08.83,yin,,0,0,0,,还有其他的状态 比如\\N{\\fs12}But there's other states like UIGestureRecognizerState--\r\nDialogue: 0,0:37:10.97,0:37:12.56,yin,,0,0,0,,UIGestureRecognizerStateRecognized\\N{\\fs12}what's it called-- recognized.\r\nDialogue: 0,0:37:12.73,0:37:15.42,yin,,0,0,0,,它出现于不连续手势的情况\\N{\\fs12}Okay? That one you get for discrete gestures\r\nDialogue: 0,0:37:15.45,0:37:17.01,yin,,0,0,0,,比如点击或滑动\\N{\\fs12}like taps or swipes.\r\nDialogue: 0,0:37:17.25,0:37:21.73,yin,,0,0,0,,你不会得到Began Changed Ended状态\\N{\\fs12}You don't get all this began, moved or began changed ended.\r\nDialogue: 0,0:37:21.85,0:37:23.32,yin,,0,0,0,,只会得到Recognized\\N{\\fs12}You just get recognized.\r\nDialogue: 0,0:37:23.33,0:37:24.46,yin,,0,0,0,,我识别出了滑动\\N{\\fs12}I recognize the swipe.\r\nDialogue: 0,0:37:24.47,0:37:25.71,yin,,0,0,0,,我识别出了点击\\N{\\fs12}I recognize the tap.\r\nDialogue: 0,0:37:26.37,0:37:28.52,yin,,0,0,0,,明白吗 有几种不同的状态\\N{\\fs12}You see? So different state there.\r\nDialogue: 0,0:37:28.67,0:37:31.80,yin,,0,0,0,,所以连续手势是得不到Recognized的\\N{\\fs12}So recognized you'll never get on the continuous ones.\r\nDialogue: 0,0:37:32.51,0:37:33.25,yin,,0,0,0,,可能会得到\\N{\\fs12}Well, you might get it,\r\nDialogue: 0,0:37:33.27,0:37:34.69,yin,,0,0,0,,但是不会太在意它\\N{\\fs12}but you wouldn't pay much attention to it.\r\nDialogue: 0,0:37:34.83,0:37:36.49,yin,,0,0,0,,但是不连续手势中就是要看这个状态\\N{\\fs12}But on the discrete ones that's what you look at,\r\nDialogue: 0,0:37:36.49,0:37:39.07,yin,,0,0,0,,连续手势对应的是Began Changed Ended\\N{\\fs12}vice versa with the began, changed, ended.\r\nDialogue: 0,0:37:39.55,0:37:41.73,yin,,0,0,0,,还可以得到Cancelled和Failed\\N{\\fs12}You can also get cancelled and failed,\r\nDialogue: 0,0:37:41.84,0:37:42.67,yin,,0,0,0,,这类状态\\N{\\fs12}things like that.\r\nDialogue: 0,0:37:42.95,0:37:44.20,yin,,0,0,0,,它们出现的情况是\\N{\\fs12}These happen when things like\r\nDialogue: 0,0:37:44.21,0:37:45.10,yin,,0,0,0,,你正在做手势时\\N{\\fs12}you're in the middle of a gesture\r\nDialogue: 0,0:37:45.11,0:37:46.46,yin,,0,0,0,,有电话打进来了\\N{\\fs12}and a phone call comes in.\r\nDialogue: 0,0:37:46.62,0:37:49.15,yin,,0,0,0,,这时手势就断掉了\\N{\\fs12}Okay? Boom, that gesture just got blown out of the water.\r\nDialogue: 0,0:37:49.28,0:37:52.48,yin,,0,0,0,,所以好的代码都会注意Failed和Canceled\\N{\\fs12}So really good code will pay attention to failed and canceled\r\nDialogue: 0,0:37:52.59,0:37:54.76,yin,,0,0,0,,确保当手势中断时\\N{\\fs12}and make sure these things aren't in a wacky state\r\nDialogue: 0,0:37:54.76,0:37:56.86,yin,,0,0,0,,它们的状态正常\\N{\\fs12}if the thing gets aborted right in the middle.\r\nDialogue: 0,0:37:57.93,0:37:59.42,yin,,0,0,0,,我就不演示了\\N{\\fs12}So I'm not going to show that in the demo\r\nDialogue: 0,0:37:59.43,0:38:01.66,yin,,0,0,0,,因为时间很紧张\\N{\\fs12}because time is gonna be of the essence here.\r\nDialogue: 0,0:38:01.67,0:38:03.37,yin,,0,0,0,,大家可以查看相关文档\\N{\\fs12}But you can look at the documentation\r\nDialogue: 0,0:38:03.38,0:38:04.30,yin,,0,0,0,,学习如何处理这些状态\\N{\\fs12}on how to handle those.\r\nDialogue: 0,0:38:05.20,0:38:05.64,yin,,0,0,0,,好了\\N{\\fs12}All right.\r\nDialogue: 0,0:38:05.83,0:38:07.47,yin,,0,0,0,,这些具体子类\\N{\\fs12}So what would pan look like\r\nDialogue: 0,0:38:07.51,0:38:08.96,yin,,0,0,0,,为我们提供了这些方法\\N{\\fs12}given that we have those methods\r\nDialogue: 0,0:38:08.97,0:38:10.76,yin,,0,0,0,,那么pan方法是如何实现的呢\\N{\\fs12}that the concrete things provides?\r\nDialogue: 0,0:38:10.91,0:38:13.03,yin,,0,0,0,,当手指刚放到屏幕上的时候\\N{\\fs12}So I'm probably not going to do anything\r\nDialogue: 0,0:38:13.03,0:38:14.80,yin,,0,0,0,,我可能不会做任何操作\\N{\\fs12}when the finger first goes down\r\nDialogue: 0,0:38:15.15,0:38:16.79,yin,,0,0,0,,因为还没有发生任何实际的变化\\N{\\fs12}because nothing has really changed yet.\r\nDialogue: 0,0:38:16.90,0:38:18.52,yin,,0,0,0,,但只要手指开始移动\\N{\\fs12}But as soon as it starts changing\r\nDialogue: 0,0:38:18.63,0:38:20.86,yin,,0,0,0,,或者离开屏幕\\N{\\fs12}or when the finger goes back up\r\nDialogue: 0,0:38:21.03,0:38:24.41,yin,,0,0,0,,我就要根据新位置的不同\\N{\\fs12}I'm then going to update something inside my view\r\nDialogue: 0,0:38:24.54,0:38:28.35,yin,,0,0,0,,更新视图内的某些内容\\N{\\fs12}based on where this new position is.\r\nDialogue: 0,0:38:28.37,0:38:29.49,yin,,0,0,0,,而获取新位置的方法\\N{\\fs12}And I'm going to get that new position\r\nDialogue: 0,0:38:29.49,0:38:32.55,yin,,0,0,0,,就是向recognizer这个UIPanGestureRecognizer请求\\N{\\fs12}by asking the recognizer, the pan gesture recognizer\r\nDialogue: 0,0:38:32.89,0:38:35.25,yin,,0,0,0,,在当前视图中的移动距离\\N{\\fs12}what's the translation in the view self.\r\nDialogue: 0,0:38:35.27,0:38:37.64,yin,,0,0,0,,在获取移动距离时\\N{\\fs12}Okay? The reason we specify the view\r\nDialogue: 0,0:38:37.66,0:38:38.73,yin,,0,0,0,,指定视图\\N{\\fs12}when we say the translation\r\nDialogue: 0,0:38:38.73,0:38:40.23,yin,,0,0,0,,是因为我们需要坐标系\\N{\\fs12}is because we need a coordinate system.\r\nDialogue: 0,0:38:41.02,0:38:42.52,yin,,0,0,0,,我们需要知道\\N{\\fs12}Okay? We got to know what coordinate system\r\nDialogue: 0,0:38:42.53,0:38:45.02,yin,,0,0,0,,是在哪个坐标系中移动的\\N{\\fs12}we're talking about this translation being.\r\nDialogue: 0,0:38:45.22,0:38:47.22,yin,,0,0,0,,所以在这个例子中是self\\N{\\fs12}All right. So self in this case,\r\nDialogue: 0,0:38:47.23,0:38:48.95,yin,,0,0,0,,因为拖动调用发生在视图中\\N{\\fs12}because pan calling is in the view.\r\nDialogue: 0,0:38:49.72,0:38:52.27,yin,,0,0,0,,我可能会设置原点或者某些属性\\N{\\fs12}Like I might set my origin or some property.\r\nDialogue: 0,0:38:52.27,0:38:53.84,yin,,0,0,0,,这行示例代码\\N{\\fs12}This is just an example line of code\r\nDialogue: 0,0:38:53.85,0:38:55.03,yin,,0,0,0,,就是假设我有一幅图之类的\\N{\\fs12}if I had a graph of something like that.\r\nDialogue: 0,0:38:55.03,0:38:56.94,yin,,0,0,0,,或许会移动这幅图\\N{\\fs12}Maybe moving the graph around.\r\nDialogue: 0,0:38:57.40,0:38:59.21,yin,,0,0,0,,就是不断重置原点\\N{\\fs12}It's just constantly resetting the origin.\r\nDialogue: 0,0:38:59.44,0:39:02.47,yin,,0,0,0,,既然我在移动原点时\\N{\\fs12}And here since I'm moving the origin\r\nDialogue: 0,0:39:02.48,0:39:04.98,yin,,0,0,0,,是将原点从调用时所在位置\\N{\\fs12}from where it exists at the time this is called\r\nDialogue: 0,0:39:05.22,0:39:06.76,yin,,0,0,0,,按照移动距离进行移动\\N{\\fs12}by some little translation\r\nDialogue: 0,0:39:06.91,0:39:09.33,yin,,0,0,0,,我希望每次都重置移动距离\\N{\\fs12}I want to reset that translation every time.\r\nDialogue: 0,0:39:09.78,0:39:13.16,yin,,0,0,0,,这样就总能得到小的移动距离增量\\N{\\fs12}So that I'm always getting little incremental translation movements\r\nDialogue: 0,0:39:13.18,0:39:15.58,yin,,0,0,0,,一点点地移动原点\\N{\\fs12}and I'm moving my origin around incrementally.\r\nDialogue: 0,0:39:15.90,0:39:18.76,yin,,0,0,0,,否则我还得记着原点最初的位置\\N{\\fs12}Otherwise I'd have to keep track of where did my origin start,\r\nDialogue: 0,0:39:18.88,0:39:20.09,yin,,0,0,0,,然后每次调用这个方法时\\N{\\fs12}and then every time this was called\r\nDialogue: 0,0:39:20.10,0:39:22.19,yin,,0,0,0,,还要找出不同 然后再移动\\N{\\fs12}I'd have to find the difference and then move it .\r\nDialogue: 0,0:39:22.71,0:39:23.91,yin,,0,0,0,,用这里的这种方法 我就不用担心了\\N{\\fs12}This way I don't have to worry about it.\r\nDialogue: 0,0:39:23.91,0:39:26.14,yin,,0,0,0,,我只要不断将距离重置为零\\N{\\fs12}I just keep resetting the thing back to zero\r\nDialogue: 0,0:39:26.31,0:39:28.67,yin,,0,0,0,,这样就会不断得到较小的移动距离\\N{\\fs12}and so I keep getting these tiny changes.\r\nDialogue: 0,0:39:28.67,0:39:30.39,yin,,0,0,0,,随时将其应用到视图中\\N{\\fs12}I just keep applying them to my view.\r\nDialogue: 0,0:39:30.57,0:39:33.74,yin,,0,0,0,,连续手势采用这种模式是很常见的\\N{\\fs12}This's very common pattern to do this for these continuous ones.\r\nDialogue: 0,0:39:33.81,0:39:34.95,yin,,0,0,0,,不断重置\\N{\\fs12}Constantly resetting.\r\nDialogue: 0,0:39:35.41,0:39:36.42,yin,,0,0,0,,我们会在演示中实现\\N{\\fs12}We'll do that in our demo.\r\nDialogue: 0,0:39:36.42,0:39:38.51,yin,,0,0,0,,我们要实现的是缩放 但同样是通过重置的方法\\N{\\fs12}We're going to do pinch but we'll do the same resetting.\r\nDialogue: 0,0:39:41.46,0:39:44.97,yin,,0,0,0,,我们再看看其他具体识别类\\N{\\fs12}Okay, so let's look at some of the other concrete recognizers.\r\nDialogue: 0,0:39:45.33,0:39:47.79,yin,,0,0,0,,Pinch捏合 它没有移动距离属性\\N{\\fs12}Pinch. Okay, pinch doesn't have translation,\r\nDialogue: 0,0:39:47.80,0:39:48.83,yin,,0,0,0,,它有一个缩放比例属性scale\\N{\\fs12}it has a scale.\r\nDialogue: 0,0:39:49.34,0:39:52.79,yin,,0,0,0,,捏合手势刚开始时 缩放比例为1.0\\N{\\fs12}So when the pinch first starts, the scale is one, 1.0.\r\nDialogue: 0,0:39:53.14,0:39:57.50,yin,,0,0,0,,随着逐渐放大 比例变为1.1 1.2 1.5 2.0\\N{\\fs12}And as I go out 1.1, 1.2, 1.5, 2.0.\r\nDialogue: 0,0:39:58.11,0:40:02.15,yin,,0,0,0,,随着缩小又变为1.5, 1.2, 1.0, 0.9, 0.8, 0.7, 0.6\\N{\\fs12}1.5, 1.2, 1.0, 0.9, 0.8, 0.7, 0.6.\r\nDialogue: 0,0:40:03.18,0:40:04.49,yin,,0,0,0,,明白吗\\N{\\fs12}Okay? That make sense?\r\nDialogue: 0,0:40:04.71,0:40:05.64,yin,,0,0,0,,就是这样变化的\\N{\\fs12}So, that's what is happening there.\r\nDialogue: 0,0:40:05.68,0:40:09.60,yin,,0,0,0,,速度velocity指的是比例系数的变化速度\\N{\\fs12}And then, the velocity is how fast in scale factor change,\r\nDialogue: 0,0:40:09.61,0:40:11.88,yin,,0,0,0,,每秒钟变化多少\\N{\\fs12}per second that's happening.\r\nDialogue: 0,0:40:11.89,0:40:13.89,yin,,0,0,0,,你是在快速缩小呢\\N{\\fs12}So, are you pinching really fast in,\r\nDialogue: 0,0:40:13.91,0:40:15.47,yin,,0,0,0,,还是在快速放大 等等\\N{\\fs12}pinching fast out, etcetera?\r\nDialogue: 0,0:40:15.48,0:40:17.42,yin,,0,0,0,,这可以告诉你某些迹象\\N{\\fs12}So, that's giving you, again, some indication,\r\nDialogue: 0,0:40:17.42,0:40:18.67,yin,,0,0,0,,用户在做什么\\N{\\fs12}what's the user--\r\nDialogue: 0,0:40:18.70,0:40:20.80,yin,,0,0,0,,如果他们迅速反复放大\\N{\\fs12}if they're pinching out really quickly, repeatedly,\r\nDialogue: 0,0:40:20.81,0:40:22.37,yin,,0,0,0,,也许他们是想要快速放大\\N{\\fs12}maybe they're trying to really zoom out fast,\r\nDialogue: 0,0:40:22.37,0:40:24.54,yin,,0,0,0,,你可以用更快的速度放大之类的\\N{\\fs12}you can zoom out faster than usual or something.\r\nDialogue: 0,0:40:25.73,0:40:28.53,yin,,0,0,0,,旋转手势识别 也是两指手势\\N{\\fs12}Rotation Gesture Recognizer, also a two-finger thing,\r\nDialogue: 0,0:40:28.53,0:40:30.73,yin,,0,0,0,,和捏合很像 但是会旋转手指\\N{\\fs12}like a pinch, except for you turn your fingers.\r\nDialogue: 0,0:40:31.05,0:40:34.58,yin,,0,0,0,,它会通过弧度告诉你旋转的信息\\N{\\fs12}And it's going to tell you the rotation in radians.\r\nDialogue: 0,0:40:34.85,0:40:36.59,yin,,0,0,0,,大家都知道什么是弧度吧\\N{\\fs12}Everyone know what radians are, right?\r\nDialogue: 0,0:40:36.61,0:40:39.29,yin,,0,0,0,,一圈对应的弧度是0到2π\\N{\\fs12}Zero to 2 pi around a circle, in radians.\r\nDialogue: 0,0:40:40.19,0:40:41.44,yin,,0,0,0,,如果不知道就去查一下\\N{\\fs12}Look it up if you don't know it.\r\nDialogue: 0,0:40:41.58,0:40:44.36,yin,,0,0,0,,它也有速度属性 告诉你每秒的变化弧度\\N{\\fs12}And that's also telling you velocity in radians per second,\r\nDialogue: 0,0:40:44.69,0:40:47.42,yin,,0,0,0,,用户旋转的速度是怎样的\\N{\\fs12}how fast they're-- the person're rotating.\r\nDialogue: 0,0:40:48.24,0:40:50.69,yin,,0,0,0,,滑动手势是不连续手势之一\\N{\\fs12}Swipe Gesture is one of these discrete gestures.\r\nDialogue: 0,0:40:50.78,0:40:52.90,yin,,0,0,0,,你只要设好这个滑动手势\\N{\\fs12}You just set up this Swipe Gesture,\r\nDialogue: 0,0:40:52.91,0:40:55.67,yin,,0,0,0,,使用alloc/init设好目标和操作\\N{\\fs12}you alloc and init with the target and the action,\r\nDialogue: 0,0:40:55.75,0:40:58.07,yin,,0,0,0,,然后设置好方向direction属性\\N{\\fs12}and then you set these properties' direction\r\nDialogue: 0,0:40:58.07,0:40:59.67,yin,,0,0,0,,或者所需触控数量numberOfTouchesRequired属性\\N{\\fs12}or numberOfTouchesRequired.\r\nDialogue: 0,0:40:59.68,0:41:00.67,yin,,0,0,0,,触控数量的意思是\\N{\\fs12}Number of touches means\r\nDialogue: 0,0:41:00.73,0:41:03.44,yin,,0,0,0,,这个滑动手势需要两根手指还是一根手指来完成\\N{\\fs12}this is a swipe with two fingers or one finger.\r\nDialogue: 0,0:41:03.45,0:41:05.45,yin,,0,0,0,,这就是触控数量的意思 两指 一指\\N{\\fs12}That's what number of touches means, two finger, one finger,\r\nDialogue: 0,0:41:05.45,0:41:08.01,yin,,0,0,0,,三指 五指 按你的需要设置\\N{\\fs12}three finger, five fingers, whatever you want,\r\nDialogue: 0,0:41:08.05,0:41:10.66,yin,,0,0,0,,方向是从左到右 从右到左\\N{\\fs12}and the direction is left to right, right to left,\r\nDialogue: 0,0:41:10.67,0:41:12.21,yin,,0,0,0,,从上到下 从下到上\\N{\\fs12}top to bottom, or bottom to top.\r\nDialogue: 0,0:41:12.35,0:41:13.96,yin,,0,0,0,,你创建好之后\\N{\\fs12}Okay? So, you create it\r\nDialogue: 0,0:41:14.04,0:41:15.81,yin,,0,0,0,,如果出现了滑动手势\\N{\\fs12}and then if a swipe happens\r\nDialogue: 0,0:41:15.82,0:41:17.92,yin,,0,0,0,,符合你的条件 你就会得到...\\N{\\fs12}that meets all that, you'll get the --\r\nDialogue: 0,0:41:18.47,0:41:21.98,yin,,0,0,0,,你的处理器就会被调用一次 传递状态为Recognized\\N{\\fs12}your handler called once with \"Recognized\" as the state.\r\nDialogue: 0,0:41:23.06,0:41:23.81,yin,,0,0,0,,明白吗\\N{\\fs12}That make sense?\r\nDialogue: 0,0:41:24.25,0:41:26.30,yin,,0,0,0,,滑动手势并不需要追踪\\N{\\fs12}So, swipe is something you don't track,\r\nDialogue: 0,0:41:26.30,0:41:28.15,yin,,0,0,0,,它直接告诉你 我发现了一个滑动手势\\N{\\fs12}it just tells you, \"Oh, I saw a swipe.\"\r\nDialogue: 0,0:41:28.59,0:41:30.42,yin,,0,0,0,,而且它很聪明\\N{\\fs12}And, yes, it's smart about--\r\nDialogue: 0,0:41:30.42,0:41:32.19,yin,,0,0,0,,如果你同时有拖动手势识别器\\N{\\fs12}if you have a Pan Gesture Recognizer\r\nDialogue: 0,0:41:32.20,0:41:33.82,yin,,0,0,0,,和滑动手势识别\\N{\\fs12}and a Swipe Gesture Recognizer,\r\nDialogue: 0,0:41:34.09,0:41:35.95,yin,,0,0,0,,如果你非常顺畅地进行滑动\\N{\\fs12}if you swipe smoothly enough,\r\nDialogue: 0,0:41:36.03,0:41:37.16,yin,,0,0,0,,系统就会判断手势为滑动\\N{\\fs12}it will see it as a swipe.\r\nDialogue: 0,0:41:37.37,0:41:40.15,yin,,0,0,0,,但是如果你移动得很慢\\N{\\fs12}But if you go slower, or you don't go, you know--\r\nDialogue: 0,0:41:40.21,0:41:42.15,yin,,0,0,0,,或者走的是斜线等等\\N{\\fs12}you're going in a diagonal or something like that,\r\nDialogue: 0,0:41:42.16,0:41:43.79,yin,,0,0,0,,系统就会认为手势是拖动\\N{\\fs12}it will say, \"Oh, no, that's a pan.\"\r\nDialogue: 0,0:41:44.19,0:41:46.47,yin,,0,0,0,,所以系统知道\\N{\\fs12}Okay, so it knows how to kind of\r\nDialogue: 0,0:41:46.79,0:41:48.59,yin,,0,0,0,,如何辨别手势的不同之处\\N{\\fs12}tell the difference between gestures.\r\nDialogue: 0,0:41:49.16,0:41:50.56,yin,,0,0,0,,越多越好\\N{\\fs12}Okay? As much as possible.\r\nDialogue: 0,0:41:50.76,0:41:51.41,yin,,0,0,0,,非常好用\\N{\\fs12}It's pretty cool.\r\nDialogue: 0,0:41:52.33,0:41:53.95,yin,,0,0,0,,点击手势和滑动手势是一样的\\N{\\fs12}Tap Gesture, just like Swipe Gesture.\r\nDialogue: 0,0:41:53.96,0:41:54.75,yin,,0,0,0,,是不连续手势\\N{\\fs12}It's discrete.\r\nDialogue: 0,0:41:54.76,0:41:55.31,yin,,0,0,0,,你先设置好\\N{\\fs12}You set it up,\r\nDialogue: 0,0:41:55.33,0:41:57.08,yin,,0,0,0,,点击几下 双击还是单击\\N{\\fs12}how many taps, double tap, single tap,\r\nDialogue: 0,0:41:57.10,0:41:58.26,yin,,0,0,0,,用几根手指等等\\N{\\fs12}how many fingers, etcetera.\r\nDialogue: 0,0:41:58.51,0:42:01.35,yin,,0,0,0,,发现手势后 它会向你发送Recognized\\N{\\fs12}And it will send you \"Recognized\" when it sees it.\r\nDialogue: 0,0:42:02.21,0:42:06.57,yin,,0,0,0,,滑动手势识别器可以识别对角线滑动吗\\N{\\fs12}Can you do Swipe Gesture Recognizer for corners or no?\r\nDialogue: 0,0:42:06.70,0:42:08.60,yin,,0,0,0,,只有那四个方向吗\\N{\\fs12}Is it only those four directions?\r\nDialogue: 0,0:42:09.56,0:42:12.26,yin,,0,0,0,,问题是 滑动手势是否可以\\N{\\fs12}The question is, can you do Swipe Gestures like,\r\nDialogue: 0,0:42:12.27,0:42:14.39,yin,,0,0,0,,斜着滑向四角 而不是水平滑动\\N{\\fs12}you mean, like swiping up into a corner, as opposed to...\r\nDialogue: 0,0:42:14.40,0:42:14.86,yin,,0,0,0,,是的\\N{\\fs12}Right .\r\nDialogue: 0,0:42:15.50,0:42:16.10,yin,,0,0,0,,我觉得不能\\N{\\fs12}I don't think so.\r\nDialogue: 0,0:42:16.10,0:42:17.57,yin,,0,0,0,,我认为只有上下左右四个方向\\N{\\fs12}I think it's just left-right, up and down.\r\nDialogue: 0,0:42:17.71,0:42:18.64,yin,,0,0,0,,我可能说的不对\\N{\\fs12}I could be wrong about that.\r\nDialogue: 0,0:42:18.65,0:42:20.01,yin,,0,0,0,,我有一段时间没看文档了\\N{\\fs12}I haven't looked in the documentation for a while,\r\nDialogue: 0,0:42:20.03,0:42:21.10,yin,,0,0,0,,但是我认为只有那四种方向\\N{\\fs12}but I think it's only those four.\r\nDialogue: 0,0:42:22.38,0:42:23.86,yin,,0,0,0,,好了 我们来演示\\N{\\fs12}All right, so let's do the demo.\r\nDialogue: 0,0:42:24.42,0:42:25.64,yin,,0,0,0,,演示呢\\N{\\fs12}Okay? So, it's going to be--\r\nDialogue: 0,0:42:26.26,0:42:27.21,yin,,0,0,0,,我会快速演示一遍\\N{\\fs12}I'm going to go fast,\r\nDialogue: 0,0:42:27.22,0:42:28.87,yin,,0,0,0,,需要演示的内容很多\\N{\\fs12}there's a lot to show you here, okay?\r\nDialogue: 0,0:42:28.88,0:42:30.19,yin,,0,0,0,,但我只准备演示\\N{\\fs12}But I'm only going to show you\r\nDialogue: 0,0:42:30.28,0:42:31.74,yin,,0,0,0,,今天讲过的全部内容\\N{\\fs12}all the things we just talked about today.\r\nDialogue: 0,0:42:31.75,0:42:33.60,yin,,0,0,0,,我准备用一个综合示例\\N{\\fs12}But I'm going to try to show all of it to you\r\nDialogue: 0,0:42:33.80,0:42:35.17,yin,,0,0,0,,尽量演示全部内容\\N{\\fs12}in a comprehensive demo.\r\nDialogue: 0,0:42:36.30,0:42:37.71,yin,,0,0,0,,我先讲讲下面的安排\\N{\\fs12}Let me talk about what's coming up\r\nDialogue: 0,0:42:37.71,0:42:39.52,yin,,0,0,0,,这样我们演示完就可以直接下课了\\N{\\fs12}so that we can just finish the demo and be done.\r\nDialogue: 0,0:42:40.57,0:42:42.70,yin,,0,0,0,,同样 我们希望周五的时候\\N{\\fs12}Again, we're hoping on Friday\r\nDialogue: 0,0:42:42.91,0:42:45.65,yin,,0,0,0,,能正常运行大学开发者计划\\N{\\fs12}to get this university developer program thing going,\r\nDialogue: 0,0:42:45.65,0:42:47.56,yin,,0,0,0,,但是似乎还是不能用\\N{\\fs12}but it looks like that's still not working.\r\nDialogue: 0,0:42:48.13,0:42:51.74,yin,,0,0,0,,明天会在Piazza上通知周五是否取消\\N{\\fs12}Watch Piazza tomorrow for whether Friday is canceled.\r\nDialogue: 0,0:42:51.75,0:42:53.56,yin,,0,0,0,,现在看起来不乐观\\N{\\fs12}At this point, it's not looking good.\r\nDialogue: 0,0:42:54.52,0:42:56.52,yin,,0,0,0,,这是只适用于斯坦福大学的\\N{\\fs12}That would be a Stanford-only thing, anyway.\r\nDialogue: 0,0:42:57.48,0:42:59.51,yin,,0,0,0,,作业期限是从周一开始的一个星期\\N{\\fs12}The homework, as I said, is due a week from Monday.\r\nDialogue: 0,0:42:59.51,0:43:02.41,yin,,0,0,0,,从今天开始的话 超过七天\\N{\\fs12}So, more than seven days from now,\r\nDialogue: 0,0:43:02.42,0:43:03.46,yin,,0,0,0,,是周一之后的一个星期\\N{\\fs12}a week from Monday.\r\nDialogue: 0,0:43:04.37,0:43:07.04,yin,,0,0,0,,我强烈建议大家马上开始做\\N{\\fs12}I really strongly recommend you get started\r\nDialogue: 0,0:43:07.05,0:43:08.76,yin,,0,0,0,,先完成自定义视图\\N{\\fs12}on the part that is a custom view\r\nDialogue: 0,0:43:08.77,0:43:11.24,yin,,0,0,0,,和手势识别器的部分\\N{\\fs12}and gesture recognizer immediately.\r\nDialogue: 0,0:43:11.45,0:43:13.71,yin,,0,0,0,,不要等到下周二或周三\\N{\\fs12}Do not wait until next Tuesday or Wednesday,\r\nDialogue: 0,0:43:13.72,0:43:15.15,yin,,0,0,0,,因为到了那个时候你就会发现\\N{\\fs12}because then you're going to find that\r\nDialogue: 0,0:43:15.16,0:43:17.16,yin,,0,0,0,,想要一周内赶完这个作业\\N{\\fs12}this is a lot of work for this assignment\r\nDialogue: 0,0:43:17.17,0:43:18.42,yin,,0,0,0,,工作量很大\\N{\\fs12}to try and jam into one week.\r\nDialogue: 0,0:43:18.42,0:43:20.30,yin,,0,0,0,,所以我才给大家\\N{\\fs12}That's why I've given you, you know, whatever--\r\nDialogue: 0,0:43:20.30,0:43:21.51,yin,,0,0,0,,留了这么多天\\N{\\fs12}however many days it is.\r\nDialogue: 0,0:43:22.23,0:43:23.31,yin,,0,0,0,,这部分\\N{\\fs12}Do this part--\r\nDialogue: 0,0:43:23.32,0:43:26.10,yin,,0,0,0,,如果可以 最好在周一前做完\\N{\\fs12}I would try and do this part before next Monday if you can,\r\nDialogue: 0,0:43:26.11,0:43:29.33,yin,,0,0,0,,当然越早越好\\N{\\fs12}but certainly do this part as soon as possible.\r\nDialogue: 0,0:43:29.42,0:43:30.53,yin,,0,0,0,,剩下的部分\\N{\\fs12}Then, the rest of the part,\r\nDialogue: 0,0:43:30.54,0:43:32.68,yin,,0,0,0,,动画和自动布局\\N{\\fs12}which is animation and autolayout,\r\nDialogue: 0,0:43:32.69,0:43:34.05,yin,,0,0,0,,我会在下周一\\N{\\fs12}which I'll be talking about on Monday\r\nDialogue: 0,0:43:34.07,0:43:35.30,yin,,0,0,0,,或者下周三讲到\\N{\\fs12}and maybe next Wednesday,\r\nDialogue: 0,0:43:35.72,0:43:38.29,yin,,0,0,0,,可以完成这部分之后 再完成那一部分\\N{\\fs12}you can leave that-- you can do that after you do this part.\r\nDialogue: 0,0:43:38.29,0:43:40.50,yin,,0,0,0,,它们之间的关联并不紧密\\N{\\fs12}They're not so intertwined that it's like, oh,\r\nDialogue: 0,0:43:40.50,0:43:41.94,yin,,0,0,0,,不要求同时完成\\N{\\fs12}you've got to do them all at the same time.\r\nDialogue: 0,0:43:41.94,0:43:43.48,yin,,0,0,0,,可以有先后顺序\\N{\\fs12}It's something that you can do after.\r\nDialogue: 0,0:43:46.68,0:43:48.25,yin,,0,0,0,,好了\\N{\\fs12}Okey dokey.\r\nDialogue: 0,0:43:48.26,0:43:54.41,yin,,0,0,0,,我们要在Xcode中新建一个项目\\N{\\fs12}So, we are going to create a new project in Xcode here.\r\nDialogue: 0,0:43:54.92,0:43:55.81,yin,,0,0,0,,我要叫它...\\N{\\fs12}And, I'm going to call that--\r\nDialogue: 0,0:43:55.82,0:43:58.10,yin,,0,0,0,,这些开始设置我就快速带过了\\N{\\fs12}I'm going fast through a lot of these starting up things,\r\nDialogue: 0,0:43:58.10,0:43:59.47,yin,,0,0,0,,大家都已经知道怎么做了\\N{\\fs12}because you know how to do this already.\r\nDialogue: 0,0:43:59.47,0:44:01.18,yin,,0,0,0,,我要叫它SuperCard\\N{\\fs12}So, I'm going to call this one SuperCard.\r\nDialogue: 0,0:44:01.33,0:44:02.34,yin,,0,0,0,,这里有趣的一点是\\N{\\fs12}One thing interesting here,\r\nDialogue: 0,0:44:02.35,0:44:04.23,yin,,0,0,0,,我不指定类前缀\\N{\\fs12}I'm not going to specify a class prefix,\r\nDialogue: 0,0:44:04.24,0:44:05.67,yin,,0,0,0,,大家可以看一下是什么样的\\N{\\fs12}just so you see what that looks like,\r\nDialogue: 0,0:44:05.68,0:44:07.05,yin,,0,0,0,,我们之前总是指定类前缀\\N{\\fs12}because we've always specified that,\r\nDialogue: 0,0:44:07.06,0:44:08.77,yin,,0,0,0,,比如CardGame等\\N{\\fs12}like CardGame or something like that.\r\nDialogue: 0,0:44:08.77,0:44:11.73,yin,,0,0,0,,这里我就不指定了 我们再看看\\N{\\fs12}So, I'm just going to not specify that, and we'll see.\r\nDialogue: 0,0:44:11.74,0:44:13.77,yin,,0,0,0,,保存在主目录Developer下\\N{\\fs12}I'm going to create it in my home directory Developer\r\nDialogue: 0,0:44:13.78,0:44:14.73,yin,,0,0,0,,和往常一样\\N{\\fs12}as I usually do.\r\nDialogue: 0,0:44:15.45,0:44:16.89,yin,,0,0,0,,可以看这里\\N{\\fs12}Here, you can go and see right here\r\nDialogue: 0,0:44:16.90,0:44:19.54,yin,,0,0,0,,列着ViewController.h和ViewController.m\\N{\\fs12}where it says ViewController.h and ViewController.m,\r\nDialogue: 0,0:44:19.67,0:44:22.28,yin,,0,0,0,,这是我的视图控制器类的名字\\N{\\fs12}that's the name of my view controller classes,\r\nDialogue: 0,0:44:22.43,0:44:24.25,yin,,0,0,0,,这种名字真的很糟糕\\N{\\fs12}which is really-- those are bad names.\r\nDialogue: 0,0:44:24.35,0:44:25.94,yin,,0,0,0,,这也就是为什么我们通常都要添加类前缀\\N{\\fs12}And that's why we usually want to put something\r\nDialogue: 0,0:44:25.94,0:44:28.44,yin,,0,0,0,,比如CardGameViewController\\N{\\fs12}in that class prefix, like CardGameViewController.\r\nDialogue: 0,0:44:28.97,0:44:32.18,yin,,0,0,0,,我要把这些移走\\N{\\fs12}Okay? I'm going to move these down out of the way.\r\nDialogue: 0,0:44:33.44,0:44:37.31,yin,,0,0,0,,这边这是我的视图 storyboard视图\\N{\\fs12}Otherwise, here's my view, right, my storyboard view.\r\nDialogue: 0,0:44:37.61,0:44:42.27,yin,,0,0,0,,可以在这边打开它的控制器\\N{\\fs12}And I could bring up the controller for it right here.\r\nDialogue: 0,0:44:42.48,0:44:44.10,yin,,0,0,0,,可以看到 系统自动添加了viewDidLoad方法\\N{\\fs12}You can see I've got a viewDidLoad,\r\nDialogue: 0,0:44:44.19,0:44:45.29,yin,,0,0,0,,我会留下\\N{\\fs12}which I'll go ahead and leave.\r\nDialogue: 0,0:44:45.66,0:44:47.26,yin,,0,0,0,,内存警告方法不需要 删掉\\N{\\fs12}Memory warning, don't need that.\r\nDialogue: 0,0:44:48.18,0:44:51.59,yin,,0,0,0,,我只要在这个视图中做一件事\\N{\\fs12}Okay. And all I'm going to do in this view--\r\nDialogue: 0,0:44:51.76,0:44:52.72,yin,,0,0,0,,我们把它变小点\\N{\\fs12}let's make this a little smaller--\r\nDialogue: 0,0:44:55.36,0:44:57.82,yin,,0,0,0,,就是添加一个自定义视图\\N{\\fs12}is put a single view, custom view,\r\nDialogue: 0,0:44:57.84,0:44:58.97,yin,,0,0,0,,是一张扑克牌\\N{\\fs12}which is going to be a playing card\r\nDialogue: 0,0:44:59.42,0:45:02.46,yin,,0,0,0,,一张真正的扑克牌 绘制出来的牌\\N{\\fs12}but a real playing card, drawn playing card. Okay?\r\nDialogue: 0,0:45:02.97,0:45:06.47,yin,,0,0,0,,我们先从我们总爱做的事情入手\\N{\\fs12}So, let's start by doing what we always love to do,\r\nDialogue: 0,0:45:06.48,0:45:10.35,yin,,0,0,0,,也就是将背景设为苔藓色\\N{\\fs12}but which is setting our background here to moss.\r\nDialogue: 0,0:45:10.99,0:45:12.31,yin,,0,0,0,,我爱苔藓色 在这\\N{\\fs12}I love moss. There it is.\r\nDialogue: 0,0:45:12.31,0:45:13.35,yin,,0,0,0,,背景变为了苔藓色\\N{\\fs12}Okay, there's our moss.\r\nDialogue: 0,0:45:13.36,0:45:14.06,yin,,0,0,0,,我们喜欢这样\\N{\\fs12}We like that.\r\nDialogue: 0,0:45:14.25,0:45:16.92,yin,,0,0,0,,我这样做主要是为了能让大家看得更清楚\\N{\\fs12}I'm doing that mostly so you can see what's going on better.\r\nDialogue: 0,0:45:17.17,0:45:20.09,yin,,0,0,0,,然后我要从这里拖出自定义视图\\N{\\fs12}And, then I'm going to grab this custom view out of here.\r\nDialogue: 0,0:45:20.11,0:45:21.00,yin,,0,0,0,,在列表下面\\N{\\fs12}So, let's go down here.\r\nDialogue: 0,0:45:21.10,0:45:25.87,yin,,0,0,0,,UIView位置很靠下 在下半部分 在这\\N{\\fs12}UIView is pretty far down, past halfway. There it is.\r\nDialogue: 0,0:45:26.06,0:45:26.69,yin,,0,0,0,,看这里写的\\N{\\fs12}See right here,\r\nDialogue: 0,0:45:26.71,0:45:28.77,yin,,0,0,0,,视图代表一个矩形区域\\N{\\fs12}\"View represents a rectangular region\r\nDialogue: 0,0:45:28.78,0:45:29.78,yin,,0,0,0,,在其内绘制和接收事件\\N{\\fs12}which draws and receive events.\"\r\nDialogue: 0,0:45:29.79,0:45:32.12,yin,,0,0,0,,只要将它拖出来 放到这里\\N{\\fs12}And you just drag it out and put it out here.\r\nDialogue: 0,0:45:32.12,0:45:33.37,yin,,0,0,0,,我不想要它这么大\\N{\\fs12}I don't want it to be this big,\r\nDialogue: 0,0:45:33.37,0:45:34.55,yin,,0,0,0,,所以我要把它缩小一点\\N{\\fs12}so I'm going to make it smaller.\r\nDialogue: 0,0:45:34.87,0:45:37.92,yin,,0,0,0,,它的大小究竟是多少并不重要\\N{\\fs12}It really doesn't matter exactly what size I make this,\r\nDialogue: 0,0:45:38.05,0:45:41.84,yin,,0,0,0,,因为我要让我的绘制类\\N{\\fs12}because I'm going to make my class, my drawing class,\r\nDialogue: 0,0:45:41.94,0:45:44.45,yin,,0,0,0,,在任意尺寸下都可以正常绘制\\N{\\fs12}so that it'll draw properly in pretty much any size.\r\nDialogue: 0,0:45:44.45,0:45:46.82,yin,,0,0,0,,但如果不是常规比例就不好看了\\N{\\fs12}Now, it's going to look pretty bad if it's not--\r\nDialogue: 0,0:45:47.09,0:45:48.66,yin,,0,0,0,,通常是高大于宽\\N{\\fs12}you know, mostly tall than wide,\r\nDialogue: 0,0:45:48.67,0:45:50.22,yin,,0,0,0,,如果扑克牌又宽又短\\N{\\fs12}because playing cards don't look very good\r\nDialogue: 0,0:45:50.24,0:45:51.54,yin,,0,0,0,,看起来也不太好看\\N{\\fs12}if they're wide and short.\r\nDialogue: 0,0:45:51.72,0:45:53.90,yin,,0,0,0,,视图可以正常运行\\N{\\fs12}Okay? My view will work, it won't--\r\nDialogue: 0,0:45:54.02,0:45:56.07,yin,,0,0,0,,但用户会认不太出来它是一张牌\\N{\\fs12}people won't recognize it very much as a card,\r\nDialogue: 0,0:45:56.50,0:45:58.26,yin,,0,0,0,,但是当然没问题\\N{\\fs12}but it certainly would be fine.\r\nDialogue: 0,0:45:58.68,0:45:59.81,yin,,0,0,0,,在作业中\\N{\\fs12}And in your assignment,\r\nDialogue: 0,0:45:59.96,0:46:01.58,yin,,0,0,0,,大家创建自定义视图时\\N{\\fs12}the custom view you're going to create,\r\nDialogue: 0,0:46:01.59,0:46:03.05,yin,,0,0,0,,也要这样做\\N{\\fs12}you also want to make it that way\r\nDialogue: 0,0:46:03.07,0:46:05.14,yin,,0,0,0,,这样它就可以正常运行于任意大小的bounds\\N{\\fs12}so that it works in any size bounds.\r\nDialogue: 0,0:46:05.43,0:46:06.12,yin,,0,0,0,,在作业中\\N{\\fs12}And in that card,\r\nDialogue: 0,0:46:06.12,0:46:07.89,yin,,0,0,0,,要实现的是Set卡牌\\N{\\fs12}since it's gonna be a set card for you,\r\nDialogue: 0,0:46:08.02,0:46:10.46,yin,,0,0,0,,Set卡牌实际上可以是横向的\\N{\\fs12}set cards actually could make sense being sideways.\r\nDialogue: 0,0:46:10.60,0:46:12.58,yin,,0,0,0,,卡牌上的三个符号最好是横向排列\\N{\\fs12}You would want the three symbols, you know,\r\nDialogue: 0,0:46:12.60,0:46:14.23,yin,,0,0,0,,而不是竖向排列\\N{\\fs12}going sideways instead of up and down.\r\nDialogue: 0,0:46:14.25,0:46:16.21,yin,,0,0,0,,一个好的解决办法\\N{\\fs12}So, a good solution would make, really,\r\nDialogue: 0,0:46:16.21,0:46:20.03,yin,,0,0,0,,会让Set卡牌在任意纵横比下都很好看\\N{\\fs12}any aspect ratio look nice for a set card.\r\nDialogue: 0,0:46:20.03,0:46:20.95,yin,,0,0,0,,但是扑克牌\\N{\\fs12}But playing cards\r\nDialogue: 0,0:46:21.12,0:46:23.51,yin,,0,0,0,,大多只有竖向时才好看\\N{\\fs12}mostly only going to look good kind of set up.\r\nDialogue: 0,0:46:24.91,0:46:26.51,yin,,0,0,0,,接下来\\N{\\fs12}So, what we do here then\r\nDialogue: 0,0:46:26.52,0:46:28.13,yin,,0,0,0,,我们转到标识符检查器\\N{\\fs12}is we go to this identity inspector,\r\nDialogue: 0,0:46:28.13,0:46:30.62,yin,,0,0,0,,在这里设置这个视图的类\\N{\\fs12}and here we want to set our class of this view\r\nDialogue: 0,0:46:30.78,0:46:32.29,yin,,0,0,0,,将其设为某个自定义类\\N{\\fs12}to be some custom class, right?\r\nDialogue: 0,0:46:32.29,0:46:34.38,yin,,0,0,0,,目前它只是一个通用的UIView\\N{\\fs12}Right now, it's just a generic UIView,\r\nDialogue: 0,0:46:34.90,0:46:36.21,yin,,0,0,0,,那我们来创建那个类\\N{\\fs12}and so let's go create that class.\r\nDialogue: 0,0:46:36.21,0:46:38.28,yin,,0,0,0,,选择新建文件\\N{\\fs12}So, I'm just going to do File, New File,\r\nDialogue: 0,0:46:38.29,0:46:39.84,yin,,0,0,0,,和之前新建类一样\\N{\\fs12}just like we always do to create a class.\r\nDialogue: 0,0:46:39.85,0:46:40.67,yin,,0,0,0,,选择Objective-C类\\N{\\fs12}Objective-C.\r\nDialogue: 0,0:46:40.80,0:46:42.96,yin,,0,0,0,,它会是UIView的子类\\N{\\fs12}This one's going to be a subclass of UIView,\r\nDialogue: 0,0:46:43.23,0:46:45.45,yin,,0,0,0,,而不是UIViewController等的子类\\N{\\fs12}okay, instead of UIViewController or anything else.\r\nDialogue: 0,0:46:45.60,0:46:47.69,yin,,0,0,0,,我要叫它PlayingCardView\\N{\\fs12}I'm going to call it PlayingCardView.\r\nDialogue: 0,0:46:48.21,0:46:49.56,yin,,0,0,0,,它会是一个\\N{\\fs12}Okay, this is going to be\r\nDialogue: 0,0:46:49.58,0:46:52.99,yin,,0,0,0,,通用扑克牌显示视图\\N{\\fs12}a generic playing card displaying view.\r\nDialogue: 0,0:46:53.08,0:46:53.93,yin,,0,0,0,,完全通用\\N{\\fs12}Completely generic,\r\nDialogue: 0,0:46:54.09,0:46:56.47,yin,,0,0,0,,不和Machismo模型绑定\\N{\\fs12}not tied to the Machismo model,\r\nDialogue: 0,0:46:56.63,0:46:58.83,yin,,0,0,0,,也不和其他东西绑定\\N{\\fs12}not tied to anything else.\r\nDialogue: 0,0:46:58.85,0:47:00.15,yin,,0,0,0,,就像是独立的\\N{\\fs12}It's just like standalone.\r\nDialogue: 0,0:47:00.15,0:47:02.38,yin,,0,0,0,,要记住 创建视图时\\N{\\fs12}And remember that when we create views,\r\nDialogue: 0,0:47:02.53,0:47:03.86,yin,,0,0,0,,进入视图阵营的东西\\N{\\fs12}things that go in the view camp,\r\nDialogue: 0,0:47:03.93,0:47:05.54,yin,,0,0,0,,通用性越强越好\\N{\\fs12}they want to be as generic as possible\r\nDialogue: 0,0:47:05.54,0:47:06.80,yin,,0,0,0,,可重用性越强越好\\N{\\fs12}and reusable as possible,\r\nDialogue: 0,0:47:06.97,0:47:08.27,yin,,0,0,0,,这样这个PlayingCardView\\N{\\fs12}so that I could use this PlayingCardView\r\nDialogue: 0,0:47:08.27,0:47:10.86,yin,,0,0,0,,在扑克牌游戏和Machismo中都可以使用\\N{\\fs12}in my poker game app and also in Machismo.\r\nDialogue: 0,0:47:11.64,0:47:13.18,yin,,0,0,0,,这也就是为什么\\N{\\fs12}Okay? That's why--\r\nDialogue: 0,0:47:13.82,0:47:15.43,yin,,0,0,0,,我们强调使用\\N{\\fs12}we really want to try and enforce\r\nDialogue: 0,0:47:15.43,0:47:17.74,yin,,0,0,0,,它的通用性\\N{\\fs12}that kind of generic nature of it.\r\nDialogue: 0,0:47:17.97,0:47:20.06,yin,,0,0,0,,这是PlayingCardView的实现文件\\N{\\fs12}So, here's PlayingCardView's implementation.\r\nDialogue: 0,0:47:20.06,0:47:22.30,yin,,0,0,0,,可以看到这里有intiWithFrame方法\\N{\\fs12}You can see that I've got intiWithFrame right here,\r\nDialogue: 0,0:47:22.45,0:47:24.13,yin,,0,0,0,,这是它的指定初始化方法\\N{\\fs12}that's its designated initializer.\r\nDialogue: 0,0:47:24.25,0:47:26.95,yin,,0,0,0,,还可以看到我把这个非常重要的drawRect方法\\N{\\fs12}And you can see I've got the all-important drawRect\r\nDialogue: 0,0:47:27.00,0:47:27.96,yin,,0,0,0,,注释掉了\\N{\\fs12}commented out.\r\nDialogue: 0,0:47:28.31,0:47:29.81,yin,,0,0,0,,如果你不注释掉\\N{\\fs12}If you don't comment--\r\nDialogue: 0,0:47:29.81,0:47:30.85,yin,,0,0,0,,如果你把它注释掉\\N{\\fs12}if you comment this out,\r\nDialogue: 0,0:47:30.86,0:47:32.23,yin,,0,0,0,,不添加任何内容\\N{\\fs12}and you don't put anything in there,\r\nDialogue: 0,0:47:32.25,0:47:33.91,yin,,0,0,0,,就会占用大量性能资源\\N{\\fs12}that's going to give you a performance hit,\r\nDialogue: 0,0:47:34.12,0:47:34.95,yin,,0,0,0,,因为系统会认为\\N{\\fs12}because it's going to think\r\nDialogue: 0,0:47:34.96,0:47:36.68,yin,,0,0,0,,这个视图需要不断重绘\\N{\\fs12}this view needs to be redrawn all the time,\r\nDialogue: 0,0:47:36.68,0:47:37.54,yin,,0,0,0,,但其实它不需要\\N{\\fs12}when in fact it doesn't.\r\nDialogue: 0,0:47:37.54,0:47:39.54,yin,,0,0,0,,所以我们要先把它注释掉\\N{\\fs12}So, that's why it starts out commented out,\r\nDialogue: 0,0:47:39.55,0:47:41.02,yin,,0,0,0,,但是我们要在这里绘制\\N{\\fs12}but we are going to draw in here,\r\nDialogue: 0,0:47:41.26,0:47:43.01,yin,,0,0,0,,所以会再取消注释\\N{\\fs12}so we will be uncommented it out.\r\nDialogue: 0,0:47:43.15,0:47:44.34,yin,,0,0,0,,我要把这个方法移动一下\\N{\\fs12}I'm going to move this--\r\nDialogue: 0,0:47:44.35,0:47:46.22,yin,,0,0,0,,我们要在方法中添加某些操作\\N{\\fs12}we're going to do something in there,\r\nDialogue: 0,0:47:46.22,0:47:48.43,yin,,0,0,0,,但我要把它先移开 放到下面来\\N{\\fs12}but I'm going to move it down, out of the way,\r\nDialogue: 0,0:47:48.50,0:47:50.23,yin,,0,0,0,,合适的时候再来实现\\N{\\fs12}because we're going to do that at the appropriate time.\r\nDialogue: 0,0:47:51.43,0:47:54.23,yin,,0,0,0,,每次新建类\\N{\\fs12}Okay, so any time we create a new class,\r\nDialogue: 0,0:47:54.28,0:47:56.47,yin,,0,0,0,,需要考虑的很重要的一点就是公有API\\N{\\fs12}really important to think about is public APIs,\r\nDialogue: 0,0:47:56.48,0:47:57.19,yin,,0,0,0,,我们来做一下\\N{\\fs12}so let's do that.\r\nDialogue: 0,0:47:57.20,0:47:58.78,yin,,0,0,0,,看一下它的公有API\\N{\\fs12}Let's look at its public API.\r\nDialogue: 0,0:47:58.98,0:48:00.48,yin,,0,0,0,,它是个视图 对吧\\N{\\fs12}It's a view, right?\r\nDialogue: 0,0:48:00.71,0:48:01.64,yin,,0,0,0,,它需要做什么\\N{\\fs12}What does it need to do?\r\nDialogue: 0,0:48:01.65,0:48:04.08,yin,,0,0,0,,这个PlayingCard需要显示...\\N{\\fs12}Well, this playing card needs to display--\r\nDialogue: 0,0:48:04.19,0:48:06.21,yin,,0,0,0,,PlayingCardView需要显示扑克牌\\N{\\fs12}PlayingCardView needs to display a playing card,\r\nDialogue: 0,0:48:06.21,0:48:09.47,yin,,0,0,0,,所以我们最好能够指定要哪张牌\\N{\\fs12}so we better have some way of specifying which card we want.\r\nDialogue: 0,0:48:09.71,0:48:10.90,yin,,0,0,0,,有些人可能会认为\\N{\\fs12}Now, some of you might say,\r\nDialogue: 0,0:48:10.91,0:48:12.93,yin,,0,0,0,,太棒了 我们用Card\\N{\\fs12}\"Oh, great. Let's use Card star.\"\r\nDialogue: 0,0:48:13.01,0:48:15.23,yin,,0,0,0,,或者PlayingCard *也不错\\N{\\fs12}or, \"PlayingCard star would be great\r\nDialogue: 0,0:48:15.23,0:48:17.19,yin,,0,0,0,,PlayingCard *包含了所有我们需要的内容\\N{\\fs12}because PlayingCard star has got everything we need.\"\r\nDialogue: 0,0:48:17.44,0:48:18.48,yin,,0,0,0,,但是我说过了 我不想\\N{\\fs12}But, again, I don't want to\r\nDialogue: 0,0:48:18.49,0:48:21.80,yin,,0,0,0,,将这个通用可重用视图和那个模型绑定\\N{\\fs12}tie this generic reusable view to that model.\r\nDialogue: 0,0:48:21.85,0:48:26.07,yin,,0,0,0,,所以我要用NSUInteger rank\\N{\\fs12}So instead, I'm going to have NSUInteger rank,\r\nDialogue: 0,0:48:26.25,0:48:32.40,yin,,0,0,0,,还有NSString *suit\\N{\\fs12}and I'm going to have NSString suit,\r\nDialogue: 0,0:48:32.52,0:48:33.61,yin,,0,0,0,,我还要再加一个\\N{\\fs12}and I'm also going to have something\r\nDialogue: 0,0:48:33.63,0:48:34.89,yin,,0,0,0,,在另外一个模型中甚至没有它\\N{\\fs12}that's not even in that other model,\r\nDialogue: 0,0:48:34.90,0:48:37.84,yin,,0,0,0,,是nonatomic的 BOOL faceUp\\N{\\fs12}which is nonatomic BOOL faceUp.\r\nDialogue: 0,0:48:39.17,0:48:40.01,yin,,0,0,0,,添加这个属性\\N{\\fs12}Okay? I'm going to have it\r\nDialogue: 0,0:48:40.02,0:48:42.63,yin,,0,0,0,,用来记录卡牌是否正面朝上\\N{\\fs12}so my card is either face up or face down.\r\nDialogue: 0,0:48:42.63,0:48:43.68,yin,,0,0,0,,这是一个扑克牌视图\\N{\\fs12}This is a playing card view,\r\nDialogue: 0,0:48:43.69,0:48:46.35,yin,,0,0,0,,它要能显示牌面向上或向下的扑克牌\\N{\\fs12}it's got to be able to display the card in either up or down.\r\nDialogue: 0,0:48:46.78,0:48:50.92,yin,,0,0,0,,这就是我的API 我就需要这些\\N{\\fs12}So, that's my API. That's all I really need.\r\nDialogue: 0,0:48:50.93,0:48:53.12,yin,,0,0,0,,现在我们只要在实现文件中\\N{\\fs12}And so we've just got to implement that API\r\nDialogue: 0,0:48:53.13,0:48:54.20,yin,,0,0,0,,实现API\\N{\\fs12}in our implementation.\r\nDialogue: 0,0:48:54.54,0:48:57.27,yin,,0,0,0,,我先要做一件事 就是这个\\N{\\fs12}One thing I'm going to do right off the bat is this.\r\nDialogue: 0,0:48:58.51,0:49:00.70,yin,,0,0,0,,看到了吗 我一下就把这些都打出来了\\N{\\fs12}Okay? Now, I typed this really fast.\r\nDialogue: 0,0:49:01.52,0:49:02.21,yin,,0,0,0,,就这样\\N{\\fs12}That was it.\r\nDialogue: 0,0:49:02.74,0:49:06.67,yin,,0,0,0,,这里做的是在所有公有API的setter中\\N{\\fs12}All I'm doing here is all the setters for all my public API,\r\nDialogue: 0,0:49:06.91,0:49:09.97,yin,,0,0,0,,调用setNeedsDisplay\\N{\\fs12}I am calling setNeedsDisplay.\r\nDialogue: 0,0:49:10.92,0:49:13.56,yin,,0,0,0,,因为如果有人修改了suit 或者...\\N{\\fs12}Okay? Because if someone changes the suit, or the--\r\nDialogue: 0,0:49:13.56,0:49:14.58,yin,,0,0,0,,这里我可以写上\\N{\\fs12}and yes, I could say,\r\nDialogue: 0,0:49:14.58,0:49:16.19,yin,,0,0,0,,if _suit!=suit\\N{\\fs12}if underbar suit does not equal suit,\r\nDialogue: 0,0:49:16.19,0:49:17.62,yin,,0,0,0,,就保存自己 然后setNeedsDisplay\\N{\\fs12}then save myself and setNeedsDisplay,\r\nDialogue: 0,0:49:17.62,0:49:19.71,yin,,0,0,0,,但这里只是演示一下\\N{\\fs12}but-- okay, demo time here.\r\nDialogue: 0,0:49:19.98,0:49:21.86,yin,,0,0,0,,用setNeedsDisplay只是为了确保\\N{\\fs12}So I'm doing setNeedsDisplay just to make sure,\r\nDialogue: 0,0:49:21.86,0:49:24.16,yin,,0,0,0,,如果有人修改了rank或者suit\\N{\\fs12}if anyone changes the rank or the suit\r\nDialogue: 0,0:49:24.24,0:49:26.47,yin,,0,0,0,,或者牌面朝向\\N{\\fs12}or the faceUp-ness of my thing,\r\nDialogue: 0,0:49:26.52,0:49:28.76,yin,,0,0,0,,我就告诉系统我需要被重绘\\N{\\fs12}I tell the system I need to be redrawn.\r\nDialogue: 0,0:49:29.85,0:49:31.54,yin,,0,0,0,,明白吗 我为什么这么做\\N{\\fs12}Do you understand this, why I do that?\r\nDialogue: 0,0:49:32.34,0:49:33.37,yin,,0,0,0,,好极了\\N{\\fs12}Okay, excellent.\r\nDialogue: 0,0:49:33.39,0:49:35.45,yin,,0,0,0,,我们来实现drawRect\\N{\\fs12}So, let's dive into drawRect here.\r\nDialogue: 0,0:49:35.45,0:49:37.04,yin,,0,0,0,,取消它的注释\\N{\\fs12}I'm going to uncomment it out,\r\nDialogue: 0,0:49:38.46,0:49:39.96,yin,,0,0,0,,在这里开始绘制\\N{\\fs12}okay, and start drawing here.\r\nDialogue: 0,0:49:40.12,0:49:40.89,yin,,0,0,0,,如果我没有...\\N{\\fs12}Now, if I'm not--\r\nDialogue: 0,0:49:40.89,0:49:45.52,yin,,0,0,0,,我全部都会用UIBezierPath来实现\\N{\\fs12}I'm going to do all my stuff with UIBezierPath, so--\r\nDialogue: 0,0:49:45.96,0:49:47.41,yin,,0,0,0,,不了 我会用一次context\\N{\\fs12}well, actually, no, I'll do a context here,\r\nDialogue: 0,0:49:47.43,0:49:48.30,yin,,0,0,0,,演示一下上下文的用法\\N{\\fs12}just to show you the context.\r\nDialogue: 0,0:49:48.32,0:49:49.08,yin,,0,0,0,,我们稍后再用它\\N{\\fs12}We'll do it a little later,\r\nDialogue: 0,0:49:49.10,0:49:51.22,yin,,0,0,0,,先用UIBezierPath\\N{\\fs12}but we're going to start off doing UIBezierPath,\r\nDialogue: 0,0:49:51.40,0:49:53.56,yin,,0,0,0,,我们先设置扑克牌的外观\\N{\\fs12}and let's start with the outside of my card\r\nDialogue: 0,0:49:53.57,0:49:55.69,yin,,0,0,0,,我想要圆角矩形的\\N{\\fs12}which I want to be a rounded rect, right?\r\nDialogue: 0,0:49:55.69,0:49:57.02,yin,,0,0,0,,我想让扑克牌是圆角矩形的\\N{\\fs12}I want my cards to be a rounded rect.\r\nDialogue: 0,0:49:57.02,0:50:00.28,yin,,0,0,0,,我只要在这里创建一个贝赛尔曲线 UIBezierPath\\N{\\fs12}So, I'm just gonna create a Bezier path here, UIBezierPath.\r\nDialogue: 0,0:50:01.21,0:50:01.94,yin,,0,0,0,,我要叫它...\\N{\\fs12}I'm going to call it--\r\nDialogue: 0,0:50:02.00,0:50:03.04,yin,,0,0,0,,把其他面板隐藏起来\\N{\\fs12}and let me make some more space,\r\nDialogue: 0,0:50:03.05,0:50:05.05,yin,,0,0,0,,方便大家看到更多代码\\N{\\fs12}so we can see lots of code here.\r\nDialogue: 0,0:50:06.40,0:50:08.06,yin,,0,0,0,,我要叫它roundedRect\\N{\\fs12}RoundedRect, I'll call it.\r\nDialogue: 0,0:50:08.16,0:50:09.84,yin,,0,0,0,,我要用UIBezierPath\\N{\\fs12}And I do that with UIBezier--\r\nDialogue: 0,0:50:09.85,0:50:12.03,yin,,0,0,0,,实际上有一个类方法可以实现\\N{\\fs12}actually there's a class method that does that,\r\nDialogue: 0,0:50:13.63,0:50:19.00,yin,,0,0,0,,bezierPathWithRoundedRect 下面这个\\N{\\fs12}bezierPath for RoundedRects, down here, this one.\r\nDialogue: 0,0:50:19.35,0:50:21.25,yin,,0,0,0,,我要让这个圆角矩形\\N{\\fs12}And I'm going to have that rounded rect\r\nDialogue: 0,0:50:21.26,0:50:22.45,yin,,0,0,0,,越大越好\\N{\\fs12}be as big as possible,\r\nDialogue: 0,0:50:22.47,0:50:24.35,yin,,0,0,0,,所以我指定self.bounds\\N{\\fs12}so I specify self.bounds\r\nDialogue: 0,0:50:25.14,0:50:27.88,yin,,0,0,0,,为绘制roundedRect的矩形\\N{\\fs12}as the rectangle to draw this roundedRect in.\r\nDialogue: 0,0:50:27.98,0:50:30.08,yin,,0,0,0,,self.bounds是我的坐标系\\N{\\fs12}Okay? Self.bounds is my coordinate system.\r\nDialogue: 0,0:50:30.37,0:50:32.35,yin,,0,0,0,,它的宽度和高度组成的空间\\N{\\fs12}Its width and height is the amount of space\r\nDialogue: 0,0:50:32.36,0:50:33.87,yin,,0,0,0,,就是我在屏幕上用来绘制的范围\\N{\\fs12}I have onscreen to draw in.\r\nDialogue: 0,0:50:34.51,0:50:36.12,yin,,0,0,0,,cornerRadius呢\\N{\\fs12}Okay, cornerRadius,\r\nDialogue: 0,0:50:37.34,0:50:42.19,yin,,0,0,0,,我要在这里添加一段神奇的代码\\N{\\fs12}I'm going to throw in some magic code here for that.\r\nDialogue: 0,0:50:42.39,0:50:43.89,yin,,0,0,0,,这很重要\\N{\\fs12}This is an important thing.\r\nDialogue: 0,0:50:43.89,0:50:48.84,yin,,0,0,0,,cornerRadius代表圆角矩形的\\N{\\fs12}This cornerRadius is how many points is in the radius\r\nDialogue: 0,0:50:48.84,0:50:51.25,yin,,0,0,0,,圆角的半径有多少个点\\N{\\fs12}as it goes around the corner of the rounded rect.\r\nDialogue: 0,0:50:51.51,0:50:54.90,yin,,0,0,0,,它的值取决于卡牌的大小\\N{\\fs12}And, really, that number depends on how big my card is.\r\nDialogue: 0,0:50:54.91,0:50:57.51,yin,,0,0,0,,如果卡牌很大 半径就要很大\\N{\\fs12}If I have a big card, I want a big radius,\r\nDialogue: 0,0:50:57.62,0:50:59.88,yin,,0,0,0,,如果卡牌很小 半径就要很小\\N{\\fs12}if I have a really small card, I want a really small radius.\r\nDialogue: 0,0:51:00.01,0:51:02.60,yin,,0,0,0,,所以我创建了这个cornerScaleFactor\\N{\\fs12}So, I've created this cornerScaleFactor,\r\nDialogue: 0,0:51:02.72,0:51:06.00,yin,,0,0,0,,定义了高度的标准值\\N{\\fs12}which I've just standardized to some height,\r\nDialogue: 0,0:51:06.01,0:51:07.55,yin,,0,0,0,,可以研究一下这些数字\\N{\\fs12}and I can play with these numbers\r\nDialogue: 0,0:51:07.56,0:51:10.20,yin,,0,0,0,,找到适用于全部尺寸的数值\\N{\\fs12}to see what works for all sizes.\r\nDialogue: 0,0:51:10.33,0:51:11.76,yin,,0,0,0,,然后选择一个半径值\\N{\\fs12}And then, I'm going to pick a radius\r\nDialogue: 0,0:51:11.77,0:51:14.22,yin,,0,0,0,,这个高度对应的半径是12\\N{\\fs12}that at this height is 12,\r\nDialogue: 0,0:51:14.28,0:51:16.18,yin,,0,0,0,,用起来很不错\\N{\\fs12}and that works pretty nicely, right?\r\nDialogue: 0,0:51:16.20,0:51:17.59,yin,,0,0,0,,然后对它进行等比缩放\\N{\\fs12}And then, I'm going to scale it.\r\nDialogue: 0,0:51:18.18,0:51:20.48,yin,,0,0,0,,我要在这里调用这个方法\\N{\\fs12}Okay? So I'm going to call this method right here,\r\nDialogue: 0,0:51:21.02,0:51:25.63,yin,,0,0,0,,cornerRadius\\N{\\fs12}cornerRadius, corner radius.\r\nDialogue: 0,0:51:25.64,0:51:26.05,yin,,0,0,0,,你会看到\\N{\\fs12}And you'll see\r\nDialogue: 0,0:51:26.06,0:51:30.42,yin,,0,0,0,,我还会在其他地方用到比例系数\\N{\\fs12}I'm gonna use that scale factor in other places, too,\r\nDialogue: 0,0:51:30.43,0:51:31.43,yin,,0,0,0,,用来进行放大\\N{\\fs12}to try and scale it up.\r\nDialogue: 0,0:51:31.43,0:51:32.55,yin,,0,0,0,,这就是我说过的\\N{\\fs12}And this is part of what I'm talking about,\r\nDialogue: 0,0:51:32.55,0:51:34.07,yin,,0,0,0,,你需要实现在任意bounds下\\N{\\fs12}you need this thing to draw\r\nDialogue: 0,0:51:34.16,0:51:36.03,yin,,0,0,0,,都能正常进行绘制\\N{\\fs12}in any size bounds to make sense.\r\nDialogue: 0,0:51:36.03,0:51:38.26,yin,,0,0,0,,所以你需要这些内容\\N{\\fs12}So, you're gonna have to have a little bit of stuff\r\nDialogue: 0,0:51:38.26,0:51:42.29,yin,,0,0,0,,根据目标的大小\\N{\\fs12}that is dependent on, you know, the size and height of this thing\r\nDialogue: 0,0:51:42.30,0:51:45.09,yin,,0,0,0,,选择合适尺寸的圆角矩形等\\N{\\fs12}to pick the right size rounded rects and things like that.\r\nDialogue: 0,0:51:45.49,0:51:46.36,yin,,0,0,0,,对于这个roundedRect\\N{\\fs12}So, the first thing that\r\nDialogue: 0,0:51:46.37,0:51:47.87,yin,,0,0,0,,我先要做的是\\N{\\fs12}I'm gonna do to this roundedRect actually,\r\nDialogue: 0,0:51:47.89,0:51:49.11,yin,,0,0,0,,进行裁剪\\N{\\fs12}is I'm gonna clip to it,\r\nDialogue: 0,0:51:50.08,0:51:54.26,yin,,0,0,0,,抱歉 是addClip\\N{\\fs12}because I don't-- sorry addClip.\r\nDialogue: 0,0:51:54.26,0:51:55.36,yin,,0,0,0,,我要...\\N{\\fs12}I'm going to--\r\nDialogue: 0,0:51:55.37,0:51:57.68,yin,,0,0,0,,我并不想在roundedRect之外绘图\\N{\\fs12}I don't ever want to draw outside that roundedRect.\r\nDialogue: 0,0:51:58.05,0:51:59.76,yin,,0,0,0,,它是我的卡牌的内部绘制区\\N{\\fs12}Okay? That's the interior of my card,\r\nDialogue: 0,0:52:00.02,0:52:01.64,yin,,0,0,0,,所以我要用它进行裁剪\\N{\\fs12}so I'm just going to clip to that.\r\nDialogue: 0,0:52:01.86,0:52:04.13,yin,,0,0,0,,还可以这样做\\N{\\fs12}It also lets me do something like this.\r\nDialogue: 0,0:52:04.19,0:52:08.68,yin,,0,0,0,,UIColor whiteColor 设置为填充色\\N{\\fs12}UIColor whiteColor, set my fill color,\r\nDialogue: 0,0:52:09.68,0:52:10.78,yin,,0,0,0,,然后我可以...\\N{\\fs12}and then I can just--\r\nDialogue: 0,0:52:11.61,0:52:12.73,yin,,0,0,0,,抱歉 多打了个括号\\N{\\fs12}Sorry, I do that a lot.\r\nDialogue: 0,0:52:13.52,0:52:16.06,yin,,0,0,0,,然后我只要用这个C函数\\N{\\fs12}Then, I'm just going to use this C function,\r\nDialogue: 0,0:52:16.07,0:52:17.56,yin,,0,0,0,,因为我想演示它的用法\\N{\\fs12}because I just want to show this to you.\r\nDialogue: 0,0:52:17.72,0:52:23.83,yin,,0,0,0,,UIRectFil 然后指定一个矩形self.bounds\\N{\\fs12}UIRectFill, and you specify a rectangle, self.bounds.\r\nDialogue: 0,0:52:24.53,0:52:27.16,yin,,0,0,0,,这样就填充了这个矩形\\N{\\fs12}Okay, this just fills this rectangle.\r\nDialogue: 0,0:52:27.16,0:52:30.65,yin,,0,0,0,,这就像是创建路径\\N{\\fs12}So, it's kind of like shorthand for creating that path,\r\nDialogue: 0,0:52:30.94,0:52:32.65,yin,,0,0,0,,填充等等的简化版本\\N{\\fs12}filling it and all that stuff.\r\nDialogue: 0,0:52:32.65,0:52:35.65,yin,,0,0,0,,它直接就填充了 很好用的UIKit的内容\\N{\\fs12}It just fills it, this nice little UIKit thing.\r\nDialogue: 0,0:52:35.65,0:52:37.34,yin,,0,0,0,,它会创建一个大矩形\\N{\\fs12}And this is going to make a big rectangle,\r\nDialogue: 0,0:52:37.34,0:52:40.32,yin,,0,0,0,,这个裁剪区域会让roundedRect的内部\\N{\\fs12}but this clip is going to keep the white of this\r\nDialogue: 0,0:52:40.33,0:52:41.99,yin,,0,0,0,,是白色的\\N{\\fs12}on the inside of that roundedRect.\r\nDialogue: 0,0:52:42.41,0:52:44.60,yin,,0,0,0,,所以不会绘制四角的白色区域\\N{\\fs12}So it's not going to draw the white in the corners up there.\r\nDialogue: 0,0:52:44.91,0:52:47.76,yin,,0,0,0,,但是这里有个问题\\N{\\fs12}However, I've got a problem here,\r\nDialogue: 0,0:52:47.77,0:52:51.26,yin,,0,0,0,,这个视图的背景色默认为白色\\N{\\fs12}in that my background color for this view is by default white,\r\nDialogue: 0,0:52:51.27,0:52:54.18,yin,,0,0,0,,所以这些操作都位于一个大的白色矩形中\\N{\\fs12}so it's doing this all on a big white rectangle\r\nDialogue: 0,0:52:54.18,0:52:55.58,yin,,0,0,0,,包括那四个角\\N{\\fs12}that includes those corners.\r\nDialogue: 0,0:52:55.86,0:52:59.20,yin,,0,0,0,,所以背景色不能是白色了\\N{\\fs12}So, I need to stop my background from being white,\r\nDialogue: 0,0:52:59.22,0:53:00.63,yin,,0,0,0,,我还需要告诉系统\\N{\\fs12}and I also need to tell the system\r\nDialogue: 0,0:53:00.63,0:53:03.01,yin,,0,0,0,,我的扑克牌是透明的\\N{\\fs12}that my playing card is not opaque.\r\nDialogue: 0,0:53:03.44,0:53:06.34,yin,,0,0,0,,我要在initWithFrame中实现\\N{\\fs12}Okay? So, I'm gonna do that in initWithFrame down here,\r\nDialogue: 0,0:53:06.50,0:53:07.90,yin,,0,0,0,,但我要用正确的方法来实现\\N{\\fs12}but I'm going to do it in the right way,\r\nDialogue: 0,0:53:07.91,0:53:11.56,yin,,0,0,0,,添加一个setup方法\\N{\\fs12}which is to have a setup method.\r\nDialogue: 0,0:53:11.65,0:53:15.67,yin,,0,0,0,,在setup中 我要将背景色设为nil\\N{\\fs12}And in setup, I'm going to set my background color to nil,\r\nDialogue: 0,0:53:15.68,0:53:18.39,yin,,0,0,0,,表示不要绘制背景\\N{\\fs12}which means that I don't-- don't draw a background for me,\r\nDialogue: 0,0:53:18.49,0:53:23.07,yin,,0,0,0,,将opaque设为NO 是透明的\\N{\\fs12}and I'm going to set opaque to no, I'm not opaque.\r\nDialogue: 0,0:53:23.29,0:53:24.05,yin,,0,0,0,,我还要加上\\N{\\fs12}I'm also going to do\r\nDialogue: 0,0:53:24.06,0:53:29.23,yin,,0,0,0,,contentMode=UIViewContentModeRedraw\\N{\\fs12}that contentMode equals UIViewContentModeRedraw.\r\nDialogue: 0,0:53:29.39,0:53:31.70,yin,,0,0,0,,还记得吗 我说了如果bounds变化了\\N{\\fs12}Remember I told you that if my bounds ever change,\r\nDialogue: 0,0:53:31.89,0:53:34.67,yin,,0,0,0,,我就要调用drawRect\\N{\\fs12}I want to get my drawRect called.\r\nDialogue: 0,0:53:34.68,0:53:36.80,yin,,0,0,0,,在这个示例中 bounds不会发生变化\\N{\\fs12}Now, my bounds is not gonna change in this demo,\r\nDialogue: 0,0:53:36.80,0:53:39.54,yin,,0,0,0,,但我知道如果它变化了 我需要这样做\\N{\\fs12}but I know that if it ever does, that's what I want.\r\nDialogue: 0,0:53:39.70,0:53:40.89,yin,,0,0,0,,然后 很重要的一点是\\N{\\fs12}And then, really importantly,\r\nDialogue: 0,0:53:40.90,0:53:43.14,yin,,0,0,0,,我要在awakeFromNib中执行它\\N{\\fs12}I want to make sure I do this in awakeFromNib.\r\nDialogue: 0,0:53:43.52,0:53:45.09,yin,,0,0,0,,self setup\\N{\\fs12}Okay, self setup.\r\nDialogue: 0,0:53:45.70,0:53:48.39,yin,,0,0,0,,因为实际上 在这个示例中\\N{\\fs12}Because, in fact, in this demo,\r\nDialogue: 0,0:53:48.54,0:53:50.72,yin,,0,0,0,,我要从storyboard中创建视图\\N{\\fs12}I am going to be creating this view in a storyboard.\r\nDialogue: 0,0:53:51.03,0:53:52.91,yin,,0,0,0,,而不用alloc/init\\N{\\fs12}I'm not doing alloc init on it,\r\nDialogue: 0,0:53:52.98,0:53:54.70,yin,,0,0,0,,所以我要用这种方法来做准备\\N{\\fs12}so this is how I'm going to get set up.\r\nDialogue: 0,0:53:55.37,0:53:56.21,yin,,0,0,0,,有什么问题\\N{\\fs12}Okay? Question.\r\nDialogue: 0,0:53:56.58,0:53:59.09,yin,,0,0,0,,将背景色设为nil 而不用UIColor clearColor\\N{\\fs12}What's the advantage of setting background color to nil,\r\nDialogue: 0,0:53:59.10,0:54:01.35,yin,,0,0,0,,有什么优点吗\\N{\\fs12}instead of UIColor clearColor?\r\nDialogue: 0,0:54:01.36,0:54:02.18,yin,,0,0,0,,问题是\\N{\\fs12}Yeah, so the question is,\r\nDialogue: 0,0:54:02.19,0:54:03.88,yin,,0,0,0,,这里用nil 而不用UIColor clearColor\\N{\\fs12}What's the advantage here of saying nil\r\nDialogue: 0,0:54:04.04,0:54:06.75,yin,,0,0,0,,有什么优点\\N{\\fs12}versus UIColor clearColor?\r\nDialogue: 0,0:54:07.55,0:54:08.98,yin,,0,0,0,,答案是没有什么优点\\N{\\fs12}And the answer is there's no advantage,\r\nDialogue: 0,0:54:08.99,0:54:11.89,yin,,0,0,0,,除了用nil能比较直观地表达我的意思\\N{\\fs12}except for that, really, what I intend here is\r\nDialogue: 0,0:54:12.33,0:54:13.73,yin,,0,0,0,,就是没有背景色\\N{\\fs12}I don't have a background color.\r\nDialogue: 0,0:54:13.97,0:54:15.19,yin,,0,0,0,,你们可以不这样用\\N{\\fs12}So you can argue--\r\nDialogue: 0,0:54:15.20,0:54:16.01,yin,,0,0,0,,只是风格不同\\N{\\fs12}It's just a style thing,\r\nDialogue: 0,0:54:16.02,0:54:17.36,yin,,0,0,0,,两种方式没有什么不同\\N{\\fs12}but there's no difference in there.\r\nDialogue: 0,0:54:17.97,0:54:20.85,yin,,0,0,0,,这样我们就准备好了\\N{\\fs12}Okay? So, now we're nice and set up.\r\nDialogue: 0,0:54:20.99,0:54:22.33,yin,,0,0,0,,还要快速讲一个东西\\N{\\fs12}Oh, one thing I'm going to show you real quick here\r\nDialogue: 0,0:54:22.34,0:54:23.72,yin,,0,0,0,,#pragma\\N{\\fs12}is pound sign pragma.\r\nDialogue: 0,0:54:23.83,0:54:24.88,yin,,0,0,0,,大家知不知道它\\N{\\fs12}I don't know if you guys know about that.\r\nDialogue: 0,0:54:24.89,0:54:26.77,yin,,0,0,0,,有多少人知道#pragma是什么意思\\N{\\fs12}How many people know what pound sign pragma is?\r\nDialogue: 0,0:54:27.45,0:54:28.90,yin,,0,0,0,,几乎没人知道 很好\\N{\\fs12}Okay, almost nobody. This is awesome, then.\r\nDialogue: 0,0:54:29.17,0:54:32.06,yin,,0,0,0,,如果加一个mark 变为pragma mark\\N{\\fs12}Okay, so if you do a mark, a pragma mark,\r\nDialogue: 0,0:54:32.71,0:54:34.92,yin,,0,0,0,,你可以加一段注释\\N{\\fs12}you can put a little comment\r\nDialogue: 0,0:54:34.93,0:54:36.60,yin,,0,0,0,,比如Initialization 像这样\\N{\\fs12}like initialization, like this.\r\nDialogue: 0,0:54:36.86,0:54:39.31,yin,,0,0,0,,看上面这里 显示的是\\N{\\fs12}And now, up here. See where it says\r\nDialogue: 0,0:54:39.31,0:54:40.62,yin,,0,0,0,,implementation PlayingCardView\\N{\\fs12}\"Implementation PlayingCardView?\"\r\nDialogue: 0,0:54:40.66,0:54:43.63,yin,,0,0,0,,如果我单击它 看到这里加了一条线吗\\N{\\fs12}If I click on that, you see how it's put a line here?\r\nDialogue: 0,0:54:43.63,0:54:46.75,yin,,0,0,0,,这个破折号就是这条线\\N{\\fs12}That's this dash is this line,\r\nDialogue: 0,0:54:46.94,0:54:48.50,yin,,0,0,0,,initialization显示在这里\\N{\\fs12}and then Initialization appears here,\r\nDialogue: 0,0:54:48.50,0:54:50.36,yin,,0,0,0,,将这些方法分成了一组\\N{\\fs12}and it's grouped these for me.\r\nDialogue: 0,0:54:51.07,0:54:53.71,yin,,0,0,0,,我可以在上面这里也加上\\N{\\fs12}So, I can put, like up here as well,\r\nDialogue: 0,0:54:53.93,0:54:57.64,yin,,0,0,0,,#pragma mark - Drawing\\N{\\fs12}pound sign pragma, mark Drawing.\r\nDialogue: 0,0:54:57.97,0:54:58.85,yin,,0,0,0,,还可以加在这\\N{\\fs12}And maybe up here,\r\nDialogue: 0,0:54:58.86,0:55:03.57,yin,,0,0,0,,#pragma mark - Properties\\N{\\fs12}I could put pound sign pragma, mark Properties.\r\nDialogue: 0,0:55:04.18,0:55:07.88,yin,,0,0,0,,这样这些方法就很好地分组显示了\\N{\\fs12}And then my stuff really gets nicely grouped, okay?\r\nDialogue: 0,0:55:08.18,0:55:09.58,yin,,0,0,0,,可以考虑用这个方法\\N{\\fs12}So, something to think about there.\r\nDialogue: 0,0:55:10.87,0:55:12.33,yin,,0,0,0,,好了 回到这里\\N{\\fs12}All right, so back to here.\r\nDialogue: 0,0:55:12.33,0:55:14.84,yin,,0,0,0,,现在我的背景色是白色\\N{\\fs12}So, now I've got my background white\r\nDialogue: 0,0:55:14.85,0:55:16.57,yin,,0,0,0,,显示在一个圆角矩形中 非常好\\N{\\fs12}in a rounded rect, which is great.\r\nDialogue: 0,0:55:16.64,0:55:19.53,yin,,0,0,0,,但我还想在卡牌边缘\\N{\\fs12}But I actually also want to draw a little black line\r\nDialogue: 0,0:55:19.53,0:55:20.92,yin,,0,0,0,,添加一圈黑色边框\\N{\\fs12}around the edge of my card.\r\nDialogue: 0,0:55:21.44,0:55:23.14,yin,,0,0,0,,怎么做呢\\N{\\fs12}Okay? So how would I do that?\r\nDialogue: 0,0:55:23.42,0:55:24.50,yin,,0,0,0,,非常非常简单\\N{\\fs12}Very, very, very simple.\r\nDialogue: 0,0:55:24.51,0:55:27.46,yin,,0,0,0,,我只要设置描边颜色\\N{\\fs12}I'm just going to set my stroke color\r\nDialogue: 0,0:55:27.48,0:55:31.61,yin,,0,0,0,,[[UIColor blackColor] setStroke]\\N{\\fs12}which is UIColor blackColor setStroke.\r\nDialogue: 0,0:55:32.30,0:55:36.71,yin,,0,0,0,,然后让roundedRect\\N{\\fs12}And then I'm going to ask this roundedRect thing,\r\nDialogue: 0,0:55:36.98,0:55:39.33,yin,,0,0,0,,让这个贝塞尔路径描边\\N{\\fs12}this Bezier path, to stroke.\r\nDialogue: 0,0:55:40.36,0:55:43.09,yin,,0,0,0,,它的线宽是默认值\\N{\\fs12}Okay? And this can have the default line width,\r\nDialogue: 0,0:55:43.27,0:55:45.72,yin,,0,0,0,,可能是1 正是我想要的\\N{\\fs12}which is probably one point, which is what I want,\r\nDialogue: 0,0:55:45.73,0:55:47.50,yin,,0,0,0,,但可以让线条变粗之类的\\N{\\fs12}but I could make it thicker or whatever.\r\nDialogue: 0,0:55:48.40,0:55:49.98,yin,,0,0,0,,我们运行一下\\N{\\fs12}So let's go ahead and run, and see what--\r\nDialogue: 0,0:55:50.13,0:55:51.17,yin,,0,0,0,,看看目前是什么样子\\N{\\fs12}how things look so far.\r\nDialogue: 0,0:55:51.18,0:55:52.26,yin,,0,0,0,,现在是不会正常显示的\\N{\\fs12}Now, this is not going to work.\r\nDialogue: 0,0:55:53.23,0:55:54.12,yin,,0,0,0,,我是故意的\\N{\\fs12}And I'm doing this intentionally,\r\nDialogue: 0,0:55:54.12,0:55:55.61,yin,,0,0,0,,因为你们可能也会犯同样的错误\\N{\\fs12}because you'll probably do the same thing.\r\nDialogue: 0,0:55:56.80,0:55:59.80,yin,,0,0,0,,缩小一点 好了\\N{\\fs12}Let's put this down here. There we go.\r\nDialogue: 0,0:56:01.54,0:56:03.08,yin,,0,0,0,,好奇怪 为什么不行 好了\\N{\\fs12}Surprised that doesn't do that. Okay.\r\nDialogue: 0,0:56:04.18,0:56:06.39,yin,,0,0,0,,可以看到 矩形没有圆角\\N{\\fs12}So, you can see that I don't have my rounded corners,\r\nDialogue: 0,0:56:06.39,0:56:07.64,yin,,0,0,0,,也没有黑色边框\\N{\\fs12}and I don't have a black line.\r\nDialogue: 0,0:56:07.64,0:56:08.40,yin,,0,0,0,,为什么呢\\N{\\fs12}Why is this?\r\nDialogue: 0,0:56:08.65,0:56:09.51,yin,,0,0,0,,有谁知道吗\\N{\\fs12}Anybody know?\r\nDialogue: 0,0:56:12.13,0:56:14.15,yin,,0,0,0,,因为没有连接类\\N{\\fs12}Because you didn't hook up the class.\r\nDialogue: 0,0:56:14.15,0:56:16.79,yin,,0,0,0,,没错 因为我没有连接类\\N{\\fs12}Exactly, because I didn't hook up the class.\r\nDialogue: 0,0:56:17.10,0:56:19.28,yin,,0,0,0,,如果我回到storyboard这里\\N{\\fs12}Okay, so if I go back to my storyboard here,\r\nDialogue: 0,0:56:19.35,0:56:21.71,yin,,0,0,0,,它还是一个普通的UIView\\N{\\fs12}this is still a plain UIView.\r\nDialogue: 0,0:56:22.16,0:56:23.50,yin,,0,0,0,,看到了吗 UIView\\N{\\fs12}You see? UIView.\r\nDialogue: 0,0:56:23.75,0:56:26.13,yin,,0,0,0,,我需要把它改为PlayingCardView\\N{\\fs12}So I need to change this to be a PlayingCardView.\r\nDialogue: 0,0:56:26.56,0:56:27.95,yin,,0,0,0,,现在再运行时\\N{\\fs12}Now, when I run\r\nDialogue: 0,0:56:28.13,0:56:29.80,yin,,0,0,0,,系统知道它是一个PlayingCardView\\N{\\fs12}the system knows that's a PlayingCardView\r\nDialogue: 0,0:56:29.81,0:56:31.31,yin,,0,0,0,,出现了好看的圆角\\N{\\fs12}and I get nice, rounded rects.\r\nDialogue: 0,0:56:32.25,0:56:34.57,yin,,0,0,0,,看到四角被切掉了吗\\N{\\fs12}Okay? See my corners cut off there?\r\nDialogue: 0,0:56:34.80,0:56:35.33,yin,,0,0,0,,都很好\\N{\\fs12}It's all good.\r\nDialogue: 0,0:56:35.34,0:56:36.71,yin,,0,0,0,,外面有一圈黑色边框\\N{\\fs12}And there is a little black line around there.\r\nDialogue: 0,0:56:36.72,0:56:38.20,yin,,0,0,0,,很难看清 但是有的\\N{\\fs12}It's hard to see, but it's there.\r\nDialogue: 0,0:56:38.76,0:56:41.83,yin,,0,0,0,,好了 这部分完成了\\N{\\fs12}Okay? All right, so we're off and running here.\r\nDialogue: 0,0:56:42.02,0:56:45.13,yin,,0,0,0,,下面我要绘制牌角\\N{\\fs12}The next thing I'm going to do is draw the corners.\r\nDialogue: 0,0:56:45.15,0:56:47.43,yin,,0,0,0,,就是写着梅花A的那个地方\\N{\\fs12}You know, like where it says ace of clubs?\r\nDialogue: 0,0:56:47.54,0:56:48.70,yin,,0,0,0,,在牌角有一个A\\N{\\fs12}And in the corner there is an ace,\r\nDialogue: 0,0:56:48.70,0:56:49.87,yin,,0,0,0,,下面是一个梅花\\N{\\fs12}and then underneath is a club,\r\nDialogue: 0,0:56:49.88,0:56:52.39,yin,,0,0,0,,在与之相对的那个角上是一个倒A\\N{\\fs12}and then down in the other corner is upside-down ace,\r\nDialogue: 0,0:56:52.40,0:56:53.92,yin,,0,0,0,,然后上面是梅花\\N{\\fs12}and then clubs above it.\r\nDialogue: 0,0:56:54.23,0:56:55.64,yin,,0,0,0,,知道我说的扑克牌是什么样的吧\\N{\\fs12}You know what I'm talking about in a playing card?\r\nDialogue: 0,0:56:55.84,0:56:56.93,yin,,0,0,0,,我们要把它绘制出来\\N{\\fs12}So, we're going to draw that.\r\nDialogue: 0,0:56:57.33,0:56:58.81,yin,,0,0,0,,方法是...\\N{\\fs12}I'm going to do that by saying--\r\nDialogue: 0,0:56:59.12,0:57:01.40,yin,,0,0,0,,同样 扩大点空间\\N{\\fs12}Again, let's make more space here.\r\nDialogue: 0,0:57:01.82,0:57:04.09,yin,,0,0,0,,我要写self drawCorners\\N{\\fs12}I'm going to say self drawCorners,\r\nDialogue: 0,0:57:04.43,0:57:06.14,yin,,0,0,0,,用一个不同的方法来完成\\N{\\fs12}but do this in a different method,\r\nDialogue: 0,0:57:08.12,0:57:10.25,yin,,0,0,0,,(void) drawCorners\\N{\\fs12}void drawCorners.\r\nDialogue: 0,0:57:10.75,0:57:12.13,yin,,0,0,0,,想要实现它\\N{\\fs12}Okay. So, to do this,\r\nDialogue: 0,0:57:12.14,0:57:14.24,yin,,0,0,0,,我需要用NSAttributedString\\N{\\fs12}I'm going to use NSAttributedString.\r\nDialogue: 0,0:57:14.88,0:57:16.92,yin,,0,0,0,,我要做的是\\N{\\fs12}Okay? And what I'm going to do is\r\nDialogue: 0,0:57:16.93,0:57:18.67,yin,,0,0,0,,将要放在左上角的\\N{\\fs12}I'm going to make the string\r\nDialogue: 0,0:57:18.67,0:57:20.40,yin,,0,0,0,,那个字符串设为\\N{\\fs12}that I'm going to put in that upper corner\r\nDialogue: 0,0:57:20.48,0:57:23.54,yin,,0,0,0,,A 回车 梅花\\N{\\fs12}be ace, carriage return, clubs.\r\nDialogue: 0,0:57:23.96,0:57:25.30,yin,,0,0,0,,我要把它\\N{\\fs12}Okay? So, I'm just going to put that\r\nDialogue: 0,0:57:25.31,0:57:26.39,yin,,0,0,0,,放在左上角\\N{\\fs12}in the upper left corner.\r\nDialogue: 0,0:57:26.75,0:57:28.01,yin,,0,0,0,,这就是我需要的全部内容\\N{\\fs12}Bingo, that's all I need.\r\nDialogue: 0,0:57:28.13,0:57:30.53,yin,,0,0,0,,但在属性化字符串中\\N{\\fs12}But, I-- there's two things I need to set\r\nDialogue: 0,0:57:30.53,0:57:31.41,yin,,0,0,0,,有两项需要设置\\N{\\fs12}in my attributed string.\r\nDialogue: 0,0:57:31.41,0:57:32.51,yin,,0,0,0,,一是字体\\N{\\fs12}One is the font,\r\nDialogue: 0,0:57:32.51,0:57:34.02,yin,,0,0,0,,我要用预设字体\\N{\\fs12}and I'm going to use preferred font,\r\nDialogue: 0,0:57:34.06,0:57:37.42,yin,,0,0,0,,二是我需要将段落样式设为居中\\N{\\fs12}and number two is, I need the paragraph style to be centered.\r\nDialogue: 0,0:57:37.72,0:57:40.25,yin,,0,0,0,,我希望A和梅花\\N{\\fs12}I want those two things, the ace and the club,\r\nDialogue: 0,0:57:40.27,0:57:41.49,yin,,0,0,0,,上下对齐居中\\N{\\fs12}to be centered on top of each other.\r\nDialogue: 0,0:57:41.49,0:57:42.76,yin,,0,0,0,,我不想让它们左对齐\\N{\\fs12}I don't want them to be left aligned,\r\nDialogue: 0,0:57:42.76,0:57:43.63,yin,,0,0,0,,那样看起来会很奇怪\\N{\\fs12}that's going to look weird.\r\nDialogue: 0,0:57:43.65,0:57:46.10,yin,,0,0,0,,尤其是梅花10这种会看起来很搞笑\\N{\\fs12}Especially like a 10 of clubs would look really funny.\r\nDialogue: 0,0:57:46.10,0:57:46.97,yin,,0,0,0,,我想让它们居中\\N{\\fs12}I want them centered.\r\nDialogue: 0,0:57:46.97,0:57:49.67,yin,,0,0,0,,我们没讲过如何在属性化字符串中\\N{\\fs12}So, we didn't really talk about how to set that kind\r\nDialogue: 0,0:57:49.67,0:57:54.53,yin,,0,0,0,,实现段落对齐等等\\N{\\fs12}of paragraph-level alignment and stuff in a attribute string,\r\nDialogue: 0,0:57:54.53,0:57:55.94,yin,,0,0,0,,正好可以演示一下\\N{\\fs12}so here's a chance to show you.\r\nDialogue: 0,0:57:56.99,0:57:58.31,yin,,0,0,0,,想要实现这个功能\\N{\\fs12}So, to do that,\r\nDialogue: 0,0:57:58.32,0:58:01.01,yin,,0,0,0,,我们用这个ParagraphStyle类\\N{\\fs12}we use this class called paragraph style.\r\nDialogue: 0,0:58:01.45,0:58:03.14,yin,,0,0,0,,它指定了\\N{\\fs12}Okay, paragraph style specifies things\r\nDialogue: 0,0:58:03.14,0:58:04.64,yin,,0,0,0,,段落的对齐方式等\\N{\\fs12}like the alignment of a paragraph.\r\nDialogue: 0,0:58:04.89,0:58:06.43,yin,,0,0,0,,所以我要创建一个它的可变版本\\N{\\fs12}So I'm going to create a mutable one\r\nDialogue: 0,0:58:06.43,0:58:07.95,yin,,0,0,0,,这样就能进行设置了\\N{\\fs12}that I can set things in,\r\nDialogue: 0,0:58:08.22,0:58:11.51,yin,,0,0,0,,方法是[NSMutableParagraphStyle alloc] init]\\N{\\fs12}and I do that with NSMutableParagraphStyle, alloc init.\r\nDialogue: 0,0:58:11.99,0:58:14.79,yin,,0,0,0,,然后将paragraphStyle的对齐属性\\N{\\fs12}And then, I'm going to set the paragraphStyle's alignment\r\nDialogue: 0,0:58:14.88,0:58:18.71,yin,,0,0,0,,设为NSTextAlignmentCenter\\N{\\fs12}to be NSTextAlignmentCenter.\r\nDialogue: 0,0:58:19.09,0:58:19.93,yin,,0,0,0,,表示居中\\N{\\fs12}So that just mean centered.\r\nDialogue: 0,0:58:19.93,0:58:20.93,yin,,0,0,0,,然后我要在属性化字符串中\\N{\\fs12}And then I'm going to set this\r\nDialogue: 0,0:58:20.94,0:58:22.98,yin,,0,0,0,,将它作为属性 进行设置\\N{\\fs12}as an attribute on my attributed string.\r\nDialogue: 0,0:58:23.75,0:58:25.56,yin,,0,0,0,,我还需要一个字体属性\\N{\\fs12}The other attribute I need is the font,\r\nDialogue: 0,0:58:25.58,0:58:28.34,yin,,0,0,0,,在这里创建一个cornerFont\\N{\\fs12}so I'm going to say a cornerFont here, and--\r\nDialogue: 0,0:58:28.56,0:58:29.36,yin,,0,0,0,,打错了是Font\\N{\\fs12}whoops, font--\r\nDialogue: 0,0:58:29.36,0:58:33.07,yin,,0,0,0,,当然我需要用预设字体\\N{\\fs12}and I need, of course, to use a preferred font.\r\nDialogue: 0,0:58:33.40,0:58:35.46,yin,,0,0,0,,这有些参数\\N{\\fs12}And, you know, there's some arguments here.\r\nDialogue: 0,0:58:35.46,0:58:42.90,yin,,0,0,0,,最适合这里的样式是什么呢\\N{\\fs12}What would be the best style here?\r\nDialogue: 0,0:58:42.90,0:58:46.56,yin,,0,0,0,,标题样式吗 还是副标题样式\\N{\\fs12}You know, maybe Headline, maybe even subHeadline.\r\nDialogue: 0,0:58:46.91,0:58:50.01,yin,,0,0,0,,但我要试试正文样式 看看是什么样\\N{\\fs12}But I'm going to try Body, and we'll see how it looks.\r\nDialogue: 0,0:58:50.02,0:58:50.72,yin,,0,0,0,,如果我不喜欢\\N{\\fs12}And if I don't like it,\r\nDialogue: 0,0:58:50.73,0:58:52.09,yin,,0,0,0,,可以再改成别的样式\\N{\\fs12}I can go change it to something else.\r\nDialogue: 0,0:58:52.14,0:58:53.13,yin,,0,0,0,,但是关于这个字体\\N{\\fs12}But there's something really important\r\nDialogue: 0,0:58:53.13,0:58:54.32,yin,,0,0,0,,有一点很重要 需要注意\\N{\\fs12}to notice about this font.\r\nDialogue: 0,0:58:54.33,0:58:56.71,yin,,0,0,0,,它会以特定大小显示\\N{\\fs12}It's going to come in in a certain size,\r\nDialogue: 0,0:58:56.72,0:58:59.02,yin,,0,0,0,,用户可以随意选择\\N{\\fs12}whatever size the user wants,\r\nDialogue: 0,0:58:59.02,0:59:02.07,yin,,0,0,0,,像我这样上岁数的人想要大字 好看清\\N{\\fs12}old people like me want big ones, so I can see.\r\nDialogue: 0,0:59:02.07,0:59:04.82,yin,,0,0,0,,像你们这样的年轻人可能想要小字\\N{\\fs12}And younger people like you probably want smaller ones.\r\nDialogue: 0,0:59:05.60,0:59:07.51,yin,,0,0,0,,但我们还要在此基础上对它进行缩放\\N{\\fs12}But we still need to scale it from there.\r\nDialogue: 0,0:59:07.51,0:59:09.04,yin,,0,0,0,,我们要用预设字体大小的信息\\N{\\fs12}So, we want to use that information,\r\nDialogue: 0,0:59:09.05,0:59:10.10,yin,,0,0,0,,但还要对它进行缩放\\N{\\fs12}but then we want to scale it\r\nDialogue: 0,0:59:10.11,0:59:11.81,yin,,0,0,0,,同样取决于卡牌的大小\\N{\\fs12}again, depending on how big our card is.\r\nDialogue: 0,0:59:11.86,0:59:14.87,yin,,0,0,0,,大牌显示大字 小牌显示小字\\N{\\fs12}Big cards want big font, little cards want little fonts.\r\nDialogue: 0,0:59:14.99,0:59:16.92,yin,,0,0,0,,实现它的缩放的方法\\N{\\fs12}Okay. So, we're going to scale it\r\nDialogue: 0,0:59:16.93,0:59:18.80,yin,,0,0,0,,就是在这新建一个字体\\N{\\fs12}just by creating a new font here.\r\nDialogue: 0,0:59:20.20,0:59:23.16,yin,,0,0,0,,我们要怎么做呢\\N{\\fs12}And we're going to do that.\r\nDialogue: 0,0:59:23.44,0:59:27.68,yin,,0,0,0,,确认一下 要和我之前定好的方法一样\\N{\\fs12}Make sure I do this the way that I predefined it here.\r\nDialogue: 0,0:59:28.48,0:59:29.59,yin,,0,0,0,,我要这样做\\N{\\fs12}So, I'm going to do this\r\nDialogue: 0,0:59:29.59,0:59:33.29,yin,,0,0,0,,cornerFont fontWithSize\\N{\\fs12}by saying cornerFont, fontWithSize.\r\nDialogue: 0,0:59:33.29,0:59:35.84,yin,,0,0,0,,它是字体的一个实例方法\\N{\\fs12}So, this is a method in font, an instance method in font.\r\nDialogue: 0,0:59:35.84,0:59:37.04,yin,,0,0,0,,它会新建一个字体\\N{\\fs12}This is create me a new font\r\nDialogue: 0,0:59:37.07,0:59:38.85,yin,,0,0,0,,和我发送给它的字体一样\\N{\\fs12}that's just like the font I'm sending this to\r\nDialogue: 0,0:59:38.87,0:59:40.04,yin,,0,0,0,,但是大小不同\\N{\\fs12}but with a different size.\r\nDialogue: 0,0:59:40.43,0:59:42.62,yin,,0,0,0,,我要用的大小是\\N{\\fs12}And the size I'm going to use is\r\nDialogue: 0,0:59:42.79,0:59:45.36,yin,,0,0,0,,cornerFont的当前大小\\N{\\fs12}cornerFont current size--\r\nDialogue: 0,0:59:45.45,0:59:47.58,yin,,0,0,0,,pointSize是字体的一个属性\\N{\\fs12}pointSize is property in a font\r\nDialogue: 0,0:59:47.58,0:59:49.29,yin,,0,0,0,,能告诉你当前磅值是多少\\N{\\fs12}that tells you what its current point size is--\r\nDialogue: 0,0:59:49.62,0:59:54.12,yin,,0,0,0,,用它乘以cornerScaleFactor\\N{\\fs12}times that cornerScaleFactor\r\nDialogue: 0,0:59:54.74,0:59:57.01,yin,,0,0,0,,我之前用过的 在上面这里\\N{\\fs12}that I used earlier, up here,\r\nDialogue: 0,0:59:57.08,0:59:59.21,yin,,0,0,0,,求cornerRadius时用到的\\N{\\fs12}to do this cornerRadius, okay?\r\nDialogue: 0,0:59:59.35,1:00:00.76,yin,,0,0,0,,就是这个cornerScaleFactor\\N{\\fs12}So this is this cornerScaleFactor.\r\nDialogue: 0,1:00:00.76,1:00:02.79,yin,,0,0,0,,用的是相同的比例系数\\N{\\fs12}I'm using the same factor here.\r\nDialogue: 0,1:00:03.31,1:00:05.57,yin,,0,0,0,,我们会检查显示效果是否正确\\N{\\fs12}And, again, we'll see if that turns out to be right,\r\nDialogue: 0,1:00:05.59,1:00:06.78,yin,,0,0,0,,如果不对 还可以修改\\N{\\fs12}if not, we can always change it.\r\nDialogue: 0,1:00:07.38,1:00:09.68,yin,,0,0,0,,现在 我们来创建这个属性化字符串\\N{\\fs12}So now, let's go ahead and create this attributed string.\r\nDialogue: 0,1:00:11.02,1:00:14.13,yin,,0,0,0,,我要叫它cornerText\\N{\\fs12}I'm going to call this the cornerText, and I'm--\r\nDialogue: 0,1:00:14.13,1:00:19.28,yin,,0,0,0,,[NSAttributedString alloc] initWithString\\N{\\fs12}it's just NSAttributedString, alloc, initWithString.\r\nDialogue: 0,1:00:20.67,1:00:24.92,yin,,0,0,0,,我要创建的字符串是NSString stringWithFormat\\N{\\fs12}The string I'm going to create is NSString stringWithFormat,\r\nDialogue: 0,1:00:25.17,1:00:29.87,yin,,0,0,0,,就是刚才说过的 %@\\N{\\fs12}%@\\N{\\fs12}as I promised, % at sign, carriage return, % at sign.\r\nDialogue: 0,1:00:30.22,1:00:32.85,yin,,0,0,0,,第一个占位符是rank\\N{\\fs12}Okay. The first thing is the rank.\r\nDialogue: 0,1:00:32.91,1:00:35.70,yin,,0,0,0,,这里要写self rankAsString\\N{\\fs12}So, I need self rankAsString,\r\nDialogue: 0,1:00:35.71,1:00:37.26,yin,,0,0,0,,因为rank是一个数字\\N{\\fs12}because my rank is a number,\r\nDialogue: 0,1:00:37.26,1:00:38.57,yin,,0,0,0,,需要把它转换为字符串\\N{\\fs12}and I need it as a string.\r\nDialogue: 0,1:00:38.79,1:00:40.66,yin,,0,0,0,,我要到上面这里...\\N{\\fs12}So I'm going to go up here and really--\r\nDialogue: 0,1:00:40.91,1:00:42.48,yin,,0,0,0,,出来了 rankAsString\\N{\\fs12}whoop, look at that, rankAsString.\r\nDialogue: 0,1:00:42.78,1:00:44.40,yin,,0,0,0,,和之前做过的一样\\N{\\fs12}So, same thing we did before,\r\nDialogue: 0,1:00:44.41,1:00:46.46,yin,,0,0,0,,一个排列数组 然后是self.rank\\N{\\fs12}little array with that in there, self rank.\r\nDialogue: 0,1:00:46.46,1:00:48.15,yin,,0,0,0,,没有检查bounds之类的操作\\N{\\fs12}I don't do any bounds checking and stuff,\r\nDialogue: 0,1:00:48.15,1:00:50.48,yin,,0,0,0,,这个示例缺少bounds检查\\N{\\fs12}this demo is light on bounds checking.\r\nDialogue: 0,1:00:50.48,1:00:52.61,yin,,0,0,0,,好的代码会在自我保护上做的更好一些\\N{\\fs12}You know, good code would protect yourself a little better.\r\nDialogue: 0,1:00:52.95,1:00:54.48,yin,,0,0,0,,然后是suit\\N{\\fs12}And then, here is the suit.\r\nDialogue: 0,1:00:55.18,1:00:57.44,yin,,0,0,0,,suit\\N{\\fs12}Okay? Suit, suit.\r\nDialogue: 0,1:00:58.61,1:01:01.35,yin,,0,0,0,,检查一下方括号对不对\\N{\\fs12}All right, so make sure I have my square brackets right here.\r\nDialogue: 0,1:01:01.62,1:01:06.57,yin,,0,0,0,,self suit 不对 好了\\N{\\fs12}self suit, no, and there we go.\r\nDialogue: 0,1:01:07.19,1:01:08.40,yin,,0,0,0,,这就是字符串\\N{\\fs12}So, there's the string.\r\nDialogue: 0,1:01:08.48,1:01:10.85,yin,,0,0,0,,这里我们要设置的属性\\N{\\fs12}And then, the attributes we're gonna\r\nDialogue: 0,1:01:10.85,1:01:12.70,yin,,0,0,0,,是一个dictionary\\N{\\fs12}set here is a dictionary.\r\nDialogue: 0,1:01:12.90,1:01:15.15,yin,,0,0,0,,我要设置字体\\N{\\fs12}And I need to set the font.\r\nDialogue: 0,1:01:16.68,1:01:19.39,yin,,0,0,0,,叫什么来着\\N{\\fs12}Font-- what's it called again?\r\nDialogue: 0,1:01:19.52,1:01:24.24,yin,,0,0,0,,NSFontAttributeName\\N{\\fs12}Font-- NSFontAttributeName.\r\nDialogue: 0,1:01:25.08,1:01:27.12,yin,,0,0,0,,然后是cornerFont\\N{\\fs12}And that's the cornerFont right there.\r\nDialogue: 0,1:01:27.12,1:01:30.53,yin,,0,0,0,,然后是NSParagraphStyleAttribute\\N{\\fs12}And then, I need NSParagraphStyle attribute,\r\nDialogue: 0,1:01:30.53,1:01:32.41,yin,,0,0,0,,这个大家没见过\\N{\\fs12}which is a new one you haven't seen before\r\nDialogue: 0,1:01:32.66,1:01:34.14,yin,,0,0,0,,我们叫它paragraphStyle\\N{\\fs12}and we'll call that paragraphStyle.\r\nDialogue: 0,1:01:35.32,1:01:36.86,yin,,0,0,0,,加上大括号\\N{\\fs12}Okay, close curly brace.\r\nDialogue: 0,1:01:37.40,1:01:38.93,yin,,0,0,0,,错了 谢谢\\N{\\fs12}Oops! Thank you.\r\nDialogue: 0,1:01:40.07,1:01:41.03,yin,,0,0,0,,删掉它\\N{\\fs12}Delete that.\r\nDialogue: 0,1:01:42.01,1:01:44.49,yin,,0,0,0,,分号\\N{\\fs12}Okay, semicolon.\r\nDialogue: 0,1:01:44.62,1:01:45.40,yin,,0,0,0,,对了吗\\N{\\fs12}Are we good there?\r\nDialogue: 0,1:01:45.54,1:01:46.25,yin,,0,0,0,,我觉得可以了\\N{\\fs12}I think we're good.\r\nDialogue: 0,1:01:46.25,1:01:47.82,yin,,0,0,0,,好了 这就是cornerText\\N{\\fs12}Okay. So, there's the cornerText,\r\nDialogue: 0,1:01:47.82,1:01:50.02,yin,,0,0,0,,就是这个回车字符串\\N{\\fs12}which is just this carriage return thing,\r\nDialogue: 0,1:01:50.03,1:01:52.65,yin,,0,0,0,,希望字体大小合适且居中\\N{\\fs12}centered with the, hopefully, good-sized font.\r\nDialogue: 0,1:01:52.90,1:01:55.58,yin,,0,0,0,,现在我要得到它的bounds\\N{\\fs12}And now, I'm going to get the bounds of that.\r\nDialogue: 0,1:01:55.69,1:01:57.01,yin,,0,0,0,,我要得到bounds\\N{\\fs12}Okay? I'm going to get the bounds,\r\nDialogue: 0,1:01:57.01,1:01:58.12,yin,,0,0,0,,然后将它放进去\\N{\\fs12}then I'm going to put that in.\r\nDialogue: 0,1:01:58.28,1:01:59.74,yin,,0,0,0,,bounds有两个参数\\N{\\fs12}And there's two things to the bounds.\r\nDialogue: 0,1:01:59.74,1:02:03.06,yin,,0,0,0,,一是左上角那个点\\N{\\fs12}One is the point, the upper left-hand point of it.\r\nDialogue: 0,1:02:03.22,1:02:05.48,yin,,0,0,0,,我可以直接...\\N{\\fs12}And I could just make that be--\r\nDialogue: 0,1:02:06.12,1:02:07.43,yin,,0,0,0,,实际上 我甚至不需要用局部变量\\N{\\fs12}actually, I don't even need a local variable.\r\nDialogue: 0,1:02:07.44,1:02:09.64,yin,,0,0,0,,就直接用textBounds.origin\\N{\\fs12}Let's just go straight to bounds dot origin.\r\nDialogue: 0,1:02:10.17,1:02:13.50,yin,,0,0,0,,其实我可以将它设为(0,0)\\N{\\fs12}So, I could make that be zero-zero, actually,\r\nDialogue: 0,1:02:13.50,1:02:16.46,yin,,0,0,0,,但这样的话 A回车梅花\\N{\\fs12}but then my little A return clubs\r\nDialogue: 0,1:02:16.47,1:02:19.14,yin,,0,0,0,,可能会和roundedRect的边线重叠\\N{\\fs12}might kind of bang into my roundedRect a little.\r\nDialogue: 0,1:02:19.14,1:02:20.70,yin,,0,0,0,,所以要把它往里移一点\\N{\\fs12}So, I want to move it in a little bit,\r\nDialogue: 0,1:02:20.83,1:02:22.73,yin,,0,0,0,,这里同样要根据roundedRect的大小\\N{\\fs12}but again, it depends on how big the roundedRect is\r\nDialogue: 0,1:02:22.74,1:02:24.07,yin,,0,0,0,,来决定往里移动的距离\\N{\\fs12}to how much I want to move it in.\r\nDialogue: 0,1:02:24.31,1:02:26.56,yin,,0,0,0,,我们用CGPointMake\\N{\\fs12}So let's say CGPointMake,\r\nDialogue: 0,1:02:27.27,1:02:32.99,yin,,0,0,0,,[self cornerOffset] [self cornerOffset]\\N{\\fs12}how about self cornerOffset, self cornerOffset.\r\nDialogue: 0,1:02:33.00,1:02:37.25,yin,,0,0,0,,cornerOffset是我加在这里的另外一个方法\\N{\\fs12}And cornerOffset is another little method I put up here\r\nDialogue: 0,1:02:37.27,1:02:39.78,yin,,0,0,0,,它也和cornerRadius有关\\N{\\fs12}that's also related to this cornerRadius.\r\nDialogue: 0,1:02:39.78,1:02:42.50,yin,,0,0,0,,看到了吗 我用cornerRadius除以3\\N{\\fs12}You see, I took the cornerRadius divided by 3.\r\nDialogue: 0,1:02:43.32,1:02:45.06,yin,,0,0,0,,看起来大概合适\\N{\\fs12}That looks like that's probably about right.\r\nDialogue: 0,1:02:45.08,1:02:46.82,yin,,0,0,0,,你在设计UI时\\N{\\fs12}Again, these are numbers you would want to play with\r\nDialogue: 0,1:02:46.84,1:02:48.26,yin,,0,0,0,,需要考虑这些数字\\N{\\fs12}when you are designing your UI.\r\nDialogue: 0,1:02:48.46,1:02:50.10,yin,,0,0,0,,这些数字看起来还不错\\N{\\fs12}These numbers seem to work pretty good.\r\nDialogue: 0,1:02:50.44,1:02:52.51,yin,,0,0,0,,而矩形的大小\\N{\\fs12}And then, the size of this rectangle,\r\nDialogue: 0,1:02:52.52,1:02:56.07,yin,,0,0,0,,我要请求属性化字符串来告诉我\\N{\\fs12}I actually need to ask the attributed string to tell me.\r\nDialogue: 0,1:02:57.16,1:02:59.03,yin,,0,0,0,,cornerText size\\N{\\fs12}CornerText size.\r\nDialogue: 0,1:02:59.32,1:03:01.98,yin,,0,0,0,,那个A回车梅花要多大呢\\N{\\fs12}You know, how big is that A return clubs going to be?\r\nDialogue: 0,1:03:02.05,1:03:03.18,yin,,0,0,0,,因为我不知道\\N{\\fs12}Because I don't know. Right?\r\nDialogue: 0,1:03:03.19,1:03:04.68,yin,,0,0,0,,但属性化字符串可以告诉我\\N{\\fs12}The attributed string can tell me, though.\r\nDialogue: 0,1:03:05.12,1:03:06.57,yin,,0,0,0,,现在我有了一个矩形\\N{\\fs12}So, now I have a rectangle,\r\nDialogue: 0,1:03:06.59,1:03:08.68,yin,,0,0,0,,我要在里面绘制A回车梅花\\N{\\fs12}and I'm going to drew the A return clubs in,\r\nDialogue: 0,1:03:08.69,1:03:11.48,yin,,0,0,0,,二者水平居中\\N{\\fs12}and it's going to be centered horizontally on it.\r\nDialogue: 0,1:03:12.13,1:03:14.78,yin,,0,0,0,,我只要让它绘制\\N{\\fs12}And all I need to do is tell it to draw.\r\nDialogue: 0,1:03:15.47,1:03:20.96,yin,,0,0,0,,cornerText drawInRect: textBounds\\N{\\fs12}CornerText drawInRect: textBounds.\r\nDialogue: 0,1:03:21.36,1:03:23.21,yin,,0,0,0,,这样它就在矩形中绘制了\\N{\\fs12}Okay? So now it's drawing in that rect.\r\nDialogue: 0,1:03:23.22,1:03:26.10,yin,,0,0,0,,会在那个矩形中进行文字对齐\\N{\\fs12}So it's gonna be doing the text alignment inside that rectangle.\r\nDialogue: 0,1:03:26.88,1:03:28.46,yin,,0,0,0,,就是这些\\N{\\fs12}Okay? So that's it.\r\nDialogue: 0,1:03:29.28,1:03:30.45,yin,,0,0,0,,希望运行正常\\N{\\fs12}Let's hope this works.\r\nDialogue: 0,1:03:33.88,1:03:34.87,yin,,0,0,0,,这不对\\N{\\fs12}And it doesn't work.\r\nDialogue: 0,1:03:34.90,1:03:36.49,yin,,0,0,0,,为什么不行呢\\N{\\fs12}Now, why does this work-- not work?\r\nDialogue: 0,1:03:36.50,1:03:38.09,yin,,0,0,0,,因为我们还没有设置卡牌\\N{\\fs12}Well, because we haven't set any card.\r\nDialogue: 0,1:03:38.41,1:03:41.60,yin,,0,0,0,,这个PlayingCardView没有显示特定卡牌\\N{\\fs12}This PlayingCardView is not displaying any particular card.\r\nDialogue: 0,1:03:41.61,1:03:44.20,yin,,0,0,0,,所以我们要回到视图控制器\\N{\\fs12}So, we need to go back to our view controller\r\nDialogue: 0,1:03:44.37,1:03:46.16,yin,,0,0,0,,对卡牌进行设置\\N{\\fs12}and set that card to something.\r\nDialogue: 0,1:03:46.27,1:03:47.67,yin,,0,0,0,,现在想要测试一下的话\\N{\\fs12}And a great place to do that\r\nDialogue: 0,1:03:47.69,1:03:49.08,yin,,0,0,0,,有一个地方很合适\\N{\\fs12}for testing right now anyway,\r\nDialogue: 0,1:03:49.09,1:03:50.09,yin,,0,0,0,,就是在viewDidLoad中\\N{\\fs12}is in viewDidLoad.\r\nDialogue: 0,1:03:50.64,1:03:52.85,yin,,0,0,0,,我们只要选择一种卡牌\\N{\\fs12}So, we're just going to pick a particular one.\r\nDialogue: 0,1:03:52.95,1:03:56.27,yin,,0,0,0,,还要添加一个到卡牌的输出口\\N{\\fs12}We also need to make an outlet to our card here,\r\nDialogue: 0,1:03:56.29,1:03:57.57,yin,,0,0,0,,这样才能向它发送消息\\N{\\fs12}so we can talk to it.\r\nDialogue: 0,1:03:57.96,1:04:00.55,yin,,0,0,0,,从左边这里开始 到右边\\N{\\fs12}So we're going to start here, and then go over here.\r\nDialogue: 0,1:04:00.57,1:04:02.65,yin,,0,0,0,,按住control键拖拽到右边 创建输出口\\N{\\fs12}I'm going to control-drag to create an outlet.\r\nDialogue: 0,1:04:02.98,1:04:05.25,yin,,0,0,0,,我要叫它playingCardView\\N{\\fs12}I'm going to call it playingCardView.\r\nDialogue: 0,1:04:06.12,1:04:07.48,yin,,0,0,0,,这是一个输出口\\N{\\fs12}Okay, so here's an outlet,\r\nDialogue: 0,1:04:07.51,1:04:09.40,yin,,0,0,0,,拉大一点 看得更清楚\\N{\\fs12}so you can see what this is about.\r\nDialogue: 0,1:04:10.50,1:04:12.91,yin,,0,0,0,,这是一个输出口 IBOutlet\\N{\\fs12}Okay. This is an outlet, IBOutlet.\r\nDialogue: 0,1:04:12.92,1:04:13.91,yin,,0,0,0,,它是PlayingCardView\\N{\\fs12}It's a PlayingCardView,\r\nDialogue: 0,1:04:13.92,1:04:16.92,yin,,0,0,0,,所以需要导入PlayingCardView\\N{\\fs12}so we need to import PlayingCardView.\r\nDialogue: 0,1:04:18.56,1:04:20.28,yin,,0,0,0,,这样就能用了 很好\\N{\\fs12}All right, so that works. That's good.\r\nDialogue: 0,1:04:20.44,1:04:21.30,yin,,0,0,0,,我们有了playingCardView\\N{\\fs12}We have our playingCardView,\r\nDialogue: 0,1:04:21.32,1:04:23.10,yin,,0,0,0,,我只要设置playingCardView\\N{\\fs12}so I'm just going to set my playing card--\r\nDialogue: 0,1:04:23.30,1:04:24.93,yin,,0,0,0,,self.playingCardView\\N{\\fs12}self.playingCardView.\r\nDialogue: 0,1:04:25.04,1:04:27.77,yin,,0,0,0,,将它的suit设为红桃\\N{\\fs12}I'm going to set its suit to be hearts,\r\nDialogue: 0,1:04:28.01,1:04:31.11,yin,,0,0,0,,将rank设为K\\N{\\fs12}and then I'm going to set its rank to be king.\r\nDialogue: 0,1:04:31.46,1:04:33.40,yin,,0,0,0,,这是我最喜欢的牌 红桃K\\N{\\fs12}Okay, that's my favorite card, king of hearts.\r\nDialogue: 0,1:04:33.40,1:04:34.78,yin,,0,0,0,,在这里添加一个心形\\N{\\fs12}So, let's set this to hearts.\r\nDialogue: 0,1:04:36.07,1:04:37.31,yin,,0,0,0,,选择特殊字符\\N{\\fs12}Special characters.\r\nDialogue: 0,1:04:37.94,1:04:38.84,yin,,0,0,0,,这个心形\\N{\\fs12}There's a heart.\r\nDialogue: 0,1:04:40.33,1:04:41.99,yin,,0,0,0,,没选上\\N{\\fs12}Oop, missed it.\r\nDialogue: 0,1:04:43.32,1:04:45.64,yin,,0,0,0,,特殊字符 心形在这里\\N{\\fs12}Characters. There's a heart.\r\nDialogue: 0,1:04:45.98,1:04:46.79,yin,,0,0,0,,这回选上了吗\\N{\\fs12}Did I get it that time?\r\nDialogue: 0,1:04:47.15,1:04:50.33,yin,,0,0,0,,好了 红桃K设好了\\N{\\fs12}Yeah. Okay, so there's a king of hearts,\r\nDialogue: 0,1:04:50.35,1:04:51.00,yin,,0,0,0,,我们要显示这张牌\\N{\\fs12}so we're going to do that.\r\nDialogue: 0,1:04:51.00,1:04:52.03,yin,,0,0,0,,运行一下\\N{\\fs12}So, now we run.\r\nDialogue: 0,1:04:53.42,1:04:55.47,yin,,0,0,0,,希望能显示出红桃K\\N{\\fs12}And we should hopefully get the king of hearts.\r\nDialogue: 0,1:04:56.26,1:04:56.91,yin,,0,0,0,,出来了\\N{\\fs12}There it is.\r\nDialogue: 0,1:04:57.06,1:04:58.72,yin,,0,0,0,,大小看起来很合适\\N{\\fs12}And the sizes look pretty good there.\r\nDialogue: 0,1:04:59.05,1:05:00.94,yin,,0,0,0,,如果对它进行调试\\N{\\fs12}Okay. Now, if I were debugging this--\r\nDialogue: 0,1:05:00.96,1:05:02.00,yin,,0,0,0,,我们直接做一下吧\\N{\\fs12}In fact, let's just do it.\r\nDialogue: 0,1:05:02.42,1:05:04.57,yin,,0,0,0,,把牌缩到很小 看会怎么样\\N{\\fs12}Let's make this card really small, see what happens.\r\nDialogue: 0,1:05:04.77,1:05:05.49,yin,,0,0,0,,试一下\\N{\\fs12}Let's try this.\r\nDialogue: 0,1:05:07.71,1:05:08.82,yin,,0,0,0,,看起来也不错\\N{\\fs12}And that looked good, too.\r\nDialogue: 0,1:05:09.19,1:05:10.45,yin,,0,0,0,,成功了 我很开心\\N{\\fs12}Okay, so I'm pretty happy with that.\r\nDialogue: 0,1:05:10.45,1:05:12.17,yin,,0,0,0,,我还应该再转到设置页面\\N{\\fs12}And then, I would also want to go to settings\r\nDialogue: 0,1:05:12.17,1:05:13.73,yin,,0,0,0,,将字体变大和变小\\N{\\fs12}and set the fonts bigger and smaller,\r\nDialogue: 0,1:05:13.73,1:05:15.10,yin,,0,0,0,,检查是否能正常显示\\N{\\fs12}and make sure that still works.\r\nDialogue: 0,1:05:15.36,1:05:17.94,yin,,0,0,0,,但是现在这样我已经很满意了\\N{\\fs12}But, you know, I'm so far pretty darn happy with it.\r\nDialogue: 0,1:05:17.94,1:05:19.83,yin,,0,0,0,,当然了 我来之前检查过了\\N{\\fs12}Now, of course, I checked this before I came today.\r\nDialogue: 0,1:05:19.83,1:05:22.17,yin,,0,0,0,,课上就不做了\\N{\\fs12}I'm not gonna do these on the fly.\r\nDialogue: 0,1:05:22.18,1:05:22.95,yin,,0,0,0,,好了\\N{\\fs12}So, there we go.\r\nDialogue: 0,1:05:24.13,1:05:25.90,yin,,0,0,0,,下面我们要做什么呢\\N{\\fs12}Now, what do we need to do next?\r\nDialogue: 0,1:05:25.91,1:05:28.12,yin,,0,0,0,,现在我们要把那个红桃K\\N{\\fs12}Well, now we need to put that king of hearts\r\nDialogue: 0,1:05:28.13,1:05:29.92,yin,,0,0,0,,上下颠倒 放在右下角\\N{\\fs12}in the other corner, upside-down.\r\nDialogue: 0,1:05:30.77,1:05:33.08,yin,,0,0,0,,你可能会想 太好了 上下颠倒\\N{\\fs12}Okay, now you might think, \"Oh great, upside-down.\r\nDialogue: 0,1:05:33.08,1:05:34.26,yin,,0,0,0,,怎么做呢\\N{\\fs12}Well, how are we going to do this?\"\r\nDialogue: 0,1:05:34.49,1:05:37.07,yin,,0,0,0,,在Core Graphics中\\N{\\fs12}Turns out to be very, very easy to rotate\r\nDialogue: 0,1:05:37.08,1:05:39.62,yin,,0,0,0,,要旋转绘制内容非常简单\\N{\\fs12}what you draw in Core Graphics.\r\nDialogue: 0,1:05:39.84,1:05:41.04,yin,,0,0,0,,我们来做一下\\N{\\fs12}So, we're just going to do that.\r\nDialogue: 0,1:05:41.05,1:05:43.02,yin,,0,0,0,,和刚才的操作都一样\\N{\\fs12}We're just gonna do exactly what we just did\r\nDialogue: 0,1:05:43.04,1:05:44.70,yin,,0,0,0,,但是要旋转至上下颠倒\\N{\\fs12}but rotate it upside-down.\r\nDialogue: 0,1:05:45.32,1:05:46.44,yin,,0,0,0,,回到这里\\N{\\fs12}So I'm going to go back here.\r\nDialogue: 0,1:05:46.45,1:05:48.89,yin,,0,0,0,,还要做同样的操作 这个drawInRect\\N{\\fs12}I'm going to do this same thing, this drawInRect.\r\nDialogue: 0,1:05:49.25,1:05:52.67,yin,,0,0,0,,但执行这步之前 在这里\\N{\\fs12}Okay? But before I do it, inside here,\r\nDialogue: 0,1:05:52.89,1:05:55.15,yin,,0,0,0,,我要将它旋转至上下颠倒\\N{\\fs12}I'm going to rotate it upside down.\r\nDialogue: 0,1:05:55.45,1:05:57.59,yin,,0,0,0,,首先移到右下角\\N{\\fs12}First, I'm going to move down to that corner,\r\nDialogue: 0,1:05:57.97,1:05:59.34,yin,,0,0,0,,然后旋转至上下颠倒\\N{\\fs12}then I'm going to rotate upside-down.\r\nDialogue: 0,1:06:00.02,1:06:02.23,yin,,0,0,0,,如何移到一角呢\\N{\\fs12}So, how do we move over to a corner?\r\nDialogue: 0,1:06:02.23,1:06:04.83,yin,,0,0,0,,我们用一个CG函数\\N{\\fs12}Well, let's use one of these CG functions\r\nDialogue: 0,1:06:04.83,1:06:06.81,yin,,0,0,0,,这就是我说的用到上下文的地方\\N{\\fs12}that I told you you needed the context for.\r\nDialogue: 0,1:06:07.07,1:06:09.46,yin,,0,0,0,,用ContextRef\\N{\\fs12}So, let's get a contextRef.\r\nDialogue: 0,1:06:10.11,1:06:14.59,yin,,0,0,0,,context=UIGraphicsGetCurrentContext()\\N{\\fs12}Context equals UIGraphicsGetCurrentContext.\r\nDialogue: 0,1:06:14.59,1:06:16.60,yin,,0,0,0,,我讲了 这是得到当前上下文的方法\\N{\\fs12}I told you that's how you get the current context.\r\nDialogue: 0,1:06:16.80,1:06:20.53,yin,,0,0,0,,得到它之后 我可以用CGTrans...\\N{\\fs12}Now that I have it, I can use CGTrans--\r\nDialogue: 0,1:06:20.54,1:06:22.97,yin,,0,0,0,,叫什么来着 有人记得吗\\N{\\fs12}What's it called? Anybody remember?\r\nDialogue: 0,1:06:23.38,1:06:26.31,yin,,0,0,0,,ContextTranslate什么的\\N{\\fs12}Translate something, ContextTranslate something.\r\nDialogue: 0,1:06:26.51,1:06:27.14,yin,,0,0,0,,找到了\\N{\\fs12}There we go.\r\nDialogue: 0,1:06:27.51,1:06:28.86,yin,,0,0,0,,TranslateCTM\\N{\\fs12}TranslateCTM.\r\nDialogue: 0,1:06:28.88,1:06:31.14,yin,,0,0,0,,CTM表示变换矩阵\\N{\\fs12}CTM is our transformation matrix.\r\nDialogue: 0,1:06:31.36,1:06:32.65,yin,,0,0,0,,我们要转移它\\N{\\fs12}Okay, so we're just going to translate,\r\nDialogue: 0,1:06:32.65,1:06:33.85,yin,,0,0,0,,也就是移动它\\N{\\fs12}which means move it.\r\nDialogue: 0,1:06:33.90,1:06:34.79,yin,,0,0,0,,目标位置是\\N{\\fs12}So I'm going to move it down\r\nDialogue: 0,1:06:34.79,1:06:38.51,yin,,0,0,0,,self.bounds.width, self.bounds.height\\N{\\fs12}to self.bounds.width and self.bounds.height.\r\nDialogue: 0,1:06:39.62,1:06:42.62,yin,,0,0,0,,移动到右下角\\N{\\fs12}Okay, move down to the corner there.\r\nDialogue: 0,1:06:42.66,1:06:44.48,yin,,0,0,0,,我输错了吗\\N{\\fs12}Oops! Did I type something wrong?\r\nDialogue: 0,1:06:44.98,1:06:48.28,yin,,0,0,0,,忘了size\\N{\\fs12}Size, oops, size, size.\r\nDialogue: 0,1:06:48.49,1:06:52.11,yin,,0,0,0,,self.bounds.size.width, self.bounds.size.heigth\\N{\\fs12}Okay, self.bounds.size.width, self.bounds.size.heigth.\r\nDialogue: 0,1:06:52.12,1:06:54.06,yin,,0,0,0,,我要移动到右下角\\N{\\fs12}So, I'm moving down to the bottom corner there\r\nDialogue: 0,1:06:54.08,1:06:55.83,yin,,0,0,0,,要记住 原点是左上角\\N{\\fs12}Remember our origin is in the upper left.\r\nDialogue: 0,1:06:56.29,1:06:57.67,yin,,0,0,0,,现在来旋转\\N{\\fs12}And now, let's rotate.\r\nDialogue: 0,1:06:57.81,1:06:59.97,yin,,0,0,0,,用CGContextRotateCTM context\\N{\\fs12}There's a RotateCTM context\r\nDialogue: 0,1:07:00.13,1:07:01.43,yin,,0,0,0,,然后是旋转弧度\\N{\\fs12}and this is radians.\r\nDialogue: 0,1:07:01.48,1:07:03.16,yin,,0,0,0,,我要旋转半圈\\N{\\fs12}So, I'm going to go halfway around,\r\nDialogue: 0,1:07:03.18,1:07:04.12,yin,,0,0,0,,就是要上下颠倒\\N{\\fs12}in other words, upside-down,\r\nDialogue: 0,1:07:04.14,1:07:06.42,yin,,0,0,0,,也就是M_PI\\N{\\fs12}which is m underbar PI.\r\nDialogue: 0,1:07:07.58,1:07:09.61,yin,,0,0,0,,π弧度是半圈180度\\N{\\fs12}Pi radians is halfway around a circle.\r\nDialogue: 0,1:07:09.69,1:07:11.82,yin,,0,0,0,,我想让它上下颠倒\\N{\\fs12}I want it to be upside-down, directly upside-down,\r\nDialogue: 0,1:07:11.82,1:07:14.22,yin,,0,0,0,,从开始位置旋转180度\\N{\\fs12}180 degrees from where it was before.\r\nDialogue: 0,1:07:14.66,1:07:15.41,yin,,0,0,0,,就是这样\\N{\\fs12}And, that's it. Okay?\r\nDialogue: 0,1:07:16.07,1:07:19.99,yin,,0,0,0,,我移动并旋转了要绘制的内容\\N{\\fs12}So, I've translated and rotated what I wanted to draw.\r\nDialogue: 0,1:07:19.99,1:07:21.96,yin,,0,0,0,,然后我只要再绘制一遍就行了\\N{\\fs12}And then, I'm just gonna draw the exact same thing again.\r\nDialogue: 0,1:07:24.60,1:07:25.56,yin,,0,0,0,,很好 没问题\\N{\\fs12}Bingo! Okay?\r\nDialogue: 0,1:07:25.79,1:07:28.69,yin,,0,0,0,,Core Graphics中的某些操作真的很容易实现\\N{\\fs12}So, some stuff is really, really easy to do in Core Graphics.\r\nDialogue: 0,1:07:28.90,1:07:31.75,yin,,0,0,0,,旋转 移动 特别容易\\N{\\fs12}Okay? Rotating, translating things, super-duper easy.\r\nDialogue: 0,1:07:31.99,1:07:33.09,yin,,0,0,0,,明白吗 这部分做完了\\N{\\fs12}All right? So, we're good there.\r\nDialogue: 0,1:07:33.45,1:07:34.91,yin,,0,0,0,,下面我们要做的是\\N{\\fs12}Okay, the next thing we want to do\r\nDialogue: 0,1:07:35.07,1:07:37.20,yin,,0,0,0,,绘制牌面\\N{\\fs12}is draw the face of the card.\r\nDialogue: 0,1:07:37.85,1:07:40.39,yin,,0,0,0,,红桃K的牌面\\N{\\fs12}Okay? That king of hearts face.\r\nDialogue: 0,1:07:40.40,1:07:42.62,yin,,0,0,0,,扑克牌的牌面有两种\\N{\\fs12}Now, the face of the card is one of two ways,\r\nDialogue: 0,1:07:42.62,1:07:45.05,yin,,0,0,0,,一种是人头牌 比如K\\N{\\fs12}either it's a face card, like the king,\r\nDialogue: 0,1:07:45.21,1:07:47.39,yin,,0,0,0,,另一种就是花色符号组成的\\N{\\fs12}or it's just the pips, right?\r\nDialogue: 0,1:07:47.85,1:07:50.32,yin,,0,0,0,,比如红桃4的牌面就是四个小心形图案\\N{\\fs12}Like the four of hears is four little hearts in there.\r\nDialogue: 0,1:07:50.32,1:07:51.61,yin,,0,0,0,,两种我们都要做\\N{\\fs12}Okay, so we have to do both ways.\r\nDialogue: 0,1:07:51.61,1:07:54.56,yin,,0,0,0,,先做人头牌\\N{\\fs12}So, let's do the face card one first.\r\nDialogue: 0,1:07:54.74,1:07:57.07,yin,,0,0,0,,我要在上面这里完成\\N{\\fs12}Okay, so I'm going to do that up here,\r\nDialogue: 0,1:07:57.56,1:07:58.35,yin,,0,0,0,,回到drawRect方法\\N{\\fs12}back in drawRect.\r\nDialogue: 0,1:07:58.35,1:07:59.38,yin,,0,0,0,,在drawRect方法中\\N{\\fs12}So, I'm in drawRect.\r\nDialogue: 0,1:08:00.40,1:08:01.45,yin,,0,0,0,,我要做的是\\N{\\fs12}And what I'm going to do,\r\nDialogue: 0,1:08:01.47,1:08:03.87,yin,,0,0,0,,我要在这里添加一组条件判断\\N{\\fs12}I'm just gonna kind of have a design here\r\nDialogue: 0,1:08:03.95,1:08:05.98,yin,,0,0,0,,如果能找到\\N{\\fs12}where if I can find an image\r\nDialogue: 0,1:08:06.14,1:08:07.72,yin,,0,0,0,,和牌名相同的图像\\N{\\fs12}that has the name of the card,\r\nDialogue: 0,1:08:07.98,1:08:08.79,yin,,0,0,0,,就直接用它\\N{\\fs12}I'll use it.\r\nDialogue: 0,1:08:08.94,1:08:11.20,yin,,0,0,0,,否则就绘制花色符号\\N{\\fs12}Otherwise, I'll try and draw pips,\r\nDialogue: 0,1:08:11.21,1:08:12.34,yin,,0,0,0,,否则就什么都不绘制\\N{\\fs12}otherwise, I'll draw nothing.\r\nDialogue: 0,1:08:12.90,1:08:15.92,yin,,0,0,0,,这种方法挺安全的\\N{\\fs12}Okay, so it's kind of a fairly safe way to go about it.\r\nDialogue: 0,1:08:16.03,1:08:18.64,yin,,0,0,0,,如果我找不到牌面图像 就不绘制了\\N{\\fs12}If I can't find the face card image, then it'll just be--\r\nDialogue: 0,1:08:18.65,1:08:19.83,yin,,0,0,0,,两个角的内容还在\\N{\\fs12}I'll still have the corners,\r\nDialogue: 0,1:08:20.09,1:08:21.18,yin,,0,0,0,,但牌面上不会有任何图案\\N{\\fs12}but I won't have any drawing.\r\nDialogue: 0,1:08:21.19,1:08:22.79,yin,,0,0,0,,要怎么实现呢\\N{\\fs12}So, how am I going to do that?\r\nDialogue: 0,1:08:23.14,1:08:25.30,yin,,0,0,0,,先查找图像\\N{\\fs12}I'm just going to look up the image.\r\nDialogue: 0,1:08:25.31,1:08:26.81,yin,,0,0,0,,用UIImage\\N{\\fs12}I'm going to say UIImage--\r\nDialogue: 0,1:08:27.32,1:08:28.65,yin,,0,0,0,,再扩大点空间\\N{\\fs12}Let's make more space again.\r\nDialogue: 0,1:08:30.63,1:08:32.98,yin,,0,0,0,,UIImage faceImage\\N{\\fs12}UIImage, faceImage,\r\nDialogue: 0,1:08:32.99,1:08:38.09,yin,,0,0,0,,UIImage imageNamed:\\N{\\fs12}and I'm going to say UIImage, imageNamed,\r\nDialogue: 0,1:08:38.25,1:08:41.67,yin,,0,0,0,,然后创建一个字符串 stringWithFormat\\N{\\fs12}then I'm going to make a string, stringWithFormat.\r\nDialogue: 0,1:08:41.76,1:08:44.67,yin,,0,0,0,,占位符分别为rank和suit\\N{\\fs12}And it's going to have the rank and the suit.\r\nDialogue: 0,1:08:45.12,1:08:49.84,yin,,0,0,0,,[self rankAsString] self.suit\\N{\\fs12}Okay, self rankAsString, self.suit.\r\nDialogue: 0,1:08:50.91,1:08:53.05,yin,,0,0,0,,这就是图像名称\\N{\\fs12}Okay. So, there's the image name.\r\nDialogue: 0,1:08:53.05,1:08:54.57,yin,,0,0,0,,我要查找这个名称的图像\\N{\\fs12}So, I'm going to look that image up,\r\nDialogue: 0,1:08:54.58,1:08:57.40,yin,,0,0,0,,比如黑桃J\\N{\\fs12}so that would be like, J spades, right?\r\nDialogue: 0,1:08:57.41,1:08:59.66,yin,,0,0,0,,红桃10没有对应图像\\N{\\fs12}10 hearts is not going to find 10 hearts.\r\nDialogue: 0,1:08:59.67,1:09:00.65,yin,,0,0,0,,没有它的图\\N{\\fs12}There's not going to be such thing,\r\nDialogue: 0,1:09:00.66,1:09:02.10,yin,,0,0,0,,但是有梅花K\\N{\\fs12}but there will be K clubs, right?\r\nDialogue: 0,1:09:02.11,1:09:02.87,yin,,0,0,0,,可以找到这种的\\N{\\fs12}It'll find those.\r\nDialogue: 0,1:09:03.50,1:09:05.35,yin,,0,0,0,,如果找到了牌面图像\\N{\\fs12}So, if it finds the face image,\r\nDialogue: 0,1:09:05.83,1:09:08.45,yin,,0,0,0,,我就要把它显示在中间\\N{\\fs12}then I'm going to display it in the middle,\r\nDialogue: 0,1:09:08.59,1:09:12.18,yin,,0,0,0,,否则 我就要绘制花色符号\\N{\\fs12}otherwise, I need to draw the pips, basically,\r\nDialogue: 0,1:09:12.18,1:09:14.38,yin,,0,0,0,,因为它不是人头牌\\N{\\fs12}because it's not a face card.\r\nDialogue: 0,1:09:14.66,1:09:18.00,yin,,0,0,0,,在这里添加一个drawPips方法\\N{\\fs12}So let's put a little drawPips here.\r\nDialogue: 0,1:09:19.12,1:09:20.54,yin,,0,0,0,,等会实现它\\N{\\fs12}Okay, do that later.\r\nDialogue: 0,1:09:21.50,1:09:22.65,yin,,0,0,0,,牌面图像\\N{\\fs12}So, the face image.\r\nDialogue: 0,1:09:22.66,1:09:23.73,yin,,0,0,0,,要怎么显示出来呢\\N{\\fs12}How do I do this?\r\nDialogue: 0,1:09:23.81,1:09:27.03,yin,,0,0,0,,我只要告诉UIImage\\N{\\fs12}Well, really I just need to tell UIImage\r\nDialogue: 0,1:09:27.04,1:09:28.59,yin,,0,0,0,,将这幅图绘制在卡牌中间\\N{\\fs12}draw this in the middle of my card.\r\nDialogue: 0,1:09:28.71,1:09:31.84,yin,,0,0,0,,但我想让它缩进去 离开边缘一点\\N{\\fs12}But I want to move it in from the edges a little bit, right?\r\nDialogue: 0,1:09:31.84,1:09:34.29,yin,,0,0,0,,因为我不想让牌面图像\\N{\\fs12}Because I don't want whatever the face image is,\r\nDialogue: 0,1:09:34.29,1:09:36.82,yin,,0,0,0,,比如K的国王图像 破坏了两个角的图像\\N{\\fs12}like a king, to smash my corners.\r\nDialogue: 0,1:09:37.12,1:09:38.35,yin,,0,0,0,,红桃K上的国王\\N{\\fs12}Okay? My little king of hearts.\r\nDialogue: 0,1:09:38.35,1:09:39.58,yin,,0,0,0,,我想让图像缩进去一点\\N{\\fs12}So, I want to move it in a little bit,\r\nDialogue: 0,1:09:39.81,1:09:41.35,yin,,0,0,0,,所以我要新建一个矩形\\N{\\fs12}so I'm going to create a rectangle\r\nDialogue: 0,1:09:41.41,1:09:44.70,yin,,0,0,0,,让图像在其中进行缩放 叫imageRect\\N{\\fs12}to scale my image into, imageRect,\r\nDialogue: 0,1:09:45.19,1:09:51.69,yin,,0,0,0,,基本上是我的bounds\\N{\\fs12}and it's going to basically be my bounds,\r\nDialogue: 0,1:09:52.03,1:09:56.06,yin,,0,0,0,,但我要用这个CGRectInset方法\\N{\\fs12}except for I'm gonna use this CGRectInset method here\r\nDialogue: 0,1:09:56.16,1:09:58.05,yin,,0,0,0,,让它缩进去进去一点\\N{\\fs12}to inset it just a little bit.\r\nDialogue: 0,1:09:58.33,1:09:59.86,yin,,0,0,0,,缩进的距离是\\N{\\fs12}And I'm going to inset it\r\nDialogue: 0,1:09:59.88,1:10:03.10,yin,,0,0,0,,self.bounds.size.width\\N{\\fs12}by self.bounds.size.width\r\nDialogue: 0,1:10:03.11,1:10:07.54,yin,,0,0,0,,乘以 1减去一个新建属性\\N{\\fs12}times 1.0 minus a new property that I'm gonna invent,\r\nDialogue: 0,1:10:07.55,1:10:09.74,yin,,0,0,0,,叫做faceCardScaleFactor\\N{\\fs12}called faceCardScaleFactor.\r\nDialogue: 0,1:10:09.74,1:10:13.48,yin,,0,0,0,,faceCardScaleFactor如果是0.9\\N{\\fs12}So, the faceCardScaleFactor is going to be like .9,\r\nDialogue: 0,1:10:13.61,1:10:15.60,yin,,0,0,0,,代表卡牌大小的90%\\N{\\fs12}to be 90% of the size of my card.\r\nDialogue: 0,1:10:16.21,1:10:19.09,yin,,0,0,0,,0.9表示卡牌大小的90%\\N{\\fs12}Okay, .9 would be 90% of the size of the card.\r\nDialogue: 0,1:10:19.38,1:10:21.51,yin,,0,0,0,,size.height也一样\\N{\\fs12}And then, same thing with size.height.\r\nDialogue: 0,1:10:23.15,1:10:24.22,yin,,0,0,0,,height 抱歉\\N{\\fs12}Oops! Height. Sorry.\r\nDialogue: 0,1:10:25.56,1:10:27.20,yin,,0,0,0,,一样的 用height乘以\\N{\\fs12}Height times-- same thing,\r\nDialogue: 0,1:10:27.20,1:10:30.66,yin,,0,0,0,,1.0-self.faceCardScaleFactor\\N{\\fs12}1.0 minus self.faceCardScaleFactor.\r\nDialogue: 0,1:10:31.93,1:10:35.79,yin,,0,0,0,,好了 我们要添加这个属性\\N{\\fs12}All right, and we have to go make this property.\r\nDialogue: 0,1:10:35.79,1:10:36.61,yin,,0,0,0,,来做一下\\N{\\fs12}So, let's go do that.\r\nDialogue: 0,1:10:36.63,1:10:38.67,yin,,0,0,0,,放到上面这里 属性组第二个\\N{\\fs12}Let's go up here, put it in our properties second.\r\nDialogue: 0,1:10:38.77,1:10:41.37,yin,,0,0,0,,我又快速地打好了\\N{\\fs12}And I'll type it really fast, again.\r\nDialogue: 0,1:10:41.43,1:10:42.43,yin,,0,0,0,,抱歉用这个方式\\N{\\fs12}Sorry to have to use those,\r\nDialogue: 0,1:10:42.44,1:10:44.49,yin,,0,0,0,,但有时候打字很无聊\\N{\\fs12}but somethings are boring to type.\r\nDialogue: 0,1:10:45.00,1:10:47.59,yin,,0,0,0,,好了 我添加了这个faceCardScaleFactor\\N{\\fs12}All right, so I have this faceCardScaleFactor.\r\nDialogue: 0,1:10:47.59,1:10:48.54,yin,,0,0,0,,它是一个浮点数\\N{\\fs12}It's a float.\r\nDialogue: 0,1:10:48.89,1:10:51.82,yin,,0,0,0,,我要重写setter和getter\\N{\\fs12}I'm going to override both the setter and the getter.\r\nDialogue: 0,1:10:52.52,1:10:54.61,yin,,0,0,0,,在getter中 我要确保\\N{\\fs12}Okay? In the getter, I'm going to make sure that\r\nDialogue: 0,1:10:54.63,1:10:56.37,yin,,0,0,0,,它至少有一个默认值\\N{\\fs12}it's at least a default value.\r\nDialogue: 0,1:10:56.81,1:10:59.20,yin,,0,0,0,,默认值是90%\\N{\\fs12}Okay? 90% is going to be my default value,\r\nDialogue: 0,1:10:59.20,1:11:01.24,yin,,0,0,0,,它至少是这个默认值\\N{\\fs12}so it's at least going to be that default value.\r\nDialogue: 0,1:11:01.47,1:11:03.75,yin,,0,0,0,,而在setter中 我要调用setNeedsDisplay\\N{\\fs12}And in my setter, I'm going to call setNeedsDisplay.\r\nDialogue: 0,1:11:04.07,1:11:05.97,yin,,0,0,0,,因为如果有人设定了比例系数\\N{\\fs12}Because if someone sets that scaling,\r\nDialogue: 0,1:11:05.97,1:11:08.08,yin,,0,0,0,,如果是人头牌 就需要重绘卡牌\\N{\\fs12}I got it to redraw my card if it's a face card.\r\nDialogue: 0,1:11:08.83,1:11:10.29,yin,,0,0,0,,大家明白吗\\N{\\fs12}Okay? Everyone understand this?\r\nDialogue: 0,1:11:10.39,1:11:12.28,yin,,0,0,0,,因为setter和getter我都要做\\N{\\fs12}And since I do both the setter and the getter,\r\nDialogue: 0,1:11:12.28,1:11:14.61,yin,,0,0,0,,那我需要做什么呢 synthesize\\N{\\fs12}look what I have to do, synthesize.\r\nDialogue: 0,1:11:15.79,1:11:17.28,yin,,0,0,0,,大家还记得吗\\N{\\fs12}Okay? Everyone remember that?\r\nDialogue: 0,1:11:17.29,1:11:18.43,yin,,0,0,0,,如果同时用到了setter和getter\\N{\\fs12}If you put in both the setter and getter,\r\nDialogue: 0,1:11:18.44,1:11:19.84,yin,,0,0,0,,你就得synthesize自己\\N{\\fs12}you've got to synthesize yourself.\r\nDialogue: 0,1:11:20.96,1:11:22.26,yin,,0,0,0,,好好回想一下\\N{\\fs12}Okay, good reminder of that.\r\nDialogue: 0,1:11:23.00,1:11:24.85,yin,,0,0,0,,现在我有了这个imageRect\\N{\\fs12}Okay, so now I have this imageRect,\r\nDialogue: 0,1:11:25.01,1:11:28.59,yin,,0,0,0,,按照百分比向内缩小\\N{\\fs12}and it's inset by that-- whatever that percent is,\r\nDialogue: 0,1:11:28.60,1:11:31.72,yin,,0,0,0,,如果是90% 就是1-90%\\N{\\fs12}10% if it's-- you know, 90 would be 1.0 minus that,\r\nDialogue: 0,1:11:31.73,1:11:33.64,yin,,0,0,0,,也就是宽度的10% 高度的10%\\N{\\fs12}10% of my width, 10% of my height.\r\nDialogue: 0,1:11:34.05,1:11:40.16,yin,,0,0,0,,现在我可以直接用faceImage drawInRect:imageRect\\N{\\fs12}And so, now I just say faceImage, drawInRect: imageRect.\r\nDialogue: 0,1:11:40.62,1:11:44.60,yin,,0,0,0,,它就将图像缩放到适合那个矩形的大小\\N{\\fs12}Okay? And it will scale it to fit in that rect.\r\nDialogue: 0,1:11:45.57,1:11:47.91,yin,,0,0,0,,我需要这些图像 我们来添加一些\\N{\\fs12}Now, I need these images, so let's go grab those.\r\nDialogue: 0,1:11:47.92,1:11:49.54,yin,,0,0,0,,我正好有 在这里\\N{\\fs12}I happen to have them handy right here.\r\nDialogue: 0,1:11:49.76,1:11:51.60,yin,,0,0,0,,这些图片\\N{\\fs12}Okay? So, here's a bunch of images\r\nDialogue: 0,1:11:51.83,1:11:53.42,yin,,0,0,0,,就是人头牌对应的图像\\N{\\fs12}that I have for face cards.\r\nDialogue: 0,1:11:53.63,1:11:54.67,yin,,0,0,0,,把它们拖拽到\\N{\\fs12}Let's just go ahead and drag them\r\nDialogue: 0,1:11:54.67,1:11:58.74,yin,,0,0,0,,资产库中 图像资产\\N{\\fs12}into our assets library here, image assets.\r\nDialogue: 0,1:11:58.74,1:12:00.08,yin,,0,0,0,,这就是我们的图像资产库\\N{\\fs12}So, here's our image asset library.\r\nDialogue: 0,1:12:00.08,1:12:00.98,yin,,0,0,0,,还什么都没有\\N{\\fs12}We don't have any yet.\r\nDialogue: 0,1:12:01.24,1:12:02.02,yin,,0,0,0,,把它们拖进来\\N{\\fs12}Drag that in there.\r\nDialogue: 0,1:12:02.03,1:12:06.97,yin,,0,0,0,,正好在这 顺便再把斯坦福大学图标拖进来\\N{\\fs12}While I'm here, I'm also gonna drag our famous Stanford one.\r\nDialogue: 0,1:12:06.97,1:12:09.45,yin,,0,0,0,,这个高分辨率的图标也拖进来\\N{\\fs12}And, actually, let's get the high-res one, too.\r\nDialogue: 0,1:12:10.12,1:12:12.18,yin,,0,0,0,,我们还要把它作为卡牌背面图案\\N{\\fs12}Okay, we'll use that as our card back again.\r\nDialogue: 0,1:12:13.34,1:12:14.71,yin,,0,0,0,,所有图像都在这里了\\N{\\fs12}Okay, so we got all our images here.\r\nDialogue: 0,1:12:14.71,1:12:16.22,yin,,0,0,0,,这些图像 看这个\\N{\\fs12}So, the images. Look at this.\r\nDialogue: 0,1:12:16.32,1:12:17.56,yin,,0,0,0,,我们再放一张高分辨率的人头牌图像\\N{\\fs12}Let's put the high-res one in\r\nDialogue: 0,1:12:17.57,1:12:18.91,yin,,0,0,0,,至少加一张红桃K的\\N{\\fs12}for a king of hearts, at least.\r\nDialogue: 0,1:12:19.82,1:12:20.76,yin,,0,0,0,,现在这是红桃K的\\N{\\fs12}So here's the king of hearts.\r\nDialogue: 0,1:12:20.76,1:12:22.12,yin,,0,0,0,,这些图的高分辨率版本我都有\\N{\\fs12}I have a high-res for all of them,\r\nDialogue: 0,1:12:22.13,1:12:24.96,yin,,0,0,0,,但时间有限\\N{\\fs12}but just for time constraints,\r\nDialogue: 0,1:12:24.99,1:12:27.62,yin,,0,0,0,,我们就只把它放到这里\\N{\\fs12}let's go ahead and put this guy right here.\r\nDialogue: 0,1:12:27.89,1:12:29.35,yin,,0,0,0,,至少加上这张\\N{\\fs12}Okay, so we get that one at least.\r\nDialogue: 0,1:12:29.79,1:12:30.32,yin,,0,0,0,,好的\\N{\\fs12}All right.\r\nDialogue: 0,1:12:30.61,1:12:32.02,yin,,0,0,0,,我想把它们都拖进来\\N{\\fs12}I'd want to drag them all in for all.\r\nDialogue: 0,1:12:32.02,1:12:33.76,yin,,0,0,0,,但就这样吧 现在我有了这些图片\\N{\\fs12}But anyway, so now I have these images.\r\nDialogue: 0,1:12:33.84,1:12:36.92,yin,,0,0,0,,现在再运行时 它会去查找\\N{\\fs12}So now, when I run, it's going to go look\r\nDialogue: 0,1:12:37.03,1:12:39.42,yin,,0,0,0,,这些名称对应的图片\\N{\\fs12}for the image of these names, you see?\r\nDialogue: 0,1:12:39.58,1:12:41.21,yin,,0,0,0,,就会找到红桃K这张\\N{\\fs12}And it's going to find the king of hearts there.\r\nDialogue: 0,1:12:41.81,1:12:43.39,yin,,0,0,0,,就是这位自杀的国王\\N{\\fs12}Okay? So, that's the suicide king.\r\nDialogue: 0,1:12:43.81,1:12:46.45,yin,,0,0,0,,看起来很不错 大小很合适\\N{\\fs12}Right? Looks pretty decent. Size is pretty good.\r\nDialogue: 0,1:12:47.06,1:12:51.71,yin,,0,0,0,,现在我们要快速地做两件事情\\N{\\fs12}Okay. All right, so now we are going to do two quick things.\r\nDialogue: 0,1:12:51.73,1:12:53.32,yin,,0,0,0,,我知道时间快到了\\N{\\fs12}I know we're right on the edge of time here.\r\nDialogue: 0,1:12:53.52,1:12:55.68,yin,,0,0,0,,我们快速地做一下手势识别器\\N{\\fs12}We're going to do the gesture recognizers really quick.\r\nDialogue: 0,1:12:55.68,1:12:56.93,yin,,0,0,0,,我要做两件事\\N{\\fs12}So I'm going to do two things.\r\nDialogue: 0,1:12:57.68,1:13:02.32,yin,,0,0,0,,一是 让这个PlayingCardView在运行时牌面向下\\N{\\fs12}One is, let's make this PlayingCardView work facedown.\r\nDialogue: 0,1:13:02.32,1:13:04.92,yin,,0,0,0,,方法是判断现在是否牌面向上\\N{\\fs12}And we're just going to do that by saying if we're face up,\r\nDialogue: 0,1:13:06.11,1:13:08.73,yin,,0,0,0,,如果是的话 就执行这段代码\\N{\\fs12}then we'll do this, all this stuff.\r\nDialogue: 0,1:13:09.93,1:13:14.22,yin,,0,0,0,,否则就显示背景图片\\N{\\fs12}Otherwise, we will just do our background image,\r\nDialogue: 0,1:13:14.37,1:13:19.36,yin,,0,0,0,,UIImage imageNamed: 最爱的cardback\\N{\\fs12}UIImage, imageNamed, favorite cardback.\r\nDialogue: 0,1:13:19.52,1:13:20.57,yin,,0,0,0,,我要把它改名为cardback\\N{\\fs12}I'm going to change it to that.\r\nDialogue: 0,1:13:20.95,1:13:24.62,yin,,0,0,0,,然后是drawInRect self.bounds\\N{\\fs12}And then drawInRect, self.Bounds,\r\nDialogue: 0,1:13:24.86,1:13:27.21,yin,,0,0,0,,背景图的牌角没有图案\\N{\\fs12}and then for the back, I don't have the corners.\r\nDialogue: 0,1:13:27.36,1:13:30.84,yin,,0,0,0,,我可以直接用整张图\\N{\\fs12}And so, I can just go ahead and use the whole thing,\r\nDialogue: 0,1:13:30.85,1:13:31.65,yin,,0,0,0,,改成cardback\\N{\\fs12}so cardback.\r\nDialogue: 0,1:13:32.26,1:13:35.23,yin,,0,0,0,,这样扑克牌背面图案就设好了\\N{\\fs12}Okay, so now we have the front-- the back there, rather.\r\nDialogue: 0,1:13:35.23,1:13:37.87,yin,,0,0,0,,运行时 它是牌面向下的\\N{\\fs12}So now, since it's face up-- it starts out not face up.\r\nDialogue: 0,1:13:37.87,1:13:40.14,yin,,0,0,0,,所以是这样的 但我需要把它翻过来\\N{\\fs12}So, here it is, but I need to flip this over.\r\nDialogue: 0,1:13:40.42,1:13:43.20,yin,,0,0,0,,我们用滑动手势将卡牌翻过来\\N{\\fs12}So let's do a swipe gesture to flip that over.\r\nDialogue: 0,1:13:43.45,1:13:47.16,yin,,0,0,0,,我们用Xcode来添加滑动手势\\N{\\fs12}Okay, and the swipe gesture we're going to do using Xcode.\r\nDialogue: 0,1:13:47.50,1:13:49.88,yin,,0,0,0,,方法是这样的\\N{\\fs12}Okay? So, swipe gestures go like this.\r\nDialogue: 0,1:13:49.96,1:13:52.79,yin,,0,0,0,,转到右下方的对象面板\\N{\\fs12}You go down here, you get in the object palette,\r\nDialogue: 0,1:13:52.79,1:13:54.00,yin,,0,0,0,,按钮所在的地方\\N{\\fs12}same place buttons are,\r\nDialogue: 0,1:13:54.02,1:13:55.72,yin,,0,0,0,,可以看到这里有这些手势\\N{\\fs12}and you'll see that there's these gestures here.\r\nDialogue: 0,1:13:55.98,1:13:57.49,yin,,0,0,0,,选中滑动手势\\N{\\fs12}Now, I'm going to take a swipe gesture\r\nDialogue: 0,1:13:57.64,1:13:58.96,yin,,0,0,0,,将它拖拽到\\N{\\fs12}and drag it onto the view\r\nDialogue: 0,1:13:58.97,1:14:00.58,yin,,0,0,0,,要识别这个滑动手势的视图上\\N{\\fs12}that I want to recognize that swipe,\r\nDialogue: 0,1:14:00.98,1:14:02.86,yin,,0,0,0,,显然是PlayingCardView\\N{\\fs12}which is my PlayingCardView, obviously.\r\nDialogue: 0,1:14:03.29,1:14:06.93,yin,,0,0,0,,然后我只要从这个小图标进行control拖拽\\N{\\fs12}Then, I simply control-drag from this little icon\r\nDialogue: 0,1:14:06.93,1:14:07.78,yin,,0,0,0,,下面的这个小图标\\N{\\fs12}that appears down here.\r\nDialogue: 0,1:14:07.78,1:14:08.37,yin,,0,0,0,,看到了吗\\N{\\fs12}You see it?\r\nDialogue: 0,1:14:08.38,1:14:09.15,yin,,0,0,0,,代表滑动手势\\N{\\fs12}Swipe gesture.\r\nDialogue: 0,1:14:09.26,1:14:11.09,yin,,0,0,0,,还可以从这里进行拖拽\\N{\\fs12}You can also do it from here,\r\nDialogue: 0,1:14:11.10,1:14:12.05,yin,,0,0,0,,在这个文档大纲中\\N{\\fs12}this little document outline\r\nDialogue: 0,1:14:12.05,1:14:13.85,yin,,0,0,0,,今天我们没有时间讲这个了\\N{\\fs12}which we don't have time to talk about today.\r\nDialogue: 0,1:14:14.23,1:14:15.64,yin,,0,0,0,,但是可以这样做\\N{\\fs12}Okay, but you can do that, too.\r\nDialogue: 0,1:14:16.03,1:14:17.59,yin,,0,0,0,,我要从这里按住control键进行拖拽\\N{\\fs12}But I'm going to control-drag from here.\r\nDialogue: 0,1:14:18.24,1:14:21.61,yin,,0,0,0,,选择自动模式下的控制器\\N{\\fs12}Oops! Go auto in controller.\r\nDialogue: 0,1:14:21.68,1:14:23.11,yin,,0,0,0,,只要拖拽过来就可以了\\N{\\fs12}And you just drag that.\r\nDialogue: 0,1:14:23.11,1:14:25.04,yin,,0,0,0,,非常像目标操作\\N{\\fs12}It's very much like target-action.\r\nDialogue: 0,1:14:25.50,1:14:28.97,yin,,0,0,0,,我要加它swipe 比较直观\\N{\\fs12}Okay. I'll call this a swipe, just to make it clear.\r\nDialogue: 0,1:14:29.32,1:14:31.10,yin,,0,0,0,,类型参数是UISwipeGestureRecognizer\\N{\\fs12}And their argument is the swipe gesture recognizer.\r\nDialogue: 0,1:14:31.10,1:14:32.68,yin,,0,0,0,,不知道为什么默认值不是它\\N{\\fs12}I'm not sure why it doesn't default to that.\r\nDialogue: 0,1:14:33.12,1:14:34.18,yin,,0,0,0,,这样就添加了swipe\\N{\\fs12}And we have the swipe.\r\nDialogue: 0,1:14:34.32,1:14:36.00,yin,,0,0,0,,在swipe中 我们只要这样做\\N{\\fs12}And the swipe, all we need to do\r\nDialogue: 0,1:14:36.01,1:14:38.36,yin,,0,0,0,,self.playingCardView.faceUp\\N{\\fs12}is say self.playingCardView.faceUp\r\nDialogue: 0,1:14:38.38,1:14:41.37,yin,,0,0,0,,=!self.playingCardView.faceUp\\N{\\fs12}equals not self.playingCardView.faceUp.\r\nDialogue: 0,1:14:44.20,1:14:46.31,yin,,0,0,0,,只要把扑克牌翻过来\\N{\\fs12}Just flip it over. Okay?\r\nDialogue: 0,1:14:49.00,1:14:49.49,yin,,0,0,0,,出来了\\N{\\fs12}Here it is.\r\nDialogue: 0,1:14:49.50,1:14:51.07,yin,,0,0,0,,我要滑动\\N{\\fs12}I'm going to swipe, okay.\r\nDialogue: 0,1:14:51.07,1:14:53.67,yin,,0,0,0,,默认滑动方向是向右的\\N{\\fs12}The default swipe direction, by the way, is to the right,\r\nDialogue: 0,1:14:53.99,1:14:55.19,yin,,0,0,0,,随着滑动 大家可以看到\\N{\\fs12}so I'm swiping and you can see\r\nDialogue: 0,1:14:55.19,1:14:57.06,yin,,0,0,0,,扑克牌翻过来又翻回去\\N{\\fs12}that it's flipping the card back and forth.\r\nDialogue: 0,1:14:57.32,1:15:00.60,yin,,0,0,0,,还可以检查滑动方向\\N{\\fs12}By the way, you can inspect which direction the swipe is\r\nDialogue: 0,1:15:00.60,1:15:03.54,yin,,0,0,0,,只要选中它 转到检查器\\N{\\fs12}by clicking on it and going to the inspector.\r\nDialogue: 0,1:15:03.70,1:15:05.17,yin,,0,0,0,,列表中有右 左 上 下四个方向\\N{\\fs12}Then there's right, left, up, down,\r\nDialogue: 0,1:15:05.17,1:15:06.31,yin,,0,0,0,,回答了刚才的问题\\N{\\fs12}so that answers your questions,\r\nDialogue: 0,1:15:06.31,1:15:07.56,yin,,0,0,0,,只有这四个方向\\N{\\fs12}those are the only four there are.\r\nDialogue: 0,1:15:07.82,1:15:09.65,yin,,0,0,0,,还有用到几根手指\\N{\\fs12}And how many fingers have to be involved,\r\nDialogue: 0,1:15:09.77,1:15:11.37,yin,,0,0,0,,一指 多指等等\\N{\\fs12}one finger, multiple fingers, etcetera.\r\nDialogue: 0,1:15:12.46,1:15:16.86,yin,,0,0,0,,最后 我要添加一个捏合手势\\N{\\fs12}Okay? And lastly, I'm going to do a pinch gesture,\r\nDialogue: 0,1:15:17.01,1:15:18.51,yin,,0,0,0,,捏合手势的实现部分\\N{\\fs12}and I'm going to do the implementation,\r\nDialogue: 0,1:15:18.51,1:15:22.73,yin,,0,0,0,,我要全部在视图中完成\\N{\\fs12}the pinch gesture, entirely in the view, okay?\r\nDialogue: 0,1:15:22.94,1:15:25.25,yin,,0,0,0,,所以我要在视图中新建一个方法\\N{\\fs12}So I'm going to add a new method to the view,\r\nDialogue: 0,1:15:25.26,1:15:26.65,yin,,0,0,0,,叫做pinch\\N{\\fs12}which is pinch.\r\nDialogue: 0,1:15:27.90,1:15:30.76,yin,,0,0,0,,它是一个UIPinchGestureRecognizer\\N{\\fs12}And it's going to be UIPinchGestureRecognizer.\r\nDialogue: 0,1:15:32.40,1:15:34.11,yin,,0,0,0,,这个pinch非常简单\\N{\\fs12}Okay? Now, this pinch is really simple.\r\nDialogue: 0,1:15:34.12,1:15:34.76,yin,,0,0,0,,它只要判断\\N{\\fs12}It's just going to say\r\nDialogue: 0,1:15:34.76,1:15:39.01,yin,,0,0,0,,手势的状态是否为Changed\\N{\\fs12}if the gesture's state is changed--\r\nDialogue: 0,1:15:41.07,1:15:42.79,yin,,0,0,0,,不是Began 是Changed\\N{\\fs12}oops, not Began, Changed,\r\nDialogue: 0,1:15:43.15,1:15:48.26,yin,,0,0,0,,或者为Ended\\N{\\fs12}or if the gesture's state is ended.\r\nDialogue: 0,1:15:50.55,1:15:52.48,yin,,0,0,0,,然后只要\\N{\\fs12}Okay? Then, I'm simply going to\r\nDialogue: 0,1:15:52.48,1:15:55.86,yin,,0,0,0,,用我的faceCardScaleFactor\\N{\\fs12}take this faceCardScaleFactor that I have\r\nDialogue: 0,1:15:56.00,1:15:58.56,yin,,0,0,0,,乘以gesture的scale\\N{\\fs12}and multiply it by the gesture scale.\r\nDialogue: 0,1:15:59.23,1:16:01.27,yin,,0,0,0,,但我不希望结果累积\\N{\\fs12}But I don't want that to accumulate,\r\nDialogue: 0,1:16:01.42,1:16:03.82,yin,,0,0,0,,所以每次都要将gesture的scale\\N{\\fs12}so I'm going to set the gesture's scale\r\nDialogue: 0,1:16:03.83,1:16:05.32,yin,,0,0,0,,重置为1.0\\N{\\fs12}back to 1.0 all the time.\r\nDialogue: 0,1:16:05.70,1:16:07.02,yin,,0,0,0,,下次被调用时\\N{\\fs12}So, the next time I get called,\r\nDialogue: 0,1:16:07.03,1:16:08.39,yin,,0,0,0,,得到的是增量的缩放比例\\N{\\fs12}I'll get the incremental scale.\r\nDialogue: 0,1:16:09.35,1:16:11.88,yin,,0,0,0,,全部需要的就是这些\\N{\\fs12}Okay? So, that's all that's necessary there.\r\nDialogue: 0,1:16:11.89,1:16:13.49,yin,,0,0,0,,我要让它成为公有的\\N{\\fs12}I'm actually going to make this public,\r\nDialogue: 0,1:16:13.70,1:16:15.14,yin,,0,0,0,,因为我想将这个手势识别器\\N{\\fs12}because I want to be able to\r\nDialogue: 0,1:16:15.15,1:16:17.35,yin,,0,0,0,,添加到控制器中\\N{\\fs12}add this gesture recognizer in my controller.\r\nDialogue: 0,1:16:17.35,1:16:19.96,yin,,0,0,0,,我们就加到这里\\N{\\fs12}So, let's just add this here, just so my gesture--\r\nDialogue: 0,1:16:19.97,1:16:21.20,yin,,0,0,0,,这样我的控制器就知道\\N{\\fs12}so my controller knows that\r\nDialogue: 0,1:16:21.21,1:16:23.46,yin,,0,0,0,,卡牌视图可以识别这个手势\\N{\\fs12}my card view is capable of this.\r\nDialogue: 0,1:16:23.97,1:16:25.86,yin,,0,0,0,,然后只要转到viewDidLoad\\N{\\fs12}Then, I simply go in viewDidLoad,\r\nDialogue: 0,1:16:26.40,1:16:30.70,yin,,0,0,0,,self.playingCardView addGestureRecognizer\\N{\\fs12}and say self.PlayingCardView, addGestureRecognizer.\r\nDialogue: 0,1:16:33.92,1:16:40.20,yin,,0,0,0,,新建一个UIPinchGestureRecognizer\\N{\\fs12}And I'm just gonna create a new UIPinchGestureRecognizer,\r\nDialogue: 0,1:16:40.20,1:16:41.56,yin,,0,0,0,,alloc init\\N{\\fs12}alloc, init.\r\nDialogue: 0,1:16:41.56,1:16:45.16,yin,,0,0,0,,这是指定初始化方法\\N{\\fs12}You'll see that this is the designated initializer,\r\nDialogue: 0,1:16:45.24,1:16:47.07,yin,,0,0,0,,目标是视图\\N{\\fs12}the target is going to be the view,\r\nDialogue: 0,1:16:47.55,1:16:50.15,yin,,0,0,0,,操作是pinch\\N{\\fs12}and the action is going to be pinch.\r\nDialogue: 0,1:16:53.62,1:16:54.71,yin,,0,0,0,,好了 就是这样\\N{\\fs12}Okay. Well, that's it.\r\nDialogue: 0,1:16:54.73,1:16:56.66,yin,,0,0,0,,就是这样在代码中添加手势的\\N{\\fs12}So, this is how you add this in code.\r\nDialogue: 0,1:16:59.37,1:17:00.53,yin,,0,0,0,,都明白吗\\N{\\fs12}Everyone understand this?\r\nDialogue: 0,1:17:01.42,1:17:04.10,yin,,0,0,0,,我将它添加到这个视图中 创建它\\N{\\fs12}So, I'm adding it to this view, creating it.\r\nDialogue: 0,1:17:04.21,1:17:05.00,yin,,0,0,0,,这是目标\\N{\\fs12}This is the target.\r\nDialogue: 0,1:17:05.01,1:17:06.18,yin,,0,0,0,,视图会处理它\\N{\\fs12}The view is going to handle it.\r\nDialogue: 0,1:17:06.26,1:17:07.14,yin,,0,0,0,,它会处理捏合手势\\N{\\fs12}It's going to handle the pinch.\r\nDialogue: 0,1:17:07.15,1:17:08.51,yin,,0,0,0,,我们处理了滑动手势\\N{\\fs12}We handled the swipe,\r\nDialogue: 0,1:17:09.15,1:17:10.86,yin,,0,0,0,,但是捏合手势是由视图处理的\\N{\\fs12}but the view is going to handle the pinch.\r\nDialogue: 0,1:17:11.30,1:17:12.71,yin,,0,0,0,,我们看一下效果如何\\N{\\fs12}All right, so let's see, what does that do?\r\nDialogue: 0,1:17:13.32,1:17:15.66,yin,,0,0,0,,如果这里有张牌 如果进行捏合缩放\\N{\\fs12}That should allow us, when we have a card here,\r\nDialogue: 0,1:17:15.69,1:17:18.46,yin,,0,0,0,,可以改变它的大小\\N{\\fs12}if I pinch, to change the size,\r\nDialogue: 0,1:17:19.33,1:17:22.47,yin,,0,0,0,,因为它是在调整faceCardScaleFactor\\N{\\fs12}because it's adjusting that faceCardScaleFactor.\r\nDialogue: 0,1:17:22.62,1:17:23.15,yin,,0,0,0,,看到了吗\\N{\\fs12}You see?\r\nDialogue: 0,1:17:25.06,1:17:25.65,yin,,0,0,0,,明白吗\\N{\\fs12}Make sense?\r\nDialogue: 0,1:17:26.68,1:17:29.62,yin,,0,0,0,,要添加deck\\N{\\fs12}But, all we need to do to add the deck here\r\nDialogue: 0,1:17:29.88,1:17:33.06,yin,,0,0,0,,我们只要回到控制器\\N{\\fs12}is to go back to our controller and add --\r\nDialogue: 0,1:17:33.75,1:17:35.25,yin,,0,0,0,,先把模型拖进来\\N{\\fs12}Well, first of all, let me drag the model in.\r\nDialogue: 0,1:17:35.26,1:17:37.47,yin,,0,0,0,,我的模型在这里\\N{\\fs12}I've got my model right here.\r\nDialogue: 0,1:17:38.36,1:17:41.01,yin,,0,0,0,,这就是我的模型 和Machismo中用过的一样\\N{\\fs12}There's my model. Same model we used in Machismo.\r\nDialogue: 0,1:17:41.86,1:17:45.67,yin,,0,0,0,,我只要在这里添加deck\\N{\\fs12}And I'm just going to go here and add that deck,\r\nDialogue: 0,1:17:47.33,1:17:51.34,yin,,0,0,0,,[strong, nonatomic] Deck *deck\\N{\\fs12}strong nonatomic, Deck star deck.\r\nDialogue: 0,1:17:51.76,1:17:56.08,yin,,0,0,0,,导入PlayingCardDeck\\N{\\fs12}Let's go ahead and import PlayingCardDeck,\r\nDialogue: 0,1:17:56.43,1:17:59.94,yin,,0,0,0,,导入PlayingCard\\N{\\fs12}let's also import PlayingCard.\r\nDialogue: 0,1:18:00.57,1:18:02.02,yin,,0,0,0,,deck设好了\\N{\\fs12}All right, so now we have that deck.\r\nDialogue: 0,1:18:02.29,1:18:05.51,yin,,0,0,0,,这是deck的延迟实例化\\N{\\fs12}Here is the lazy instantiation of the deck,\r\nDialogue: 0,1:18:05.53,1:18:06.32,yin,,0,0,0,,你们知道的\\N{\\fs12}you know about that.\r\nDialogue: 0,1:18:06.56,1:18:08.47,yin,,0,0,0,,我还要添加一个方法\\N{\\fs12}I'm also going to have this method\r\nDialogue: 0,1:18:08.47,1:18:10.90,yin,,0,0,0,,叫做drawRandomPlayingCard\\N{\\fs12}I'm going to call drawRandomPlayingCard.\r\nDialogue: 0,1:18:11.23,1:18:13.06,yin,,0,0,0,,这个方法\\N{\\fs12}Okay, this method is just gonna\r\nDialogue: 0,1:18:13.08,1:18:14.51,yin,,0,0,0,,会从deck中绘制一张卡牌\\N{\\fs12}draw a card from that deck.\r\nDialogue: 0,1:18:14.79,1:18:16.54,yin,,0,0,0,,判断它是否为一张扑克牌\\N{\\fs12}It's gonna see if it's a playing card,\r\nDialogue: 0,1:18:16.66,1:18:18.12,yin,,0,0,0,,如果是的话 就把它放上去\\N{\\fs12}if it is, it's going to cast it\r\nDialogue: 0,1:18:18.15,1:18:19.38,yin,,0,0,0,,所以有一个局部变量\\N{\\fs12}so that we have a local variable.\r\nDialogue: 0,1:18:19.58,1:18:21.02,yin,,0,0,0,,然后进行赋值\\N{\\fs12}Then it's going to set that\r\nDialogue: 0,1:18:21.20,1:18:24.33,yin,,0,0,0,,将PlayingCardView的rank和suit\\N{\\fs12}in the PlayingCardView's rank and suit\r\nDialogue: 0,1:18:24.35,1:18:25.75,yin,,0,0,0,,设为card的rank和suit\\N{\\fs12}to the card's rank and suit.\r\nDialogue: 0,1:18:26.57,1:18:30.68,yin,,0,0,0,,每次滑动并且牌面向下时\\N{\\fs12}Okay? And I'm going to do that every time we swipe\r\nDialogue: 0,1:18:31.07,1:18:32.64,yin,,0,0,0,,都会执行它\\N{\\fs12}and it's face down.\r\nDialogue: 0,1:18:38.10,1:18:39.74,yin,,0,0,0,,就是这样\\N{\\fs12}Okay? So that's that.\r\nDialogue: 0,1:18:41.88,1:18:42.48,yin,,0,0,0,,出来了\\N{\\fs12}So, here it is.\r\nDialogue: 0,1:18:42.49,1:18:44.81,yin,,0,0,0,,现在滑动时 会得到不同的扑克牌\\N{\\fs12}So now when we swipe over, we get different cards.\r\nDialogue: 0,1:18:45.07,1:18:46.18,yin,,0,0,0,,我们还没有添加花色符号\\N{\\fs12}Okay, we have no pips yet.\r\nDialogue: 0,1:18:46.18,1:18:47.34,yin,,0,0,0,,等会就做\\N{\\fs12}I'm going to do that in a second.\r\nDialogue: 0,1:18:48.35,1:18:49.84,yin,,0,0,0,,但是有人头牌\\N{\\fs12}But we do have the face cards,\r\nDialogue: 0,1:18:49.86,1:18:51.56,yin,,0,0,0,,这是方块J 分辨率有点低\\N{\\fs12}the jack of diamonds, kind of low-res,\r\nDialogue: 0,1:18:51.57,1:18:53.18,yin,,0,0,0,,因为我没有把高分辨率的图片加进来\\N{\\fs12}because I didn't have the other ones in there.\r\nDialogue: 0,1:18:54.36,1:18:55.35,yin,,0,0,0,,梅花K 不错\\N{\\fs12}King of clubs, okay.\r\nDialogue: 0,1:18:55.73,1:18:57.06,yin,,0,0,0,,现在我们快速做一下花色符号\\N{\\fs12}Now let's do the pips real quick.\r\nDialogue: 0,1:18:57.07,1:18:58.41,yin,,0,0,0,,花色符号非常简单\\N{\\fs12}The pips are super simple,\r\nDialogue: 0,1:18:58.69,1:19:01.09,yin,,0,0,0,,如果已经有了一小段代码就更好了\\N{\\fs12}especially if you have a little snippet here.\r\nDialogue: 0,1:19:01.27,1:19:03.74,yin,,0,0,0,,还记得这个drawPips吧\\N{\\fs12}So, remember we have this drawPips, okay?\r\nDialogue: 0,1:19:03.74,1:19:06.83,yin,,0,0,0,,我直接把实现代码粘贴过来\\N{\\fs12}I'm just gonna paste that with an implementation of that.\r\nDialogue: 0,1:19:07.33,1:19:10.28,yin,,0,0,0,,大家可以课下再看看花色符号这部分做了什么\\N{\\fs12}You can go look at this offline, what pips does.\r\nDialogue: 0,1:19:10.49,1:19:11.06,yin,,0,0,0,,非常简单\\N{\\fs12}Pretty straightforward.\r\nDialogue: 0,1:19:11.07,1:19:13.46,yin,,0,0,0,,就是用属性化字符串\\N{\\fs12}It just uses attributed strings,\r\nDialogue: 0,1:19:13.46,1:19:16.09,yin,,0,0,0,,甚至只是用普通字符串来绘制\\N{\\fs12}or maybe even just regular strings, to draw.\r\nDialogue: 0,1:19:16.10,1:19:17.23,yin,,0,0,0,,我们看看效果如何\\N{\\fs12}So, let's see what that looks like.\r\nDialogue: 0,1:19:18.40,1:19:19.26,yin,,0,0,0,,这是我们的扑克牌\\N{\\fs12}So, there's our card.\r\nDialogue: 0,1:19:20.10,1:19:22.03,yin,,0,0,0,,出来了 方块6\\N{\\fs12}And there we go, six of diamonds,\r\nDialogue: 0,1:19:22.05,1:19:24.10,yin,,0,0,0,,梅花4 黑桃7\\N{\\fs12}four of clubs, seven spades.\r\nDialogue: 0,1:19:24.38,1:19:25.55,yin,,0,0,0,,还有最后一件事要做\\N{\\fs12}And the last thing I'm going to do.\r\nDialogue: 0,1:19:25.56,1:19:27.06,yin,,0,0,0,,调整视图的大小\\N{\\fs12}Let's resize this view\r\nDialogue: 0,1:19:27.06,1:19:28.77,yin,,0,0,0,,看看我们修改了这么多内容之后\\N{\\fs12}and make sure it still looks good small,\r\nDialogue: 0,1:19:28.79,1:19:30.43,yin,,0,0,0,,它是否还可以正常显示\\N{\\fs12}even with all of the changes we made.\r\nDialogue: 0,1:19:30.43,1:19:32.02,yin,,0,0,0,,我们把它缩小到这么大\\N{\\fs12}So, we'll make it, like, this big.\r\nDialogue: 0,1:19:32.99,1:19:33.70,yin,,0,0,0,,运行一下\\N{\\fs12}And run.\r\nDialogue: 0,1:19:35.33,1:19:38.00,yin,,0,0,0,,看起来还不错\\N{\\fs12}And it still looks okay,\r\nDialogue: 0,1:19:39.00,1:19:40.81,yin,,0,0,0,,花色部分看起来有点挤\\N{\\fs12}a little squishy with the pips,\r\nDialogue: 0,1:19:40.81,1:19:43.37,yin,,0,0,0,,出来了一张人头牌 还不错\\N{\\fs12}but I see a face card, that's not bad.\r\nDialogue: 0,1:19:44.47,1:19:45.85,yin,,0,0,0,,今天的内容就是这些\\N{\\fs12}Okay, that's it for today.\r\nDialogue: 0,1:19:45.85,1:19:47.54,yin,,0,0,0,,抱歉拖堂了这么长时间\\N{\\fs12}Sorry to keep you so long.\r\nDialogue: 0,1:19:47.80,1:19:51.28,yin,,0,0,0,,周一见\\N{\\fs12}And I will see you all on Monday.\r\nDialogue: 0,1:19:52.72,1:19:56.09,yin,,0,0,0,,更多内容 请访问斯坦福网站\\N{\\fs12}For more, please visit us at stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/8. Protocols, Blocks, and Animation.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.1.3\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\nLast Style Storage: Default\r\nAegisub Scroll Position: 0\r\nAegisub Active Line: 2\r\nAegisub Video Zoom Percent: 1.000000\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:10.68,0:00:13.18,yin,,0,0,0,,欢迎来到2013至2014秋季学期\\N{\\fs12}Okay, well, welcome to Lecture number 8\r\nDialogue: 0,0:00:13.20,0:00:17.98,yin,,0,0,0,,斯坦福大学CS193P第八讲\\N{\\fs12}of Stanford CS193P, fall of 2013 and 14,\r\nDialogue: 0,0:00:18.00,0:00:20.00,yin,,0,0,0,,今天我们先讲讲\\N{\\fs12}and today, we are going to talk about\r\nDialogue: 0,0:00:20.02,0:00:22.94,yin,,0,0,0,,Objective-C的内容\\N{\\fs12}a couple of \"Objective-C\" things first.\r\nDialogue: 0,0:00:23.98,0:00:25.87,yin,,0,0,0,,主要是语言特性\\N{\\fs12}Language features, basically,\r\nDialogue: 0,0:00:26.09,0:00:28.30,yin,,0,0,0,,然后会讲一下动画\\N{\\fs12}and then we're going to talk about animation.\r\nDialogue: 0,0:00:28.35,0:00:30.04,yin,,0,0,0,,动画是今天的主题\\N{\\fs12}So animation is our topic of the day,\r\nDialogue: 0,0:00:30.25,0:00:32.17,yin,,0,0,0,,最后我会做一个示例\\N{\\fs12}I'll be starting a demo at the end,\r\nDialogue: 0,0:00:32.18,0:00:34.11,yin,,0,0,0,,今天开始 周三完成\\N{\\fs12}which we'll finish on Wednesday.\r\nDialogue: 0,0:00:34.12,0:00:36.99,yin,,0,0,0,,我会演示全部讲到的内容\\N{\\fs12}And I'm going to demo pretty much everything I talk about,\r\nDialogue: 0,0:00:36.99,0:00:38.42,yin,,0,0,0,,包括Objective-C\\N{\\fs12}including the Objective-C things,\r\nDialogue: 0,0:00:38.42,0:00:39.78,yin,,0,0,0,,甚至还包括\\N{\\fs12}and even including some of the things\r\nDialogue: 0,0:00:39.79,0:00:40.61,yin,,0,0,0,,上周讲过的内容\\N{\\fs12}we talked about last week,\r\nDialogue: 0,0:00:40.62,0:00:42.38,yin,,0,0,0,,所以会是一个大型且复杂的示例演示\\N{\\fs12}so it's going to be a very big, comprehensive demo,\r\nDialogue: 0,0:00:42.38,0:00:45.74,yin,,0,0,0,,所以要分成两节课完成\\N{\\fs12}that's why it runs over into two things.\r\nDialogue: 0,0:00:45.74,0:00:47.81,yin,,0,0,0,,首先是Objective-C的内容\\N{\\fs12}So the first objective-C thing,\r\nDialogue: 0,0:00:47.81,0:00:48.89,yin,,0,0,0,,我们要讲的是协议\\N{\\fs12}we're going to talk about is protocols.\r\nDialogue: 0,0:00:48.89,0:00:51.04,yin,,0,0,0,,我之前提到过\\N{\\fs12}I hinted at this earlier in the quarter.\r\nDialogue: 0,0:00:51.23,0:00:54.49,yin,,0,0,0,,这个方法会让id更安全\\N{\\fs12}This is a way that we're gonna make id a little more useful\r\nDialogue: 0,0:00:54.49,0:00:56.76,yin,,0,0,0,,让它更加有用\\N{\\fs12}by making it a little safer, okay?\r\nDialogue: 0,0:00:57.26,0:01:00.93,yin,,0,0,0,,我们已经有了内省机制 可以让id更安全\\N{\\fs12}And we already have introspection to make id safer.\r\nDialogue: 0,0:01:00.95,0:01:02.44,yin,,0,0,0,,如果我们有一个id\\N{\\fs12}When we have something that's an id,\r\nDialogue: 0,0:01:02.45,0:01:03.91,yin,,0,0,0,,我们知道它是一个指向某个对象的指针\\N{\\fs12}we know it's a pointer to some object,\r\nDialogue: 0,0:01:03.92,0:01:05.16,yin,,0,0,0,,我们不知道对象的类型\\N{\\fs12}we don't know what kind of object,\r\nDialogue: 0,0:01:05.17,0:01:07.86,yin,,0,0,0,,我们知道如何在运行时用内省来询问\\N{\\fs12}we know how to use introspection to ask at runtime,\r\nDialogue: 0,0:01:07.86,0:01:08.77,yin,,0,0,0,,你是什么类型的对象呢\\N{\\fs12}\"What kind of object are you?\"\r\nDialogue: 0,0:01:08.77,0:01:10.48,yin,,0,0,0,,你响应哪种方法呢\\N{\\fs12}\"What kind of methods do you respond to?\"\r\nDialogue: 0,0:01:10.81,0:01:12.79,yin,,0,0,0,,这样不错 但是下面这样更好\\N{\\fs12}That's nice, but it would be better if,\r\nDialogue: 0,0:01:12.81,0:01:16.46,yin,,0,0,0,,如果我们可以在代码中增加说明\\N{\\fs12}in our code, we could document in a way\r\nDialogue: 0,0:01:16.48,0:01:18.38,yin,,0,0,0,,让代码阅读者和编译器\\N{\\fs12}that both the reader of our code can understand\r\nDialogue: 0,0:01:18.40,0:01:20.62,yin,,0,0,0,,都可以理解\\N{\\fs12}and also that the compiler can understand\r\nDialogue: 0,0:01:20.73,0:01:23.86,yin,,0,0,0,,我们想用那个id做什么\\N{\\fs12}what it is we intend, okay, with that id.\r\nDialogue: 0,0:01:24.01,0:01:26.86,yin,,0,0,0,,我们打算对那个id调用哪个方法\\N{\\fs12}What methods we plan to call on that id.\r\nDialogue: 0,0:01:26.86,0:01:28.42,yin,,0,0,0,,这就是protocol协议的功能\\N{\\fs12}And so that's what protocols do.\r\nDialogue: 0,0:01:28.56,0:01:30.18,yin,,0,0,0,,基本上就是语法\\N{\\fs12}It's basically syntax,\r\nDialogue: 0,0:01:30.20,0:01:31.62,yin,,0,0,0,,只是编译器中的语法\\N{\\fs12}it's just syntax in the compiler,\r\nDialogue: 0,0:01:31.62,0:01:32.39,yin,,0,0,0,,仅此而已\\N{\\fs12}nothing more than that.\r\nDialogue: 0,0:01:32.39,0:01:35.32,yin,,0,0,0,,与NSString *和id一样\\N{\\fs12}It's kind of the same thing in NSString star versus id,\r\nDialogue: 0,0:01:35.32,0:01:37.21,yin,,0,0,0,,只是编译器中语法的不同\\N{\\fs12}that's really just syntax in the compiler,\r\nDialogue: 0,0:01:37.21,0:01:38.73,yin,,0,0,0,,在运行时并没有区别\\N{\\fs12}it makes no difference at runtime.\r\nDialogue: 0,0:01:39.24,0:01:42.02,yin,,0,0,0,,语法的基本部分是这样的\\N{\\fs12}And the fundamental part of the syntax is right here,\r\nDialogue: 0,0:01:42.05,0:01:44.45,yin,,0,0,0,,id <Protocol> obj\\N{\\fs12}id angle bracket protocol obj.\r\nDialogue: 0,0:01:44.72,0:01:47.02,yin,,0,0,0,,声明了一个obj变量\\N{\\fs12}So that's declaring a variable of type \"obj\"\r\nDialogue: 0,0:01:47.04,0:01:48.30,yin,,0,0,0,,它是一个id\\N{\\fs12}which is an id,\r\nDialogue: 0,0:01:48.43,0:01:52.52,yin,,0,0,0,,但是加上了协议部分\\N{\\fs12}but it's got this additional little thing, my protocol,\r\nDialogue: 0,0:01:52.52,0:01:54.47,yin,,0,0,0,,可以告诉编译器和阅读者\\N{\\fs12}which tells the compiler and readers\r\nDialogue: 0,0:01:54.47,0:01:55.49,yin,,0,0,0,,更多代码的信息\\N{\\fs12}of your code a little bit more.\r\nDialogue: 0,0:01:55.49,0:01:58.91,yin,,0,0,0,,我们来讲一下协议和它的工作原理\\N{\\fs12}So let's talk about protocols and how this all works.\r\nDialogue: 0,0:01:59.47,0:02:00.48,yin,,0,0,0,,首先 我们要讲的是\\N{\\fs12}The first thing we're going to talk about\r\nDialogue: 0,0:02:00.48,0:02:01.98,yin,,0,0,0,,如何声明一个协议\\N{\\fs12}is how to declare a protocol.\r\nDialogue: 0,0:02:02.15,0:02:05.23,yin,,0,0,0,,声明协议的方法\\N{\\fs12}And declaring a protocol looks almost exactly the same\r\nDialogue: 0,0:02:05.24,0:02:07.60,yin,,0,0,0,,和@interface声明几乎完全一样\\N{\\fs12}as an at sign interface statement.\r\nDialogue: 0,0:02:07.94,0:02:09.47,yin,,0,0,0,,我们在@interface中放的是\\N{\\fs12}At sign interface is where you put\r\nDialogue: 0,0:02:09.49,0:02:11.80,yin,,0,0,0,,所有公有的方法和属性\\N{\\fs12}all your methods and properties that are public,\r\nDialogue: 0,0:02:12.05,0:02:13.78,yin,,0,0,0,,或者可以在实现文件顶部\\N{\\fs12}or you can have an at sign interface\r\nDialogue: 0,0:02:13.78,0:02:14.85,yin,,0,0,0,,添加一个@interface\\N{\\fs12}at the top of your implementation\r\nDialogue: 0,0:02:14.85,0:02:18.97,yin,,0,0,0,,来放私有的方法和属性\\N{\\fs12}and have private methods and protocols-- properties.\r\nDialogue: 0,0:02:19.05,0:02:20.71,yin,,0,0,0,,协议也是一样的\\N{\\fs12}And the same thing for protocol, just you say\r\nDialogue: 0,0:02:20.71,0:02:23.45,yin,,0,0,0,,只不过把@interface换成了@protocol\\N{\\fs12}at sign protocol instead of at sign interface.\r\nDialogue: 0,0:02:23.60,0:02:26.92,yin,,0,0,0,,协议只是方法的声明\\N{\\fs12}Now, a protocol is just a declaration of the methods.\r\nDialogue: 0,0:02:26.92,0:02:27.99,yin,,0,0,0,,没有实现部分\\N{\\fs12}There's no implementation,\r\nDialogue: 0,0:02:28.01,0:02:30.49,yin,,0,0,0,,所以@protocol没有对应的@implementation\\N{\\fs12}so there's no at sign implementation for an at sign protocol.\r\nDialogue: 0,0:02:30.49,0:02:32.25,yin,,0,0,0,,我们说的只是方法\\N{\\fs12}We're just talking about the methods.\r\nDialogue: 0,0:02:32.61,0:02:36.99,yin,,0,0,0,,协议中的方法默认是必须实现的\\N{\\fs12}And the methods in a protocol by default are all required, okay,\r\nDialogue: 0,0:02:37.27,0:02:38.92,yin,,0,0,0,,因此如果有人\\N{\\fs12}so that means if someone wants to say\r\nDialogue: 0,0:02:38.92,0:02:40.61,yin,,0,0,0,,要实现这个协议\\N{\\fs12}that they implement this protocol,\r\nDialogue: 0,0:02:40.74,0:02:42.28,yin,,0,0,0,,必须实现全部这些方法\\N{\\fs12}they have to implement all these methods,\r\nDialogue: 0,0:02:42.28,0:02:44.44,yin,,0,0,0,,这些是这个示例协议中\\N{\\fs12}and so those are all the methods\r\nDialogue: 0,0:02:44.44,0:02:46.12,yin,,0,0,0,,所有的方法\\N{\\fs12}in my little sample protocol here.\r\nDialogue: 0,0:02:46.26,0:02:48.27,yin,,0,0,0,,你可以在这里加一个@optional\\N{\\fs12}You can make some of them optional\r\nDialogue: 0,0:02:48.29,0:02:50.66,yin,,0,0,0,,将一部分方法变为可选的\\N{\\fs12}by putting at sign optional in there.\r\nDialogue: 0,0:02:51.07,0:02:52.73,yin,,0,0,0,,现在 下面这些方法都是可选的了\\N{\\fs12}And now, all the rest of those are optional,\r\nDialogue: 0,0:02:52.73,0:02:55.16,yin,,0,0,0,,在现在这个示例中 someMethod是必需的\\N{\\fs12}so now in this example, someMethod is required,\r\nDialogue: 0,0:02:55.16,0:02:56.39,yin,,0,0,0,,下面其他的都是可选的\\N{\\fs12}but all the rest are optional.\r\nDialogue: 0,0:02:56.89,0:02:58.61,yin,,0,0,0,,你还可以再加一个@required\\N{\\fs12}And you can put at sign required,\r\nDialogue: 0,0:02:58.61,0:03:00.32,yin,,0,0,0,,在下面这里\\N{\\fs12}again, down a little lower.\r\nDialogue: 0,0:03:00.44,0:03:02.07,yin,,0,0,0,,现在就只有methodWithArgument是可选的\\N{\\fs12}Now, all of these are required\r\nDialogue: 0,0:03:02.09,0:03:03.89,yin,,0,0,0,,其余都是必需的\\N{\\fs12}except for methodWithArgument is optional.\r\nDialogue: 0,0:03:05.51,0:03:08.32,yin,,0,0,0,,所以基本上 我们是定义了一堆方法\\N{\\fs12}So, we're basically defining a little pile of methods,\r\nDialogue: 0,0:03:08.33,0:03:09.51,yin,,0,0,0,,其中有些是必需的\\N{\\fs12}some of which are required,\r\nDialogue: 0,0:03:09.52,0:03:10.74,yin,,0,0,0,,有些是可选的\\N{\\fs12}and some of which are optional, okay,\r\nDialogue: 0,0:03:10.74,0:03:13.20,yin,,0,0,0,,协议声明就是这样的\\N{\\fs12}that's what a protocol declaration is all about.\r\nDialogue: 0,0:03:13.31,0:03:16.32,yin,,0,0,0,,我在@protocol Foo后面加了个<Xyzzy>\\N{\\fs12}Now you see how I've added Xyzzy and angle brackets\r\nDialogue: 0,0:03:16.32,0:03:18.77,yin,,0,0,0,,看到了吗\\N{\\fs12}after protocol Foo there?\r\nDialogue: 0,0:03:19.13,0:03:21.63,yin,,0,0,0,,它的意思是\\N{\\fs12}So what that says is, if you want to implement,\r\nDialogue: 0,0:03:21.63,0:03:24.04,yin,,0,0,0,,如果你想要实现协议Foo\\N{\\fs12}if you want to say you implement protocol Foo,\r\nDialogue: 0,0:03:24.14,0:03:28.56,yin,,0,0,0,,就也要实现Xyzzy协议中全部必需的方法\\N{\\fs12}you also have to implement all the required methods of protocol Xyzzy.\r\nDialogue: 0,0:03:28.75,0:03:29.50,yin,,0,0,0,,不管是什么方法\\N{\\fs12}Whatever that is.\r\nDialogue: 0,0:03:29.84,0:03:33.37,yin,,0,0,0,,大体上有点像是父协议\\N{\\fs12}Okay? So it's basically a way of kind of like super protocol,\r\nDialogue: 0,0:03:33.51,0:03:35.12,yin,,0,0,0,,不是继承之类的\\N{\\fs12}it's not really like inherent or anything,\r\nDialogue: 0,0:03:35.14,0:03:36.73,yin,,0,0,0,,就是增加了协议\\N{\\fs12}but just kind of adds to the methods\r\nDialogue: 0,0:03:37.08,0:03:38.46,yin,,0,0,0,,必须要实现的方法\\N{\\fs12}that is required by a protocol,\r\nDialogue: 0,0:03:38.54,0:03:40.47,yin,,0,0,0,,实际上 这里可以添加多个协议\\N{\\fs12}and in fact, you can have multiple ones,\r\nDialogue: 0,0:03:40.47,0:03:43.10,yin,,0,0,0,,现在这个协议要求你实现\\N{\\fs12}so here's protocols now requiring you implement\r\nDialogue: 0,0:03:43.10,0:03:46.82,yin,,0,0,0,,Xyzzy协议和NSObject协议\\N{\\fs12}the Xyzzy protocol and a protocol called NSObject.\r\nDialogue: 0,0:03:47.16,0:03:49.69,yin,,0,0,0,,现在我们来说一下这个NSObject协议\\N{\\fs12}Okay, now, let's talk about this NSObject protocol\r\nDialogue: 0,0:03:49.69,0:03:51.27,yin,,0,0,0,,因为它是一个很常见的协议\\N{\\fs12}because it's a very common protocol.\r\nDialogue: 0,0:03:51.53,0:03:54.31,yin,,0,0,0,,大家都很熟悉NSObject类 对吧\\N{\\fs12}You're used to the NSObject class, right?\r\nDialogue: 0,0:03:54.79,0:03:58.00,yin,,0,0,0,,NSObject协议基本上就是一个\\N{\\fs12}And NSObject protocol is basically a protocol\r\nDialogue: 0,0:03:58.00,0:04:01.52,yin,,0,0,0,,包括了NSObject类中全部方法的协议\\N{\\fs12}that includes almost all the methods in the NSObject class.\r\nDialogue: 0,0:04:02.07,0:04:04.04,yin,,0,0,0,,为什么要这样做呢\\N{\\fs12}Okay. And why do we do this?\r\nDialogue: 0,0:04:04.04,0:04:05.79,yin,,0,0,0,,为什么要同时创建一个叫做NSObject的协议\\N{\\fs12}Why do we have a protocol named NSObject\r\nDialogue: 0,0:04:05.97,0:04:07.12,yin,,0,0,0,,和一个叫NSObject的类呢\\N{\\fs12}and a class named NSObject,\r\nDialogue: 0,0:04:07.12,0:04:08.70,yin,,0,0,0,,二者几乎有完全相同的方法\\N{\\fs12}and they have pretty much the same methods in it,\r\nDialogue: 0,0:04:08.71,0:04:12.59,yin,,0,0,0,,isEqual isKindOfClass description performSelector\\N{\\fs12}isEqual, isKindOfClass, description, performSelector,\r\nDialogue: 0,0:04:12.60,0:04:14.32,yin,,0,0,0,,全部这些NSObject的内容\\N{\\fs12}all those NSObject things.\r\nDialogue: 0,0:04:14.51,0:04:17.98,yin,,0,0,0,,是因为有时我们在声明协议时\\N{\\fs12}The answer is because we sometimes want to declare a protocol\r\nDialogue: 0,0:04:18.72,0:04:20.28,yin,,0,0,0,,有些方法是必需的\\N{\\fs12}where some methods are required,\r\nDialogue: 0,0:04:20.29,0:04:22.23,yin,,0,0,0,,但我们还想让实现这个协议的对象\\N{\\fs12}but we also want to require the thing\r\nDialogue: 0,0:04:22.23,0:04:25.47,yin,,0,0,0,,从本质上说 是一个NSObject\\N{\\fs12}that implements the protocol to essentially be an NSObject.\r\nDialogue: 0,0:04:25.89,0:04:27.19,yin,,0,0,0,,我们希望它是一个NSObject\\N{\\fs12}Okay. We want it to be an NSObject,\r\nDialogue: 0,0:04:27.21,0:04:30.39,yin,,0,0,0,,我们也许想要用内省等等\\N{\\fs12}we want to be able to maybe use introspection, things like that.\r\nDialogue: 0,0:04:30.53,0:04:33.38,yin,,0,0,0,,唯一的方法就是让这个协议\\N{\\fs12}Well, the only way to do that is to have the protocol\r\nDialogue: 0,0:04:33.38,0:04:36.30,yin,,0,0,0,,有一个父协议 附加的协议\\N{\\fs12}have like a super protocol, you know, an additional protocol,\r\nDialogue: 0,0:04:36.42,0:04:38.98,yin,,0,0,0,,所以我们直接将NSObject中全部的方法\\N{\\fs12}and so we just took all the methods in NSObject,\r\nDialogue: 0,0:04:38.98,0:04:40.32,yin,,0,0,0,,放到一个大协议中\\N{\\fs12}we put them all in a big protocol\r\nDialogue: 0,0:04:40.33,0:04:42.63,yin,,0,0,0,,然后让NSobject来实现那个协议\\N{\\fs12}and have NSObject implement that protocol.\r\nDialogue: 0,0:04:43.02,0:04:45.54,yin,,0,0,0,,所以NSObject协议和类\\N{\\fs12}Okay. So NSObject protocol and class,\r\nDialogue: 0,0:04:45.55,0:04:47.58,yin,,0,0,0,,差不多有完全一样的方法\\N{\\fs12}all the same methods pretty much.\r\nDialogue: 0,0:04:48.14,0:04:50.18,yin,,0,0,0,,只不过NSObject类\\N{\\fs12}Okay. It's just that NSObject class\r\nDialogue: 0,0:04:50.19,0:04:52.31,yin,,0,0,0,,真正实现了这些方法\\N{\\fs12}is an actual implementation of those methods.\r\nDialogue: 0,0:04:53.97,0:04:55.43,yin,,0,0,0,,那么这些协议声明...\\N{\\fs12}So where do these protocol declaration--\r\nDialogue: 0,0:04:55.43,0:04:56.27,yin,,0,0,0,,抱歉 有问题吗\\N{\\fs12}Oh yeah, sorry, question?\r\nDialogue: 0,0:04:57.05,0:05:00.31,yin,,0,0,0,,在Java中 所有类都是自动从对象继承的\\N{\\fs12}In Java, all class is automatically inherit from object,\r\nDialogue: 0,0:05:00.33,0:05:02.03,yin,,0,0,0,,NSObject不是这样吗\\N{\\fs12}is that not the case with NSObject here?\r\nDialogue: 0,0:05:02.03,0:05:03.53,yin,,0,0,0,,问题是 在Java中\\N{\\fs12}Yeah, so the question is, in Java,\r\nDialogue: 0,0:05:03.55,0:05:06.68,yin,,0,0,0,,差不多所有的类都是从对象继承的\\N{\\fs12}all class is pretty much inherit from object,\r\nDialogue: 0,0:05:06.88,0:05:08.72,yin,,0,0,0,,Objective-C中不是这样的\\N{\\fs12}and that's not true in Objective-C,\r\nDialogue: 0,0:05:08.84,0:05:10.72,yin,,0,0,0,,你可以直接用\\N{\\fs12}you could have a class where it just says\r\nDialogue: 0,0:05:10.72,0:05:14.53,yin,,0,0,0,,@interface 类名 没有冒号和父类\\N{\\fs12}at sign interface, name of class, no colon super class.\r\nDialogue: 0,0:05:14.53,0:05:17.24,yin,,0,0,0,,这种情况下 它不会继承任何方法\\N{\\fs12}In which case, it inherits no methods from anywhere.\r\nDialogue: 0,0:05:17.36,0:05:18.55,yin,,0,0,0,,只会有它自己的方法\\N{\\fs12}Okay, will only have its own method.\r\nDialogue: 0,0:05:18.83,0:05:20.28,yin,,0,0,0,,但我们不会这样做\\N{\\fs12}We never do that, however.\r\nDialogue: 0,0:05:20.29,0:05:22.60,yin,,0,0,0,,在iOS中 我们总是从NSObject继承而来\\N{\\fs12}In iOS we always inherit from NSObject.\r\nDialogue: 0,0:05:22.63,0:05:24.90,yin,,0,0,0,,因为我们需要内省等这些方法\\N{\\fs12}Because we want the introspection and all these things,\r\nDialogue: 0,0:05:25.52,0:05:27.13,yin,,0,0,0,,但这是惯例\\N{\\fs12}but it's by convention rather than\r\nDialogue: 0,0:05:27.15,0:05:30.04,yin,,0,0,0,,而不是编译器的强制要求\\N{\\fs12}by some sort of enforcement for the compiler.\r\nDialogue: 0,0:05:31.29,0:05:33.61,yin,,0,0,0,,那么 这些方法的@protocol声明\\N{\\fs12}Alright, so these at sign protocol declarations\r\nDialogue: 0,0:05:33.61,0:05:35.04,yin,,0,0,0,,要放在哪里呢\\N{\\fs12}of these methods, where do they go?\r\nDialogue: 0,0:05:35.10,0:05:36.39,yin,,0,0,0,,放在头文件中\\N{\\fs12}They go in header files,\r\nDialogue: 0,0:05:36.48,0:05:38.18,yin,,0,0,0,,可以放在它们自己的头文件中\\N{\\fs12}they can go in their own header file,\r\nDialogue: 0,0:05:38.40,0:05:41.05,yin,,0,0,0,,比如Foo协议的头文件就是Foo.h\\N{\\fs12}so like have a Foo.h for my protocol Foo,\r\nDialogue: 0,0:05:41.31,0:05:44.06,yin,,0,0,0,,或者可以放在某个相关类的头文件中\\N{\\fs12}or they can go in the header file of some related class,\r\nDialogue: 0,0:05:44.08,0:05:46.97,yin,,0,0,0,,比如要实现那个协议的某个类\\N{\\fs12}like some class that wants somebody to implement that protocol,\r\nDialogue: 0,0:05:46.97,0:05:47.73,yin,,0,0,0,,也可以放在它的头文件中\\N{\\fs12}you could put it in there.\r\nDialogue: 0,0:05:47.73,0:05:51.27,yin,,0,0,0,,比如iOS中有滚动视图类\\N{\\fs12}So, for example, iOS has scroll view class, right?\r\nDialogue: 0,0:05:51.27,0:05:51.84,yin,,0,0,0,,用于滚动\\N{\\fs12}For scrolling.\r\nDialogue: 0,0:05:51.84,0:05:53.15,yin,,0,0,0,,我们下周会讲到它\\N{\\fs12}We're going to talk about that next week.\r\nDialogue: 0,0:05:53.40,0:05:56.85,yin,,0,0,0,,它有一个协议叫做UIScrollViewDelegate\\N{\\fs12}It has a protocol called the UIScrollViewDelegate,\r\nDialogue: 0,0:05:57.17,0:06:01.33,yin,,0,0,0,,里面有一堆willScroll didScroll等这类方法\\N{\\fs12}which is a bunch of willScroll, didScroll things, methods,\r\nDialogue: 0,0:06:01.44,0:06:05.12,yin,,0,0,0,,这个协议只适用于UIScrollView\\N{\\fs12}and it's only good for UIScrollView, so that delegate,\r\nDialogue: 0,0:06:05.15,0:06:08.34,yin,,0,0,0,,所以这个协议是在UIScrollView.h中定义的\\N{\\fs12}that protocol is defined in UIScrollView.h,\r\nDialogue: 0,0:06:08.46,0:06:10.08,yin,,0,0,0,,而不是在它自己的头文件中\\N{\\fs12}not in its own header file.\r\nDialogue: 0,0:06:10.23,0:06:12.53,yin,,0,0,0,,所以这两种方法大家可以任选\\N{\\fs12}Okay? So you can kind of do which ever one you want,\r\nDialogue: 0,0:06:12.53,0:06:14.37,yin,,0,0,0,,两种方法都会见到\\N{\\fs12}and you'll see them both ways.\r\nDialogue: 0,0:06:15.92,0:06:17.63,yin,,0,0,0,,现在我们声明了协议\\N{\\fs12}Alright, so now we have the protocol declared,\r\nDialogue: 0,0:06:17.66,0:06:19.67,yin,,0,0,0,,定义了这些方法\\N{\\fs12}we defined this little bundle of methods,\r\nDialogue: 0,0:06:19.68,0:06:22.11,yin,,0,0,0,,也许包括属性的setter和getter\\N{\\fs12}including the setters and getters of properties, perhaps,\r\nDialogue: 0,0:06:23.05,0:06:27.76,yin,,0,0,0,,现在要有一个类保证实现这个协议\\N{\\fs12}now some class has to promise to implement that protocol.\r\nDialogue: 0,0:06:28.03,0:06:29.02,yin,,0,0,0,,如果你是一个类\\N{\\fs12}And how do you promise\r\nDialogue: 0,0:06:29.03,0:06:30.92,yin,,0,0,0,,如何保证实现一个协议呢\\N{\\fs12}to implement a protocol if you're a class?\r\nDialogue: 0,0:06:31.03,0:06:34.16,yin,,0,0,0,,只要在@interface那一行\\N{\\fs12}You just put angle brackets, the name of the protocol,\r\nDialogue: 0,0:06:34.16,0:06:35.62,yin,,0,0,0,,加上<协议名>\\N{\\fs12}on your at sign interface line.\r\nDialogue: 0,0:06:36.52,0:06:40.06,yin,,0,0,0,,这一行是我的公有的@interface\\N{\\fs12}Okay? So here, it's my public at sign interface line,\r\nDialogue: 0,0:06:40.07,0:06:42.91,yin,,0,0,0,,myClass 从NSobject继承来的 然后是<Foo>\\N{\\fs12}myClass, inherits from NSObject, angle brackets Foo.\r\nDialogue: 0,0:06:42.91,0:06:45.15,yin,,0,0,0,,这表示的是\\N{\\fs12}That means my class is promising\r\nDialogue: 0,0:06:45.45,0:06:47.48,yin,,0,0,0,,我的类向编译器和阅读者们保证\\N{\\fs12}to the compiler and to readers of this code,\r\nDialogue: 0,0:06:47.60,0:06:49.89,yin,,0,0,0,,我要实现Foo中全部必须实现的方法\\N{\\fs12}I'm going to implement all the required methods in Foo.\r\nDialogue: 0,0:06:50.78,0:06:52.72,yin,,0,0,0,,我做出了这样的保证\\N{\\fs12}Okay? So I'm just making that promise.\r\nDialogue: 0,0:06:52.78,0:06:54.99,yin,,0,0,0,,可以像这样公开保证\\N{\\fs12}And you can make the promise publicly like that,\r\nDialogue: 0,0:06:54.99,0:06:56.71,yin,,0,0,0,,或者也可以将其变为私有的\\N{\\fs12}or you can make the promise privately\r\nDialogue: 0,0:06:56.93,0:07:01.27,yin,,0,0,0,,方法是将其放在@interface myClass()中\\N{\\fs12}by putting it in your at sign interface myClass() thing\r\nDialogue: 0,0:07:01.28,0:07:03.10,yin,,0,0,0,,这是在实现部分中的\\N{\\fs12}that goes in your implementation,\r\nDialogue: 0,0:07:03.33,0:07:04.49,yin,,0,0,0,,需要的话 可以直接放在那里\\N{\\fs12}you can just put it there if you want.\r\nDialogue: 0,0:07:04.86,0:07:08.28,yin,,0,0,0,,只用于需要实现...\\N{\\fs12}That's if you only need to be able to implement that--\r\nDialogue: 0,0:07:08.63,0:07:10.12,yin,,0,0,0,,你只需要为实现文件中独有的某对象\\N{\\fs12}you're only required to implement that protocol\r\nDialogue: 0,0:07:10.12,0:07:12.51,yin,,0,0,0,,实现那个协议\\N{\\fs12}for something that's in your implementation only, okay,\r\nDialogue: 0,0:07:12.76,0:07:14.31,yin,,0,0,0,,不是公有的\\N{\\fs12}not on your public thing.\r\nDialogue: 0,0:07:15.43,0:07:17.90,yin,,0,0,0,,现在我有了一个协议\\N{\\fs12}Okay, so now I've got a protocol,\r\nDialogue: 0,0:07:18.01,0:07:19.16,yin,,0,0,0,,有了一个对象\\N{\\fs12}I've got an object,\r\nDialogue: 0,0:07:19.24,0:07:22.15,yin,,0,0,0,,至少有一个说了要实现它 然后呢\\N{\\fs12}at least one that signs up to implement it, now what?\r\nDialogue: 0,0:07:22.15,0:07:27.02,yin,,0,0,0,,现在我可以声明id类型的变量\\N{\\fs12}Well, now I can declare variables that are ids\r\nDialogue: 0,0:07:27.17,0:07:28.55,yin,,0,0,0,,加上附加要求\\N{\\fs12}with the additional requirement\r\nDialogue: 0,0:07:28.72,0:07:30.81,yin,,0,0,0,,要求实现某个协议中的必需方法\\N{\\fs12}to implement the required methods of a protocol.\r\nDialogue: 0,0:07:31.28,0:07:33.54,yin,,0,0,0,,也就是id <Foo> obj\\N{\\fs12}So id angle bracket Foo obj,\r\nDialogue: 0,0:07:33.57,0:07:35.87,yin,,0,0,0,,希望大家现在明白它的意思了\\N{\\fs12}hopefully, you understand what that means now,\r\nDialogue: 0,0:07:35.93,0:07:38.23,yin,,0,0,0,,它表示obj是一个变量 是一个id类型\\N{\\fs12}that means obj is a variable, it's an id,\r\nDialogue: 0,0:07:38.25,0:07:41.67,yin,,0,0,0,,我不知道它的类是什么 它是个id\\N{\\fs12}I have no idea what class it is, okay, it's id,\r\nDialogue: 0,0:07:41.69,0:07:42.52,yin,,0,0,0,,是完全不可知的\\N{\\fs12}it's completely blind,\r\nDialogue: 0,0:07:42.69,0:07:43.98,yin,,0,0,0,,但是我知道它实现了\\N{\\fs12}however, I know it implements\r\nDialogue: 0,0:07:43.99,0:07:47.77,yin,,0,0,0,,Foo中全部私有或必需的方法\\N{\\fs12}all the private or the required methods in Foo. Okay?\r\nDialogue: 0,0:07:48.07,0:07:49.95,yin,,0,0,0,,它也许也实现了某些可选方法\\N{\\fs12}And it might implement some of the optional ones too,\r\nDialogue: 0,0:07:49.95,0:07:51.84,yin,,0,0,0,,但我知道至少它实现了必需的方法\\N{\\fs12}but I know at least the required ones.\r\nDialogue: 0,0:07:52.27,0:07:56.85,yin,,0,0,0,,如果我用id <Foo> obj=[[MyClass alloc] init]\\N{\\fs12}So if I say id <Foo> obj MyClass alloc init,\r\nDialogue: 0,0:07:56.85,0:07:58.72,yin,,0,0,0,,这样就很不错 因为在上一张幻灯片中\\N{\\fs12}that looks good because on the previous slide\r\nDialogue: 0,0:07:58.74,0:08:00.88,yin,,0,0,0,,我说了MyClass保证会实现Foo\\N{\\fs12}I just said that MyClass promised to implement Foo.\r\nDialogue: 0,0:08:01.15,0:08:02.43,yin,,0,0,0,,编译器会很喜欢这行代码\\N{\\fs12}So the compiler is going to love that.\r\nDialogue: 0,0:08:02.74,0:08:06.51,yin,,0,0,0,,但如果用的是id <Foo> obj=[NSArray array]\\N{\\fs12}But if I said id Foo obj NS equals NSArray,\r\nDialogue: 0,0:08:06.93,0:08:08.37,yin,,0,0,0,,编译器不喜欢这样的\\N{\\fs12}that compiler is not going to like that\r\nDialogue: 0,0:08:08.38,0:08:10.64,yin,,0,0,0,,因为array显然没有实现协议Foo\\N{\\fs12}because array clearly don't implement a protocol Foo.\r\nDialogue: 0,0:08:10.64,0:08:12.04,yin,,0,0,0,,它们没有实现那些方法\\N{\\fs12}They don't implement those methods.\r\nDialogue: 0,0:08:12.52,0:08:16.01,yin,,0,0,0,,所以如果这样用了 编译器会警告你\\N{\\fs12}Okay? So the compiler will warn you in that case.\r\nDialogue: 0,0:08:16.69,0:08:19.54,yin,,0,0,0,,你这样做的话 编译器会发出警告\\N{\\fs12}Okay, so the compiler here will warn you if you do this,\r\nDialogue: 0,0:08:19.54,0:08:22.30,yin,,0,0,0,,如果你说了要实现一个协议\\N{\\fs12}it will also warn you if you sign up to do a protocol,\r\nDialogue: 0,0:08:22.30,0:08:23.22,yin,,0,0,0,,保证了要做某些事情\\N{\\fs12}you promise to do something,\r\nDialogue: 0,0:08:23.23,0:08:25.25,yin,,0,0,0,,但你却没有实现必需的方法\\N{\\fs12}and you don't implement the methods that are required,\r\nDialogue: 0,0:08:25.26,0:08:26.37,yin,,0,0,0,,编译器也会发出警告\\N{\\fs12}it will warn you about that too,\r\nDialogue: 0,0:08:27.09,0:08:29.18,yin,,0,0,0,,所以两种问题都会发出警告\\N{\\fs12}okay so it will warn you both coming and going.\r\nDialogue: 0,0:08:30.23,0:08:32.08,yin,,0,0,0,,除了声明变量\\N{\\fs12}In addition to declaring variables,\r\nDialogue: 0,0:08:32.09,0:08:34.85,yin,,0,0,0,,比如例子中的局部变量之外\\N{\\fs12}like local variables under the examples there,\r\nDialogue: 0,0:08:34.97,0:08:37.62,yin,,0,0,0,,你还可以传递它们\\N{\\fs12}you can also pass these around,\r\nDialogue: 0,0:08:37.86,0:08:40.73,yin,,0,0,0,,将这些带有协议的id\\N{\\fs12}these ids that are modified by the protocol,\r\nDialogue: 0,0:08:40.92,0:08:42.17,yin,,0,0,0,,作为方法的参数\\N{\\fs12}as arguments to methods.\r\nDialogue: 0,0:08:42.23,0:08:43.34,yin,,0,0,0,,还可以作为属性\\N{\\fs12}And as properties.\r\nDialogue: 0,0:08:43.97,0:08:46.98,yin,,0,0,0,,它就是另外一种类型\\N{\\fs12}Okay? So, it's really just another type,\r\nDialogue: 0,0:08:47.28,0:08:49.85,yin,,0,0,0,,不像NSString*那样\\N{\\fs12}it's not quite an NSString star\r\nDialogue: 0,0:08:49.86,0:08:51.11,yin,,0,0,0,,你知道它的类是什么\\N{\\fs12}where you know exactly the class\r\nDialogue: 0,0:08:51.12,0:08:52.82,yin,,0,0,0,,知道全部方法的功能\\N{\\fs12}and all the methods exactly that it does,\r\nDialogue: 0,0:08:52.96,0:08:54.28,yin,,0,0,0,,但也不是像id那样\\N{\\fs12}but it's not quite an id,\r\nDialogue: 0,0:08:54.29,0:08:55.61,yin,,0,0,0,,完全什么都不知道\\N{\\fs12}where you know nothing about it.\r\nDialogue: 0,0:08:55.63,0:08:56.35,yin,,0,0,0,,它在二者之间\\N{\\fs12}It's in between.\r\nDialogue: 0,0:08:56.73,0:08:57.83,yin,,0,0,0,,它是一个id\\N{\\fs12}Right? It's an id,\r\nDialogue: 0,0:08:57.85,0:09:00.74,yin,,0,0,0,,但你知道Foo中的某些方法\\N{\\fs12}but you kind of know some of the methods in Foo.\r\nDialogue: 0,0:09:04.70,0:09:05.92,yin,,0,0,0,,类似于静态类型\\N{\\fs12}Just like static typing,\r\nDialogue: 0,0:09:06.11,0:09:08.45,yin,,0,0,0,,只是编译器中的语法糖\\N{\\fs12}this is all just syntactic sugar in the compiler,\r\nDialogue: 0,0:09:08.46,0:09:10.33,yin,,0,0,0,,运行时毫无区别\\N{\\fs12}makes absolutely no difference at runtime,\r\nDialogue: 0,0:09:10.91,0:09:12.61,yin,,0,0,0,,编译器生成的代码\\N{\\fs12}no code is generated any differently\r\nDialogue: 0,0:09:12.61,0:09:14.20,yin,,0,0,0,,不会因为它们发生任何变化\\N{\\fs12}by the compiler because of these things.\r\nDialogue: 0,0:09:14.20,0:09:15.97,yin,,0,0,0,,只不过编译器现在可以发出警告了\\N{\\fs12}The compiler is just able to warn you now.\r\nDialogue: 0,0:09:16.10,0:09:17.10,yin,,0,0,0,,只有这点区别\\N{\\fs12}That is the only difference.\r\nDialogue: 0,0:09:17.64,0:09:20.50,yin,,0,0,0,,有些人不太理解\\N{\\fs12}Some people had a little difficulty accepting this,\r\nDialogue: 0,0:09:20.50,0:09:21.32,yin,,0,0,0,,但就是这样的\\N{\\fs12}but it's true.\r\nDialogue: 0,0:09:21.51,0:09:23.96,yin,,0,0,0,,编译器生成的代码不会因为这些协议\\N{\\fs12}No code generation is any different by the compiler\r\nDialogue: 0,0:09:23.96,0:09:25.13,yin,,0,0,0,,发生任何变化\\N{\\fs12}because of these protocols.\r\nDialogue: 0,0:09:25.23,0:09:27.20,yin,,0,0,0,,与NSString和id一样\\N{\\fs12}Same thing with NSString star versus id.\r\nDialogue: 0,0:09:27.21,0:09:28.52,yin,,0,0,0,,编译器生成的代码\\N{\\fs12}It's all exactly the same stuff\r\nDialogue: 0,0:09:28.53,0:09:29.66,yin,,0,0,0,,是完全一样的\\N{\\fs12}gets generated by the compiler.\r\nDialogue: 0,0:09:29.95,0:09:31.31,yin,,0,0,0,,只不过编译器可以发出警告\\N{\\fs12}It's just the compiler can warn you\r\nDialogue: 0,0:09:31.69,0:09:32.90,yin,,0,0,0,,因为它们知道你要做什么\\N{\\fs12}because they know what you intend.\r\nDialogue: 0,0:09:33.83,0:09:37.42,yin,,0,0,0,,iOS中 协议主要用于\\N{\\fs12}Okay? The number-one use of protocols in iOS\r\nDialogue: 0,0:09:37.52,0:09:39.89,yin,,0,0,0,,委托和数据源\\N{\\fs12}is delegation and data sources.\r\nDialogue: 0,0:09:40.00,0:09:40.86,yin,,0,0,0,,这就回到了\\N{\\fs12}This is back to--\r\nDialogue: 0,0:09:40.88,0:09:42.75,yin,,0,0,0,,还记得第一节课讲MVC的时候吗\\N{\\fs12}Remember lecture 1, I had the MVC\r\nDialogue: 0,0:09:42.76,0:09:44.90,yin,,0,0,0,,我说视图可以向它们的控制器发送消息\\N{\\fs12}and I told you that the views could talk to their controller\r\nDialogue: 0,0:09:44.90,0:09:46.98,yin,,0,0,0,,方法是通过不可视结构化通信\\N{\\fs12}with blind structured communication,\r\nDialogue: 0,0:09:47.22,0:09:49.03,yin,,0,0,0,,我们讲了各种will方法\\N{\\fs12}and we talked about will do this,\r\nDialogue: 0,0:09:49.05,0:09:50.72,yin,,0,0,0,,did方法 还有数据源\\N{\\fs12}did do that, or the data source,\r\nDialogue: 0,0:09:50.72,0:09:53.54,yin,,0,0,0,,dataAt和count等等\\N{\\fs12}which is data at, count, that kind of stuff.\r\nDialogue: 0,0:09:53.54,0:09:55.45,yin,,0,0,0,,还记得这些内容吗 这种通信方式\\N{\\fs12}All of those, remember that communication?\r\nDialogue: 0,0:09:55.54,0:09:56.68,yin,,0,0,0,,我们就是这样实现的\\N{\\fs12}This is how we do that.\r\nDialogue: 0,0:09:57.08,0:09:59.35,yin,,0,0,0,,通信是不可视的 因为它们是id类型\\N{\\fs12}So it's blind, because they're ids,\r\nDialogue: 0,0:09:59.37,0:10:01.66,yin,,0,0,0,,视图通信时使用的是id类型\\N{\\fs12}the views are talking through ids.\r\nDialogue: 0,0:10:01.72,0:10:04.17,yin,,0,0,0,,但它是结构化的 因为视图向其他不可视对象发送消息时\\N{\\fs12}But it's structured because there's a protocol\r\nDialogue: 0,0:10:04.44,0:10:08.20,yin,,0,0,0,,使用的是一个协议\\N{\\fs12}that the view uses to talk to that object blindly,\r\nDialogue: 0,0:10:08.42,0:10:09.76,yin,,0,0,0,,所以它知道里面的内容\\N{\\fs12}so it knows what's in there.\r\nDialogue: 0,0:10:09.78,0:10:11.62,yin,,0,0,0,,比如说 我们来讲一下\\N{\\fs12}So let's talk about, for example,\r\nDialogue: 0,0:10:11.62,0:10:14.39,yin,,0,0,0,,视图的数据源协议\\N{\\fs12}the dataSource protocols of views.\r\nDialogue: 0,0:10:14.85,0:10:16.39,yin,,0,0,0,,如果是一个表视图\\N{\\fs12}If it was a table view, let's say,\r\nDialogue: 0,0:10:16.40,0:10:17.78,yin,,0,0,0,,表视图是一个通用视图\\N{\\fs12}a table view is a generic view\r\nDialogue: 0,0:10:17.79,0:10:19.50,yin,,0,0,0,,用来展示信息表\\N{\\fs12}for showing a table of information,\r\nDialogue: 0,0:10:19.74,0:10:23.18,yin,,0,0,0,,它用来获取数据源的协议是\\N{\\fs12}its protocol for accessing its data source\r\nDialogue: 0,0:10:23.25,0:10:25.21,yin,,0,0,0,,表中有多少行\\N{\\fs12}is how many rows are there,\r\nDialogue: 0,0:10:25.68,0:10:27.61,yin,,0,0,0,,现在给我第七行的数据\\N{\\fs12}and now give me the data at row 7,\r\nDialogue: 0,0:10:27.63,0:10:29.33,yin,,0,0,0,,给我第500行的数据\\N{\\fs12}give me the data at row 500.\r\nDialogue: 0,0:10:29.76,0:10:31.30,yin,,0,0,0,,这就是它的协议\\N{\\fs12}Okay? That's its protocol.\r\nDialogue: 0,0:10:31.34,0:10:32.04,yin,,0,0,0,,这些方法\\N{\\fs12}Those methods.\r\nDialogue: 0,0:10:32.71,0:10:35.37,yin,,0,0,0,,count和dataAt 还有其他方法\\N{\\fs12}Count, and data at, it has other ones,\r\nDialogue: 0,0:10:35.37,0:10:37.60,yin,,0,0,0,,但这些是最基础的方法\\N{\\fs12}but those are the basic ones, okay?\r\nDialogue: 0,0:10:37.88,0:10:40.08,yin,,0,0,0,,我们真的很需要这些数据源协议\\N{\\fs12}And we really need those data source protocols\r\nDialogue: 0,0:10:40.20,0:10:41.95,yin,,0,0,0,,因为视图不能自己保存数据\\N{\\fs12}because views can't own their data.\r\nDialogue: 0,0:10:41.95,0:10:44.46,yin,,0,0,0,,表视图不能抓取全部数据 然后显示出来\\N{\\fs12}That table view can't grab all its data and display it,\r\nDialogue: 0,0:10:44.46,0:10:46.62,yin,,0,0,0,,它需要不断地询问其他对象\\N{\\fs12}it has to keep asking someone else,\r\nDialogue: 0,0:10:46.65,0:10:48.99,yin,,0,0,0,,但它并不想绑定某个数据源\\N{\\fs12}but it doesn't want to be tied to any source of the data,\r\nDialogue: 0,0:10:49.10,0:10:51.18,yin,,0,0,0,,所以它最好是一个id 是不可见的\\N{\\fs12}so it wants to be an id, it wants to be blind.\r\nDialogue: 0,0:10:52.05,0:10:53.65,yin,,0,0,0,,我们下周讲到表视图时\\N{\\fs12}Okay? And we'll see all this next week\r\nDialogue: 0,0:10:53.65,0:10:54.89,yin,,0,0,0,,会讲到这一部分\\N{\\fs12}when we talk about table views.\r\nDialogue: 0,0:10:55.90,0:10:57.33,yin,,0,0,0,,除了不可视结构化通信之外\\N{\\fs12}There are other uses of protocols\r\nDialogue: 0,0:10:57.34,0:10:59.99,yin,,0,0,0,,协议还可以用在其他地方\\N{\\fs12}besides that blind structured communication,\r\nDialogue: 0,0:11:00.01,0:11:01.99,yin,,0,0,0,,我们今天会讲一个 也就是动画\\N{\\fs12}and we're going to see one today which is animation,\r\nDialogue: 0,0:11:02.88,0:11:04.83,yin,,0,0,0,,我会讲得很清楚\\N{\\fs12}and I'll let that speak for itself,\r\nDialogue: 0,0:11:05.38,0:11:07.44,yin,,0,0,0,,但是基本上 我们是要用\\N{\\fs12}but basically we're going to have ids out there\r\nDialogue: 0,0:11:07.44,0:11:08.65,yin,,0,0,0,,具有动画性的id\\N{\\fs12}that are animatable,\r\nDialogue: 0,0:11:08.78,0:11:10.42,yin,,0,0,0,,我们知道它们是具有动画性的\\N{\\fs12}and we're going to know they're animatable\r\nDialogue: 0,0:11:10.43,0:11:12.41,yin,,0,0,0,,因为它们要实现某个特定协议\\N{\\fs12}because they're going to implement a certain protocol,\r\nDialogue: 0,0:11:12.85,0:11:13.69,yin,,0,0,0,,我们就是通过这个方法知道\\N{\\fs12}and that's how we're going to know\r\nDialogue: 0,0:11:13.70,0:11:14.78,yin,,0,0,0,,它们是具有动画性的\\N{\\fs12}that they're animatable things,\r\nDialogue: 0,0:11:14.79,0:11:16.56,yin,,0,0,0,,UIView会实现这个协议\\N{\\fs12}and UIView is going to implement that protocol\r\nDialogue: 0,0:11:16.56,0:11:18.07,yin,,0,0,0,,我们就是这样为视图添加动画的\\N{\\fs12}and that's how we're going to animate our views.\r\nDialogue: 0,0:11:19.55,0:11:21.28,yin,,0,0,0,,我今天要讲的第二个objective-C知识点\\N{\\fs12}Alright, the second objective-C thing\r\nDialogue: 0,0:11:21.30,0:11:23.11,yin,,0,0,0,,是block\\N{\\fs12}I want to talk about today is blocks.\r\nDialogue: 0,0:11:23.18,0:11:24.97,yin,,0,0,0,,和协议完全不一样\\N{\\fs12}Okay, it's a totally different thing that protocols.\r\nDialogue: 0,0:11:25.33,0:11:28.68,yin,,0,0,0,,block很重要 在iOS中广泛使用\\N{\\fs12}Blocks very important, used throughout iOS,\r\nDialogue: 0,0:11:28.84,0:11:30.24,yin,,0,0,0,,实际上 讲到第五周或者第四周\\N{\\fs12}in fact, sometimes I have difficulty getting\r\nDialogue: 0,0:11:30.26,0:11:33.89,yin,,0,0,0,,有的时候我很难不涉及到block\\N{\\fs12}all the way to week 5 here or 4 without putting blocks\r\nDialogue: 0,0:11:33.90,0:11:36.39,yin,,0,0,0,,因为它在iOS的API中太常用了\\N{\\fs12}because it's so much in the API of iOS.\r\nDialogue: 0,0:11:37.15,0:11:38.07,yin,,0,0,0,,什么是block\\N{\\fs12}What is a block?\r\nDialogue: 0,0:11:38.08,0:11:40.12,yin,,0,0,0,,block就是一段代码块\\N{\\fs12}A block is a block of code.\r\nDialogue: 0,0:11:40.76,0:11:43.59,yin,,0,0,0,,为什么我们要定义一个术语block\\N{\\fs12}Okay? Why do we define this term block,\r\nDialogue: 0,0:11:43.60,0:11:45.50,yin,,0,0,0,,只是用来代表一段代码块 我们已经知道了\\N{\\fs12}just to mean block of code, we already know that,\r\nDialogue: 0,0:11:45.61,0:11:46.77,yin,,0,0,0,,因为这段代码块\\N{\\fs12}it's because it's a block of code\r\nDialogue: 0,0:11:46.78,0:11:49.73,yin,,0,0,0,,可以嵌入到其他代码中\\N{\\fs12}that can be embedded inside other code,\r\nDialogue: 0,0:11:49.89,0:11:53.34,yin,,0,0,0,,可以作为参数进行传递 储存在数组中\\N{\\fs12}passed as an argument, stored in an array, okay?\r\nDialogue: 0,0:11:53.93,0:11:56.88,yin,,0,0,0,,我们可以操纵这段代码块\\N{\\fs12}So it's a block of code that we manipulate\r\nDialogue: 0,0:11:56.89,0:11:59.65,yin,,0,0,0,,在API中进行使用\\N{\\fs12}and move around our API.\r\nDialogue: 0,0:12:00.23,0:12:01.33,yin,,0,0,0,,那么是什么样子的呢\\N{\\fs12}So what does it look like?\r\nDialogue: 0,0:12:01.42,0:12:02.68,yin,,0,0,0,,这个示例是\\N{\\fs12}Here's an example of a method\r\nDialogue: 0,0:12:02.68,0:12:04.60,yin,,0,0,0,,一个参数为block的方法\\N{\\fs12}that takes a block as an argument.\r\nDialogue: 0,0:12:04.66,0:12:06.76,yin,,0,0,0,,这是在调用这个方法\\N{\\fs12}Okay? This is the calling of this method.\r\nDialogue: 0,0:12:06.76,0:12:09.01,yin,,0,0,0,,这是一个NSDictionary方法 真正的方法\\N{\\fs12}There's an NSDictionary method, it's a real method,\r\nDialogue: 0,0:12:09.29,0:12:12.47,yin,,0,0,0,,叫做enumerateKeysAndObjectsUsingBlock\\N{\\fs12}it's called enumerateKeysAndObjectsUsingBlock.\r\nDialogue: 0,0:12:12.87,0:12:16.86,yin,,0,0,0,,参数是一个没有返回值的block\\N{\\fs12}Okay? The argument is a block that has no return value\r\nDialogue: 0,0:12:17.03,0:12:20.42,yin,,0,0,0,,带有三个参数 其中前两个是id类型\\N{\\fs12}and takes three arguments, two of the arguments are ids,\r\nDialogue: 0,0:12:20.53,0:12:22.53,yin,,0,0,0,,分别是字典中的键和值\\N{\\fs12}which are they keys and values in the dictionary,\r\nDialogue: 0,0:12:22.74,0:12:25.23,yin,,0,0,0,,第三个参数是一个BOOL\\N{\\fs12}and a third one is actually a BOOL star,\r\nDialogue: 0,0:12:25.26,0:12:26.52,yin,,0,0,0,,一个指向BOOL的指针\\N{\\fs12}a pointer to a BOOL,\r\nDialogue: 0,0:12:27.20,0:12:28.48,yin,,0,0,0,,是一个外部的BOOL\\N{\\fs12}it's an outgoing BOOL.\r\nDialogue: 0,0:12:29.07,0:12:32.83,yin,,0,0,0,,当调用这个方法时\\N{\\fs12}Okay? And basically when you call this method,\r\nDialogue: 0,0:12:33.64,0:12:37.12,yin,,0,0,0,,字典会重复执行这段代码块\\N{\\fs12}Dictionary will execute that block of code, repeatedly,\r\nDialogue: 0,0:12:37.12,0:12:38.28,yin,,0,0,0,,每对键值执行一遍\\N{\\fs12}for every key and value,\r\nDialogue: 0,0:12:39.26,0:12:42.99,yin,,0,0,0,,直到你将*stop设为了YES\\N{\\fs12}until you set the stop, star stop, to yes,\r\nDialogue: 0,0:12:43.09,0:12:44.67,yin,,0,0,0,,或者循环执行完全部键值\\N{\\fs12}or until it runs out of keys and values.\r\nDialogue: 0,0:12:45.51,0:12:46.88,yin,,0,0,0,,而且它真的会实现\\N{\\fs12}Okay? And it's actually going to implement\r\nDialogue: 0,0:12:46.88,0:12:48.25,yin,,0,0,0,,中间的代码\\N{\\fs12}that code that's right there,\r\nDialogue: 0,0:12:48.28,0:12:49.73,yin,,0,0,0,,嵌套在方法调用中的代码\\N{\\fs12}embedded inside that method call.\r\nDialogue: 0,0:12:49.73,0:12:51.10,yin,,0,0,0,,看到这个枚举键值方法的\\N{\\fs12}You can see the open square bracket\r\nDialogue: 0,0:12:51.10,0:12:52.86,yin,,0,0,0,,左方括号了吗\\N{\\fs12}for enumerate keys and objects,\r\nDialogue: 0,0:12:52.99,0:12:54.12,yin,,0,0,0,,在aDictionary前面\\N{\\fs12}before aDictionary,\r\nDialogue: 0,0:12:54.17,0:12:56.60,yin,,0,0,0,,而右方括号在下面的大括号后面\\N{\\fs12}the close square bracket is down after the curly brace.\r\nDialogue: 0,0:12:57.28,0:12:59.79,yin,,0,0,0,,真正的大括号表示的代码\\N{\\fs12}Okay? So the code, the actual curly brace,\r\nDialogue: 0,0:12:59.80,0:13:01.50,yin,,0,0,0,,放在中间\\N{\\fs12}we put right in there,\r\nDialogue: 0,0:13:01.80,0:13:02.80,yin,,0,0,0,,放在方法调用的中间\\N{\\fs12}in the middle of our method call.\r\nDialogue: 0,0:13:02.89,0:13:05.06,yin,,0,0,0,,而在一般计算机科学的其他语言中\\N{\\fs12}Other languages, in computer science in general,\r\nDialogue: 0,0:13:05.06,0:13:06.41,yin,,0,0,0,,我们把这叫做闭包\\N{\\fs12}we call this a closure.\r\nDialogue: 0,0:13:06.54,0:13:08.45,yin,,0,0,0,,有多少人知道闭包这个词\\N{\\fs12}Okay, how many people know the name closure,\r\nDialogue: 0,0:13:08.45,0:13:09.40,yin,,0,0,0,,以前听到过\\N{\\fs12}ever heard that before?\r\nDialogue: 0,0:13:09.54,0:13:11.92,yin,,0,0,0,,好的 那大家就都知道这是什么了 是一个闭包\\N{\\fs12}Okay, so you guys generally know what this is, it's a closure.\r\nDialogue: 0,0:13:13.01,0:13:16.20,yin,,0,0,0,,Objective-C中的block常以脱字符号^开始\\N{\\fs12}Blocks in Objective-C always start with the caret.\r\nDialogue: 0,0:13:16.34,0:13:18.05,yin,,0,0,0,,它代表着block的开始\\N{\\fs12}That's the magic block character.\r\nDialogue: 0,0:13:18.23,0:13:21.95,yin,,0,0,0,,然后可能会指定一个返回类型\\N{\\fs12}And then there might be a return type, possibly specified,\r\nDialogue: 0,0:13:21.95,0:13:23.72,yin,,0,0,0,,可能会有一些参数\\N{\\fs12}and maybe some arguments, possibly,\r\nDialogue: 0,0:13:23.72,0:13:25.52,yin,,0,0,0,,然后是一个大括号 一些代码\\N{\\fs12}and then a curly brace, and some code,\r\nDialogue: 0,0:13:25.55,0:13:26.77,yin,,0,0,0,,最后以大括号结束\\N{\\fs12}and an end curly brace.\r\nDialogue: 0,0:13:27.13,0:13:29.72,yin,,0,0,0,,当然 还有一些有趣的功能\\N{\\fs12}Now, of course, to make this really interesting,\r\nDialogue: 0,0:13:29.90,0:13:34.32,yin,,0,0,0,,比如编译器知道如何使用一个局部变量\\N{\\fs12}the compiler knows how to do things like have local variables\r\nDialogue: 0,0:13:34.32,0:13:36.52,yin,,0,0,0,,在block使用之前声明\\N{\\fs12}that are declared before the block is used,\r\nDialogue: 0,0:13:36.67,0:13:38.09,yin,,0,0,0,,在block内部使用\\N{\\fs12}work inside the block.\r\nDialogue: 0,0:13:39.18,0:13:40.57,yin,,0,0,0,,如果我用了这个block\\N{\\fs12}Okay? So if I had that block\r\nDialogue: 0,0:13:40.58,0:13:44.27,yin,,0,0,0,,我希望不只在发现ENOUGH键时停下来\\N{\\fs12}and I wanted to stop not just when I see the key ENOUGH\r\nDialogue: 0,0:13:44.28,0:13:47.39,yin,,0,0,0,,还要在发现stopValue这个值时也停下来\\N{\\fs12}but also when I see the value, stopValue,\r\nDialogue: 0,0:13:47.61,0:13:50.30,yin,,0,0,0,,它是一个局部变量\\N{\\fs12}which is a local variable defined in the scope\r\nDialogue: 0,0:13:50.32,0:13:53.50,yin,,0,0,0,,是在调用enumerateKeysAndObjectsUsingBlock时定义的\\N{\\fs12}that's calling the method enumerateKeysAndObjectsUsingBlock,\r\nDialogue: 0,0:13:53.67,0:13:54.44,yin,,0,0,0,,我可以用它\\N{\\fs12}I can use it.\r\nDialogue: 0,0:13:54.46,0:13:56.61,yin,,0,0,0,,编译器确保了可以将它的值\\N{\\fs12}The compiler makes sure that the value of that\r\nDialogue: 0,0:13:56.63,0:13:57.89,yin,,0,0,0,,正确地传递进来\\N{\\fs12}gets properly passed in.\r\nDialogue: 0,0:13:58.37,0:13:59.48,yin,,0,0,0,,你有问题吗\\N{\\fs12}However-- you have a question?\r\nDialogue: 0,0:13:59.91,0:14:03.19,yin,,0,0,0,,这个是静态范围吗\\N{\\fs12}Now is this statically scoped for using things outside?\r\nDialogue: 0,0:14:03.78,0:14:06.28,yin,,0,0,0,,对 这是...\\N{\\fs12}Uh...yeah, it is the loc--\r\nDialogue: 0,0:14:06.30,0:14:09.75,yin,,0,0,0,,aDictionary enumerateKeysAndObjects的调用范围\\N{\\fs12}whatever scope the aDictionary enumerateKeysAndObjects,\r\nDialogue: 0,0:14:09.76,0:14:11.69,yin,,0,0,0,,不管它的范围是什么\\N{\\fs12}that call, whatever scope there,\r\nDialogue: 0,0:14:11.70,0:14:14.21,yin,,0,0,0,,它的范围就是变量的使用范围\\N{\\fs12}that's the scope in which the variables can be used,\r\nDialogue: 0,0:14:14.21,0:14:16.62,yin,,0,0,0,,基本上就是局部堆栈\\N{\\fs12}which is pretty much the local stack, right?\r\nDialogue: 0,0:14:16.63,0:14:18.32,yin,,0,0,0,,你自己的堆栈\\N{\\fs12}The stack from your thing,\r\nDialogue: 0,0:14:18.33,0:14:21.90,yin,,0,0,0,,但是这些变量是只读的\\N{\\fs12}now, those variables though are read only.\r\nDialogue: 0,0:14:22.72,0:14:25.85,yin,,0,0,0,,如果再增加一个BOOL类型stoppedEarly\\N{\\fs12}Okay? So if I had another one, a BOOL stoppedEarly\r\nDialogue: 0,0:14:25.86,0:14:29.01,yin,,0,0,0,,然后我想在block内部设置它\\N{\\fs12}and I tried to set that inside my block,\r\nDialogue: 0,0:14:29.10,0:14:31.31,yin,,0,0,0,,就会出现错误\\N{\\fs12}that would be an error,\r\nDialogue: 0,0:14:31.60,0:14:33.07,yin,,0,0,0,,编译器不允许这样的操作\\N{\\fs12}compiler would not allow that, okay?\r\nDialogue: 0,0:14:33.22,0:14:35.83,yin,,0,0,0,,因为stoppedEarly是只读的\\N{\\fs12}Because stoppedEarly is read only.\r\nDialogue: 0,0:14:35.83,0:14:37.97,yin,,0,0,0,,但是其实有一种方法\\N{\\fs12}However, there's actually a way to make it\r\nDialogue: 0,0:14:37.97,0:14:39.77,yin,,0,0,0,,能够让变量不是只读的\\N{\\fs12}so it's not read only,\r\nDialogue: 0,0:14:39.78,0:14:41.91,yin,,0,0,0,,方法是在变量前面加上__block\\N{\\fs12}which is to put underbar, underbar, block in front of it.\r\nDialogue: 0,0:14:42.23,0:14:43.71,yin,,0,0,0,,如果你在局部变量前面\\N{\\fs12}If you put underbar, underbar, block\r\nDialogue: 0,0:14:43.74,0:14:45.13,yin,,0,0,0,,加上双下划线block\\N{\\fs12}in front of a local variable,\r\nDialogue: 0,0:14:45.36,0:14:47.86,yin,,0,0,0,,编译器就会生成一段代码\\N{\\fs12}then the compiler will generate code\r\nDialogue: 0,0:14:47.86,0:14:51.90,yin,,0,0,0,,将stoppedEarly从栈中移到堆中\\N{\\fs12}that transfers stoppedEarly off the stack into the heap\r\nDialogue: 0,0:14:52.44,0:14:53.94,yin,,0,0,0,,这样它就可以在block中使用了\\N{\\fs12}so that it can be used by the block,\r\nDialogue: 0,0:14:54.09,0:14:55.90,yin,,0,0,0,,然后block结束时\\N{\\fs12}and then when the block is finished,\r\nDialogue: 0,0:14:56.01,0:14:58.31,yin,,0,0,0,,它会将信息复制回堆中\\N{\\fs12}it will copy the information back into the heap\r\nDialogue: 0,0:14:58.37,0:14:59.63,yin,,0,0,0,,再放回到栈上\\N{\\fs12}and then back onto the stack.\r\nDialogue: 0,0:15:00.20,0:15:01.97,yin,,0,0,0,,都神奇地自动实现了\\N{\\fs12}Okay? All happens magically.\r\nDialogue: 0,0:15:02.69,0:15:04.37,yin,,0,0,0,,所以如果你加上__block\\N{\\fs12}So if you have underbar, underbar, block,\r\nDialogue: 0,0:15:04.38,0:15:05.19,yin,,0,0,0,,系统就知道怎样做了\\N{\\fs12}it knows to do that.\r\nDialogue: 0,0:15:05.19,0:15:06.40,yin,,0,0,0,,只要加上这个神奇的__block\\N{\\fs12}So that's the magic you put in there,\r\nDialogue: 0,0:15:06.40,0:15:08.03,yin,,0,0,0,,你的变量就可以读写了\\N{\\fs12}and now your variables can go both ways,\r\nDialogue: 0,0:15:08.03,0:15:10.04,yin,,0,0,0,,这时stoppedEarly=YES就是合法的了\\N{\\fs12}and now stoppedEarly is yes is legal.\r\nDialogue: 0,0:15:11.00,0:15:13.71,yin,,0,0,0,,如果变量是个实例变量\\N{\\fs12}Okay? This also works\r\nDialogue: 0,0:15:13.71,0:15:16.08,yin,,0,0,0,,也是可以的\\N{\\fs12}if the variable is an instance variable.\r\nDialogue: 0,0:15:16.09,0:15:17.34,yin,,0,0,0,,除了用setter和getter\\N{\\fs12}We don't really access instance variables\r\nDialogue: 0,0:15:17.35,0:15:19.01,yin,,0,0,0,,我们并不直接获取实例变量\\N{\\fs12}except for setters and getters,\r\nDialogue: 0,0:15:19.17,0:15:20.54,yin,,0,0,0,,那是因为实例变量\\N{\\fs12}but that's because instance variables,\r\nDialogue: 0,0:15:20.54,0:15:22.05,yin,,0,0,0,,当然是在堆中的\\N{\\fs12}of course, are in the heap.\r\nDialogue: 0,0:15:22.49,0:15:24.08,yin,,0,0,0,,因为全部对象都保存在堆中\\N{\\fs12}Because all objects are stored in the heap.\r\nDialogue: 0,0:15:25.68,0:15:28.71,yin,,0,0,0,,那么block中使用的对象呢\\N{\\fs12}What about objects that are messaged inside of a block?\r\nDialogue: 0,0:15:28.72,0:15:30.90,yin,,0,0,0,,因为这里有个特殊的问题需要考虑\\N{\\fs12}Because there's a little special thing to think about there.\r\nDialogue: 0,0:15:31.01,0:15:34.17,yin,,0,0,0,,如果我有一个字符串stopKey 值为ENOUGH\\N{\\fs12}So if I had a string stopKey, which was enough,\r\nDialogue: 0,0:15:34.19,0:15:37.72,yin,,0,0,0,,我想在block中使用这个stopKey 就像这样\\N{\\fs12}and I wanted to use stopKey inside that block, like this,\r\nDialogue: 0,0:15:38.14,0:15:40.78,yin,,0,0,0,,我要确保 也不是我要确保\\N{\\fs12}I have to make sure-- well not I have to make sure,\r\nDialogue: 0,0:15:40.78,0:15:43.40,yin,,0,0,0,,编译器要确保它生成了代码\\N{\\fs12}the compiler has to make sure that it generates code\r\nDialogue: 0,0:15:43.53,0:15:45.19,yin,,0,0,0,,运行环境要确保它正常工作\\N{\\fs12}and the runtime has to make sure it works,\r\nDialogue: 0,0:15:45.26,0:15:48.34,yin,,0,0,0,,所以有一个强指针指向这个stopKey\\N{\\fs12}so that stopKey, that there's a strong pointer to it,\r\nDialogue: 0,0:15:48.50,0:15:49.88,yin,,0,0,0,,否则执行这个block时\\N{\\fs12}otherwise it could leave the heap\r\nDialogue: 0,0:15:50.10,0:15:51.50,yin,,0,0,0,,stopKey可能已经离开堆了\\N{\\fs12}by the time this block executes.\r\nDialogue: 0,0:15:51.50,0:15:53.62,yin,,0,0,0,,因为这个block可以在任意时间执行\\N{\\fs12}Because this block could execute at any time.\r\nDialogue: 0,0:15:53.84,0:15:56.28,yin,,0,0,0,,当你调用这个block时\\N{\\fs12}Okay? This block happens to execute immediately\r\nDialogue: 0,0:15:56.49,0:15:57.23,yin,,0,0,0,,它会立刻执行\\N{\\fs12}when you call this,\r\nDialogue: 0,0:15:57.36,0:15:59.79,yin,,0,0,0,,但是可以使用字典\\N{\\fs12}but it's legal for the dictionary\r\nDialogue: 0,0:15:59.79,0:16:01.90,yin,,0,0,0,,抓取这个block 保存在某个地方\\N{\\fs12}to grab this block and store it somewhere\r\nDialogue: 0,0:16:01.90,0:16:04.33,yin,,0,0,0,,在后面某个需要的时候再调用\\N{\\fs12}and execute it sometime later that it wants to.\r\nDialogue: 0,0:16:04.57,0:16:08.00,yin,,0,0,0,,仔细听下面这点\\N{\\fs12}Okay? So every time you-- listen to this carefully,\r\nDialogue: 0,0:16:08.09,0:16:10.92,yin,,0,0,0,,每次向block中的对象发送消息时\\N{\\fs12}every time you send a message to an object inside a block,\r\nDialogue: 0,0:16:11.19,0:16:14.37,yin,,0,0,0,,系统就会创建一个指向该对象的强指针\\N{\\fs12}a strong pointer is created to that object,\r\nDialogue: 0,0:16:14.51,0:16:17.60,yin,,0,0,0,,该指针会一直保持到block超出范围以后\\N{\\fs12}and it stays around until the block goes out of scope,\r\nDialogue: 0,0:16:17.81,0:16:19.60,yin,,0,0,0,,直到block不存在\\N{\\fs12}until the block no longer exists.\r\nDialogue: 0,0:16:20.09,0:16:21.88,yin,,0,0,0,,只要block存在\\N{\\fs12}Okay? As long as that block exists,\r\nDialogue: 0,0:16:21.95,0:16:23.80,yin,,0,0,0,,消息中每个对象\\N{\\fs12}a strong pointer to every single object\r\nDialogue: 0,0:16:23.82,0:16:25.28,yin,,0,0,0,,都会被一个强指针指着\\N{\\fs12}in there this message will exist.\r\nDialogue: 0,0:16:25.56,0:16:28.18,yin,,0,0,0,,在仔细讲解之前 我想先讲个简写方法\\N{\\fs12}Before I talk about that, I want to talk about some shorthand.\r\nDialogue: 0,0:16:28.34,0:16:31.67,yin,,0,0,0,,如果block没有参数 就像这个block一样\\N{\\fs12}If the block has no arguments, like this block, see?\r\nDialogue: 0,0:16:32.09,0:16:33.19,yin,,0,0,0,,这里没有参数\\N{\\fs12}No arguments there.\r\nDialogue: 0,0:16:33.41,0:16:35.91,yin,,0,0,0,,可以不用添加括号\\N{\\fs12}You do not need to put the parentheses, okay?\r\nDialogue: 0,0:16:36.02,0:16:37.13,yin,,0,0,0,,直接删掉就行\\N{\\fs12}You can just leave those off.\r\nDialogue: 0,0:16:37.28,0:16:40.38,yin,,0,0,0,,同样的 如果block的返回值...\\N{\\fs12}And similarly, if the return value of the block--\r\nDialogue: 0,0:16:40.38,0:16:42.02,yin,,0,0,0,,这个block是大家第一次见到\\N{\\fs12}so this block which is the first time\r\nDialogue: 0,0:16:42.04,0:16:43.42,yin,,0,0,0,,带有返回值的block\\N{\\fs12}you've seen a block with a return value,\r\nDialogue: 0,0:16:43.43,0:16:45.58,yin,,0,0,0,,返回一个BOOL值 看到那个BOOL了吗\\N{\\fs12}it returns a BOOL, see that BOOL?\r\nDialogue: 0,0:16:45.69,0:16:47.98,yin,,0,0,0,,如果返回值\\N{\\fs12}If the return value can be inferred\r\nDialogue: 0,0:16:48.19,0:16:50.74,yin,,0,0,0,,能够从block的内容推断出来\\N{\\fs12}from the contents of the block, right?\r\nDialogue: 0,0:16:51.05,0:16:54.55,yin,,0,0,0,,这个例子中 return [obj isKindOfClass: UIView class]\\N{\\fs12}So in this case, return obj isKindOfClass UI class,\r\nDialogue: 0,0:16:54.56,0:16:56.04,yin,,0,0,0,,肯定会返回一个BOOL值\\N{\\fs12}definitely going to return a BOOL,\r\nDialogue: 0,0:16:56.18,0:16:58.19,yin,,0,0,0,,不需要在这里再加一个BOOL\\N{\\fs12}you do not need to put the BOOL there.\r\nDialogue: 0,0:16:58.29,0:17:00.57,yin,,0,0,0,,换句话说 如果能够推断出来\\N{\\fs12}In other words, if it can be inferred,\r\nDialogue: 0,0:17:00.74,0:17:03.15,yin,,0,0,0,,系统就会自动为你识别出来\\N{\\fs12}it will figure it out for you, okay?\r\nDialogue: 0,0:17:03.73,0:17:05.85,yin,,0,0,0,,可以直接省略一部分语法\\N{\\fs12}So just to clean up the syntax,\r\nDialogue: 0,0:17:05.95,0:17:08.66,yin,,0,0,0,,不用总是再在那里加上BOOL等等\\N{\\fs12}you don't have to put the BOOL in there all the time or whatever.\r\nDialogue: 0,0:17:09.58,0:17:10.63,yin,,0,0,0,,好了 接下来呢\\N{\\fs12}Okay. Now.\r\nDialogue: 0,0:17:10.63,0:17:14.28,yin,,0,0,0,,我们来讲一下block是如何表现得像对象的\\N{\\fs12}Let's talk about how blocks sort of act like objects.\r\nDialogue: 0,0:17:14.28,0:17:16.98,yin,,0,0,0,,block不是对象\\N{\\fs12}Blocks are not objects, okay they're not,\r\nDialogue: 0,0:17:17.26,0:17:19.04,yin,,0,0,0,,但它们有时会表现得像对象\\N{\\fs12}but they sort of act like objects\r\nDialogue: 0,0:17:19.17,0:17:22.19,yin,,0,0,0,,只表现在这一个小的方面\\N{\\fs12}in the only in this fine really small way,\r\nDialogue: 0,0:17:22.19,0:17:24.29,yin,,0,0,0,,也就是它们可以被存储\\N{\\fs12}which is, they can be stored.\r\nDialogue: 0,0:17:24.96,0:17:26.71,yin,,0,0,0,,自动引用计数会统计\\N{\\fs12}Okay? And they are reference counted\r\nDialogue: 0,0:17:26.88,0:17:28.85,yin,,0,0,0,,它们的引用数目\\N{\\fs12}by the automatic reference counter. Okay?\r\nDialogue: 0,0:17:29.22,0:17:32.45,yin,,0,0,0,,能够存储意味着它们可以被保存在变量中\\N{\\fs12}So storing them means they can be stored in variables,\r\nDialogue: 0,0:17:32.56,0:17:36.41,yin,,0,0,0,,属性中 字典和数组中\\N{\\fs12}in properties, and in dictionaries and arrays.\r\nDialogue: 0,0:17:37.10,0:17:39.28,yin,,0,0,0,,所以block可以像对象一样进行存储\\N{\\fs12}Okay? So they can be stored just like they're objects,\r\nDialogue: 0,0:17:39.38,0:17:41.46,yin,,0,0,0,,但并不像对象那样可以理解消息\\N{\\fs12}but they don't understand any messages like an object.\r\nDialogue: 0,0:17:41.46,0:17:43.24,yin,,0,0,0,,实际上 它们理解一个消息 就是复制\\N{\\fs12}Actually, they understand one message which is copy,\r\nDialogue: 0,0:17:43.24,0:17:44.90,yin,,0,0,0,,这是一个挺重要的消息\\N{\\fs12}which is kind of an important message\r\nDialogue: 0,0:17:44.93,0:17:46.77,yin,,0,0,0,,因为它会在堆中复制block\\N{\\fs12}because that copies them in the heap,\r\nDialogue: 0,0:17:46.78,0:17:48.76,yin,,0,0,0,,如果你想要用一个指针始终指向block\\N{\\fs12}and if you want to keep a pointer to a block around,\r\nDialogue: 0,0:17:48.77,0:17:50.46,yin,,0,0,0,,可能你要对它进行复制\\N{\\fs12}you probably want to copy it, okay,\r\nDialogue: 0,0:17:50.55,0:17:52.85,yin,,0,0,0,,这样它才不会从栈中释放\\N{\\fs12}so it doesn't just go off the stack somewhere.\r\nDialogue: 0,0:17:54.36,0:17:57.80,yin,,0,0,0,,比如说 这里我将一个block放入一个数组\\N{\\fs12}So for example, here I am putting a block into an array,\r\nDialogue: 0,0:17:57.99,0:18:01.17,yin,,0,0,0,,我的类中有一个属性myBlocks\\N{\\fs12}so I have a property in my class myBlocks,\r\nDialogue: 0,0:18:01.19,0:18:02.95,yin,,0,0,0,,是一个block的可变数组\\N{\\fs12}it's a mutable array of blocks,\r\nDialogue: 0,0:18:03.58,0:18:08.16,yin,,0,0,0,,只要用self.myBlocks addObject:block\\N{\\fs12}and I just say self dot myBlocks addObject colon a block.\r\nDialogue: 0,0:18:09.04,0:18:11.86,yin,,0,0,0,,我知道这看起来很奇怪 是很怪\\N{\\fs12}Okay? I know this looks weird, and it is weird,\r\nDialogue: 0,0:18:11.96,0:18:13.11,yin,,0,0,0,,因为block不是对象\\N{\\fs12}because blocks are not objects,\r\nDialogue: 0,0:18:13.14,0:18:14.28,yin,,0,0,0,,但当要将它们进行存储时\\N{\\fs12}but they act like objects\r\nDialogue: 0,0:18:14.28,0:18:17.20,yin,,0,0,0,,和对象的操作是类似的\\N{\\fs12}for this purpose of storing them in things.\r\nDialogue: 0,0:18:17.81,0:18:19.85,yin,,0,0,0,,非常好用\\N{\\fs12}Okay? So pretty neat.\r\nDialogue: 0,0:18:19.85,0:18:22.27,yin,,0,0,0,,对了 我还没讲\\N{\\fs12}And by the way, I have not talked about\r\nDialogue: 0,0:18:22.34,0:18:24.28,yin,,0,0,0,,如何调用block\\N{\\fs12}basically how you would call this block.\r\nDialogue: 0,0:18:24.39,0:18:26.56,yin,,0,0,0,,如果我将这个block从数组中取出\\N{\\fs12}Like if I grab this block out of this array\r\nDialogue: 0,0:18:26.57,0:18:28.92,yin,,0,0,0,,想要调用它 要怎么做呢\\N{\\fs12}and wanted to invoke it, how would I do it?\r\nDialogue: 0,0:18:29.26,0:18:30.59,yin,,0,0,0,,我今天不讲\\N{\\fs12}I'm not going to talk about that today,\r\nDialogue: 0,0:18:30.59,0:18:31.73,yin,,0,0,0,,但是会演示\\N{\\fs12}but I'm going to show you\r\nDialogue: 0,0:18:32.00,0:18:33.22,yin,,0,0,0,,这样大家就能看到是怎样做的了\\N{\\fs12}so that you can see it.\r\nDialogue: 0,0:18:34.07,0:18:37.46,yin,,0,0,0,,在这门课中 大家不需要实现调用\\N{\\fs12}Really, you're not going to have to do that in this class,\r\nDialogue: 0,0:18:37.84,0:18:39.75,yin,,0,0,0,,因为要把block传递给iOS\\N{\\fs12}because you're going to be passing blocks to iOS\r\nDialogue: 0,0:18:39.76,0:18:41.03,yin,,0,0,0,,它来执行它们\\N{\\fs12}and it's going to be executing them,\r\nDialogue: 0,0:18:41.05,0:18:42.97,yin,,0,0,0,,但如果大家想知道 语法就是这样的\\N{\\fs12}but if you wanted to know, that's the syntax,\r\nDialogue: 0,0:18:42.98,0:18:44.88,yin,,0,0,0,,有点像C函数语法\\N{\\fs12}it's kind of like C-function syntax,\r\nDialogue: 0,0:18:45.14,0:18:46.15,yin,,0,0,0,,大家可以课下再看\\N{\\fs12}you can look offline,\r\nDialogue: 0,0:18:46.17,0:18:48.13,yin,,0,0,0,,很可惜 我没有时间讲这个了\\N{\\fs12}I just don't have time to cover it unfortunately.\r\nDialogue: 0,0:18:48.88,0:18:51.93,yin,,0,0,0,,这里有一个危险的地方\\N{\\fs12}But there's a real danger lurking here.\r\nDialogue: 0,0:18:52.69,0:18:54.64,yin,,0,0,0,,在上面的这段代码中\\N{\\fs12}Okay? In this code, above.\r\nDialogue: 0,0:18:54.86,0:18:56.45,yin,,0,0,0,,self doSomething这里\\N{\\fs12}Okay, this self, doSomething, thing.\r\nDialogue: 0,0:18:56.48,0:18:57.13,yin,,0,0,0,,是什么\\N{\\fs12}And what is it?\r\nDialogue: 0,0:18:57.15,0:18:59.20,yin,,0,0,0,,它叫做存储循环\\N{\\fs12}Well, it's called a memory cycle.\r\nDialogue: 0,0:18:59.25,0:19:00.84,yin,,0,0,0,,有多少人知道存储循环是什么\\N{\\fs12}How many people know what a memory cycle is?\r\nDialogue: 0,0:19:01.44,0:19:03.80,yin,,0,0,0,,不太多 很好 我来讲一下\\N{\\fs12}Okay, not very many, that's good so I'll cover this.\r\nDialogue: 0,0:19:05.08,0:19:07.69,yin,,0,0,0,,出现存储循环问题的原因是\\N{\\fs12}A memory cycle, it's caused\r\nDialogue: 0,0:19:07.70,0:19:11.26,yin,,0,0,0,,只要block存在\\N{\\fs12}because all the objects inside that block\r\nDialogue: 0,0:19:11.41,0:19:13.82,yin,,0,0,0,,block中的所有对象\\N{\\fs12}have a strong pointer to them,\r\nDialogue: 0,0:19:13.83,0:19:15.45,yin,,0,0,0,,就都有一个强指针指向它们\\N{\\fs12}as long as the block exists.\r\nDialogue: 0,0:19:15.62,0:19:18.84,yin,,0,0,0,,比如在这段代码中\\N{\\fs12}Okay? So, for example, in this code, self--\r\nDialogue: 0,0:19:20.08,0:19:23.08,yin,,0,0,0,,block会有一个强指针指向self\\N{\\fs12}a strong pointer will be held by that block to self.\r\nDialogue: 0,0:19:23.51,0:19:24.23,yin,,0,0,0,,知道为什么吗\\N{\\fs12}You see why?\r\nDialogue: 0,0:19:24.31,0:19:27.01,yin,,0,0,0,,因为只要这个block保存在数组中\\N{\\fs12}Because the block, as long as it stays around in that array,\r\nDialogue: 0,0:19:27.05,0:19:28.87,yin,,0,0,0,,它就需要能够调用self doSomething\\N{\\fs12}it needs to be able to call self doSomething,\r\nDialogue: 0,0:19:28.87,0:19:31.07,yin,,0,0,0,,所以它需要始终用一个强指针指向self\\N{\\fs12}so it needs to always keep a strong pointer to self,\r\nDialogue: 0,0:19:31.08,0:19:32.88,yin,,0,0,0,,只要这个block存在\\N{\\fs12}as long as the block exists.\r\nDialogue: 0,0:19:33.20,0:19:35.83,yin,,0,0,0,,但是问题是\\N{\\fs12}However, the problem is\r\nDialogue: 0,0:19:36.01,0:19:38.87,yin,,0,0,0,,self也有一个强指针指向block\\N{\\fs12}that self has a strong pointer to the block.\r\nDialogue: 0,0:19:39.47,0:19:41.25,yin,,0,0,0,,通过它的myBlocks数组 对吧\\N{\\fs12}Through its myBlocks array. Right?\r\nDialogue: 0,0:19:41.26,0:19:42.91,yin,,0,0,0,,self有一个指向myBlocks的强指针\\N{\\fs12}Self has a strong pointer to myBlocks,\r\nDialogue: 0,0:19:42.92,0:19:43.55,yin,,0,0,0,,myBlocks是一个数组\\N{\\fs12}which is an array,\r\nDialogue: 0,0:19:43.56,0:19:45.59,yin,,0,0,0,,数组对其内容都是强引用的\\N{\\fs12}the array always hold their things strongly,\r\nDialogue: 0,0:19:45.74,0:19:48.15,yin,,0,0,0,,现在它们都用强指针指向对方\\N{\\fs12}so now both of them are pointing strongly to each other.\r\nDialogue: 0,0:19:48.19,0:19:50.89,yin,,0,0,0,,self指向block block指向self\\N{\\fs12}The block is pointing to self, self is pointing to the block.\r\nDialogue: 0,0:19:51.26,0:19:55.02,yin,,0,0,0,,这种情况下 二者都无法从栈中释放\\N{\\fs12}Neither of them can ever leave the heap in that situation\r\nDialogue: 0,0:19:55.14,0:19:56.62,yin,,0,0,0,,因为始终会有对方的强指针\\N{\\fs12}because there's always going to be a strong pointer\r\nDialogue: 0,0:19:56.62,0:19:58.52,yin,,0,0,0,,指向自己\\N{\\fs12}to them, each other's, right?\r\nDialogue: 0,0:19:58.53,0:19:59.98,yin,,0,0,0,,没有办法让一个先释放\\N{\\fs12}One of them can't leave first\r\nDialogue: 0,0:20:00.14,0:20:01.81,yin,,0,0,0,,然后另外一个就没有指针指着了\\N{\\fs12}and make it so there's no pointer to the other,\r\nDialogue: 0,0:20:02.06,0:20:03.81,yin,,0,0,0,,因为它们都不让对方释放\\N{\\fs12}because they are keeping each other in.\r\nDialogue: 0,0:20:03.81,0:20:05.06,yin,,0,0,0,,这叫做存储循环\\N{\\fs12}That's called a memory cycle.\r\nDialogue: 0,0:20:05.48,0:20:07.63,yin,,0,0,0,,我们得打破这种循环\\N{\\fs12}Okay? And we have to break these cycles.\r\nDialogue: 0,0:20:08.11,0:20:09.22,yin,,0,0,0,,这是个严重的问题\\N{\\fs12}Okay? This is a serious problem,\r\nDialogue: 0,0:20:09.24,0:20:11.11,yin,,0,0,0,,我们当然希望能够打破这种循环\\N{\\fs12}you definitely want to be able to break these cycles,\r\nDialogue: 0,0:20:11.29,0:20:12.34,yin,,0,0,0,,方法是这样的\\N{\\fs12}and here's how we do it.\r\nDialogue: 0,0:20:12.43,0:20:14.36,yin,,0,0,0,,我们要用一个局部变量\\N{\\fs12}We're going to do it with a local variable.\r\nDialogue: 0,0:20:14.99,0:20:18.17,yin,,0,0,0,,局部变量都是怎样的\\N{\\fs12}Okay? Now, local variables are all what?\r\nDialogue: 0,0:20:18.27,0:20:19.08,yin,,0,0,0,,都是强类型\\N{\\fs12}They're all strong.\r\nDialogue: 0,0:20:19.64,0:20:21.15,yin,,0,0,0,,局部变量都是强类型\\N{\\fs12}Right? Local variables are strong,\r\nDialogue: 0,0:20:21.17,0:20:23.97,yin,,0,0,0,,是指向堆中的强指针 指针变量\\N{\\fs12}they're strong pointers into the heap, pointer variables,\r\nDialogue: 0,0:20:24.04,0:20:27.70,yin,,0,0,0,,直到方法结束 这时强指针被释放\\N{\\fs12}until the method ends, and now the strong pointer goes away\r\nDialogue: 0,0:20:27.70,0:20:29.76,yin,,0,0,0,,这时局部变量\\N{\\fs12}and so now that local variable obviously\r\nDialogue: 0,0:20:29.77,0:20:32.20,yin,,0,0,0,,显然就不再用强指针指向堆中的内容了\\N{\\fs12}is not holding something in the heap by being strong.\r\nDialogue: 0,0:20:32.65,0:20:36.08,yin,,0,0,0,,但是有一种方法可以创建弱类型局部变量\\N{\\fs12}But there is a way to actually create weak local variables,\r\nDialogue: 0,0:20:36.41,0:20:38.16,yin,,0,0,0,,就是在前面加上__weak\\N{\\fs12}with underbar, underbar, weak.\r\nDialogue: 0,0:20:38.58,0:20:40.83,yin,,0,0,0,,将双下划线weak\\N{\\fs12}Okay? Underbar, underbar, weak\r\nDialogue: 0,0:20:40.85,0:20:42.46,yin,,0,0,0,,添加到一个局部变量声明之前\\N{\\fs12}before a local variable declaration\r\nDialogue: 0,0:20:42.47,0:20:45.17,yin,,0,0,0,,这个变量就是弱类型的了\\N{\\fs12}will make that variable weak, okay?\r\nDialogue: 0,0:20:45.18,0:20:48.29,yin,,0,0,0,,记得吗 弱类型表示它不会在堆中保存该对象\\N{\\fs12}Remember that weak means it's not keeping the object\r\nDialogue: 0,0:20:48.29,0:20:50.09,yin,,0,0,0,,如果没有其他元素指向它\\N{\\fs12}in the heap, if no one else is pointing to it,\r\nDialogue: 0,0:20:50.09,0:20:52.99,yin,,0,0,0,,它就会被释放 弱变量变为nil\\N{\\fs12}it just goes away, and the weak variable gets set to nil.\r\nDialogue: 0,0:20:53.88,0:20:57.79,yin,,0,0,0,,所以我要创建一个局部变量weakSelf\\N{\\fs12}Okay? So I'm going to make a local variable, weakSelf,\r\nDialogue: 0,0:20:58.31,0:21:01.06,yin,,0,0,0,,它指向self 但用的是弱指针\\N{\\fs12}which points to self, but is weak pointer to self,\r\nDialogue: 0,0:21:01.32,0:21:05.31,yin,,0,0,0,,现在我可以在block中使用它\\N{\\fs12}and now I can use that inside this block that I added.\r\nDialogue: 0,0:21:05.68,0:21:07.52,yin,,0,0,0,,我要将doSomething发送给weakSelf\\N{\\fs12}I'll send doSomething to weakSelf,\r\nDialogue: 0,0:21:08.05,0:21:09.70,yin,,0,0,0,,这时就不会再出现循环了\\N{\\fs12}and now I don't have this cycle anymore,\r\nDialogue: 0,0:21:10.03,0:21:12.34,yin,,0,0,0,,因为block没有了指向self的强指针\\N{\\fs12}because the block no longer has a strong pointer to self,\r\nDialogue: 0,0:21:12.47,0:21:13.41,yin,,0,0,0,,是一个弱指针\\N{\\fs12}it has a weak pointer.\r\nDialogue: 0,0:21:14.57,0:21:16.71,yin,,0,0,0,,我们要使用这个方法\\N{\\fs12}Okay? So yes, we will do this.\r\nDialogue: 0,0:21:17.02,0:21:18.29,yin,,0,0,0,,大家可能要在作业中用到\\N{\\fs12}You might have to do it in your homework,\r\nDialogue: 0,0:21:18.29,0:21:20.08,yin,,0,0,0,,取决于你们的实现方法\\N{\\fs12}depending on how you decide to implement it,\r\nDialogue: 0,0:21:20.34,0:21:21.93,yin,,0,0,0,,我肯定会在示例中演示它\\N{\\fs12}and I will definitely do it in the demo today\r\nDialogue: 0,0:21:22.03,0:21:24.24,yin,,0,0,0,,大家可以看到是如何使用的\\N{\\fs12}so you can see how this works. Okay?\r\nDialogue: 0,0:21:24.49,0:21:26.88,yin,,0,0,0,,我们使用自动引用计数时\\N{\\fs12}This is really the only place we have these kind of cycles,\r\nDialogue: 0,0:21:27.10,0:21:29.63,yin,,0,0,0,,只会在这种情况下遇到这种循环\\N{\\fs12}with ARC, with the automatic reference counter,\r\nDialogue: 0,0:21:29.97,0:21:31.08,yin,,0,0,0,,并不是太糟糕\\N{\\fs12}it's not too bad,\r\nDialogue: 0,0:21:31.09,0:21:34.13,yin,,0,0,0,,但你要知道有这个问题 并处理它\\N{\\fs12}you just have to know it's there, and deal with it.\r\nDialogue: 0,0:21:36.76,0:21:37.15,yin,,0,0,0,,好的\\N{\\fs12}Okay.\r\nDialogue: 0,0:21:37.60,0:21:39.49,yin,,0,0,0,,在iOS中 何时使用block呢\\N{\\fs12}So when do we use blocks in iOS?\r\nDialogue: 0,0:21:39.50,0:21:42.00,yin,,0,0,0,,可以用于枚举 我们刚才就用了字典\\N{\\fs12}We use them for enumeration, you saw that dictionary,\r\nDialogue: 0,0:21:42.00,0:21:43.25,yin,,0,0,0,,枚举 键和值\\N{\\fs12}enumerate, keys and values.\r\nDialogue: 0,0:21:43.25,0:21:45.04,yin,,0,0,0,,常用于枚举\\N{\\fs12}We use it a lot for enumeration.\r\nDialogue: 0,0:21:45.30,0:21:46.89,yin,,0,0,0,,我们还会用于视图动画\\N{\\fs12}We use it for view animation,\r\nDialogue: 0,0:21:46.90,0:21:49.01,yin,,0,0,0,,这节课后面的部分\\N{\\fs12}I'm going to do the whole rest of this lecture\r\nDialogue: 0,0:21:49.02,0:21:50.66,yin,,0,0,0,,和下节课前面部分都是关于视图动画的\\N{\\fs12}and the start of next lecture is going to be about that.\r\nDialogue: 0,0:21:51.13,0:21:52.31,yin,,0,0,0,,我们还会用于排序\\N{\\fs12}And we use it for sorting.\r\nDialogue: 0,0:21:52.99,0:21:56.77,yin,,0,0,0,,你可以向数组发送消息 让这个数组进行排序\\N{\\fs12}There's messages you can send to arrays like sort this array,\r\nDialogue: 0,0:21:56.83,0:22:00.04,yin,,0,0,0,,用这个block比较数组中的两个对象\\N{\\fs12}and use this block to compare two objects in the array.\r\nDialogue: 0,0:22:00.96,0:22:02.95,yin,,0,0,0,,还用于通知\\N{\\fs12}Okay? Notifications.\r\nDialogue: 0,0:22:03.02,0:22:04.70,yin,,0,0,0,,当进行广播时\\N{\\fs12}Right? When a radio station broadcasts\r\nDialogue: 0,0:22:04.72,0:22:05.98,yin,,0,0,0,,不用发送通知消息\\N{\\fs12}instead of sending a notification message,\r\nDialogue: 0,0:22:05.98,0:22:07.87,yin,,0,0,0,,可以直接说 执行这个block\\N{\\fs12}you can say \"Just execute this block\"\r\nDialogue: 0,0:22:08.58,0:22:10.96,yin,,0,0,0,,当广播站进行广播时\\N{\\fs12}when broadcast happens on the radio station.\r\nDialogue: 0,0:22:11.45,0:22:12.92,yin,,0,0,0,,错误处理程序很常见\\N{\\fs12}Error handler is very common.\r\nDialogue: 0,0:22:13.20,0:22:15.53,yin,,0,0,0,,执行这个操作 出现错误时\\N{\\fs12}Do this thing, and when an error happens,\r\nDialogue: 0,0:22:15.55,0:22:17.20,yin,,0,0,0,,执行这个block 我会进行处理\\N{\\fs12}execute this block and I'll handle it.\r\nDialogue: 0,0:22:18.30,0:22:21.42,yin,,0,0,0,,完成处理程序同样很常见\\N{\\fs12}Okay? Completion handlers also very common.\r\nDialogue: 0,0:22:21.77,0:22:23.94,yin,,0,0,0,,某个操作需要一段时间才能完成\\N{\\fs12}Do this thing that's going to take a long time,\r\nDialogue: 0,0:22:23.95,0:22:26.09,yin,,0,0,0,,会在后台线程中完成\\N{\\fs12}and it's gonna be done in a background thread,\r\nDialogue: 0,0:22:26.38,0:22:28.09,yin,,0,0,0,,当它完成时\\N{\\fs12}and when it's done,\r\nDialogue: 0,0:22:28.48,0:22:29.98,yin,,0,0,0,,执行这个block 让我知道\\N{\\fs12}execute this block to let me know.\r\nDialogue: 0,0:22:30.95,0:22:33.36,yin,,0,0,0,,实际上 动画会完成这个操作\\N{\\fs12}Okay? Animation does that, in fact,\r\nDialogue: 0,0:22:33.36,0:22:34.65,yin,,0,0,0,,我们也会在动画中见到\\N{\\fs12}we'll see that in animation too.\r\nDialogue: 0,0:22:35.29,0:22:35.74,yin,,0,0,0,,有问题吗\\N{\\fs12}Question?\r\nDialogue: 0,0:22:36.00,0:22:38.61,yin,,0,0,0,,如果你在类中定义了一个方法\\N{\\fs12}So you have like a method defined in your class\r\nDialogue: 0,0:22:38.61,0:22:41.06,yin,,0,0,0,,而你想将它作为block使用\\N{\\fs12}and you want to use that function as a block.\r\nDialogue: 0,0:22:41.42,0:22:43.27,yin,,0,0,0,,有什么简单方法来引用它吗\\N{\\fs12}Is there any easy way to refer to it,\r\nDialogue: 0,0:22:43.30,0:22:44.40,yin,,0,0,0,,还是必须要将它写成block呢\\N{\\fs12}or do you have to like write it as a block?\r\nDialogue: 0,0:22:44.55,0:22:46.60,yin,,0,0,0,,问题是 如果我有一个方法\\N{\\fs12}Yeah, so the question is, if I had a method,\r\nDialogue: 0,0:22:47.16,0:22:48.40,yin,,0,0,0,,定义在类中等等\\N{\\fs12}defined in my class or whatever,\r\nDialogue: 0,0:22:48.41,0:22:50.55,yin,,0,0,0,,我想将它作为block的内容\\N{\\fs12}and I want to use it as the contents of the block,\r\nDialogue: 0,0:22:50.73,0:22:53.01,yin,,0,0,0,,只要在block中调用self和那个方法\\N{\\fs12}just call self and that method inside the block,\r\nDialogue: 0,0:22:53.55,0:22:54.55,yin,,0,0,0,,就可以调用了\\N{\\fs12}and that will call it.\r\nDialogue: 0,0:22:54.75,0:22:56.34,yin,,0,0,0,,这个操作实际上很常用\\N{\\fs12}That's a common thing to want to do, actually.\r\nDialogue: 0,0:22:57.94,0:22:59.73,yin,,0,0,0,,block还有一个非常非常重要的用处\\N{\\fs12}A very, very important use of blocks,\r\nDialogue: 0,0:22:59.75,0:23:01.10,yin,,0,0,0,,我们会在后面的课程中讲到\\N{\\fs12}which we're going to talk about later in the quarter,\r\nDialogue: 0,0:23:01.11,0:23:02.26,yin,,0,0,0,,就是多线程\\N{\\fs12}is multi-threading.\r\nDialogue: 0,0:23:02.66,0:23:05.56,yin,,0,0,0,,就是让应用\\N{\\fs12}Okay? Which is getting your application\r\nDialogue: 0,0:23:05.57,0:23:07.49,yin,,0,0,0,,同时执行多个操作\\N{\\fs12}doing multiple things at the same time,\r\nDialogue: 0,0:23:07.86,0:23:08.61,yin,,0,0,0,,严格来说 不是同时\\N{\\fs12}not really at the same time,\r\nDialogue: 0,0:23:08.61,0:23:10.32,yin,,0,0,0,,但看起来是同时执行\\N{\\fs12}but seemingly at the same time.\r\nDialogue: 0,0:23:11.13,0:23:13.10,yin,,0,0,0,,我真的推荐大家...\\N{\\fs12}And I really encourage you,\r\nDialogue: 0,0:23:13.11,0:23:15.07,yin,,0,0,0,,只有几个地方 我会让你们回去查看文档\\N{\\fs12}this is one of the few times I'm going to tell you go look\r\nDialogue: 0,0:23:15.07,0:23:17.50,yin,,0,0,0,,这里就是其中之一 建议大家查看block相关文档\\N{\\fs12}in the documentation to find out about blocks,\r\nDialogue: 0,0:23:17.51,0:23:20.85,yin,,0,0,0,,直接在Xcode文档中搜索block\\N{\\fs12}just search for blocks in Xcode documentation,\r\nDialogue: 0,0:23:21.03,0:23:22.07,yin,,0,0,0,,就会找到相关内容\\N{\\fs12}and you can find out things like\r\nDialogue: 0,0:23:22.09,0:23:24.88,yin,,0,0,0,,比如 如何声明一个block类型的局部变量\\N{\\fs12}how to declare a local variable that is a block,\r\nDialogue: 0,0:23:24.89,0:23:25.50,yin,,0,0,0,,这类内容\\N{\\fs12}and things like that,\r\nDialogue: 0,0:23:25.51,0:23:26.80,yin,,0,0,0,,因为我没有仔细讲这些内容\\N{\\fs12}because I haven't really talked about those things.\r\nDialogue: 0,0:23:26.91,0:23:28.74,yin,,0,0,0,,我讲的关于block的内容\\N{\\fs12}Mostly I've just talked to you enough about blocks\r\nDialogue: 0,0:23:28.79,0:23:31.51,yin,,0,0,0,,可以让大家学会调用参数为block的方法\\N{\\fs12}to be able to call methods that take blocks as arguments.\r\nDialogue: 0,0:23:31.97,0:23:34.57,yin,,0,0,0,,到目前为止 我讲过的就是这些内容\\N{\\fs12}Okay? That's all I've pretty much shown you so far.\r\nDialogue: 0,0:23:35.91,0:23:37.96,yin,,0,0,0,,这就是我想要讲的\\N{\\fs12}Okay. So that's it for the Objective-C\r\nDialogue: 0,0:23:38.54,0:23:39.51,yin,,0,0,0,,Objective-C的内容\\N{\\fs12}that I wanted to cover.\r\nDialogue: 0,0:23:39.65,0:23:42.74,yin,,0,0,0,,现在我们可以进入有趣的部分了 也就是动画\\N{\\fs12}And now we can get into the fun stuff, which is animation.\r\nDialogue: 0,0:23:43.09,0:23:45.52,yin,,0,0,0,,今天这节课剩下的时间都是这个内容\\N{\\fs12}Alright? So that's going to be the rest of today\r\nDialogue: 0,0:23:45.53,0:23:47.59,yin,,0,0,0,,周三可能还要再讲一会\\N{\\fs12}and probably the start of Wednesday\r\nDialogue: 0,0:23:47.62,0:23:49.50,yin,,0,0,0,,因为这个示例很大\\N{\\fs12}because this demo is really big.\r\nDialogue: 0,0:23:49.94,0:23:55.59,yin,,0,0,0,,iOS中有很多不同的动画\\N{\\fs12}And there's lots of different animation that goes on in iOS.\r\nDialogue: 0,0:23:55.60,0:23:59.25,yin,,0,0,0,,我今天要讲的 大概只会在这门课上讲到\\N{\\fs12}I'm going to talk today, and only really in this course,\r\nDialogue: 0,0:24:00.02,0:24:02.29,yin,,0,0,0,,是关于为视图添加动画的\\N{\\fs12}for the most part, about animating views.\r\nDialogue: 0,0:24:02.78,0:24:04.75,yin,,0,0,0,,大家知道如何创建自定义视图 对吧\\N{\\fs12}Okay? You know how to create custom views, right?\r\nDialogue: 0,0:24:04.96,0:24:07.25,yin,,0,0,0,,你甚至可以为非自定义视图添加动画\\N{\\fs12}And you can even animate non-custom views,\r\nDialogue: 0,0:24:07.26,0:24:08.59,yin,,0,0,0,,按钮等等\\N{\\fs12}buttons, or whatever you want,\r\nDialogue: 0,0:24:08.73,0:24:11.52,yin,,0,0,0,,就是要让视图在屏幕上移动\\N{\\fs12}but basically making views move around the screen,\r\nDialogue: 0,0:24:11.53,0:24:15.29,yin,,0,0,0,,缩放 淡入淡出 旋转\\N{\\fs12}get bigger and smaller, fade in and out, spin around and rotate,\r\nDialogue: 0,0:24:15.48,0:24:16.57,yin,,0,0,0,,这是我们要讲的内容\\N{\\fs12}that's what we're going to talk about.\r\nDialogue: 0,0:24:16.57,0:24:17.99,yin,,0,0,0,,为视图添加动画\\N{\\fs12}Okay? Animating views.\r\nDialogue: 0,0:24:18.07,0:24:19.99,yin,,0,0,0,,但还有其他动画\\N{\\fs12}But there's other animation that goes on,\r\nDialogue: 0,0:24:20.00,0:24:22.98,yin,,0,0,0,,比如进入导航控制器后 进行点击\\N{\\fs12}like when you go into a navigation controller, and you click,\r\nDialogue: 0,0:24:22.98,0:24:25.37,yin,,0,0,0,,一个新视图就会滑进来\\N{\\fs12}and a new view slides in, okay?\r\nDialogue: 0,0:24:25.37,0:24:27.31,yin,,0,0,0,,这也是动画\\N{\\fs12}That's animation. Alright?\r\nDialogue: 0,0:24:27.32,0:24:29.93,yin,,0,0,0,,如果是在地图应用中\\N{\\fs12}And it's possible, also, okay you're in the maps app\r\nDialogue: 0,0:24:30.22,0:24:31.65,yin,,0,0,0,,在角落点击\\N{\\fs12}and you click in the corner\r\nDialogue: 0,0:24:31.65,0:24:33.96,yin,,0,0,0,,它会卷起来 显示其他选项\\N{\\fs12}and it curls up to show you other options?\r\nDialogue: 0,0:24:34.03,0:24:35.26,yin,,0,0,0,,这也是动画\\N{\\fs12}That's animation, okay?\r\nDialogue: 0,0:24:35.40,0:24:37.98,yin,,0,0,0,,这种视图控制器的动画\\N{\\fs12}All that kind of view controller animation,\r\nDialogue: 0,0:24:37.99,0:24:39.78,yin,,0,0,0,,我大概不会讲\\N{\\fs12}I'm not going to talk about, for the most part.\r\nDialogue: 0,0:24:40.08,0:24:43.48,yin,,0,0,0,,但也有对这部分的支持\\N{\\fs12}Okay? But that's all-- there's all support for that as well.\r\nDialogue: 0,0:24:43.57,0:24:45.70,yin,,0,0,0,,iOS中还有一套机制\\N{\\fs12}There's also a whole other thing in iOS\r\nDialogue: 0,0:24:45.72,0:24:48.26,yin,,0,0,0,,叫做集合视图 是一个视图的集合\\N{\\fs12}called the collection view, which is a collection of views\r\nDialogue: 0,0:24:48.27,0:24:51.91,yin,,0,0,0,,视图排列在网格中或是流程型\\N{\\fs12}that kind of live in a grid, sort of, or in a flow,\r\nDialogue: 0,0:24:52.14,0:24:55.13,yin,,0,0,0,,这些都可以添加动画效果\\N{\\fs12}kind of layout, and those all can be animated.\r\nDialogue: 0,0:24:55.13,0:24:56.59,yin,,0,0,0,,里面也有动画\\N{\\fs12}What's going on in there as well,\r\nDialogue: 0,0:24:57.20,0:24:58.58,yin,,0,0,0,,但是我只会讲解视图的动画\\N{\\fs12}okay, but I'm only going to talk about views.\r\nDialogue: 0,0:24:59.11,0:25:03.17,yin,,0,0,0,,它们的底层是这个Core Animation核心动画框架\\N{\\fs12}Underneath all of that is this framework called core animation,\r\nDialogue: 0,0:25:03.18,0:25:06.06,yin,,0,0,0,,非常强大的框架\\N{\\fs12}super powerful framework, I mean,\r\nDialogue: 0,0:25:06.47,0:25:09.13,yin,,0,0,0,,是技术等级的动画框架\\N{\\fs12}industrial grade animation framework there,\r\nDialogue: 0,0:25:09.77,0:25:12.19,yin,,0,0,0,,但我们要通过比它高得多的层级入手\\N{\\fs12}but we're going to be doing it all at a much higher level,\r\nDialogue: 0,0:25:12.20,0:25:16.47,yin,,0,0,0,,更容易编程\\N{\\fs12}much easier to program, and you know, kind of easier to--\r\nDialogue: 0,0:25:17.32,0:25:18.93,yin,,0,0,0,,你不必知道太多\\N{\\fs12}you don't have to know quite so much about the detail\r\nDialogue: 0,0:25:18.95,0:25:20.58,yin,,0,0,0,,动画工作的细节\\N{\\fs12}of how animation really works.\r\nDialogue: 0,0:25:20.99,0:25:23.75,yin,,0,0,0,,Core Animation适用于那些专业动画人员\\N{\\fs12}Whereas core animation is really for animation people\r\nDialogue: 0,0:25:23.77,0:25:25.52,yin,,0,0,0,,制作重要的动画效果\\N{\\fs12}who want really to do serious animations,\r\nDialogue: 0,0:25:25.52,0:25:28.84,yin,,0,0,0,,很多iOS应用都是游戏之类的应用\\N{\\fs12}and a lot of iOS applications are games, or other things\r\nDialogue: 0,0:25:28.84,0:25:31.07,yin,,0,0,0,,里面有很重要的动画\\N{\\fs12}that have a very serious animation going on in there.\r\nDialogue: 0,0:25:31.37,0:25:32.38,yin,,0,0,0,,在iOS7中\\N{\\fs12}By the way, in iOS 7\r\nDialogue: 0,0:25:32.40,0:25:33.99,yin,,0,0,0,,还有很多实现动画的工具\\N{\\fs12}there's a lot of other things for doing animation,\r\nDialogue: 0,0:25:34.00,0:25:37.75,yin,,0,0,0,,比如 Sprite Kit用来添加sprite动画\\N{\\fs12}for example, Sprite Kit is a way to animate sprites,\r\nDialogue: 0,0:25:37.76,0:25:41.81,yin,,0,0,0,,从本质上说是2D图形元素\\N{\\fs12}which are essentially 2D graphic elements\r\nDialogue: 0,0:25:41.82,0:25:43.56,yin,,0,0,0,,以某种方式混合\\N{\\fs12}that are being composited in a way\r\nDialogue: 0,0:25:43.57,0:25:45.67,yin,,0,0,0,,以此获得3D视觉环境\\N{\\fs12}to try to get a 3D looking environment,\r\nDialogue: 0,0:25:45.67,0:25:47.83,yin,,0,0,0,,很多电子游戏就是这样的\\N{\\fs12}like a lot of video games are,\r\nDialogue: 0,0:25:48.31,0:25:49.94,yin,,0,0,0,,我们甚至不会用到Sprite Kit\\N{\\fs12}and we're not even going to touch Sprite Kit,\r\nDialogue: 0,0:25:49.95,0:25:51.99,yin,,0,0,0,,我认为不会的 除非最后一周用到了它\\N{\\fs12}I don't think, unless we get to it the last week.\r\nDialogue: 0,0:25:52.44,0:25:54.67,yin,,0,0,0,,内容很多 我不可能全部讲到\\N{\\fs12}So there's a lot of stuff that I can't possibly cover,\r\nDialogue: 0,0:25:54.67,0:25:57.44,yin,,0,0,0,,所以这里我们就只讲动画的基础部分\\N{\\fs12}so let's just talk the basics here of animation.\r\nDialogue: 0,0:25:58.02,0:26:02.31,yin,,0,0,0,,为视图添加动画主要有三种方法\\N{\\fs12}So there's three ways to animate views, basically.\r\nDialogue: 0,0:26:02.48,0:26:05.06,yin,,0,0,0,,第一种方法是\\N{\\fs12}Okay? The first way is that\r\nDialogue: 0,0:26:05.07,0:26:08.20,yin,,0,0,0,,视图中有一些非常特殊的属性\\N{\\fs12}there are some very special properties in view,\r\nDialogue: 0,0:26:08.20,0:26:10.05,yin,,0,0,0,,比如视图的frame属性\\N{\\fs12}namely the view's frame,\r\nDialogue: 0,0:26:10.06,0:26:11.95,yin,,0,0,0,,记得吗 就是包含它的那个矩形\\N{\\fs12}remember that's the rectangle enclosing it,\r\nDialogue: 0,0:26:12.30,0:26:15.28,yin,,0,0,0,,还有transform属性 讲卡牌游戏的时候\\N{\\fs12}its transform, which we talked about briefly,\r\nDialogue: 0,0:26:15.30,0:26:16.72,yin,,0,0,0,,简单提到过\\N{\\fs12}when we did the playing card thing,\r\nDialogue: 0,0:26:16.89,0:26:19.95,yin,,0,0,0,,transform指视图的缩放比例\\N{\\fs12}transform is the view scale,\r\nDialogue: 0,0:26:20.26,0:26:21.59,yin,,0,0,0,,视图可以被放大缩小\\N{\\fs12}can be used to scale it up and down,\r\nDialogue: 0,0:26:21.68,0:26:24.03,yin,,0,0,0,,以及旋转情况 视图可以被旋转\\N{\\fs12}and it's rotation, views can be rotated,\r\nDialogue: 0,0:26:24.24,0:26:25.05,yin,,0,0,0,,还有移动距离\\N{\\fs12}and also translation,\r\nDialogue: 0,0:26:25.05,0:26:27.02,yin,,0,0,0,,尽管通常情况下 我们会使用frame来移动\\N{\\fs12}although usually for translation we use the frame,\r\nDialogue: 0,0:26:27.02,0:26:28.08,yin,,0,0,0,,直接移动frame\\N{\\fs12}we move the frame around.\r\nDialogue: 0,0:26:28.44,0:26:30.66,yin,,0,0,0,,还有alpha 代表它的不透明度\\N{\\fs12}And also alpha, its opacity,\r\nDialogue: 0,0:26:30.97,0:26:35.43,yin,,0,0,0,,可以在任意时间向视图中添加这三个的动画\\N{\\fs12}these three things can be animated at any time into view.\r\nDialogue: 0,0:26:35.54,0:26:37.64,yin,,0,0,0,,意思是 你将它们设为新值\\N{\\fs12}Meaning, you set them to a new value\r\nDialogue: 0,0:26:37.78,0:26:39.97,yin,,0,0,0,,它会立刻变为那个新值\\N{\\fs12}and it will set to that new value immediately,\r\nDialogue: 0,0:26:40.05,0:26:43.10,yin,,0,0,0,,但是效果会过一段时间\\N{\\fs12}but the effect will appear on screen animated\r\nDialogue: 0,0:26:43.44,0:26:44.50,yin,,0,0,0,,才以动画显示在屏幕上\\N{\\fs12}over some amount of time.\r\nDialogue: 0,0:26:44.70,0:26:47.97,yin,,0,0,0,,我们来看一下它的工作原理\\N{\\fs12}So, let's take a look at how this works.\r\nDialogue: 0,0:26:47.97,0:26:51.12,yin,,0,0,0,,是通过UIView的一个类方法实现的\\N{\\fs12}It's done with a class method in UIView.\r\nDialogue: 0,0:26:51.30,0:26:53.91,yin,,0,0,0,,是UIView的类方法 而不是实例方法\\N{\\fs12}Okay? A class method, it's not an instance method in UIView,\r\nDialogue: 0,0:26:53.91,0:26:55.05,yin,,0,0,0,,是一个类方法\\N{\\fs12}it's a class method,\r\nDialogue: 0,0:26:55.44,0:26:59.69,yin,,0,0,0,,类方法的参数为动画参数\\N{\\fs12}and the class method basically takes the animation parameters,\r\nDialogue: 0,0:26:59.70,0:27:01.37,yin,,0,0,0,,时间多长之类的\\N{\\fs12}how long to take and stuff like that,\r\nDialogue: 0,0:27:01.47,0:27:04.17,yin,,0,0,0,,还有一个block参数 在这个block中\\N{\\fs12}and it takes a block, and inside that block,\r\nDialogue: 0,0:27:04.34,0:27:07.89,yin,,0,0,0,,可以修改这三个属性\\N{\\fs12}you can modify these three properties.\r\nDialogue: 0,0:27:08.14,0:27:09.31,yin,,0,0,0,,其实还可以做其他操作\\N{\\fs12}There's actually a few others you can do,\r\nDialogue: 0,0:27:09.32,0:27:11.04,yin,,0,0,0,,但是这里\\N{\\fs12}but these are the three main ones\r\nDialogue: 0,0:27:11.04,0:27:12.15,yin,,0,0,0,,我主要讲一下这三个属性\\N{\\fs12}I'm going to talk about here.\r\nDialogue: 0,0:27:12.66,0:27:13.57,yin,,0,0,0,,就是这样的\\N{\\fs12}So it looks like this.\r\nDialogue: 0,0:27:13.58,0:27:15.31,yin,,0,0,0,,叫做animationWithDuration\\N{\\fs12}It's called animationWithDuration,\r\nDialogue: 0,0:27:15.72,0:27:18.35,yin,,0,0,0,,第一个参数代表这个动画\\N{\\fs12}and the first argument is how long you want it to take\r\nDialogue: 0,0:27:18.56,0:27:20.34,yin,,0,0,0,,出现在屏幕上的时间\\N{\\fs12}for this thing to appear on screen,\r\nDialogue: 0,0:27:20.58,0:27:23.87,yin,,0,0,0,,要记住 你所做的改变会立刻生效\\N{\\fs12}remember that the change you make happens immediately.\r\nDialogue: 0,0:27:24.46,0:27:26.46,yin,,0,0,0,,所以如果你修改了alpha或者frame\\N{\\fs12}So if you change the alpha or the frame,\r\nDialogue: 0,0:27:26.51,0:27:29.07,yin,,0,0,0,,或者transform 会立刻生效\\N{\\fs12}or the transform, it instantly happens.\r\nDialogue: 0,0:27:29.07,0:27:31.48,yin,,0,0,0,,这个方法一执行就会生效\\N{\\fs12}As soon as this method is executed.\r\nDialogue: 0,0:27:31.52,0:27:34.79,yin,,0,0,0,,这个方法总会立即返回\\N{\\fs12}And this method returns immediately at all times, okay?\r\nDialogue: 0,0:27:34.96,0:27:36.98,yin,,0,0,0,,会立即执行block中的操作\\N{\\fs12}It does what's in the block immediately.\r\nDialogue: 0,0:27:37.23,0:27:41.04,yin,,0,0,0,,但是会过一段时间才显示出来\\N{\\fs12}But the appearance of it is going to happen over time.\r\nDialogue: 0,0:27:41.30,0:27:43.31,yin,,0,0,0,,如果修改了alpha 会淡入显示出来\\N{\\fs12}Right? It's going to fade in, if it's alpha,\r\nDialogue: 0,0:27:43.34,0:27:45.62,yin,,0,0,0,,如果修改了frame 会移动过去\\N{\\fs12}it's going to move over if it's the frame,\r\nDialogue: 0,0:27:45.74,0:27:48.18,yin,,0,0,0,,如果修改了transform 会进行旋转\\N{\\fs12}it's going to rotate if it's the transform.\r\nDialogue: 0,0:27:48.18,0:27:49.66,yin,,0,0,0,,需要一段时间才能发生\\N{\\fs12}Okay, that's going to happen over time.\r\nDialogue: 0,0:27:49.77,0:27:52.46,yin,,0,0,0,,duration表示需要多少时间来执行\\N{\\fs12}Duration says how long to take to do that.\r\nDialogue: 0,0:27:52.94,0:27:57.31,yin,,0,0,0,,delay代表等待多长时间再开始执行\\N{\\fs12}Okay? Delay is how long to wait to start doing it.\r\nDialogue: 0,0:27:57.94,0:27:59.32,yin,,0,0,0,,为什么会需要延迟呢\\N{\\fs12}And why would you want a delay?\r\nDialogue: 0,0:27:59.41,0:28:01.50,yin,,0,0,0,,因为有时你需要连锁动画\\N{\\fs12}Well, becomes sometimes you want to chain animations,\r\nDialogue: 0,0:28:01.50,0:28:04.17,yin,,0,0,0,,你想要先做一个两秒钟的动画\\N{\\fs12}you want to do one animation first, that takes two seconds,\r\nDialogue: 0,0:28:04.24,0:28:06.29,yin,,0,0,0,,然后再做另外一个动画\\N{\\fs12}then you want to do another animation after that.\r\nDialogue: 0,0:28:06.30,0:28:07.96,yin,,0,0,0,,有两种方法可以连接起来\\N{\\fs12}Well, there's two ways to chain.\r\nDialogue: 0,0:28:07.98,0:28:12.05,yin,,0,0,0,,一是用第二个参数delay来延迟第二个动画发生\\N{\\fs12}One is to delay the second one using this delay, second argument,\r\nDialogue: 0,0:28:12.26,0:28:14.00,yin,,0,0,0,,或者用completion block\\N{\\fs12}or there's a completion block--\r\nDialogue: 0,0:28:14.00,0:28:16.31,yin,,0,0,0,,最下面的那个completion block\\N{\\fs12}you see the completion block at the bottom there,\r\nDialogue: 0,0:28:16.70,0:28:18.92,yin,,0,0,0,,实际上 你可以在其中执行另一个动画\\N{\\fs12}you can actually do another animation in that.\r\nDialogue: 0,0:28:19.26,0:28:20.67,yin,,0,0,0,,因为这个completion block\\N{\\fs12}Because that completion block is called\r\nDialogue: 0,0:28:20.69,0:28:22.14,yin,,0,0,0,,会在动画完成时被调用\\N{\\fs12}when the animation completes.\r\nDialogue: 0,0:28:23.06,0:28:24.31,yin,,0,0,0,,明白吗 还有options\\N{\\fs12}Alright? Options.\r\nDialogue: 0,0:28:24.32,0:28:25.44,yin,,0,0,0,,我们会讲到所有options\\N{\\fs12}We're going to talk about all the options,\r\nDialogue: 0,0:28:25.44,0:28:27.70,yin,,0,0,0,,动画有不少对应的options\\N{\\fs12}and quite a few options for animating.\r\nDialogue: 0,0:28:27.82,0:28:30.79,yin,,0,0,0,,然后是这个最重要的animations参数\\N{\\fs12}And then there's the all important animations argument.\r\nDialogue: 0,0:28:30.79,0:28:33.43,yin,,0,0,0,,它是一个block 没有参数\\N{\\fs12}That is a block, you can see, it takes no arguments\r\nDialogue: 0,0:28:33.44,0:28:35.03,yin,,0,0,0,,也没有返回值\\N{\\fs12}and has no return value.\r\nDialogue: 0,0:28:35.12,0:28:37.56,yin,,0,0,0,,在这个block中 你可以修改frame\\N{\\fs12}In that block is where you change frame\r\nDialogue: 0,0:28:37.75,0:28:42.40,yin,,0,0,0,,还可以修改center center和frame是关联的\\N{\\fs12}and you can also change center, center and frame are related,\r\nDialogue: 0,0:28:42.59,0:28:44.01,yin,,0,0,0,,还可以修改transform和alpha\\N{\\fs12}and transform and alpha.\r\nDialogue: 0,0:28:44.37,0:28:46.43,yin,,0,0,0,,这是调用它的例子\\N{\\fs12}Okay? So here's an example of calling it.\r\nDialogue: 0,0:28:47.14,0:28:49.75,yin,,0,0,0,,UIView 类方法animateWithDuration\\N{\\fs12}So I'm saying UIView class method, animateWithDuration,\r\nDialogue: 0,0:28:49.75,0:28:51.74,yin,,0,0,0,,这个动画需要三秒\\N{\\fs12}this animation is going to take 3 seconds,\r\nDialogue: 0,0:28:51.89,0:28:54.74,yin,,0,0,0,,我要做的是 不管我的视图是什么状态\\N{\\fs12}and what I'm going to do is, whatever state my view is in,\r\nDialogue: 0,0:28:54.75,0:28:57.66,yin,,0,0,0,,我要让它淡出并消失\\N{\\fs12}I'm going to make it fade out and disappear.\r\nDialogue: 0,0:28:58.55,0:29:00.84,yin,,0,0,0,,看到animation这个block了吗\\N{\\fs12}Okay? So, you see in the animation block?\r\nDialogue: 0,0:29:00.85,0:29:03.07,yin,,0,0,0,,里面是myView.alpha=0.0\\N{\\fs12}MyView dot alpha equals zero.\r\nDialogue: 0,0:29:03.21,0:29:04.54,yin,,0,0,0,,表示完全透明\\N{\\fs12}That means fully transparent.\r\nDialogue: 0,0:29:05.32,0:29:09.62,yin,,0,0,0,,不管它现在的透明度是多少\\N{\\fs12}Okay? So that is, whatever it's at now, okay, could be anything,\r\nDialogue: 0,0:29:09.81,0:29:13.38,yin,,0,0,0,,它的透明度要从当前值变为0\\N{\\fs12}it's going to go from whatever it's at now to zero\r\nDialogue: 0,0:29:13.56,0:29:16.11,yin,,0,0,0,,在三秒内从屏幕上消失\\N{\\fs12}in three seconds, on screen, okay?\r\nDialogue: 0,0:29:16.32,0:29:18.07,yin,,0,0,0,,在代码中 这是立即发生的\\N{\\fs12}But in the code, this happens immediately.\r\nDialogue: 0,0:29:18.40,0:29:20.46,yin,,0,0,0,,视图的alpha值立即就变为0\\N{\\fs12}Immediately the view has gone to alpha of zero,\r\nDialogue: 0,0:29:20.52,0:29:23.93,yin,,0,0,0,,只不过在屏幕上不会显示当前状态\\N{\\fs12}it's just onscreen it's not showing what's currently the state,\r\nDialogue: 0,0:29:23.96,0:29:25.14,yin,,0,0,0,,会显示这个动画\\N{\\fs12}it's showing this animation.\r\nDialogue: 0,0:29:25.68,0:29:28.64,yin,,0,0,0,,还要注意这里的完成处理程序\\N{\\fs12}Okay? And notice the completion handler there.\r\nDialogue: 0,0:29:29.24,0:29:32.35,yin,,0,0,0,,完成处理程序block的参数\\N{\\fs12}Okay? The argument to the completion handler's block\r\nDialogue: 0,0:29:32.44,0:29:35.14,yin,,0,0,0,,是一个BOOL值 代表动画是否结束\\N{\\fs12}is a BOOL that says whether the animation finished.\r\nDialogue: 0,0:29:35.14,0:29:36.96,yin,,0,0,0,,这个动画为什么不会结束呢\\N{\\fs12}Why wouldn't this animation finish?\r\nDialogue: 0,0:29:37.15,0:29:39.95,yin,,0,0,0,,可能会有其他动画开始了alpha动画\\N{\\fs12}Well, some other animation might start animating alpha.\r\nDialogue: 0,0:29:40.42,0:29:41.99,yin,,0,0,0,,或者可能直接修改了alpha\\N{\\fs12}Or someone might just set alpha.\r\nDialogue: 0,0:29:42.51,0:29:45.00,yin,,0,0,0,,如果有人干扰了alpha的变化\\N{\\fs12}So if anyone interferes, with alpha,\r\nDialogue: 0,0:29:45.43,0:29:47.37,yin,,0,0,0,,那么完成处理程序就会被调用\\N{\\fs12}then the completion handler will get called,\r\nDialogue: 0,0:29:47.55,0:29:49.17,yin,,0,0,0,,这个动画会被中断\\N{\\fs12}this animation will get interrupted,\r\nDialogue: 0,0:29:49.42,0:29:51.00,yin,,0,0,0,,完成处理程序会被调用\\N{\\fs12}the completion handler will get called,\r\nDialogue: 0,0:29:51.09,0:29:52.54,yin,,0,0,0,,但是BOOL值为NO\\N{\\fs12}but the BOOL there will be no.\r\nDialogue: 0,0:29:53.34,0:29:54.58,yin,,0,0,0,,但如果没人中断它\\N{\\fs12}But if nothing interrupts it,\r\nDialogue: 0,0:29:54.60,0:29:56.52,yin,,0,0,0,,alpha就会变为0\\N{\\fs12}and the alpha goes all the way to zero,\r\nDialogue: 0,0:29:56.66,0:29:58.34,yin,,0,0,0,,然后这个完成处理程序会被调用\\N{\\fs12}then this completion handler will be called,\r\nDialogue: 0,0:29:58.41,0:30:01.41,yin,,0,0,0,,参数为YES 代表动画完成了\\N{\\fs12}and the argument will be yes, yes it completed,\r\nDialogue: 0,0:30:01.67,0:30:04.81,yin,,0,0,0,,如果动画完成了 我就要将视图\\N{\\fs12}and if that happens, I'm then going to remove my view\r\nDialogue: 0,0:30:04.85,0:30:05.95,yin,,0,0,0,,从视图层级中移除\\N{\\fs12}from the view hierarchy.\r\nDialogue: 0,0:30:06.47,0:30:10.36,yin,,0,0,0,,所以这行代码的意思就是淡出我的视图\\N{\\fs12}So what this single line of code does is it fades out my view,\r\nDialogue: 0,0:30:10.47,0:30:11.85,yin,,0,0,0,,如果成功淡出了\\N{\\fs12}and if it successfully fades it out,\r\nDialogue: 0,0:30:11.85,0:30:13.27,yin,,0,0,0,,就将它从视图层级中移除\\N{\\fs12}removes it from the view hierarchy.\r\nDialogue: 0,0:30:14.07,0:30:14.47,yin,,0,0,0,,有问题吗\\N{\\fs12}Question?\r\nDialogue: 0,0:30:14.85,0:30:16.44,yin,,0,0,0,,如果在下一行代码中\\N{\\fs12}Did you, in the next line,\r\nDialogue: 0,0:30:17.17,0:30:18.31,yin,,0,0,0,,做了同样的操作\\N{\\fs12}did kind of the same thing\r\nDialogue: 0,0:30:18.32,0:30:20.87,yin,,0,0,0,,但将alpha修改为了其他值\\N{\\fs12}except changed the alpha to something else?\r\nDialogue: 0,0:30:21.34,0:30:23.32,yin,,0,0,0,,并将delay设为了3秒\\N{\\fs12}And you had delay equals three seconds.\r\nDialogue: 0,0:30:23.77,0:30:25.44,yin,,0,0,0,,看起来就在二者交接的地方\\N{\\fs12}It seems like it's right on the edge there,\r\nDialogue: 0,0:30:25.77,0:30:27.81,yin,,0,0,0,,它也许是在第一个结束之后发生的\\N{\\fs12}maybe it happens after this one finishes,\r\nDialogue: 0,0:30:27.82,0:30:29.69,yin,,0,0,0,,也许是在结束之前发生的\\N{\\fs12}or maybe it happens before.\r\nDialogue: 0,0:30:29.70,0:30:30.33,yin,,0,0,0,,是怎样的呢\\N{\\fs12}Is there...?\r\nDialogue: 0,0:30:31.38,0:30:34.30,yin,,0,0,0,,好的 问题是 如果我又增加了一个动画\\N{\\fs12}Yeah, so the question is, what if I have another animation\r\nDialogue: 0,0:30:34.30,0:30:36.22,yin,,0,0,0,,在下一行执行\\N{\\fs12}that I execute on the very next line.\r\nDialogue: 0,0:30:36.38,0:30:38.84,yin,,0,0,0,,首先 假设我延迟了第一个动画\\N{\\fs12}Well first of all, let's say I delay this one, right?\r\nDialogue: 0,0:30:39.02,0:30:41.51,yin,,0,0,0,,你的意思是延迟第一个调用\\N{\\fs12}So you're saying delay this first call, put delay in there,\r\nDialogue: 0,0:30:41.51,0:30:42.88,yin,,0,0,0,,让delay为3 是吗\\N{\\fs12}delay equals three or something?\r\nDialogue: 0,0:30:43.06,0:30:45.81,yin,,0,0,0,,是延迟执行第二个 这样它就...\\N{\\fs12}Actually delay the second one, so that it has to--\r\nDialogue: 0,0:30:45.82,0:30:48.42,yin,,0,0,0,,好的 延迟第二个 3秒吗\\N{\\fs12}Okay, delay the second one, exactly three seconds?\r\nDialogue: 0,0:30:48.77,0:30:50.48,yin,,0,0,0,,这样也是没问题的\\N{\\fs12}Okay, so that will be fine\r\nDialogue: 0,0:30:50.50,0:30:52.39,yin,,0,0,0,,因为第一个动画\\N{\\fs12}because the first one will finish instantly\r\nDialogue: 0,0:30:52.41,0:30:54.16,yin,,0,0,0,,会在第二个开始前立即结束\\N{\\fs12}right before the second one starts, okay?\r\nDialogue: 0,0:30:54.17,0:30:56.27,yin,,0,0,0,,这种做法很常见\\N{\\fs12}Because it's a common practice to do just exactly that.\r\nDialogue: 0,0:30:56.41,0:30:57.67,yin,,0,0,0,,让第一个动画执行3秒\\N{\\fs12}Have something take three seconds,\r\nDialogue: 0,0:30:57.67,0:30:59.74,yin,,0,0,0,,然后让第二个动画延迟3秒执行\\N{\\fs12}and then start the other one with a delay of three seconds,\r\nDialogue: 0,0:30:59.85,0:31:00.75,yin,,0,0,0,,没问题 可以运行\\N{\\fs12}so yeah, it'll work.\r\nDialogue: 0,0:31:03.31,0:31:05.00,yin,,0,0,0,,还有一个... 错了\\N{\\fs12}Here's another-- oops!\r\nDialogue: 0,0:31:05.22,0:31:06.88,yin,,0,0,0,,我可以做一下这个例子 但是...\\N{\\fs12}Well I guess I can do that example, but anyway--\r\nDialogue: 0,0:31:06.98,0:31:08.19,yin,,0,0,0,,这是...\\N{\\fs12}so that is--\r\nDialogue: 0,0:31:09.40,0:31:10.88,yin,,0,0,0,,大家明白这里是怎么回事吗\\N{\\fs12}does everyone understand what's going on there?\r\nDialogue: 0,0:31:11.97,0:31:14.30,yin,,0,0,0,,就是这么简单 需要理解的主要是\\N{\\fs12}It's really that simple, the main thing to understand is\r\nDialogue: 0,0:31:14.32,0:31:16.89,yin,,0,0,0,,alpha会被立刻设为0\\N{\\fs12}that alpha would be set immediately to zero,\r\nDialogue: 0,0:31:17.15,0:31:18.92,yin,,0,0,0,,动画只是显示在屏幕上\\N{\\fs12}it's just on screen that it will show.\r\nDialogue: 0,0:31:20.01,0:31:21.46,yin,,0,0,0,,好了 我们讲一下这些options选项\\N{\\fs12}Alright, let's talk about some of the options.\r\nDialogue: 0,0:31:21.59,0:31:22.93,yin,,0,0,0,,第一个选项很有意思\\N{\\fs12}The first one's an interesting option,\r\nDialogue: 0,0:31:22.93,0:31:24.18,yin,,0,0,0,,BeginFromCurrentState\\N{\\fs12}BeginFromCurrentState.\r\nDialogue: 0,0:31:24.56,0:31:28.67,yin,,0,0,0,,如果你开启这个选项\\N{\\fs12}So if you set this option on, okay, and when--\r\nDialogue: 0,0:31:28.67,0:31:30.84,yin,,0,0,0,,在选项列表中开启这个选项 意思就是\\N{\\fs12}in the options list-- what this means is\r\nDialogue: 0,0:31:30.86,0:31:33.18,yin,,0,0,0,,如果还有一个正在执行的动画\\N{\\fs12}if there is another animation that is going on\r\nDialogue: 0,0:31:33.19,0:31:35.58,yin,,0,0,0,,动画的对象与我想要的是同一个\\N{\\fs12}that is animating the things I want to animate,\r\nDialogue: 0,0:31:35.82,0:31:39.39,yin,,0,0,0,,那么执行我的动画时 从它们的当前状态开始\\N{\\fs12}then pick up from wherever they are when you do my animation.\r\nDialogue: 0,0:31:40.01,0:31:43.53,yin,,0,0,0,,所以如果我要修改alpha 让它逐渐消失\\N{\\fs12}Okay? So if I'm doing that alpha thing and it's fading down\r\nDialogue: 0,0:31:43.53,0:31:45.89,yin,,0,0,0,,alpha变为0.2之类的\\N{\\fs12}and it's down to 0.2, or something,\r\nDialogue: 0,0:31:45.95,0:31:48.46,yin,,0,0,0,,然后我让另一个动画开始执行\\N{\\fs12}and then I issue another animation to start,\r\nDialogue: 0,0:31:48.64,0:31:50.63,yin,,0,0,0,,alpha增大到0.7\\N{\\fs12}that goes up to 0.7 alpha,\r\nDialogue: 0,0:31:51.06,0:31:53.90,yin,,0,0,0,,如果开启了beginFromCurrentState\\N{\\fs12}if I have beginFromCurrentState option on,\r\nDialogue: 0,0:31:53.96,0:31:56.50,yin,,0,0,0,,那么alpha就会从0.2变为0.7\\N{\\fs12}then it will start at 0.2 and go up to 0.7.\r\nDialogue: 0,0:31:56.98,0:31:59.22,yin,,0,0,0,,如果不开启这个选项 就会从0开始\\N{\\fs12}If I don't have this on, it will start at zero,\r\nDialogue: 0,0:31:59.34,0:32:02.92,yin,,0,0,0,,因为0才是alpha的真正的值 然后再增大到0.7\\N{\\fs12}because zero is what the real alpha is, and go up to 0.7.\r\nDialogue: 0,0:32:03.43,0:32:05.24,yin,,0,0,0,,所以beginFromCurrentState可以用来\\N{\\fs12}So beginFromCurrentState is a way\r\nDialogue: 0,0:32:05.24,0:32:07.66,yin,,0,0,0,,拦截其他动画\\N{\\fs12}of intercepting other animations,\r\nDialogue: 0,0:32:07.66,0:32:08.71,yin,,0,0,0,,拦截它们\\N{\\fs12}intercepting them, right?\r\nDialogue: 0,0:32:08.71,0:32:09.61,yin,,0,0,0,,在动画过程中拦截它们\\N{\\fs12}In mid-flight.\r\nDialogue: 0,0:32:10.50,0:32:13.35,yin,,0,0,0,,之所以需要这样做\\N{\\fs12}Okay? You need this because remember that\r\nDialogue: 0,0:32:13.43,0:32:15.08,yin,,0,0,0,,是因为设置动画参数后\\N{\\fs12}when you set these animation parameters,\r\nDialogue: 0,0:32:15.09,0:32:16.15,yin,,0,0,0,,会立即生效\\N{\\fs12}it happens immediately.\r\nDialogue: 0,0:32:16.36,0:32:18.14,yin,,0,0,0,,所以如果你想要拦截正在执行的动画\\N{\\fs12}So if you want to intercept animation in flight\r\nDialogue: 0,0:32:18.15,0:32:19.54,yin,,0,0,0,,你需要设置一些选项\\N{\\fs12}you need some option for the system\r\nDialogue: 0,0:32:19.56,0:32:21.85,yin,,0,0,0,,让系统检查视图的位置\\N{\\fs12}to go check and see where the view is,\r\nDialogue: 0,0:32:21.86,0:32:23.30,yin,,0,0,0,,在让它显示在新位置之前\\N{\\fs12}if it's flying across screen,\r\nDialogue: 0,0:32:23.89,0:32:25.43,yin,,0,0,0,,看它是否正在划过屏幕\\N{\\fs12}before it sends it to a new place\r\nDialogue: 0,0:32:25.45,0:32:28.17,yin,,0,0,0,,当想让它淡出时 看它是否已经正在淡出\\N{\\fs12}or if it's fading out, it fades at its new level.\r\nDialogue: 0,0:32:28.75,0:32:31.05,yin,,0,0,0,,通常情况下 这个选项都是开启的\\N{\\fs12}It's very common to have that option on, actually.\r\nDialogue: 0,0:32:32.03,0:32:34.09,yin,,0,0,0,,可以看到 下面还有AllowUserInteraction\\N{\\fs12}And then you see things like AllowUserInteraction,\r\nDialogue: 0,0:32:34.09,0:32:36.36,yin,,0,0,0,,动画正在执行时 这个视图中\\N{\\fs12}do you want to allow gestures to happen in this view\r\nDialogue: 0,0:32:36.38,0:32:37.35,yin,,0,0,0,,是否允许手势发生\\N{\\fs12}while it's in flight?\r\nDialogue: 0,0:32:37.37,0:32:39.26,yin,,0,0,0,,有的时候有用 有的时候没有\\N{\\fs12}Sometimes that makes sense, sometimes not.\r\nDialogue: 0,0:32:40.03,0:32:41.88,yin,,0,0,0,,看到下面这些Curve开头的选项了吗\\N{\\fs12}Down at the bottom, you see those curves?\r\nDialogue: 0,0:32:41.90,0:32:43.88,yin,,0,0,0,,CurveEaseIn和CurveEaseInEaseOut\\N{\\fs12}CurveEaseIn, CurveEaseOut?\r\nDialogue: 0,0:32:44.13,0:32:46.65,yin,,0,0,0,,有时当你在屏幕上移动视图时\\N{\\fs12}Sometimes when you move a view across screen\r\nDialogue: 0,0:32:46.74,0:32:48.72,yin,,0,0,0,,并不想直接将它提起来移动\\N{\\fs12}you don't want it to just up and move,\r\nDialogue: 0,0:32:49.11,0:32:51.25,yin,,0,0,0,,你想要的是慢慢地提起来\\N{\\fs12}you want it to kind of slowly pick up speed,\r\nDialogue: 0,0:32:51.45,0:32:53.85,yin,,0,0,0,,加速到最快 最后再减速\\N{\\fs12}get up to full speed, and then slow down at the end.\r\nDialogue: 0,0:32:54.12,0:32:56.14,yin,,0,0,0,,这样动画看起来更平滑\\N{\\fs12}It's a little smoother kind of animation\r\nDialogue: 0,0:32:56.14,0:32:59.46,yin,,0,0,0,,并不是生硬的移动视图\\N{\\fs12}than just here's my view, mmmmm, that's a little, mmmmmm,\r\nDialogue: 0,0:32:59.46,0:33:02.10,yin,,0,0,0,,而是有一个加速减速的过程\\N{\\fs12}you know, but mmmmmmmmmmmmm, okay?\r\nDialogue: 0,0:33:02.56,0:33:03.76,yin,,0,0,0,,效果更好 更平滑\\N{\\fs12}Better. Smoother.\r\nDialogue: 0,0:33:03.91,0:33:07.09,yin,,0,0,0,,CurveEaseIn和CurveEaseInEaseOut就是用来控制的\\N{\\fs12}So curve in, ease and out, that's for controlling that.\r\nDialogue: 0,0:33:07.42,0:33:10.60,yin,,0,0,0,,淡入淡出也是一样的 也可以这样处理\\N{\\fs12}Okay? Same thing for fading, you could do it for fading as well.\r\nDialogue: 0,0:33:10.60,0:33:12.43,yin,,0,0,0,,尽管淡入淡出更倾向于线性运动\\N{\\fs12}Though fading tends to be okay linear.\r\nDialogue: 0,0:33:12.73,0:33:16.02,yin,,0,0,0,,但是移动时用这个选项是很不错的\\N{\\fs12}But moving definitely curving in and out is a pretty good idea.\r\nDialogue: 0,0:33:16.52,0:33:17.67,yin,,0,0,0,,大家可以回去看文档\\N{\\fs12}So you can look in the documentation\r\nDialogue: 0,0:33:17.67,0:33:19.48,yin,,0,0,0,,看看这些选项的作用\\N{\\fs12}and see what all these options do,\r\nDialogue: 0,0:33:19.49,0:33:20.77,yin,,0,0,0,,你可以重复动画\\N{\\fs12}you can repeat animations,\r\nDialogue: 0,0:33:20.77,0:33:22.66,yin,,0,0,0,,让它们反复执行等等\\N{\\fs12}have them go over and over and things like that.\r\nDialogue: 0,0:33:23.46,0:33:26.57,yin,,0,0,0,,这就是为这些特殊属性添加动画的方法\\N{\\fs12}So that's how you animate those special properties, okay?\r\nDialogue: 0,0:33:26.91,0:33:30.72,yin,,0,0,0,,系统自动为他们添加动画 处理中间过程\\N{\\fs12}And it animates them, it figures out all the in between.\r\nDialogue: 0,0:33:30.73,0:33:32.72,yin,,0,0,0,,即便你是同时执行多个动画\\N{\\fs12}Even if you animate multiple of them at the same time.\r\nDialogue: 0,0:33:32.72,0:33:35.36,yin,,0,0,0,,移动 淡入淡出 旋转\\N{\\fs12}It's moving, it's fading, it's rotating,\r\nDialogue: 0,0:33:35.51,0:33:38.74,yin,,0,0,0,,系统会自动插入\\N{\\fs12}it will find, you know, it will interpolate all those points\r\nDialogue: 0,0:33:38.78,0:33:40.45,yin,,0,0,0,,变化路径上的所有点\\N{\\fs12}all the way along automatically.\r\nDialogue: 0,0:33:40.94,0:33:42.80,yin,,0,0,0,,性能也很高\\N{\\fs12}Okay? And pretty high performance, as well.\r\nDialogue: 0,0:33:44.97,0:33:47.57,yin,,0,0,0,,但有时 你在修改视图内容时\\N{\\fs12}Okay. Sometimes though, you're changing your contents\r\nDialogue: 0,0:33:47.57,0:33:51.43,yin,,0,0,0,,用的不是这三个属性\\N{\\fs12}of your view in a way that's other than those three things.\r\nDialogue: 0,0:33:51.54,0:33:53.79,yin,,0,0,0,,一个经典的例子就是卡牌游戏\\N{\\fs12}The classic example here, the playing card.\r\nDialogue: 0,0:33:54.09,0:33:55.99,yin,,0,0,0,,当翻转卡牌时\\N{\\fs12}When I'm flipping my playing card over,\r\nDialogue: 0,0:33:56.43,0:33:58.32,yin,,0,0,0,,我只设置了视图的一个属性\\N{\\fs12}the only property I'm setting in my view\r\nDialogue: 0,0:33:58.33,0:34:00.95,yin,,0,0,0,,就是让faceUp等于YES\\N{\\fs12}is faceUp equals yes, right?\r\nDialogue: 0,0:34:00.97,0:34:02.55,yin,,0,0,0,,这时卡牌就会翻到正面朝上\\N{\\fs12}And now my card flips over to face up.\r\nDialogue: 0,0:34:02.55,0:34:04.68,yin,,0,0,0,,faceUp等于NO 卡牌翻到正面朝下\\N{\\fs12}FaceUp equals no, now it flips over to down.\r\nDialogue: 0,0:34:04.88,0:34:07.20,yin,,0,0,0,,它本身并不是一个动画属性\\N{\\fs12}So that's not an animatable property per se,\r\nDialogue: 0,0:34:07.34,0:34:11.26,yin,,0,0,0,,但是我想让这个视图通过动画\\N{\\fs12}however, what I'd like to do is have the view change\r\nDialogue: 0,0:34:11.27,0:34:14.47,yin,,0,0,0,,实现从正面朝上到正面朝下的翻转\\N{\\fs12}from face up to face down through some animation,\r\nDialogue: 0,0:34:14.86,0:34:16.70,yin,,0,0,0,,比如翻转卡牌\\N{\\fs12}like flipping the card over,\r\nDialogue: 0,0:34:16.71,0:34:18.67,yin,,0,0,0,,或从一种状态渐变为另一种状态\\N{\\fs12}or dissolving between the two.\r\nDialogue: 0,0:34:18.78,0:34:21.09,yin,,0,0,0,,换句话说 我要通过某些动画\\N{\\fs12}In other words, I want to change the entire view\r\nDialogue: 0,0:34:21.25,0:34:25.39,yin,,0,0,0,,修改整个视图的状态\\N{\\fs12}through some animation to a new state.\r\nDialogue: 0,0:34:25.70,0:34:26.89,yin,,0,0,0,,这就是这个方法的功能\\N{\\fs12}And that's what this one is for.\r\nDialogue: 0,0:34:26.91,0:34:27.97,yin,,0,0,0,,transitionWithView\\N{\\fs12}TransitionWithView.\r\nDialogue: 0,0:34:28.37,0:34:31.11,yin,,0,0,0,,transitionWithView的一个参数为view\\N{\\fs12}So transitionWithView takes a view\r\nDialogue: 0,0:34:31.23,0:34:33.14,yin,,0,0,0,,即你的目标视图 比如playingCardView\\N{\\fs12}that you want to do, like a playing card view,\r\nDialogue: 0,0:34:33.39,0:34:35.28,yin,,0,0,0,,还有一个duration参数\\N{\\fs12}and it takes a duration.\r\nDialogue: 0,0:34:35.36,0:34:37.23,yin,,0,0,0,,代表从原有状态到新状态\\N{\\fs12}How long it's going to take to go\r\nDialogue: 0,0:34:37.23,0:34:39.28,yin,,0,0,0,,需要多长时间\\N{\\fs12}from the old state to the new state.\r\nDialogue: 0,0:34:39.61,0:34:42.00,yin,,0,0,0,,options和刚才的options类似\\N{\\fs12}Options, again, similar to the other options,\r\nDialogue: 0,0:34:42.00,0:34:44.24,yin,,0,0,0,,但这里要用上面这里\\N{\\fs12}but this is especially where you would specify the options\r\nDialogue: 0,0:34:44.25,0:34:45.38,yin,,0,0,0,,列出的选项\\N{\\fs12}listed at the top there,\r\nDialogue: 0,0:34:45.39,0:34:48.71,yin,,0,0,0,,比如UIViewAnimationOptionsTransitionFlipFormLeft\\N{\\fs12}like UIViewAnimationOptionsTransitionFlipFormLeft\r\nDialogue: 0,0:34:49.06,0:34:51.91,yin,,0,0,0,,代表我想让它翻过去\\N{\\fs12}would mean I want this to flip over\r\nDialogue: 0,0:34:51.92,0:34:54.92,yin,,0,0,0,,或者选择交叉溶解 或者向上卷起\\N{\\fs12}or cross dissolve, or curl up.\r\nDialogue: 0,0:34:56.61,0:34:58.97,yin,,0,0,0,,然后是animations 也是一个block\\N{\\fs12}And then animations, again, is a block,\r\nDialogue: 0,0:34:59.17,0:35:00.93,yin,,0,0,0,,就是在这里设置faceUp\\N{\\fs12}that's where you're going to set faceUp.\r\nDialogue: 0,0:35:02.23,0:35:04.52,yin,,0,0,0,,在这个block中 你可以对视图进行各种设置\\N{\\fs12}In that block, you can set anything you want about the view\r\nDialogue: 0,0:35:04.53,0:35:06.09,yin,,0,0,0,,让它变为新状态\\N{\\fs12}to make it be in its new state,\r\nDialogue: 0,0:35:06.59,0:35:09.36,yin,,0,0,0,,系统会应用这些修改\\N{\\fs12}and the system will apply all those changes,\r\nDialogue: 0,0:35:09.46,0:35:12.38,yin,,0,0,0,,在屏外重绘新状态的视图\\N{\\fs12}re-draw the view in the new state, off screen,\r\nDialogue: 0,0:35:12.50,0:35:14.28,yin,,0,0,0,,然后在二者之间进行转换\\N{\\fs12}and then transition between the two.\r\nDialogue: 0,0:35:14.53,0:35:16.15,yin,,0,0,0,,原来的状态现在显示在屏幕上\\N{\\fs12}The old state is on screen now,\r\nDialogue: 0,0:35:16.15,0:35:18.04,yin,,0,0,0,,变化后的视图在这边\\N{\\fs12}and whatever your changes result in.\r\nDialogue: 0,0:35:18.64,0:35:19.27,yin,,0,0,0,,明白吗\\N{\\fs12}Make sense?\r\nDialogue: 0,0:35:19.93,0:35:20.73,yin,,0,0,0,,有问题吗\\N{\\fs12}Questions about that?\r\nDialogue: 0,0:35:21.59,0:35:24.88,yin,,0,0,0,,然后是completion 一样的 如果动画被中断了\\N{\\fs12}And then completion, same thing, if you get interrupted somehow,\r\nDialogue: 0,0:35:25.10,0:35:27.44,yin,,0,0,0,,这里比较不容易中断\\N{\\fs12}you know, it's harder to get interrupted on this one,\r\nDialogue: 0,0:35:27.44,0:35:30.39,yin,,0,0,0,,但是可以中断 然后完成处理程序就会被调用\\N{\\fs12}but it can happen, then the completion handler gets called.\r\nDialogue: 0,0:35:30.61,0:35:31.09,yin,,0,0,0,,两种方式\\N{\\fs12}Either way.\r\nDialogue: 0,0:35:32.00,0:35:33.72,yin,,0,0,0,,这个很好用\\N{\\fs12}Okay? So this one will be great.\r\nDialogue: 0,0:35:33.74,0:35:35.91,yin,,0,0,0,,作业的一部分是要翻转卡牌\\N{\\fs12}Part of your homework is to flip that card over,\r\nDialogue: 0,0:35:36.26,0:35:38.14,yin,,0,0,0,,你要用的就是这个方法\\N{\\fs12}and this is the method you're going to want to use,\r\nDialogue: 0,0:35:39.74,0:35:41.10,yin,,0,0,0,,非常简单\\N{\\fs12}so very, very straightforward.\r\nDialogue: 0,0:35:43.15,0:35:44.94,yin,,0,0,0,,如果你要修改视图层级\\N{\\fs12}If you're changing the view hierarchy,\r\nDialogue: 0,0:35:44.97,0:35:47.23,yin,,0,0,0,,比如置换出一个视图\\N{\\fs12}like you're swapping a view out, okay?\r\nDialogue: 0,0:35:47.23,0:35:48.35,yin,,0,0,0,,视图层级中有一个视图\\N{\\fs12}You got a view in the view hierarchy\r\nDialogue: 0,0:35:48.35,0:35:50.03,yin,,0,0,0,,你将它换成了一个新视图\\N{\\fs12}and you're swapping a new one in,\r\nDialogue: 0,0:35:50.41,0:35:53.82,yin,,0,0,0,,或者是隐藏一个视图 显示另外一个\\N{\\fs12}or if you want to hide a view in favor of another view,\r\nDialogue: 0,0:35:54.83,0:35:57.25,yin,,0,0,0,,可以用这个transitionFromView toView方法\\N{\\fs12}you can use this transitionFromView toView.\r\nDialogue: 0,0:35:57.81,0:36:01.50,yin,,0,0,0,,这个方法类似那个修改的方法\\N{\\fs12}So this one is kind of like the other one in that you're changing,\r\nDialogue: 0,0:36:01.52,0:36:02.79,yin,,0,0,0,,但并不是只作用于一个视图\\N{\\fs12}but instead of having a single view\r\nDialogue: 0,0:36:02.79,0:36:05.18,yin,,0,0,0,,改变它的状态 然后翻转它\\N{\\fs12}that you're changing its state and then flipping it over,\r\nDialogue: 0,0:36:05.28,0:36:08.08,yin,,0,0,0,,这里是用另一个视图来替换这个视图\\N{\\fs12}here you're replacing a view with another view.\r\nDialogue: 0,0:36:08.69,0:36:10.02,yin,,0,0,0,,但除此之外都很相似\\N{\\fs12}Okay? But otherwise is very similar.\r\nDialogue: 0,0:36:10.05,0:36:12.28,yin,,0,0,0,,调用的对象基本一致 都是transition\\N{\\fs12}It's even called almost the same thing, transition, right?\r\nDialogue: 0,0:36:12.53,0:36:13.84,yin,,0,0,0,,transitionFromView toView\\N{\\fs12}Transition from view to view.\r\nDialogue: 0,0:36:14.85,0:36:16.59,yin,,0,0,0,,明白吗 好的\\N{\\fs12}Okay? Alright.\r\nDialogue: 0,0:36:17.52,0:36:21.14,yin,,0,0,0,,这就是直接修改视图 属性\\N{\\fs12}So that's it for direct changing of views, properties,\r\nDialogue: 0,0:36:21.14,0:36:23.08,yin,,0,0,0,,实现动画效果的方法\\N{\\fs12}and making things happen. Okay?\r\nDialogue: 0,0:36:23.30,0:36:25.81,yin,,0,0,0,,下面我们要讲的是另外一种动画\\N{\\fs12}The next kind of animation we're going to talk about,\r\nDialogue: 0,0:36:25.81,0:36:28.82,yin,,0,0,0,,是完全不同的系统 是iOS7的新增内容\\N{\\fs12}which is a totally different system, new for iOS 7,\r\nDialogue: 0,0:36:30.92,0:36:32.53,yin,,0,0,0,,叫做dynamic animation动力动画\\N{\\fs12}is called dynamic animation.\r\nDialogue: 0,0:36:32.91,0:36:35.23,yin,,0,0,0,,这是一个完全不同的概念\\N{\\fs12}And this one's a completely different concept.\r\nDialogue: 0,0:36:35.53,0:36:39.04,yin,,0,0,0,,你要做的是 定义一些物理效果\\N{\\fs12}Here, what you're going to do, is define a bunch of physics\r\nDialogue: 0,0:36:39.22,0:36:42.36,yin,,0,0,0,,然后应用于要添加动画效果的视图\\N{\\fs12}that apply to all the views that you want to animate,\r\nDialogue: 0,0:36:42.63,0:36:44.93,yin,,0,0,0,,然后只要说 好了做吧\\N{\\fs12}and then you're just going to say \"Okay, do it!\"\r\nDialogue: 0,0:36:45.37,0:36:48.46,yin,,0,0,0,,系统就会将这些物理效果应用于这些视图\\N{\\fs12}And they're going to go have those physics apply to them.\r\nDialogue: 0,0:36:48.96,0:36:51.46,yin,,0,0,0,,有什么物理效果呢\\N{\\fs12}So what kind of physics are we talking about here?\r\nDialogue: 0,0:36:51.56,0:36:54.18,yin,,0,0,0,,有重力 碰撞\\N{\\fs12}We're talking about gravity, collisions,\r\nDialogue: 0,0:36:54.41,0:36:56.51,yin,,0,0,0,,作用力 等等\\N{\\fs12}forces applied to them, things like that.\r\nDialogue: 0,0:36:56.76,0:36:59.50,yin,,0,0,0,,动画会一直运行\\N{\\fs12}Okay? And they're just going to keep on animating\r\nDialogue: 0,0:36:59.50,0:37:01.52,yin,,0,0,0,,直到力量平衡\\N{\\fs12}until the forces all balance out.\r\nDialogue: 0,0:37:02.01,0:37:03.89,yin,,0,0,0,,我们会看到是怎样的\\N{\\fs12}Okay? And we'll see what that looks like.\r\nDialogue: 0,0:37:04.87,0:37:07.72,yin,,0,0,0,,想要实现它 这个API非常好用\\N{\\fs12}The way we do this, this is a really nice API,\r\nDialogue: 0,0:37:07.80,0:37:08.85,yin,,0,0,0,,非常易用\\N{\\fs12}very easy to use.\r\nDialogue: 0,0:37:08.85,0:37:10.86,yin,,0,0,0,,新建一个UIDynamicAnimator\\N{\\fs12}You create a UIDynamicAnimator,\r\nDialogue: 0,0:37:10.86,0:37:12.02,yin,,0,0,0,,只需要创建一个\\N{\\fs12}you just need to create one.\r\nDialogue: 0,0:37:12.26,0:37:14.82,yin,,0,0,0,,可以创建多个 但是一个较常见\\N{\\fs12}You can do multiple, but just one--\r\nDialogue: 0,0:37:15.40,0:37:17.24,yin,,0,0,0,,是为了对这些行为进行分组\\N{\\fs12}it's really for grouping these behaviors,\r\nDialogue: 0,0:37:17.24,0:37:19.22,yin,,0,0,0,,通常会用alloc/init\\N{\\fs12}but usually create one dynamic animator\r\nDialogue: 0,0:37:19.22,0:37:20.80,yin,,0,0,0,,来创建UIDynamicAnimator\\N{\\fs12}with alloc and init, basically.\r\nDialogue: 0,0:37:21.35,0:37:22.18,yin,,0,0,0,,我会演示的\\N{\\fs12}I'll show you that.\r\nDialogue: 0,0:37:22.32,0:37:24.21,yin,,0,0,0,,然后向其中添加动力行为\\N{\\fs12}And then you're going to add behaviors to it.\r\nDialogue: 0,0:37:24.24,0:37:28.00,yin,,0,0,0,,行为包括重力 碰撞 推动等等\\N{\\fs12}Behaviors are like gravity, collisions, pushes,\r\nDialogue: 0,0:37:28.00,0:37:29.56,yin,,0,0,0,,这些叫做行为\\N{\\fs12}those kinds of things, those are behaviors.\r\nDialogue: 0,0:37:29.56,0:37:32.20,yin,,0,0,0,,这些动力行为会应用于目标对象上\\N{\\fs12}Things that are going to be applied to the things.\r\nDialogue: 0,0:37:32.48,0:37:34.55,yin,,0,0,0,,然后向其中添加内容\\N{\\fs12}And then you put the things in there,\r\nDialogue: 0,0:37:34.98,0:37:37.75,yin,,0,0,0,,添加的是UIDynamicItem\\N{\\fs12}and the things you put in there are UIDynamicItems,\r\nDialogue: 0,0:37:37.77,0:37:41.31,yin,,0,0,0,,代表它们响应或实现了那个协议\\N{\\fs12}meaning they respond or they implement that protocol.\r\nDialogue: 0,0:37:41.40,0:37:42.00,yin,,0,0,0,,我也会演示的\\N{\\fs12}I'll show you that.\r\nDialogue: 0,0:37:42.19,0:37:45.90,yin,,0,0,0,,将它们加进去时 动画会立刻开始执行\\N{\\fs12}And the instant you put them in there, they'll start animating.\r\nDialogue: 0,0:37:45.96,0:37:48.22,yin,,0,0,0,,你不用告诉它运行 什么都不用说\\N{\\fs12}You don't have to say run, you don't have to say anything,\r\nDialogue: 0,0:37:48.22,0:37:50.30,yin,,0,0,0,,只要动力动画者中有一个动力行为\\N{\\fs12}immediately, any time there's an item\r\nDialogue: 0,0:37:50.36,0:37:53.00,yin,,0,0,0,,动力行为中有一个动力项\\N{\\fs12}that's in a behavior that's in a dynamic animator,\r\nDialogue: 0,0:37:53.07,0:37:56.48,yin,,0,0,0,,动画就会立即开始 直到有力作用于它\\N{\\fs12}it will start animating until the forces on it,\r\nDialogue: 0,0:37:56.53,0:37:59.37,yin,,0,0,0,,代表不用再移动了 这时就会停下来\\N{\\fs12}meaning that it doesn't need to move, then it will stop.\r\nDialogue: 0,0:38:00.20,0:38:02.76,yin,,0,0,0,,我们详细讲一下\\N{\\fs12}Okay? So let's look at all these things.\r\nDialogue: 0,0:38:02.86,0:38:06.07,yin,,0,0,0,,UIDynamicAnimator 可以直接用alloc/init\\N{\\fs12}UIDynamicAnimator, you can just do alloc init,\r\nDialogue: 0,0:38:06.29,0:38:08.03,yin,,0,0,0,,但如果对象是视图\\N{\\fs12}but when you're doing views,\r\nDialogue: 0,0:38:08.04,0:38:09.72,yin,,0,0,0,,如果要添加动画的是视图\\N{\\fs12}if it's views that you want to animate,\r\nDialogue: 0,0:38:09.73,0:38:11.86,yin,,0,0,0,,就要用alloc/initWithReferenceView\\N{\\fs12}you want to do alloc initWithReferenceView.\r\nDialogue: 0,0:38:12.24,0:38:13.54,yin,,0,0,0,,在initWithReferenceView中\\N{\\fs12}Okay? And initWithReferenceView,\r\nDialogue: 0,0:38:13.54,0:38:16.81,yin,,0,0,0,,指定视图层级的顶级视图\\N{\\fs12}you're specifying the top view of a view hierarchy,\r\nDialogue: 0,0:38:16.82,0:38:19.56,yin,,0,0,0,,所有要添加动画的视图都要在这个视图层级中\\N{\\fs12}all the views you animate have to be in that view hierarchy,\r\nDialogue: 0,0:38:19.93,0:38:20.88,yin,,0,0,0,,也就是说 它们必须在这个层级中的某一层\\N{\\fs12}in other words, they have to be somewhere,\r\nDialogue: 0,0:38:20.88,0:38:23.37,yin,,0,0,0,,是这个参考视图的子视图 或者是子视图的子视图\\N{\\fs12}a subview of this reference view or a subview of that\r\nDialogue: 0,0:38:23.37,0:38:25.40,yin,,0,0,0,,或者再下面的子视图 层级可以很深\\N{\\fs12}or a subview of that, as deep as you want to go,\r\nDialogue: 0,0:38:25.63,0:38:27.67,yin,,0,0,0,,但是你需要指定它的顶级视图\\N{\\fs12}but you have to specify the top level view.\r\nDialogue: 0,0:38:28.39,0:38:31.51,yin,,0,0,0,,然后创建行为\\N{\\fs12}Okay? Then you create these behaviors.\r\nDialogue: 0,0:38:31.73,0:38:33.69,yin,,0,0,0,,直接用alloc/init就可以了\\N{\\fs12}Behaviors are just alloc init,\r\nDialogue: 0,0:38:33.71,0:38:36.03,yin,,0,0,0,,比如[UIGravityBehavior alloc] init\\N{\\fs12}like UIGravityBehavior alloc init.\r\nDialogue: 0,0:38:37.12,0:38:39.38,yin,,0,0,0,,还有[UICollisionBehavior alloc] init\\N{\\fs12}UICollisionBehavior alloc init,\r\nDialogue: 0,0:38:39.45,0:38:41.86,yin,,0,0,0,,然后将这些行为添加到animator中\\N{\\fs12}and then you add these behaviors to the animator,\r\nDialogue: 0,0:38:42.24,0:38:43.19,yin,,0,0,0,,用addBehavior方法\\N{\\fs12}using addBehavior,\r\nDialogue: 0,0:38:43.19,0:38:45.19,yin,,0,0,0,,是一个动力动画者方法\\N{\\fs12}which is a dynamic animator method.\r\nDialogue: 0,0:38:45.62,0:38:47.38,yin,,0,0,0,,再简单不过了\\N{\\fs12}Okay? Couldn't be simpler.\r\nDialogue: 0,0:38:47.69,0:38:50.60,yin,,0,0,0,,然后将动力项添加到动力行为中\\N{\\fs12}And then, you add the items to the behaviors.\r\nDialogue: 0,0:38:50.71,0:38:51.66,yin,,0,0,0,,方法是什么\\N{\\fs12}And you do that with?\r\nDialogue: 0,0:38:51.77,0:38:54.23,yin,,0,0,0,,在动力行为中使用addItem来添加\\N{\\fs12}AddItem, in dynamic behavior.\r\nDialogue: 0,0:38:54.90,0:38:58.03,yin,,0,0,0,,动力项是一个id\\N{\\fs12}So an item is just an id\r\nDialogue: 0,0:38:58.29,0:39:00.67,yin,,0,0,0,,实现了UIDynamicItem协议\\N{\\fs12}that implements the protocol UIDynamicItem\r\nDialogue: 0,0:39:00.67,0:39:02.02,yin,,0,0,0,,就是下面这段\\N{\\fs12}which you can see there below.\r\nDialogue: 0,0:39:02.40,0:39:05.81,yin,,0,0,0,,同样的 UIView实现了这个协议\\N{\\fs12}And again, UIView implements that protocol,\r\nDialogue: 0,0:39:06.03,0:39:08.49,yin,,0,0,0,,所以通常情况下 加入的动力项是UIView\\N{\\fs12}so usually the items we put in there are UIViews,\r\nDialogue: 0,0:39:08.49,0:39:09.71,yin,,0,0,0,,90%的情况下都是UIView\\N{\\fs12}about 90 percent of the time.\r\nDialogue: 0,0:39:09.72,0:39:11.12,yin,,0,0,0,,在这门课上全部都是\\N{\\fs12}100 percent of the time in this class,\r\nDialogue: 0,0:39:11.14,0:39:12.87,yin,,0,0,0,,作业中用到的也全部都是UIView\\N{\\fs12}100 percent of the time in your homework,\r\nDialogue: 0,0:39:12.89,0:39:14.72,yin,,0,0,0,,我只要求大家实现视图动画\\N{\\fs12}I'm only asking you to animate views,\r\nDialogue: 0,0:39:14.87,0:39:18.81,yin,,0,0,0,,但也可以为非视觉项添加动画\\N{\\fs12}but you could animate completely non-visual items.\r\nDialogue: 0,0:39:18.87,0:39:21.62,yin,,0,0,0,,只要它们实现了这个协议\\N{\\fs12}They could be-- as long as they implement this protocol,\r\nDialogue: 0,0:39:21.62,0:39:22.59,yin,,0,0,0,,就可以做任何想做的事情\\N{\\fs12}they can do anything they want.\r\nDialogue: 0,0:39:22.79,0:39:24.07,yin,,0,0,0,,协议中有什么呢\\N{\\fs12}So what's in the protocol?\r\nDialogue: 0,0:39:24.14,0:39:25.34,yin,,0,0,0,,有一个bounds\\N{\\fs12}There's the bounds.\r\nDialogue: 0,0:39:25.35,0:39:29.27,yin,,0,0,0,,是动力项的bounds\\N{\\fs12}That's again the bounds in the items world.\r\nDialogue: 0,0:39:29.40,0:39:31.04,yin,,0,0,0,,就像视图的bounds\\N{\\fs12}It's like the view's bounds, right?\r\nDialogue: 0,0:39:31.04,0:39:32.88,yin,,0,0,0,,它自己的绘制坐标系\\N{\\fs12}Its own drawing coordinate system.\r\nDialogue: 0,0:39:32.96,0:39:34.24,yin,,0,0,0,,注意bounds是只读的\\N{\\fs12}Notice that's read only.\r\nDialogue: 0,0:39:34.62,0:39:38.32,yin,,0,0,0,,动力项可以通过变换 居中 移动等进行修改\\N{\\fs12}Okay? It could be modified by the transform, centering,\r\nDialogue: 0,0:39:38.33,0:39:41.93,yin,,0,0,0,,大多数情况下是通过变换\\N{\\fs12}moving the thing around, possibly, mostly the transform.\r\nDialogue: 0,0:39:42.00,0:39:45.67,yin,,0,0,0,,而bounds只是动力项的绘制区域\\N{\\fs12}So the bounds, though, is just the drawing area for the item.\r\nDialogue: 0,0:39:45.94,0:39:49.58,yin,,0,0,0,,但是center中心 也就是动力项的位置\\N{\\fs12}But the center, in other words, the position of the item,\r\nDialogue: 0,0:39:49.92,0:39:52.80,yin,,0,0,0,,以及transform变换 也就是旋转和缩放比例\\N{\\fs12}and its transform, it's rotation and scale,\r\nDialogue: 0,0:39:53.02,0:39:54.11,yin,,0,0,0,,这两个属性是可读写的\\N{\\fs12}those are read-write.\r\nDialogue: 0,0:39:54.37,0:39:55.70,yin,,0,0,0,,它们是可以被设置的\\N{\\fs12}Those can actually be set.\r\nDialogue: 0,0:39:56.30,0:39:58.32,yin,,0,0,0,,显然是由animator设置的\\N{\\fs12}They're obviously set by the animator,\r\nDialogue: 0,0:39:58.49,0:40:00.83,yin,,0,0,0,,动力动画者的作用\\N{\\fs12}that's what the dynamic animator does is go\r\nDialogue: 0,0:40:00.84,0:40:04.26,yin,,0,0,0,,就是弄清楚动力项的中心 旋转和缩放比例的值\\N{\\fs12}figure out what the center and rotation and scale should be.\r\nDialogue: 0,0:40:04.41,0:40:05.48,yin,,0,0,0,,你也可以设置它们\\N{\\fs12}And you could set them too,\r\nDialogue: 0,0:40:05.48,0:40:08.70,yin,,0,0,0,,但是如果你要与animator同时进行设置\\N{\\fs12}but if you do set them while the animator is also setting them,\r\nDialogue: 0,0:40:08.78,0:40:11.40,yin,,0,0,0,,需要调用这个方法updateItemUsingCurrentState\\N{\\fs12}you have to call this method updateItemUsingCurrentState,\r\nDialogue: 0,0:40:11.40,0:40:12.83,yin,,0,0,0,,animator的当前状态\\N{\\fs12}current state in the animator,\r\nDialogue: 0,0:40:12.96,0:40:14.59,yin,,0,0,0,,否则animator不会...\\N{\\fs12}otherwise the animator will not--\r\nDialogue: 0,0:40:14.74,0:40:16.82,yin,,0,0,0,,它会忽略其他操作\\N{\\fs12}will ignore anything that's going on.\r\nDialogue: 0,0:40:16.82,0:40:19.58,yin,,0,0,0,,所以如果你想要设置中心\\N{\\fs12}Okay? So if you want to be setting the center,\r\nDialogue: 0,0:40:19.67,0:40:20.95,yin,,0,0,0,,如果你想要移动对象的时候\\N{\\fs12}if you want to be moving the thing\r\nDialogue: 0,0:40:20.96,0:40:22.57,yin,,0,0,0,,animator也想要移动它\\N{\\fs12}while the animator is also trying to move it,\r\nDialogue: 0,0:40:22.59,0:40:24.17,yin,,0,0,0,,换句话说 你想要和animator抗争一下\\N{\\fs12}in other words, you want to fight it a little bit,\r\nDialogue: 0,0:40:24.29,0:40:26.79,yin,,0,0,0,,或者是animator正在移动它 而你想要让它旋转\\N{\\fs12}or if it is moving it and you want to rotate it,\r\nDialogue: 0,0:40:27.09,0:40:29.07,yin,,0,0,0,,你需要用这个updateItemUsingCurrentState方法\\N{\\fs12}you need to do this updateItemUsingCurrentState,\r\nDialogue: 0,0:40:29.07,0:40:31.30,yin,,0,0,0,,否则 出于性能方面的原因\\N{\\fs12}otherwise it will assume, for performance reasons,\r\nDialogue: 0,0:40:31.54,0:40:33.21,yin,,0,0,0,,它会假设自己知道当前状态\\N{\\fs12}that it knows the current state.\r\nDialogue: 0,0:40:33.57,0:40:35.85,yin,,0,0,0,,直到它的动画完成 一切操作完毕\\N{\\fs12}Until it's done animating, until everything settles.\r\nDialogue: 0,0:40:36.81,0:40:38.20,yin,,0,0,0,,好了 就是这样\\N{\\fs12}Okay? So that's it.\r\nDialogue: 0,0:40:38.28,0:40:40.96,yin,,0,0,0,,动力动画者 动力行为和动力项\\N{\\fs12}Animator, behaviors and items.\r\nDialogue: 0,0:40:41.66,0:40:42.75,yin,,0,0,0,,这套系统中主要就是这三项内容\\N{\\fs12}That's all there is in this system.\r\nDialogue: 0,0:40:43.21,0:40:45.03,yin,,0,0,0,,现在我们来讲一下动力行为\\N{\\fs12}So now let's talk about some of these behaviors.\r\nDialogue: 0,0:40:45.03,0:40:46.58,yin,,0,0,0,,可用的具体行为\\N{\\fs12}The concrete behaviors that are available.\r\nDialogue: 0,0:40:46.83,0:40:47.81,yin,,0,0,0,,首先是gravity重力\\N{\\fs12}There's gravity.\r\nDialogue: 0,0:40:48.23,0:40:52.54,yin,,0,0,0,,重力行为默认是向下的\\N{\\fs12}Okay? Gravity-- gravity behavior by default, gravity is down.\r\nDialogue: 0,0:40:52.72,0:40:54.55,yin,,0,0,0,,如果我拿起手机 是向下的\\N{\\fs12}So if I'm holding my phone, it's down,\r\nDialogue: 0,0:40:54.69,0:40:55.35,yin,,0,0,0,,这说得通\\N{\\fs12}which kind of makes sense\r\nDialogue: 0,0:40:55.35,0:40:58.08,yin,,0,0,0,,如果我这样拿起手机 显示内容应该是向下的\\N{\\fs12}if I hold my phone up I kind of want things to go down,\r\nDialogue: 0,0:40:58.23,0:41:00.19,yin,,0,0,0,,但其实可以将其设为任意角度\\N{\\fs12}but really it can be set to any angle.\r\nDialogue: 0,0:41:00.19,0:41:02.06,yin,,0,0,0,,可以让重力方向向上或向左\\N{\\fs12}You can have the gravity up or to the left,\r\nDialogue: 0,0:41:02.06,0:41:04.56,yin,,0,0,0,,还可以从不同的方向\\N{\\fs12}you can have multiple gravity pulling on things\r\nDialogue: 0,0:41:04.61,0:41:05.67,yin,,0,0,0,,向物体添加多个重力\\N{\\fs12}from different directions.\r\nDialogue: 0,0:41:05.93,0:41:07.47,yin,,0,0,0,,实际上 如果向一个物体添加两个力\\N{\\fs12}In fact, if you had two things pulling,\r\nDialogue: 0,0:41:07.48,0:41:08.71,yin,,0,0,0,,一个向上 一个向下\\N{\\fs12}one from the top, one from the bottom,\r\nDialogue: 0,0:41:08.73,0:41:10.21,yin,,0,0,0,,这个物体就会飘在中间\\N{\\fs12}the thing would just float in the middle\r\nDialogue: 0,0:41:10.21,0:41:12.10,yin,,0,0,0,,如果两个重力大小相等的话\\N{\\fs12}if they have the same magnitude of gravity.\r\nDialogue: 0,0:41:12.36,0:41:13.74,yin,,0,0,0,,你可以设置重力大小\\N{\\fs12}And you can set the gravity.\r\nDialogue: 0,0:41:14.08,0:41:18.59,yin,,0,0,0,,重力大小magnitude为1 代表1000p/s/s\\N{\\fs12}Magnitude of 1 means a thousand points per second squared.\r\nDialogue: 0,0:41:18.81,0:41:20.62,yin,,0,0,0,,这是重力加速度\\N{\\fs12}That's the acceleration due to gravity.\r\nDialogue: 0,0:41:21.71,0:41:25.07,yin,,0,0,0,,很像9.8m/s^2\\N{\\fs12}That feels a lot like 9.8 meters per second squared\r\nDialogue: 0,0:41:25.07,0:41:27.60,yin,,0,0,0,,9.8m/s^2是实际重力加速度\\N{\\fs12}which is acceleration due to real gravity.\r\nDialogue: 0,0:41:27.60,0:41:28.83,yin,,0,0,0,,换句话说 如果你竖起手机\\N{\\fs12}So in other words, if you hold your phone up\r\nDialogue: 0,0:41:28.83,0:41:30.37,yin,,0,0,0,,让重力起作用\\N{\\fs12}and let the gravity work,\r\nDialogue: 0,0:41:30.44,0:41:32.72,yin,,0,0,0,,感觉上 手机上物体的坠落速度\\N{\\fs12}it kind of feels like it's falling about the same speed,\r\nDialogue: 0,0:41:32.73,0:41:33.96,yin,,0,0,0,,和现实物体的坠落速度一样\\N{\\fs12}something in real life would happen,\r\nDialogue: 0,0:41:34.18,0:41:35.81,yin,,0,0,0,,这也是个很好用的整数\\N{\\fs12}and it's also a very nice round number,\r\nDialogue: 0,0:41:35.87,0:41:37.41,yin,,0,0,0,,1000p/s^2\\N{\\fs12}a thousand points per second squared.\r\nDialogue: 0,0:41:38.39,0:41:40.90,yin,,0,0,0,,但是要知道它就像是重力\\N{\\fs12}Okay? But understand, it's just like gravity,\r\nDialogue: 0,0:41:40.91,0:41:43.24,yin,,0,0,0,,是某个方向上的重力加速度\\N{\\fs12}it's an acceleration in a certain direction.\r\nDialogue: 0,0:41:44.61,0:41:46.91,yin,,0,0,0,,collision碰撞非常酷\\N{\\fs12}Collision is really cool.\r\nDialogue: 0,0:41:47.11,0:41:51.93,yin,,0,0,0,,碰撞指的是 当碰撞行为中的动力项\\N{\\fs12}Collision just means the items inside of the collision behavior,\r\nDialogue: 0,0:41:51.98,0:41:54.84,yin,,0,0,0,,碰到一起的时候 会互相弹开\\N{\\fs12}if they bump into each other, they'll bounce off each other,\r\nDialogue: 0,0:41:55.31,0:41:56.57,yin,,0,0,0,,和现实中的碰撞效果类似\\N{\\fs12}like a real world collision,\r\nDialogue: 0,0:41:56.80,0:41:58.66,yin,,0,0,0,,你可以指定弹力大小\\N{\\fs12}and you can specify the elasticity\r\nDialogue: 0,0:41:58.66,0:42:00.24,yin,,0,0,0,,它们的弹性大小\\N{\\fs12}and how bouncy they are,\r\nDialogue: 0,0:42:00.64,0:42:03.57,yin,,0,0,0,,甚至可以为二者定义不同的密度\\N{\\fs12}and even you can define the density of one versus another,\r\nDialogue: 0,0:42:03.57,0:42:06.64,yin,,0,0,0,,密度大的一方可以把密度小的撞走\\N{\\fs12}so a really dense one will smash another one out of the way,\r\nDialogue: 0,0:42:07.39,0:42:08.39,yin,,0,0,0,,这些都是可以自定义的\\N{\\fs12}all definable.\r\nDialogue: 0,0:42:08.85,0:42:10.84,yin,,0,0,0,,还可以设置边界\\N{\\fs12}You can also set boundaries.\r\nDialogue: 0,0:42:11.06,0:42:14.42,yin,,0,0,0,,可以按需要 设置任意UIBezierPath\\N{\\fs12}So any UIBezierPath that you want to come up with,\r\nDialogue: 0,0:42:14.62,0:42:16.48,yin,,0,0,0,,将它添加到碰撞行为中\\N{\\fs12}you can put it in your collision behavior\r\nDialogue: 0,0:42:16.50,0:42:17.89,yin,,0,0,0,,物体碰到它会弹开\\N{\\fs12}and things will bounce off it.\r\nDialogue: 0,0:42:17.96,0:42:20.56,yin,,0,0,0,,可以是圆形 方形等等\\N{\\fs12}So it can be round, it can be square, whatever,\r\nDialogue: 0,0:42:20.57,0:42:22.95,yin,,0,0,0,,当物体碰到它时会弹开\\N{\\fs12}and things will bounce off it when they hit it.\r\nDialogue: 0,0:42:23.16,0:42:26.54,yin,,0,0,0,,你还可以将参考视图的边界\\N{\\fs12}Also you can set the boundaries of the reference view\r\nDialogue: 0,0:42:26.75,0:42:29.37,yin,,0,0,0,,也设置为有弹性的边界\\N{\\fs12}to be bouncy boundaries as well\r\nDialogue: 0,0:42:29.38,0:42:32.89,yin,,0,0,0,,方法是将translatesReferenceBoundsIntoBoundary设为YES\\N{\\fs12}by saying translatesReferenceBoundsIntoBoundary equals yes,\r\nDialogue: 0,0:42:33.05,0:42:35.62,yin,,0,0,0,,这样物体碰到参考视图的边缘就会弹开\\N{\\fs12}and then things will bounce off the edges of the reference view,\r\nDialogue: 0,0:42:35.62,0:42:38.56,yin,,0,0,0,,也就是动力动画者的顶级视图\\N{\\fs12}the top level view in the dynamic animator. Okay?\r\nDialogue: 0,0:42:39.94,0:42:44.00,yin,,0,0,0,,collisionMode决定了动力项\\N{\\fs12}So, the collisionMode determines whether the items\r\nDialogue: 0,0:42:44.16,0:42:46.51,yin,,0,0,0,,是相互碰撞弹开 还是只从边界碰撞弹开\\N{\\fs12}bounce off each other or just off the boundaries.\r\nDialogue: 0,0:42:49.75,0:42:50.42,yin,,0,0,0,,明白吗\\N{\\fs12}Alright?\r\nDialogue: 0,0:42:50.79,0:42:51.90,yin,,0,0,0,,吸附行为\\N{\\fs12}Attachment behaviors.\r\nDialogue: 0,0:42:51.90,0:42:54.78,yin,,0,0,0,,通过它 可以将一个动力项\\N{\\fs12}Okay, this is the way to attach an item\r\nDialogue: 0,0:42:55.14,0:42:58.32,yin,,0,0,0,,吸附到一个固定锚点或另外一个动力项上\\N{\\fs12}to a fixed point or to another item.\r\nDialogue: 0,0:42:58.83,0:43:00.27,yin,,0,0,0,,这里有一点要记住\\N{\\fs12}Now one thing to remember about this,\r\nDialogue: 0,0:43:00.28,0:43:03.24,yin,,0,0,0,,如果我将一个动力项连接到一个锚点上\\N{\\fs12}if I hook an item up to a point,\r\nDialogue: 0,0:43:03.37,0:43:05.49,yin,,0,0,0,,并不意味着这个动力项就不会移动了\\N{\\fs12}that does not mean that item is not going to move.\r\nDialogue: 0,0:43:05.94,0:43:09.03,yin,,0,0,0,,如果我将一个动力项连接到这个锚点上 动力项在这里\\N{\\fs12}Okay? If I hook it up to this point and I have an item here,\r\nDialogue: 0,0:43:09.39,0:43:11.58,yin,,0,0,0,,这时重力起作用了会怎样\\N{\\fs12}right, and gravity happens?\r\nDialogue: 0,0:43:12.22,0:43:15.04,yin,,0,0,0,,动力项会这样摆动\\N{\\fs12}My item is going to go like this...it's going to swing.\r\nDialogue: 0,0:43:15.99,0:43:19.04,yin,,0,0,0,,因为吸附行为只是将两个对象连接起来\\N{\\fs12}Because the attachment is just attaching the two things,\r\nDialogue: 0,0:43:19.04,0:43:20.40,yin,,0,0,0,,锚点和动力项\\N{\\fs12}the point and the item.\r\nDialogue: 0,0:43:20.40,0:43:22.99,yin,,0,0,0,,并没有吸附到背景上 对吧\\N{\\fs12}It's not attaching to the background, okay?\r\nDialogue: 0,0:43:23.20,0:43:26.78,yin,,0,0,0,,如果我移动了这个锚点 动力项也会随之移动\\N{\\fs12}And also if I move the point, the thing will stay with it\r\nDialogue: 0,0:43:26.86,0:43:28.79,yin,,0,0,0,,会在后面摆动之类的\\N{\\fs12}and it will kind of swing around behind it.\r\nDialogue: 0,0:43:28.79,0:43:30.87,yin,,0,0,0,,演示中会看到这部分\\N{\\fs12}And we'll see this in the demo, okay?\r\nDialogue: 0,0:43:30.90,0:43:33.14,yin,,0,0,0,,吸附行为是将动力项吸附到锚点上\\N{\\fs12}So attachment is attaching the thing to a point.\r\nDialogue: 0,0:43:33.54,0:43:35.12,yin,,0,0,0,,还可以吸附两个动力项\\N{\\fs12}You can also attach two items.\r\nDialogue: 0,0:43:35.30,0:43:38.60,yin,,0,0,0,,如果这样吸附了两个动力项 然后重力作用向下\\N{\\fs12}If I attach two items like this and I gravity down,\r\nDialogue: 0,0:43:38.74,0:43:40.33,yin,,0,0,0,,它们就会撞到\\N{\\fs12}they're going to go bam!\r\nDialogue: 0,0:43:40.69,0:43:42.03,yin,,0,0,0,,它们会保持同样的距离\\N{\\fs12}They'll stay the same distance apart,\r\nDialogue: 0,0:43:42.05,0:43:43.01,yin,,0,0,0,,但是会直接掉下来\\N{\\fs12}but they're just going to go straight down\r\nDialogue: 0,0:43:43.02,0:43:45.69,yin,,0,0,0,,因为重力依旧会作用于它们\\N{\\fs12}because gravity will still be applying to them as well.\r\nDialogue: 0,0:43:46.23,0:43:48.27,yin,,0,0,0,,连接只是能够让它们在一起\\N{\\fs12}Right? And the connection just keeps them together.\r\nDialogue: 0,0:43:50.40,0:43:51.99,yin,,0,0,0,,吸附行为有点不同\\N{\\fs12}The attachment behavior is a little different\r\nDialogue: 0,0:43:52.00,0:43:53.33,yin,,0,0,0,,不用alloc/init\\N{\\fs12}in that you don't alloc init,\r\nDialogue: 0,0:43:53.34,0:43:55.93,yin,,0,0,0,,而是在初始化时指定吸附对象\\N{\\fs12}you actually specify the attachment at init time.\r\nDialogue: 0,0:43:56.05,0:43:59.18,yin,,0,0,0,,所以用alloc/initWithItem与另一个动力项吸附\\N{\\fs12}So alloc initWithItem, alloc init with other item,\r\nDialogue: 0,0:43:59.30,0:44:01.92,yin,,0,0,0,,还有一种也是吸附动力项\\N{\\fs12}there's also some versions where you can attach items,\r\nDialogue: 0,0:44:01.98,0:44:03.11,yin,,0,0,0,,但吸附点不是中心\\N{\\fs12}where the attachment point\r\nDialogue: 0,0:44:03.13,0:44:05.32,yin,,0,0,0,,而是一个偏移量\\N{\\fs12}instead of being the center is offset.\r\nDialogue: 0,0:44:05.79,0:44:07.40,yin,,0,0,0,,这样动力项是悬着的\\N{\\fs12}And that will make things kind of hang\r\nDialogue: 0,0:44:07.54,0:44:10.57,yin,,0,0,0,,动力项在旋转时是倾斜的\\N{\\fs12}if the items rotate, they'll kind of tilt,\r\nDialogue: 0,0:44:10.87,0:44:12.31,yin,,0,0,0,,因为它的吸附点不是中心\\N{\\fs12}okay, because you're not grabbing them in the middle,\r\nDialogue: 0,0:44:12.32,0:44:13.18,yin,,0,0,0,,而是偏向一侧的\\N{\\fs12}you're grabbing them on the side,\r\nDialogue: 0,0:44:13.19,0:44:15.26,yin,,0,0,0,,这样你可以做出很酷的效果\\N{\\fs12}so you can make some pretty cool effects.\r\nDialogue: 0,0:44:15.85,0:44:18.50,yin,,0,0,0,,要注意 吸附行为还有一点很棒\\N{\\fs12}The other thing to notice about attachments that's cool\r\nDialogue: 0,0:44:18.50,0:44:22.30,yin,,0,0,0,,就是两个动力项之间的长度是可写的\\N{\\fs12}is that the length between the two items is writeable.\r\nDialogue: 0,0:44:23.16,0:44:25.06,yin,,0,0,0,,比如说 你要捏合缩放\\N{\\fs12}So for example, let's say you were pinching.\r\nDialogue: 0,0:44:26.20,0:44:28.03,yin,,0,0,0,,可以改变它们之间的长度\\N{\\fs12}You could change the length\r\nDialogue: 0,0:44:28.24,0:44:30.58,yin,,0,0,0,,这两个吸附的动力项会靠近在一起\\N{\\fs12}and those two attached items would move closer together.\r\nDialogue: 0,0:44:31.47,0:44:33.18,yin,,0,0,0,,即便你设置了\\N{\\fs12}Okay? So even though you set it up\r\nDialogue: 0,0:44:33.19,0:44:35.76,yin,,0,0,0,,让这个动力项吸附到这个锚点上\\N{\\fs12}as this item attach to this point\r\nDialogue: 0,0:44:35.76,0:44:37.70,yin,,0,0,0,,或者让两个动力项互相吸附\\N{\\fs12}or these items attach to each other,\r\nDialogue: 0,0:44:37.83,0:44:39.87,yin,,0,0,0,,如果你将二者间长度缩小\\N{\\fs12}if you change the length to be smaller,\r\nDialogue: 0,0:44:39.87,0:44:43.04,yin,,0,0,0,,它们就会互相靠近 这很棒\\N{\\fs12}they'll move toward each other, okay, that which is cool,\r\nDialogue: 0,0:44:43.19,0:44:44.32,yin,,0,0,0,,锚点也是一样的\\N{\\fs12}and the same thing with the anchor point.\r\nDialogue: 0,0:44:44.33,0:44:45.71,yin,,0,0,0,,如果你移动了锚点\\N{\\fs12}If you move the anchor point around,\r\nDialogue: 0,0:44:45.99,0:44:47.31,yin,,0,0,0,,它的吸附项也会移动\\N{\\fs12}the attachment is still there\r\nDialogue: 0,0:44:47.31,0:44:49.37,yin,,0,0,0,,跟在锚点的后面\\N{\\fs12}and the thing will follow around, right?\r\nDialogue: 0,0:44:49.66,0:44:51.40,yin,,0,0,0,,再加上应用的其他行为\\N{\\fs12}With other behaviors applying to it.\r\nDialogue: 0,0:44:51.41,0:44:51.84,yin,,0,0,0,,有问题吗\\N{\\fs12}Question?\r\nDialogue: 0,0:44:51.96,0:44:54.41,yin,,0,0,0,,这个吸附长度是一个确定值吗\\N{\\fs12}Is that attachment length, is that an exact value,\r\nDialogue: 0,0:44:54.41,0:44:57.81,yin,,0,0,0,,还是像是...\\N{\\fs12}like it would be with like when they're attached or--\r\nDialogue: 0,0:44:57.83,0:44:59.40,yin,,0,0,0,,你的意思是像铁棒吗\\N{\\fs12}Iron, like an iron bar you mean?\r\nDialogue: 0,0:44:59.40,0:45:00.94,yin,,0,0,0,,对 是像铁棒呢 还是像线绳呢\\N{\\fs12}Yeah, like iron bar or string?\r\nDialogue: 0,0:45:01.11,0:45:03.20,yin,,0,0,0,,问题是 这个连接是像铁棒呢\\N{\\fs12}Okay, so the question is, is it like an iron bar\r\nDialogue: 0,0:45:03.20,0:45:04.27,yin,,0,0,0,,还是像线绳呢\\N{\\fs12}or is it more like a string?\r\nDialogue: 0,0:45:04.44,0:45:07.71,yin,,0,0,0,,实际上 它像是一个弹簧\\N{\\fs12}And actually what it is, it's like a spring, okay?\r\nDialogue: 0,0:45:07.92,0:45:09.79,yin,,0,0,0,,你移动它的时候\\N{\\fs12}So it actually as you move it around,\r\nDialogue: 0,0:45:09.79,0:45:11.33,yin,,0,0,0,,比如向上移动 它会弹上来\\N{\\fs12}like if I move it up, it will \"Whoom!\"\r\nDialogue: 0,0:45:11.35,0:45:12.07,yin,,0,0,0,,弹起来\\N{\\fs12}spring up.\r\nDialogue: 0,0:45:12.35,0:45:15.42,yin,,0,0,0,,你可以控制它的阻尼大小和震荡频率\\N{\\fs12}And you can control the damping and oscillation of that.\r\nDialogue: 0,0:45:15.68,0:45:17.49,yin,,0,0,0,,默认情况下 是像一个铁棒\\N{\\fs12}By default, it's an iron bar.\r\nDialogue: 0,0:45:17.81,0:45:19.76,yin,,0,0,0,,阻尼大小和振荡频率的默认值\\N{\\fs12}Okay? So the damping and oscillation are set\r\nDialogue: 0,0:45:19.76,0:45:21.20,yin,,0,0,0,,让它不会发生振荡\\N{\\fs12}so that it does not oscillate,\r\nDialogue: 0,0:45:21.22,0:45:23.98,yin,,0,0,0,,但是你可以自己设置 让它跟着振荡\\N{\\fs12}but you can set it so as you follow it around it kind of--\r\nDialogue: 0,0:45:23.99,0:45:25.72,yin,,0,0,0,,非常酷\\N{\\fs12}It's very, very cool.\r\nDialogue: 0,0:45:25.72,0:45:26.91,yin,,0,0,0,,做作业的时候\\N{\\fs12}So you can play with all of those\r\nDialogue: 0,0:45:27.13,0:45:28.26,yin,,0,0,0,,大家可以都试一下\\N{\\fs12}when you are doing your homework.\r\nDialogue: 0,0:45:29.08,0:45:32.31,yin,,0,0,0,,速甩行为是将一个动力项甩到一个位置\\N{\\fs12}Snap behavior snaps an item to a location,\r\nDialogue: 0,0:45:32.38,0:45:34.43,yin,,0,0,0,,不只是让它飞过去\\N{\\fs12}but it does more than just have it fly there.\r\nDialogue: 0,0:45:34.43,0:45:36.73,yin,,0,0,0,,确实是飞过去 速度很快\\N{\\fs12}It does fly there, rather rapidly I might add.\r\nDialogue: 0,0:45:36.81,0:45:38.95,yin,,0,0,0,,达到目标位置之后 可以想象成\\N{\\fs12}When it gets there, though, you can imagine that\r\nDialogue: 0,0:45:38.96,0:45:42.39,yin,,0,0,0,,动力项四角有四个弹簧\\N{\\fs12}there's four springs attached to the item in the corners,\r\nDialogue: 0,0:45:42.40,0:45:43.30,yin,,0,0,0,,稍微离开一点\\N{\\fs12}a little ways out,\r\nDialogue: 0,0:45:43.43,0:45:45.23,yin,,0,0,0,,动力项到达目标位置时会来回振动\\N{\\fs12}so the thing gets there and it goes \"Doinggg\",\r\nDialogue: 0,0:45:45.35,0:45:46.89,yin,,0,0,0,,就像弹簧振动 像这样\\N{\\fs12}kind of springs, like this.\r\nDialogue: 0,0:45:46.94,0:45:48.70,yin,,0,0,0,,你可以指定振动的大小\\N{\\fs12}And you can specify how much it does that.\r\nDialogue: 0,0:45:48.74,0:45:49.97,yin,,0,0,0,,为什么要这样做呢\\N{\\fs12}Why does it do that?\r\nDialogue: 0,0:45:50.11,0:45:52.27,yin,,0,0,0,,因为你要给用户反馈\\N{\\fs12}That's because you want to give feedback to the user,\r\nDialogue: 0,0:45:52.27,0:45:53.56,yin,,0,0,0,,让他们知道自己刚移动了它\\N{\\fs12}oh, I just moved this.\r\nDialogue: 0,0:45:53.97,0:45:55.24,yin,,0,0,0,,我们并不想让它到了位置立马停住\\N{\\fs12}So you don't want it to just go \"Blip!\"\r\nDialogue: 0,0:45:55.62,0:45:56.93,yin,,0,0,0,,而是让它晃动一下\\N{\\fs12}You want it to go \"Hmmmm,\" you know,\r\nDialogue: 0,0:45:56.93,0:45:59.55,yin,,0,0,0,,让动力项弹跳一下\\N{\\fs12}and it kind of gives them just a moment's springiness,\r\nDialogue: 0,0:45:59.56,0:46:00.59,yin,,0,0,0,,让用户明白\\N{\\fs12}so it's like \"Oh, okay.\"\r\nDialogue: 0,0:46:00.72,0:46:01.81,yin,,0,0,0,,这是个很好的动画\\N{\\fs12}So that's good animation,\r\nDialogue: 0,0:46:01.81,0:46:03.27,yin,,0,0,0,,速甩行为很常用\\N{\\fs12}the snap behavior very common.\r\nDialogue: 0,0:46:03.69,0:46:05.16,yin,,0,0,0,,还有推动行为\\N{\\fs12}Also you have push behavior,\r\nDialogue: 0,0:46:05.17,0:46:06.49,yin,,0,0,0,,你可以推一下\\N{\\fs12}which is you can push,\r\nDialogue: 0,0:46:06.69,0:46:08.34,yin,,0,0,0,,推一下对象 它就开始移动了\\N{\\fs12}push an object and it will start moving.\r\nDialogue: 0,0:46:08.34,0:46:09.87,yin,,0,0,0,,尤其是 如果你没有添加重力\\N{\\fs12}So especially if you don't have gravity,\r\nDialogue: 0,0:46:09.92,0:46:12.22,yin,,0,0,0,,推动可能就是让物体移动的原因\\N{\\fs12}this might be what causes things to move, you push it\r\nDialogue: 0,0:46:12.23,0:46:15.36,yin,,0,0,0,,它移动过去 动力项有摩擦力\\N{\\fs12}and it moves across and then these items have friction,\r\nDialogue: 0,0:46:15.45,0:46:17.60,yin,,0,0,0,,相互碰撞的时候 密度不同\\N{\\fs12}they have density when they collide with each other,\r\nDialogue: 0,0:46:17.94,0:46:20.29,yin,,0,0,0,,大家可以回去看看推动行为的文档\\N{\\fs12}so push, you can read about push\r\nDialogue: 0,0:46:20.31,0:46:24.80,yin,,0,0,0,,看一下如何指定角度和推力大小等等\\N{\\fs12}and how you specify the angle and the magnitude and all that.\r\nDialogue: 0,0:46:25.42,0:46:30.65,yin,,0,0,0,,关于行为 还有一件事是\\N{\\fs12}Okay? So another thing about behaviors is you want to be able\r\nDialogue: 0,0:46:30.65,0:46:33.60,yin,,0,0,0,,在设置摩擦力 弹力和密度等\\N{\\fs12}to set this friction, elasticity, the density,\r\nDialogue: 0,0:46:33.60,0:46:35.22,yin,,0,0,0,,设置我们刚才说过的这些属性时\\N{\\fs12}all these things that we're talking about,\r\nDialogue: 0,0:46:35.46,0:46:37.48,yin,,0,0,0,,我们想要将其设置到动力项上\\N{\\fs12}you want to set them on the items\r\nDialogue: 0,0:46:37.61,0:46:40.31,yin,,0,0,0,,与行为无关\\N{\\fs12}independent of the other behaviors, okay?\r\nDialogue: 0,0:46:40.64,0:46:43.79,yin,,0,0,0,,如果我设置了摩擦力\\N{\\fs12}So if I have friction, I want it to apply,\r\nDialogue: 0,0:46:43.81,0:46:46.43,yin,,0,0,0,,不管动力项移动是因为重力还是碰撞\\N{\\fs12}whether it's gravity that's causing the thing to move,\r\nDialogue: 0,0:46:46.43,0:46:48.39,yin,,0,0,0,,摩擦力应该是一致的\\N{\\fs12}or whether a collision caused it to move.\r\nDialogue: 0,0:46:48.72,0:46:52.27,yin,,0,0,0,,所以摩擦力 密度等属性\\N{\\fs12}So we don't put the friction and the density and stuff like that\r\nDialogue: 0,0:46:52.27,0:46:55.09,yin,,0,0,0,,不是在碰撞行为或者重力行为中进行设置\\N{\\fs12}in collision behaviors or gravity behaviors,\r\nDialogue: 0,0:46:55.16,0:46:58.17,yin,,0,0,0,,而是放在它自己的行为中 叫做动力项行为\\N{\\fs12}we put it in its own behavior called the items behavior.\r\nDialogue: 0,0:46:58.77,0:47:03.43,yin,,0,0,0,,对应的行为类叫做UIDynamicItemBehavior\\N{\\fs12}So there's a class of behavior called UIDynamicItemBehavior.\r\nDialogue: 0,0:47:03.76,0:47:07.18,yin,,0,0,0,,如果你想要设置这些属性\\N{\\fs12}Okay? And so if you want any of these things,\r\nDialogue: 0,0:47:07.18,0:47:09.43,yin,,0,0,0,,比如不允许它旋转\\N{\\fs12}like you don't want to allow it to rotate,\r\nDialogue: 0,0:47:09.45,0:47:11.08,yin,,0,0,0,,不想让视图旋转\\N{\\fs12}you don't want the view to be able to rotate,\r\nDialogue: 0,0:47:12.18,0:47:13.64,yin,,0,0,0,,不知道作业中是怎样的\\N{\\fs12}which I don't know if you're doing homework\r\nDialogue: 0,0:47:13.65,0:47:15.23,yin,,0,0,0,,有时需要 有时不需要\\N{\\fs12}sometimes you might want that, sometimes not,\r\nDialogue: 0,0:47:15.44,0:47:19.19,yin,,0,0,0,,或者是想要指定对象的摩擦力或弹力\\N{\\fs12}or you want to specify the friction or the bounciness of this object,\r\nDialogue: 0,0:47:19.26,0:47:22.27,yin,,0,0,0,,新建一个UIDynamicItemBehavior\\N{\\fs12}you create a UIDynamicItemBehavior\r\nDialogue: 0,0:47:22.41,0:47:24.43,yin,,0,0,0,,将动力项也添加到其中\\N{\\fs12}and add the items to that as well.\r\nDialogue: 0,0:47:24.60,0:47:27.36,yin,,0,0,0,,所以动力项既是重力行为的一员\\N{\\fs12}So the item would be a member of the gravity behavior,\r\nDialogue: 0,0:47:27.36,0:47:29.03,yin,,0,0,0,,又是碰撞行为的一员\\N{\\fs12}it might be of the collision behavior,\r\nDialogue: 0,0:47:29.05,0:47:32.30,yin,,0,0,0,,还是UIDynamicItemBehavior的一员\\N{\\fs12}and it's also a member of a UIDynamicItemBehavior.\r\nDialogue: 0,0:47:32.92,0:47:34.86,yin,,0,0,0,,它控制着全部选项\\N{\\fs12}Okay? And this controls all its options.\r\nDialogue: 0,0:47:34.86,0:47:36.92,yin,,0,0,0,,你可以把这看做是动画选项\\N{\\fs12}So you can think of this as kind of like the animation options,\r\nDialogue: 0,0:47:36.92,0:47:39.05,yin,,0,0,0,,但其实更像是\\N{\\fs12}but really it's more like the behavior of the--\r\nDialogue: 0,0:47:39.06,0:47:40.99,yin,,0,0,0,,动力项的内在行为\\N{\\fs12}the intrinsic behavior of that item.\r\nDialogue: 0,0:47:41.42,0:47:42.96,yin,,0,0,0,,它的密度是多少\\N{\\fs12}Okay? What is its density?\r\nDialogue: 0,0:47:43.25,0:47:44.37,yin,,0,0,0,,不管起作用的是哪个行为\\N{\\fs12}You want that to be the same\r\nDialogue: 0,0:47:44.38,0:47:46.39,yin,,0,0,0,,密度都是一样的\\N{\\fs12}no matter what behavior is acting on it.\r\nDialogue: 0,0:47:47.18,0:47:49.00,yin,,0,0,0,,还可以用UIDynamicItemBehavior\\N{\\fs12}You can also find out information about\r\nDialogue: 0,0:47:49.02,0:47:52.79,yin,,0,0,0,,获取动力项的信息\\N{\\fs12}what's going on with the item using UIDynamicItemBehavior.\r\nDialogue: 0,0:47:53.33,0:47:56.35,yin,,0,0,0,,比如linearVelocityForItem方法\\N{\\fs12}It has methods like linearVelocityForItem.\r\nDialogue: 0,0:47:56.36,0:47:58.28,yin,,0,0,0,,会告诉你这个动力项\\N{\\fs12}It will tell you the velocity of this item\r\nDialogue: 0,0:47:58.35,0:47:59.35,yin,,0,0,0,,在不同方向上的速度\\N{\\fs12}in different directions.\r\nDialogue: 0,0:47:59.62,0:48:02.63,yin,,0,0,0,,在接管动画时很好用\\N{\\fs12}Which is really cool for if you want to take over animation,\r\nDialogue: 0,0:48:02.76,0:48:06.92,yin,,0,0,0,,动力动画系统让动力项开始移动\\N{\\fs12}the dynamic animation system started this thing moving,\r\nDialogue: 0,0:48:06.97,0:48:09.11,yin,,0,0,0,,现在你想接管 让它继续移动\\N{\\fs12}and now you want to take over and keep it moving,\r\nDialogue: 0,0:48:09.41,0:48:11.19,yin,,0,0,0,,换一个方向移动之类的\\N{\\fs12}maybe in some other direction or something like that.\r\nDialogue: 0,0:48:11.19,0:48:13.14,yin,,0,0,0,,可以获取当前移动速度\\N{\\fs12}You can find out how fast is it moving right now,\r\nDialogue: 0,0:48:13.14,0:48:14.91,yin,,0,0,0,,然后以该速度继续移动\\N{\\fs12}and then continue having it move at that speed.\r\nDialogue: 0,0:48:15.59,0:48:16.97,yin,,0,0,0,,角速度也是一样的\\N{\\fs12}Same thing with angular velocity.\r\nDialogue: 0,0:48:16.98,0:48:20.19,yin,,0,0,0,,每秒旋转的弧度是多少\\N{\\fs12}How fast it's rotating in radians per second. Okay?\r\nDialogue: 0,0:48:21.92,0:48:23.95,yin,,0,0,0,,动力行为...\\N{\\fs12}Dynamic behaviors also--\r\nDialogue: 0,0:48:24.00,0:48:26.21,yin,,0,0,0,,UIDynamicBehavior\\N{\\fs12}the UIDynamicBehavior is the base class\r\nDialogue: 0,0:48:26.22,0:48:28.18,yin,,0,0,0,,是重力行为 碰撞行为等的基类\\N{\\fs12}for gravity behavior, collision behavior, all these,\r\nDialogue: 0,0:48:28.29,0:48:30.14,yin,,0,0,0,,你也可以自己创建子类\\N{\\fs12}you can also create your own subclass,\r\nDialogue: 0,0:48:30.23,0:48:32.56,yin,,0,0,0,,通常情况下 只要在实现文件中\\N{\\fs12}and usually when you do your implementation,\r\nDialogue: 0,0:48:32.57,0:48:35.62,yin,,0,0,0,,将其他行为添加为子行为\\N{\\fs12}just adds other behaviors as child behaviors.\r\nDialogue: 0,0:48:35.99,0:48:38.06,yin,,0,0,0,,UIDynamicBehavior有一个方法\\N{\\fs12}So there's a method in UIDynamicBehavior\r\nDialogue: 0,0:48:38.19,0:48:39.63,yin,,0,0,0,,叫做addChildBehavior\\N{\\fs12}called addChildBehavior,\r\nDialogue: 0,0:48:39.89,0:48:43.71,yin,,0,0,0,,你可以添加重力行为 碰撞行为 UIDynamicItemBehavior\\N{\\fs12}and you can add a gravity, collision, UIDynamicItemBehavior,\r\nDialogue: 0,0:48:43.76,0:48:44.98,yin,,0,0,0,,将其作为子行为\\N{\\fs12}as sub-behaviors.\r\nDialogue: 0,0:48:45.14,0:48:48.55,yin,,0,0,0,,这很常见 只是为了整理API\\N{\\fs12}And this is very common to do, just to clean up your API,\r\nDialogue: 0,0:48:48.56,0:48:52.74,yin,,0,0,0,,将一起使用的行为放到它们自己的类中\\N{\\fs12}to group behaviors that go together, into their own class.\r\nDialogue: 0,0:48:53.12,0:48:55.53,yin,,0,0,0,,它们自己的UIDynamicBehavior子类中\\N{\\fs12}Okay? Their own UIDynamicBehavior subclass,\r\nDialogue: 0,0:48:55.95,0:48:58.45,yin,,0,0,0,,里面通常都是子行为\\N{\\fs12}and all that thing usually has is child behaviors\r\nDialogue: 0,0:48:58.45,0:49:00.48,yin,,0,0,0,,也许还有几个API\\N{\\fs12}and then maybe a little bit of API\r\nDialogue: 0,0:49:00.68,0:49:03.11,yin,,0,0,0,,用来以某种方法添加项\\N{\\fs12}to add the items in a certain way\r\nDialogue: 0,0:49:03.13,0:49:05.46,yin,,0,0,0,,或用其他方法将它们关联起来\\N{\\fs12}or have them interrelate in some other way.\r\nDialogue: 0,0:49:06.57,0:49:11.96,yin,,0,0,0,,此外 所有UIDynamicBehavior\\N{\\fs12}Okay? What is more, all behaviors, all UIDynamicBehaviors,\r\nDialogue: 0,0:49:11.97,0:49:14.23,yin,,0,0,0,,重力 碰撞 自定义行为等等\\N{\\fs12}gravity, collision, your own custom ones, whatever,\r\nDialogue: 0,0:49:14.35,0:49:16.79,yin,,0,0,0,,都知道自己所在的动力动画者是什么\\N{\\fs12}they know what dynamic animator they are in.\r\nDialogue: 0,0:49:17.38,0:49:19.43,yin,,0,0,0,,它们有一个属性叫做dynamicAnimator\\N{\\fs12}They have a property called dynamicAnimator\r\nDialogue: 0,0:49:19.43,0:49:22.10,yin,,0,0,0,,可以返回它们所在的动力动画者的信息\\N{\\fs12}which will say what dynamic animator they're in,\r\nDialogue: 0,0:49:22.21,0:49:24.81,yin,,0,0,0,,UIDynamicBehavior有一个\\N{\\fs12}and there's kind of a view controller life cycle thing\r\nDialogue: 0,0:49:24.81,0:49:26.61,yin,,0,0,0,,类似于视图控制器生命周期的机制\\N{\\fs12}of UIDynamicBehaviors,\r\nDialogue: 0,0:49:26.81,0:49:28.61,yin,,0,0,0,,只有一个方法\\N{\\fs12}which only has one method in it,\r\nDialogue: 0,0:49:28.95,0:49:30.17,yin,,0,0,0,,willMoveToAnimator\\N{\\fs12}willMoveToAnimator.\r\nDialogue: 0,0:49:30.70,0:49:33.97,yin,,0,0,0,,当行为移动到动画者中\\N{\\fs12}So that gets called every time it gets moved to an animator\r\nDialogue: 0,0:49:33.97,0:49:35.22,yin,,0,0,0,,或从动画者中移除时\\N{\\fs12}or out of an animator.\r\nDialogue: 0,0:49:35.22,0:49:36.51,yin,,0,0,0,,这个方法会被调用 参数为nil\\N{\\fs12}So this would be called with nil.\r\nDialogue: 0,0:49:37.27,0:49:39.18,yin,,0,0,0,,可以通过这个方法知道\\N{\\fs12}Okay? So that way you can find out\r\nDialogue: 0,0:49:39.19,0:49:42.05,yin,,0,0,0,,你的行为当前是否正在执行动画\\N{\\fs12}whether your behavior is currently being animated or not,\r\nDialogue: 0,0:49:42.50,0:49:44.93,yin,,0,0,0,,是由哪个动画者执行\\N{\\fs12}and by which animator. Okay?\r\nDialogue: 0,0:49:45.72,0:49:48.10,yin,,0,0,0,,关于行为 我还要讲最后一点\\N{\\fs12}And the last thing I'm going to tell you about behaviors,\r\nDialogue: 0,0:49:48.11,0:49:52.68,yin,,0,0,0,,非常棒的属性 是一个block 叫做action\\N{\\fs12}really cool property is a block called action,\r\nDialogue: 0,0:49:53.62,0:49:55.77,yin,,0,0,0,,这个block没有返回值 也没有参数\\N{\\fs12}this block returns nothing and takes no arguments,\r\nDialogue: 0,0:49:55.79,0:49:57.02,yin,,0,0,0,,是基本的block\\N{\\fs12}so it's basic block.\r\nDialogue: 0,0:49:57.41,0:50:02.09,yin,,0,0,0,,要用这个block 只要先说行为名称\\N{\\fs12}This block you provide, you just say my whatever behavior,\r\nDialogue: 0,0:50:02.26,0:50:04.07,yin,,0,0,0,,重力行为 碰撞行为等等\\N{\\fs12}gravity behavior, collision behavior, whatever,\r\nDialogue: 0,0:50:04.27,0:50:07.26,yin,,0,0,0,,然后是.action 等于一个block\\N{\\fs12}dot action equals a block\r\nDialogue: 0,0:50:07.56,0:50:09.37,yin,,0,0,0,,每次这个行为引发动画变化时\\N{\\fs12}it will execute that block every time\r\nDialogue: 0,0:50:09.38,0:50:12.01,yin,,0,0,0,,都会执行那个block\\N{\\fs12}this behavior causes animation change.\r\nDialogue: 0,0:50:13.03,0:50:14.79,yin,,0,0,0,,这个block会被调用很多次\\N{\\fs12}Okay? So this is called a lot,\r\nDialogue: 0,0:50:15.22,0:50:17.36,yin,,0,0,0,,比如 重力作用下 物体向下时\\N{\\fs12}as gravity pulls the thing down,\r\nDialogue: 0,0:50:17.38,0:50:20.58,yin,,0,0,0,,每次移动 哪怕只移动了1像素 它也会被调用\\N{\\fs12}every time it moves, even a pixel, this thing gets called.\r\nDialogue: 0,0:50:21.07,0:50:22.70,yin,,0,0,0,,如果发生碰撞\\N{\\fs12}Okay? If a collision happens,\r\nDialogue: 0,0:50:22.84,0:50:25.42,yin,,0,0,0,,物体移动了 这个block就会被调用\\N{\\fs12}and it moves that causes it to move, this will get called.\r\nDialogue: 0,0:50:26.07,0:50:29.07,yin,,0,0,0,,可以通过这个方法参与到动画中\\N{\\fs12}Okay? So this is a way to get in there and get involved.\r\nDialogue: 0,0:50:29.11,0:50:31.81,yin,,0,0,0,,使用它的时候要负起责任\\N{\\fs12}Now, you have a responsibility when you get in there,\r\nDialogue: 0,0:50:31.90,0:50:34.32,yin,,0,0,0,,不要在action中执行资源消耗过大的操作\\N{\\fs12}don't do anything really expensive in action\r\nDialogue: 0,0:50:34.37,0:50:36.19,yin,,0,0,0,,否则动画会变得磕磕绊绊的\\N{\\fs12}or your animation will get all jerky.\r\nDialogue: 0,0:50:36.70,0:50:38.51,yin,,0,0,0,,不要做资源消耗过大的操作\\N{\\fs12}Okay? You do not want to do something expensive\r\nDialogue: 0,0:50:38.51,0:50:39.81,yin,,0,0,0,,比如绘制很多内容\\N{\\fs12}like draw too much,\r\nDialogue: 0,0:50:40.00,0:50:41.13,yin,,0,0,0,,可以绘制少量内容\\N{\\fs12}but you can draw a little bit.\r\nDialogue: 0,0:50:41.23,0:50:44.58,yin,,0,0,0,,我会在周三的演示中讲到的\\N{\\fs12}And we'll show in the demo on Wednesday, we'll get to the part\r\nDialogue: 0,0:50:44.68,0:50:46.88,yin,,0,0,0,,我会设置一个action 绘制少量内容\\N{\\fs12}where I'll set an action that draws a little bit,\r\nDialogue: 0,0:50:47.05,0:50:49.04,yin,,0,0,0,,让大家看得更清楚\\N{\\fs12}so that we can see things a little better,\r\nDialogue: 0,0:50:49.52,0:50:52.01,yin,,0,0,0,,可以看到这个action 非常好用\\N{\\fs12}and you can see this, really nice to be able to set this.\r\nDialogue: 0,0:50:52.29,0:50:55.23,yin,,0,0,0,,这是一个简单的连接方法\\N{\\fs12}Okay? So this is a simple little hook to get involved\r\nDialogue: 0,0:50:55.43,0:50:58.29,yin,,0,0,0,,用来参与到行为引发的动画中\\N{\\fs12}with the animation that these behaviors are causing to happen.\r\nDialogue: 0,0:50:59.41,0:50:59.94,yin,,0,0,0,,懂了吗\\N{\\fs12}Okay?\r\nDialogue: 0,0:51:01.08,0:51:02.88,yin,,0,0,0,,好了 我们进入演示部分\\N{\\fs12}Alright. So let's do this demo.\r\nDialogue: 0,0:51:03.82,0:51:06.98,yin,,0,0,0,,下面这个列表中的内容 稍后都会演示\\N{\\fs12}All that what to look for, you can look on later,\r\nDialogue: 0,0:51:07.09,0:51:08.83,yin,,0,0,0,,放这里只是为了让大家看到\\N{\\fs12}just to make sure you actually saw this.\r\nDialogue: 0,0:51:09.76,0:51:11.33,yin,,0,0,0,,这个示例叫做Dropit\\N{\\fs12}This demo is called \"Dropit.\"\r\nDialogue: 0,0:51:11.91,0:51:17.13,yin,,0,0,0,,基本上 就是让方块视图掉下来\\N{\\fs12}And basically going to drop views, squares, down,\r\nDialogue: 0,0:51:17.25,0:51:18.77,yin,,0,0,0,,堆积在底部\\N{\\fs12}and they're going to collect at the bottom,\r\nDialogue: 0,0:51:18.78,0:51:21.62,yin,,0,0,0,,集满一行之后 就会炸掉这一行\\N{\\fs12}and when a whole row collects, I'm going to blow them up.\r\nDialogue: 0,0:51:21.81,0:51:22.53,yin,,0,0,0,,有点像俄罗斯方块\\N{\\fs12}Kind of like Tetris.\r\nDialogue: 0,0:51:22.53,0:51:23.11,yin,,0,0,0,,知道俄罗斯方块吗\\N{\\fs12}You know Tetris?\r\nDialogue: 0,0:51:23.11,0:51:25.32,yin,,0,0,0,,将各种方块放到一起 拼成一行后\\N{\\fs12}You put the blocks in and when they fit and you get a row,\r\nDialogue: 0,0:51:25.49,0:51:27.07,yin,,0,0,0,,这一行就消掉了\\N{\\fs12}boom, the row disappears.\r\nDialogue: 0,0:51:27.29,0:51:28.80,yin,,0,0,0,,我们要做的就是这个\\N{\\fs12}We're going to do that. Okay?\r\nDialogue: 0,0:51:28.83,0:51:30.90,yin,,0,0,0,,我们不会用俄罗斯方块之类的\\N{\\fs12}We're not going to use Tetris squares and stuff like that,\r\nDialogue: 0,0:51:30.93,0:51:34.04,yin,,0,0,0,,这只是一个演示 只有45分钟\\N{\\fs12}this is a demo, I only have like 45 minutes to do,\r\nDialogue: 0,0:51:34.04,0:51:36.11,yin,,0,0,0,,我们就用方块来代替\\N{\\fs12}but we'll do blocks instead.\r\nDialogue: 0,0:51:36.47,0:51:38.95,yin,,0,0,0,,但在这段时间内\\N{\\fs12}But the main thing I just want to show you everything I can\r\nDialogue: 0,0:51:39.10,0:51:42.21,yin,,0,0,0,,我想演示的主要是动画的各种相关内容\\N{\\fs12}in that amount of time, about animation.\r\nDialogue: 0,0:51:42.21,0:51:45.55,yin,,0,0,0,,我们要新建一个应用 关掉这个\\N{\\fs12}So we're going to make a new app here, let's get rid of that.\r\nDialogue: 0,0:51:46.83,0:51:47.70,yin,,0,0,0,,不需要这个\\N{\\fs12}Don't need that.\r\nDialogue: 0,0:51:48.79,0:51:50.05,yin,,0,0,0,,新建一个项目\\N{\\fs12}We're going to create a new project.\r\nDialogue: 0,0:51:50.06,0:51:51.22,yin,,0,0,0,,我要叫它...\\N{\\fs12}I'm going to call this project--\r\nDialogue: 0,0:51:51.23,0:51:52.56,yin,,0,0,0,,这里我就快速带过了\\N{\\fs12}I'm going to go quite fast now\r\nDialogue: 0,0:51:52.56,0:51:54.70,yin,,0,0,0,,这部分大家都已经知道了\\N{\\fs12}through most of this stuff that you already know how to do.\r\nDialogue: 0,0:51:54.88,0:51:55.90,yin,,0,0,0,,我要叫它Dropit\\N{\\fs12}So I'm going to do Dropit,\r\nDialogue: 0,0:51:55.90,0:51:58.63,yin,,0,0,0,,视图控制器也叫Dropit\\N{\\fs12}I'm going to call the view controller also Dropit.\r\nDialogue: 0,0:51:59.20,0:52:01.69,yin,,0,0,0,,保存在主目录Developer下\\N{\\fs12}Okay? We'll put it in home directory Developer.\r\nDialogue: 0,0:52:02.19,0:52:03.43,yin,,0,0,0,,这就是我们的Dropit\\N{\\fs12}Here's our Dropit.\r\nDialogue: 0,0:52:03.80,0:52:05.84,yin,,0,0,0,,你们知道的 我喜欢把这些移走\\N{\\fs12}You know me, I always like to move these out of the way.\r\nDialogue: 0,0:52:06.47,0:52:08.50,yin,,0,0,0,,好了 这是我的storyboard\\N{\\fs12}Alright. So here's my storyboard.\r\nDialogue: 0,0:52:09.17,0:52:15.66,yin,,0,0,0,,我要用一个通用UIView来包含这个游戏\\N{\\fs12}I'm going to use a generic UIView to contain my game.\r\nDialogue: 0,0:52:15.96,0:52:17.35,yin,,0,0,0,,这个小的掉落游戏\\N{\\fs12}Okay? My little dropping game.\r\nDialogue: 0,0:52:17.47,0:52:20.38,yin,,0,0,0,,可以在self.view中做这个掉落游戏\\N{\\fs12}I could do all this dropping in self dot view here,\r\nDialogue: 0,0:52:20.51,0:52:21.78,yin,,0,0,0,,但并不是个好主意\\N{\\fs12}but it's usually a bad idea,\r\nDialogue: 0,0:52:21.79,0:52:23.25,yin,,0,0,0,,如果我想加一个分数\\N{\\fs12}because what if I ever want to add a score\r\nDialogue: 0,0:52:23.26,0:52:25.22,yin,,0,0,0,,或者加一个按钮之类的呢\\N{\\fs12}or another button or something like that,\r\nDialogue: 0,0:52:25.23,0:52:27.76,yin,,0,0,0,,我希望游戏是在一个稍小的空间中\\N{\\fs12}I want my game then to be in a little smaller space,\r\nDialogue: 0,0:52:27.94,0:52:30.50,yin,,0,0,0,,大家的作业中也要这样做\\N{\\fs12}and you're going to want to do that for your homework as well.\r\nDialogue: 0,0:52:30.54,0:52:33.66,yin,,0,0,0,,我只要直接拖出一个通用UIView\\N{\\fs12}So I'm just going to drag out a generic UIView.\r\nDialogue: 0,0:52:33.96,0:52:35.20,yin,,0,0,0,,我总是找不到它\\N{\\fs12}I always have trouble finding it.\r\nDialogue: 0,0:52:35.22,0:52:36.05,yin,,0,0,0,,在这呢\\N{\\fs12}Yep, there it is.\r\nDialogue: 0,0:52:36.16,0:52:38.83,yin,,0,0,0,,我只要把这个通用UIView拖到这里\\N{\\fs12}So I'm just going to drag this generic UIView in here,\r\nDialogue: 0,0:52:38.94,0:52:40.38,yin,,0,0,0,,创建一个指向它的输出口\\N{\\fs12}and I'm going to create an outlet to it,\r\nDialogue: 0,0:52:40.38,0:52:41.89,yin,,0,0,0,,我要加它gameView\\N{\\fs12}I'm going to call it my gameView.\r\nDialogue: 0,0:52:41.98,0:52:46.11,yin,,0,0,0,,只要按住control键拖到这里 叫做gameView\\N{\\fs12}So just control, drag, out here and call it gameView.\r\nDialogue: 0,0:52:46.11,0:52:47.63,yin,,0,0,0,,它是一个通用UIView\\N{\\fs12}And it's a generic UIView.\r\nDialogue: 0,0:52:48.51,0:52:49.53,yin,,0,0,0,,不是自定义的\\N{\\fs12}It's no custom thing.\r\nDialogue: 0,0:52:49.53,0:52:51.36,yin,,0,0,0,,我只是想让它成为边界\\N{\\fs12}But I just want it to be the bounds,\r\nDialogue: 0,0:52:51.72,0:52:53.95,yin,,0,0,0,,这样如果我想在里面增加UI之类的话\\N{\\fs12}and I can move these bounds in from the edge\r\nDialogue: 0,0:52:53.96,0:52:56.39,yin,,0,0,0,,就可以将边界从边缘移进来\\N{\\fs12}if I wanted to put some other UI in there or whatever.\r\nDialogue: 0,0:52:56.74,0:52:59.13,yin,,0,0,0,,游戏视图有了\\N{\\fs12}So now I have my game view.\r\nDialogue: 0,0:52:59.30,0:53:01.47,yin,,0,0,0,,我还要再加一个点击手势\\N{\\fs12}And I'm also going to have a tap gesture,\r\nDialogue: 0,0:53:01.47,0:53:03.13,yin,,0,0,0,,拖出一个点击手势\\N{\\fs12}so let's drag out a tap gesture.\r\nDialogue: 0,0:53:03.27,0:53:04.76,yin,,0,0,0,,每次点击屏幕时\\N{\\fs12}So that every time I tap on this,\r\nDialogue: 0,0:53:04.76,0:53:06.80,yin,,0,0,0,,就会有一个方块掉落下来\\N{\\fs12}I'm going to add another square to drop.\r\nDialogue: 0,0:53:07.03,0:53:09.37,yin,,0,0,0,,将它放到游戏视图中\\N{\\fs12}Okay? So I'm going to put this on my game view.\r\nDialogue: 0,0:53:09.56,0:53:11.21,yin,,0,0,0,,这是我的点击手势\\N{\\fs12}Here's my tap gesture right here.\r\nDialogue: 0,0:53:11.51,0:53:14.72,yin,,0,0,0,,control拖动到右边这里 我要叫它tap\\N{\\fs12}Control drag this out, I'll call it tap.\r\nDialogue: 0,0:53:19.51,0:53:21.56,yin,,0,0,0,,增大点空间\\N{\\fs12}Get some more space here for us.\r\nDialogue: 0,0:53:22.58,0:53:25.61,yin,,0,0,0,,每次点击游戏视图时\\N{\\fs12}So every time that you tap on my game view,\r\nDialogue: 0,0:53:25.71,0:53:31.81,yin,,0,0,0,,就会掉下一个正方形\\N{\\fs12}I'm going to drop another, drop another full square\r\nDialogue: 0,0:53:32.26,0:53:34.97,yin,,0,0,0,,就像俄罗斯方块那样\\N{\\fs12}that falls down like a Tetris kind of thing.\r\nDialogue: 0,0:53:36.02,0:53:37.43,yin,,0,0,0,,打错了\\N{\\fs12}Oops. Oops.\r\nDialogue: 0,0:53:37.85,0:53:39.70,yin,,0,0,0,,drop 好了\\N{\\fs12}Drop. Okay?\r\nDialogue: 0,0:53:39.70,0:53:41.15,yin,,0,0,0,,这就是这个方法的作用\\N{\\fs12}So that's what this method is going to do,\r\nDialogue: 0,0:53:41.15,0:53:42.39,yin,,0,0,0,,添加一个视图\\N{\\fs12}it's just going to add a view.\r\nDialogue: 0,0:53:42.39,0:53:44.68,yin,,0,0,0,,正好我可以演示一下\\N{\\fs12}So this is also a chance for me to show you\r\nDialogue: 0,0:53:44.81,0:53:47.27,yin,,0,0,0,,如何用代码创建UIView\\N{\\fs12}how to create a UIView in code,\r\nDialogue: 0,0:53:47.28,0:53:48.48,yin,,0,0,0,,希望大家都做过了\\N{\\fs12}which hopefully you've all done that\r\nDialogue: 0,0:53:48.49,0:53:49.70,yin,,0,0,0,,因为作业中有一部分\\N{\\fs12}because you've done the part of the homework\r\nDialogue: 0,0:53:49.71,0:53:50.59,yin,,0,0,0,,就是要完成自定义视图\\N{\\fs12}that's the custom view,\r\nDialogue: 0,0:53:50.59,0:53:52.18,yin,,0,0,0,,但是如果你没做过 正好学一下\\N{\\fs12}but if you haven't, here you go.\r\nDialogue: 0,0:53:52.82,0:53:55.17,yin,,0,0,0,,我要先创建frame\\N{\\fs12}I'm going to actually create the frame first.\r\nDialogue: 0,0:53:55.18,0:53:56.47,yin,,0,0,0,,所以我要设置frame\\N{\\fs12}So I'm gonna do this frame.\r\nDialogue: 0,0:53:56.69,0:54:02.35,yin,,0,0,0,,我要将frame的原点设为CGPointZero\\N{\\fs12}I'm going to have the frame origin start out at CGPointZero,\r\nDialogue: 0,0:54:02.37,0:54:04.09,yin,,0,0,0,,然后我会改变x轴原点\\N{\\fs12}but then I'm going to change the x origin.\r\nDialogue: 0,0:54:04.20,0:54:06.44,yin,,0,0,0,,掉落是从顶部开始的\\N{\\fs12}So I'm going to have that drop start out at the top\r\nDialogue: 0,0:54:06.59,0:54:10.05,yin,,0,0,0,,然后我会选取x轴上的任意一点\\N{\\fs12}and then I'm just gonna put in a random spot across the x.\r\nDialogue: 0,0:54:11.02,0:54:13.84,yin,,0,0,0,,大小呢 我要定义一个小的...\\N{\\fs12}The size, I'm going to define a nice little--\r\nDialogue: 0,0:54:15.00,0:54:16.46,yin,,0,0,0,,添加一个static值\\N{\\fs12}let's do a static.\r\nDialogue: 0,0:54:18.17,0:54:25.02,yin,,0,0,0,,static const CGSize 叫它DROP_SIZE 等于\\N{\\fs12}Static, const, CGSize, we'll call this DROP_SIZE equals\r\nDialogue: 0,0:54:25.67,0:54:27.59,yin,,0,0,0,,我要将大小设为40*40\\N{\\fs12}and I'll make it like 40 by 40,\r\nDialogue: 0,0:54:27.60,0:54:30.76,yin,,0,0,0,,我将它设为静态常量\\N{\\fs12}but I'm going to make this be static const\r\nDialogue: 0,0:54:30.77,0:54:32.74,yin,,0,0,0,,而不是设为属性之类的\\N{\\fs12}as opposed to making it be a property or something\r\nDialogue: 0,0:54:32.75,0:54:34.65,yin,,0,0,0,,因为我现在不想添加代码\\N{\\fs12}because I don't want to write the code right now\r\nDialogue: 0,0:54:34.66,0:54:36.57,yin,,0,0,0,,来处理其他对象修改大小的情况\\N{\\fs12}to deal with the fact that someone changes this,\r\nDialogue: 0,0:54:36.68,0:54:38.90,yin,,0,0,0,,那样我可能就要重绘整个视图\\N{\\fs12}because I probably have to re-draw my whole thing\r\nDialogue: 0,0:54:38.91,0:54:40.46,yin,,0,0,0,,显示更小的方块\\N{\\fs12}to have smaller squares, right?\r\nDialogue: 0,0:54:40.46,0:54:41.13,yin,,0,0,0,,或者类似的效果\\N{\\fs12}Or something like that.\r\nDialogue: 0,0:54:41.45,0:54:42.96,yin,,0,0,0,,很棒 值得实现\\N{\\fs12}Which is cool, be great to do,\r\nDialogue: 0,0:54:42.96,0:54:45.09,yin,,0,0,0,,但是时间有限 我就不做了\\N{\\fs12}but just with time constraints I'm not going to do that.\r\nDialogue: 0,0:54:45.51,0:54:48.51,yin,,0,0,0,,让frame的大小等于这个DROP_SIZE\\N{\\fs12}So I'm going to have the frame size be this drop size.\r\nDialogue: 0,0:54:48.52,0:54:51.02,yin,,0,0,0,,我是在创建一个小的掉落视图\\N{\\fs12}So I'm creating a little drop view, okay,\r\nDialogue: 0,0:54:51.02,0:54:52.42,yin,,0,0,0,,我想让它的大小是这样的\\N{\\fs12}and that's the size I want it to be.\r\nDialogue: 0,0:54:52.67,0:54:54.79,yin,,0,0,0,,然后设置随机...\\N{\\fs12}So here I'll do my random--\r\nDialogue: 0,0:54:54.80,0:54:57.03,yin,,0,0,0,,我们这样做吧\\N{\\fs12}actually let's go ahead and do this...\r\nDialogue: 0,0:54:58.06,0:55:01.04,yin,,0,0,0,,转到这里\\N{\\fs12}let's go to here.\r\nDialogue: 0,0:55:02.04,0:55:06.64,yin,,0,0,0,,在x轴上随机选取一点\\N{\\fs12}Let's go just pick a random place along the x axis,\r\nDialogue: 0,0:55:06.64,0:55:11.81,yin,,0,0,0,,用arc4random 然后取模于\\N{\\fs12}so I'm going to do arc4random, and we're going to mod\r\nDialogue: 0,0:55:11.81,0:55:18.09,yin,,0,0,0,,self.gameView.bounds.size.width\\N{\\fs12}that by the self dot gameView dot bounds dot size dot width,\r\nDialogue: 0,0:55:18.23,0:55:22.44,yin,,0,0,0,,得到x轴上的随机一点\\N{\\fs12}so somewhere along some random spot along there.\r\nDialogue: 0,0:55:23.09,0:55:27.26,yin,,0,0,0,,我还要让它们排列起来\\N{\\fs12}And I'm also going to make it be lined up\r\nDialogue: 0,0:55:27.47,0:55:29.84,yin,,0,0,0,,这样掉落的方块就是在格子里\\N{\\fs12}so the drops are, you know, in a grid.\r\nDialogue: 0,0:55:30.20,0:55:32.98,yin,,0,0,0,,直接除以DROP_SIZE.width\\N{\\fs12}So I'm just going to divide by the DROP_SIZE dot width,\r\nDialogue: 0,0:55:33.34,0:55:36.11,yin,,0,0,0,,然后做乘法\\N{\\fs12}and then I'm going to multiply by saying\r\nDialogue: 0,0:55:37.04,0:55:43.24,yin,,0,0,0,,frame.origin.x=x*DROP_SIZE.width\\N{\\fs12}frame dot origin dot x equals x times DROP_SIZE dot width,\r\nDialogue: 0,0:55:43.24,0:55:46.80,yin,,0,0,0,,我这里用了除法 这是一个整数\\N{\\fs12}so you see here, I've divided it here, this is an int,\r\nDialogue: 0,0:55:46.82,0:55:49.06,yin,,0,0,0,,这样就会排列在一行上\\N{\\fs12}so it's basically going to do a floor, right?\r\nDialogue: 0,0:55:49.08,0:55:52.61,yin,,0,0,0,,我选择了一个整数 然后乘回去\\N{\\fs12}I've picked an int and just multiply it back,\r\nDialogue: 0,0:55:52.62,0:55:55.24,yin,,0,0,0,,将它放在了一个随机点上\\N{\\fs12}that puts it at a random spot across,\r\nDialogue: 0,0:55:55.68,0:55:58.59,yin,,0,0,0,,然后创建一个视图 方法是\\N{\\fs12}and then I create a view just by saying\r\nDialogue: 0,0:55:58.67,0:56:05.73,yin,,0,0,0,,dropView=[UIView alloc] initWithFrame\\N{\\fs12}dropView equals UIView alloc initWithFrame,\r\nDialogue: 0,0:56:06.10,0:56:08.92,yin,,0,0,0,,这是视图的指定初始化方法\\N{\\fs12}which is the designated initializer for view,\r\nDialogue: 0,0:56:08.95,0:56:12.53,yin,,0,0,0,,指定这个frame 然后...\\N{\\fs12}and I'll specify this frame, and then I'm just going--\r\nDialogue: 0,0:56:12.55,0:56:16.24,yin,,0,0,0,,我要将dropView的背景色\\N{\\fs12}I'm going to set the dropView's background color\r\nDialogue: 0,0:56:16.25,0:56:18.09,yin,,0,0,0,,设为随机色\\N{\\fs12}to be a random color.\r\nDialogue: 0,0:56:20.05,0:56:23.91,yin,,0,0,0,,我正好有randomColor方法的代码\\N{\\fs12}Okay, I happen to have a little snippet for that, randomColor.\r\nDialogue: 0,0:56:24.53,0:56:27.36,yin,,0,0,0,,randomColor是从这五个颜色中随机选择一个\\N{\\fs12}Okay, so randomColor just picks one of five random colors,\r\nDialogue: 0,0:56:27.56,0:56:28.98,yin,,0,0,0,,这五个\\N{\\fs12}okay, right here.\r\nDialogue: 0,0:56:31.10,0:56:32.71,yin,,0,0,0,,然后再加上\\N{\\fs12}And then let's just go ahead\r\nDialogue: 0,0:56:32.72,0:56:36.43,yin,,0,0,0,,self.gameView addSubview:dropView\\N{\\fs12}and self dot gameView, addSubview, dropView.\r\nDialogue: 0,0:56:38.76,0:56:42.26,yin,,0,0,0,,想要实现掉落方块就是这么简单\\N{\\fs12}Okay? So it's as simple as that to drop something on here,\r\nDialogue: 0,0:56:42.26,0:56:44.84,yin,,0,0,0,,如果我没忘记步骤 都做对了的话\\N{\\fs12}so unless I've forgotten something or doing something wrong,\r\nDialogue: 0,0:56:44.85,0:56:46.26,yin,,0,0,0,,我们运行一下\\N{\\fs12}let's go ahead and run.\r\nDialogue: 0,0:56:47.11,0:56:50.47,yin,,0,0,0,,每点击一下 就会出现一个方块 很好\\N{\\fs12}Every time I tap, we get another one, so that's great.\r\nDialogue: 0,0:56:50.59,0:56:52.75,yin,,0,0,0,,都堆积在顶部 不错\\N{\\fs12}They're collecting at the top. That's nice.\r\nDialogue: 0,0:56:52.93,0:56:55.52,yin,,0,0,0,,现在我们添加重力 让它们掉下来\\N{\\fs12}Now we're going to add some gravity so that they fall down.\r\nDialogue: 0,0:56:56.53,0:56:58.86,yin,,0,0,0,,为它们添加动画 让它们掉落下来\\N{\\fs12}Okay? Animated, so they fall down.\r\nDialogue: 0,0:56:59.48,0:57:00.86,yin,,0,0,0,,怎么做呢\\N{\\fs12}So how do we do that?\r\nDialogue: 0,0:57:00.86,0:57:03.47,yin,,0,0,0,,非常简单 只要新建一个动画者\\N{\\fs12}Very simple, we're just going to create an animator,\r\nDialogue: 0,0:57:04.49,0:57:08.85,yin,,0,0,0,,添加一个属性 strong nonatomic\\N{\\fs12}have a property which is strong nonatomic,\r\nDialogue: 0,0:57:08.93,0:57:11.27,yin,,0,0,0,,是一个UIDynamicAnimator\\N{\\fs12}which is a UIDynamicAnimator,\r\nDialogue: 0,0:57:12.34,0:57:16.45,yin,,0,0,0,,再添加一个属性 strong nonatomic\\N{\\fs12}and I'm also gonna have a property which is strong, nonatomic,\r\nDialogue: 0,0:57:16.45,0:57:20.08,yin,,0,0,0,,是一个UIGravityBehavior 叫做gravity\\N{\\fs12}which is a gravity behavior, I'll call it gravity.\r\nDialogue: 0,0:57:20.50,0:57:22.42,yin,,0,0,0,,出于某些原因 名字尽量短小\\N{\\fs12}Keeping these names short kind of for a reason,\r\nDialogue: 0,0:57:22.42,0:57:24.46,yin,,0,0,0,,但你也可以叫它gravityBehavior\\N{\\fs12}but you might want to call it gravity behavior.\r\nDialogue: 0,0:57:25.33,0:57:29.62,yin,,0,0,0,,我要在这里加一些延迟实例化\\N{\\fs12}I'm going to go ahead and do some lazy instantiation here,\r\nDialogue: 0,0:57:29.62,0:57:32.65,yin,,0,0,0,,先获取一个动力动画者\\N{\\fs12}so let's get our dynamic animator,\r\nDialogue: 0,0:57:34.39,0:57:37.79,yin,,0,0,0,,如果没有动画者 就创建一个\\N{\\fs12}if not animator, then I want to create one,\r\nDialogue: 0,0:57:38.01,0:57:40.79,yin,,0,0,0,,否则就直接返回它\\N{\\fs12}otherwise I'm going to return it.\r\nDialogue: 0,0:57:42.00,0:57:44.70,yin,,0,0,0,,创建动画者的方法 我刚才讲了\\N{\\fs12}Okay? So as I said when we create the animator,\r\nDialogue: 0,0:57:44.70,0:57:51.21,yin,,0,0,0,,[UIDynamicAnimator alloc] initWithReferenceView\\N{\\fs12}it's just UIDynamicAnimator alloc initWithReferenceView\r\nDialogue: 0,0:57:51.21,0:57:53.74,yin,,0,0,0,,参考视图就是gameView\\N{\\fs12}and the reference view is just our gameView, right?\r\nDialogue: 0,0:57:53.74,0:57:55.82,yin,,0,0,0,,我刚才拖出的那个通用视图\\N{\\fs12}That view that I dragged out, that generic view,\r\nDialogue: 0,0:57:55.82,0:57:57.96,yin,,0,0,0,,参考视图可以是通用视图\\N{\\fs12}it's perfectly fine for that reference view\r\nDialogue: 0,0:57:57.96,0:57:59.08,yin,,0,0,0,,完全没问题\\N{\\fs12}to be a generic view.\r\nDialogue: 0,0:57:59.40,0:58:03.08,yin,,0,0,0,,重力行为这里也类似\\N{\\fs12}And then the gravity one similar kind of deal,\r\nDialogue: 0,0:58:03.33,0:58:07.01,yin,,0,0,0,,如果没有动力行为 就创建一个\\N{\\fs12}if the gravity is not set, then we'll create it\r\nDialogue: 0,0:58:07.74,0:58:08.91,yin,,0,0,0,,有的话就直接返回\\N{\\fs12}and we'll return it,\r\nDialogue: 0,0:58:09.74,0:58:12.30,yin,,0,0,0,,创建重力行为的方法非常简单\\N{\\fs12}and creating a gravity thing is very simple,\r\nDialogue: 0,0:58:12.30,0:58:16.50,yin,,0,0,0,,_gravity=[[UIGravityBehavior alloc] init]\\N{\\fs12}we just say gravity equals UIGravityBehavior alloc init.\r\nDialogue: 0,0:58:17.30,0:58:19.23,yin,,0,0,0,,这里我还要做一个操作\\N{\\fs12}Okay? I'm going to do one other thing here too\r\nDialogue: 0,0:58:19.25,0:58:22.63,yin,,0,0,0,,self.animator addBehavior\\N{\\fs12}is I'm going to say self dot animator addBehavior.\r\nDialogue: 0,0:58:24.87,0:58:27.55,yin,,0,0,0,,只要有人请求重力行为\\N{\\fs12}Okay? So any time someone asks me for the gravity thing,\r\nDialogue: 0,0:58:27.56,0:58:29.23,yin,,0,0,0,,我就会将它加到动画者中\\N{\\fs12}I'm going to add it to my animator.\r\nDialogue: 0,0:58:29.25,0:58:31.18,yin,,0,0,0,,这部分只会执行一次\\N{\\fs12}This is going to only happen once, right?\r\nDialogue: 0,0:58:31.20,0:58:32.69,yin,,0,0,0,,因为这是延迟实例化\\N{\\fs12}Because this is my lazy instantiator,\r\nDialogue: 0,0:58:32.70,0:58:34.12,yin,,0,0,0,,很好 我想要的就是这样\\N{\\fs12}so that's good, that's exactly what I want.\r\nDialogue: 0,0:58:34.51,0:58:36.32,yin,,0,0,0,,还可以在这里面设置其他内容\\N{\\fs12}I could also in here set things\r\nDialogue: 0,0:58:36.32,0:58:39.36,yin,,0,0,0,,比如重力大小magnitude\\N{\\fs12}like the gravity's magnitude, right?\r\nDialogue: 0,0:58:39.36,0:58:43.16,yin,,0,0,0,,我可以不用1.0 设一个小点的重力大小\\N{\\fs12}So I could say light gravity instead of 1.0,\r\nDialogue: 0,0:58:43.18,0:58:45.62,yin,,0,0,0,,稍微轻一点\\N{\\fs12}a little lighter or whatever. Okay?\r\nDialogue: 0,0:58:46.76,0:58:50.55,yin,,0,0,0,,现在我有了动画者和重力行为\\N{\\fs12}So now I have an animator, I have a gravity behavior,\r\nDialogue: 0,0:58:50.68,0:58:53.95,yin,,0,0,0,,现在我只要将我刚才创建的dropView\\N{\\fs12}all I need to do now is add this dropView,\r\nDialogue: 0,0:58:54.08,0:58:56.12,yin,,0,0,0,,添加进来就可以了\\N{\\fs12}okay, that I created to that,\r\nDialogue: 0,0:58:56.15,0:59:01.34,yin,,0,0,0,,self.gravity addItem:dropView\\N{\\fs12}so I'm just going to say self dot gravity addItem, my dropView.\r\nDialogue: 0,0:59:02.77,0:59:05.96,yin,,0,0,0,,做完这一步之后\\N{\\fs12}Okay? So now that the instant I do that\r\nDialogue: 0,0:59:05.98,0:59:07.05,yin,,0,0,0,,动画立刻就会开始\\N{\\fs12}it's going to start animating.\r\nDialogue: 0,0:59:07.18,0:59:08.34,yin,,0,0,0,,我们来看一下\\N{\\fs12}So let's take a look at that.\r\nDialogue: 0,0:59:09.57,0:59:13.26,yin,,0,0,0,,可以看到 随着我的点击 动画马上开始运行\\N{\\fs12}So you can see as I click they immediately start animating.\r\nDialogue: 0,0:59:15.09,0:59:15.53,yin,,0,0,0,,看到了吗\\N{\\fs12}Okay?\r\nDialogue: 0,0:59:16.92,0:59:18.63,yin,,0,0,0,,抱歉 跑掉了\\N{\\fs12}And sorry,\r\nDialogue: 0,0:59:20.15,0:59:23.53,yin,,0,0,0,,现在它们直接掉出屏幕了 是吧\\N{\\fs12}but they're falling off the bottom, okay?\r\nDialogue: 0,0:59:23.72,0:59:25.92,yin,,0,0,0,,这可不好 我希望它们堆积在底部\\N{\\fs12}So that's not so good, I want them to stop at the bottom.\r\nDialogue: 0,0:59:25.92,0:59:30.15,yin,,0,0,0,,为此我只需要一个碰撞行为 非常简单\\N{\\fs12}So to do that, I just need a collision behavior, very easy,\r\nDialogue: 0,0:59:30.15,0:59:35.04,yin,,0,0,0,,在上面这里加上property (strong, nonatomic)\\N{\\fs12}just go up here, property, strong, nonatomic,\r\nDialogue: 0,0:59:35.04,0:59:39.42,yin,,0,0,0,,UICollisionBehavior 我要叫它collider\\N{\\fs12}UICollisionBehavior, collider, I'm going to call it.\r\nDialogue: 0,0:59:40.23,0:59:41.70,yin,,0,0,0,,在collider里\\N{\\fs12}And my collider,\r\nDialogue: 0,0:59:45.94,0:59:51.09,yin,,0,0,0,,如果没有设置collider 我就会创建一个\\N{\\fs12}if my collider is not set, then I'll set it,\r\nDialogue: 0,0:59:52.18,0:59:53.70,yin,,0,0,0,,如果有就直接返回\\N{\\fs12}return the collider,\r\nDialogue: 0,0:59:53.81,0:59:56.02,yin,,0,0,0,,这段代码我真应该提前敲好\\N{\\fs12}I really should have a snippet for that kind of thing.\r\nDialogue: 0,0:59:56.35,0:59:58.53,yin,,0,0,0,,周五讲座的时候约翰应该演示过了吧\\N{\\fs12}I think Johan showed that in the Friday section.\r\nDialogue: 0,0:59:59.63,1:00:04.12,yin,,0,0,0,,_collider=[[UICollisionBehavior alloc] init]\\N{\\fs12}So that equals UICollisionBehavior alloc init,\r\nDialogue: 0,1:00:04.50,1:00:12.07,yin,,0,0,0,,这里我还要将bounds设为YES\\N{\\fs12}and here I'm also going to set the bounds to yes.\r\nDialogue: 0,1:00:12.07,1:00:15.16,yin,,0,0,0,,我要让这个collider用参考视图的bounds\\N{\\fs12}So I'm going to have this collider use the bounds\r\nDialogue: 0,1:00:15.16,1:00:17.75,yin,,0,0,0,,作为自己的bounds\\N{\\fs12}of the reference view as its bounds, okay,\r\nDialogue: 0,1:00:17.77,1:00:19.66,yin,,0,0,0,,一行代码就够了\\N{\\fs12}so it's a one line thing to get that in there,\r\nDialogue: 0,1:00:19.67,1:00:22.65,yin,,0,0,0,,但是我还可以加上一个UIBezierPath\\N{\\fs12}but I could make, you know, a nice UIBezierPath,\r\nDialogue: 0,1:00:23.00,1:00:25.88,yin,,0,0,0,,沿着底部放置\\N{\\fs12}you know, like down along the bottom, whatever I want,\r\nDialogue: 0,1:00:25.88,1:00:27.63,yin,,0,0,0,,但是这里用这个translation\\N{\\fs12}but it suits my purposes here\r\nDialogue: 0,1:00:27.65,1:00:30.64,yin,,0,0,0,,就可以满足我的需求了\\N{\\fs12}just to use the whole translation,\r\nDialogue: 0,1:00:30.65,1:00:32.23,yin,,0,0,0,,这里也是一样的\\N{\\fs12}and I'm going to do the same thing here,\r\nDialogue: 0,1:00:32.42,1:00:36.01,yin,,0,0,0,,self.animator addBehavior: _collider\\N{\\fs12}self dot animator addBehavior, this collider.\r\nDialogue: 0,1:00:36.70,1:00:38.73,yin,,0,0,0,,这样它就添加到了动画者中\\N{\\fs12}Okay, so it gets added to the animator.\r\nDialogue: 0,1:00:39.39,1:00:43.51,yin,,0,0,0,,这里也需要将\\N{\\fs12}So again, I need to add any items\r\nDialogue: 0,1:00:43.52,1:00:45.87,yin,,0,0,0,,受collider影响的动力项\\N{\\fs12}that I want to be affected by the collider\r\nDialogue: 0,1:00:48.52,1:00:50.09,yin,,0,0,0,,添加到collider中\\N{\\fs12}to the collider, and now it's going to--\r\nDialogue: 0,1:00:50.16,1:00:51.36,yin,,0,0,0,,这样做之后\\N{\\fs12}as soon as I do that,\r\nDialogue: 0,1:00:51.57,1:00:53.73,yin,,0,0,0,,如果有东西撞到了它 就会运行碰撞动画\\N{\\fs12}if something hit it, it would start colliding.\r\nDialogue: 0,1:00:54.36,1:00:55.77,yin,,0,0,0,,我们看一下\\N{\\fs12}Alright? So let's take a look at that.\r\nDialogue: 0,1:00:57.23,1:00:58.32,yin,,0,0,0,,它们掉到底部停下来了\\N{\\fs12}Okay, so hopefully the drop,\r\nDialogue: 0,1:00:58.33,1:01:00.74,yin,,0,0,0,,注意 它们反跳了一下\\N{\\fs12}notice they have a little bounce to them,\r\nDialogue: 0,1:01:00.76,1:01:01.80,yin,,0,0,0,,稍微跳起来了一点\\N{\\fs12}a little bounce in their step.\r\nDialogue: 0,1:01:04.74,1:01:06.61,yin,,0,0,0,,注意 它们斜了一点\\N{\\fs12}Now notice that they tilt a little.\r\nDialogue: 0,1:01:07.03,1:01:08.00,yin,,0,0,0,,为什么会这样\\N{\\fs12}Okay. Why does that happen?\r\nDialogue: 0,1:01:08.00,1:01:10.78,yin,,0,0,0,,两个方块落到下面的时候\\N{\\fs12}Well, on the way down, the two they landed,\r\nDialogue: 0,1:01:10.79,1:01:12.52,yin,,0,0,0,,一个弹起来 另一个撞到了它\\N{\\fs12}one was bouncing and the next one hit it,\r\nDialogue: 0,1:01:12.54,1:01:15.46,yin,,0,0,0,,就会有一点现实的反作用力\\N{\\fs12}and there was a little bit of real world bounce to it.\r\nDialogue: 0,1:01:15.76,1:01:18.51,yin,,0,0,0,,如果我们做的是俄罗斯方块\\N{\\fs12}Now, probably if we're building a Tetris game,\r\nDialogue: 0,1:01:18.52,1:01:21.60,yin,,0,0,0,,我们并不想让它旋转 偏离中心\\N{\\fs12}we don't want them to rotate and get off center like that,\r\nDialogue: 0,1:01:21.79,1:01:25.85,yin,,0,0,0,,所以我们可以禁用旋转\\N{\\fs12}so we would have to A, not allow rotation probably\r\nDialogue: 0,1:01:26.22,1:01:28.18,yin,,0,0,0,,或者用对它们进行网格排列\\N{\\fs12}and B, we might want to grid them up.\r\nDialogue: 0,1:01:28.19,1:01:30.41,yin,,0,0,0,,示例中可能讲不到了\\N{\\fs12}I don't think we're going to get that in the demo,\r\nDialogue: 0,1:01:30.59,1:01:32.26,yin,,0,0,0,,周三我可能会讲一下\\N{\\fs12}but maybe on Wednesday I'll get to that,\r\nDialogue: 0,1:01:32.26,1:01:34.47,yin,,0,0,0,,我会告诉大家实际上要怎么做\\N{\\fs12}I'll post how you would actually do that.\r\nDialogue: 0,1:01:34.56,1:01:37.10,yin,,0,0,0,,我们要做的就是 当它们碰撞时\\N{\\fs12}Okay? And all we're going to do is when they collide,\r\nDialogue: 0,1:01:37.12,1:01:39.20,yin,,0,0,0,,让它们排列对齐\\N{\\fs12}we're going to have them line themselves up.\r\nDialogue: 0,1:01:39.74,1:01:41.80,yin,,0,0,0,,我们会在周三讲到这部分\\N{\\fs12}Okay? So we'll do that later on Wednesday.\r\nDialogue: 0,1:01:42.97,1:01:47.99,yin,,0,0,0,,注意 这两个行为关系紧密\\N{\\fs12}Okay, notice that I have these two very related behaviors,\r\nDialogue: 0,1:01:48.22,1:01:49.29,yin,,0,0,0,,重力和碰撞行为\\N{\\fs12}gravity and collider.\r\nDialogue: 0,1:01:49.29,1:01:50.44,yin,,0,0,0,,它们常一同出现\\N{\\fs12}They really go together.\r\nDialogue: 0,1:01:50.72,1:01:52.93,yin,,0,0,0,,这里我们要\\N{\\fs12}Okay? So this is where I might want\r\nDialogue: 0,1:01:52.93,1:01:55.52,yin,,0,0,0,,创建一个自定义行为\\N{\\fs12}to create a custom UI behavior.\r\nDialogue: 0,1:01:55.52,1:01:56.61,yin,,0,0,0,,我们来快速做一下\\N{\\fs12}So let's do that real quick.\r\nDialogue: 0,1:01:56.62,1:02:00.53,yin,,0,0,0,,在文件菜单下选择新建文件 新建一个类\\N{\\fs12}I'm just going to go file, new file, okay, new class,\r\nDialogue: 0,1:02:00.67,1:02:04.44,yin,,0,0,0,,这个类是一个UIDynamicBehavior\\N{\\fs12}and this class is going to be a UIDynamicBehavior.\r\nDialogue: 0,1:02:07.76,1:02:09.65,yin,,0,0,0,,我要叫它DropitBehavior\\N{\\fs12}And I'm going to call it the DropitBehavior.\r\nDialogue: 0,1:02:10.42,1:02:13.71,yin,,0,0,0,,这是我新建的一个行为\\N{\\fs12}Okay? And that is going to be a new behavior I'm creating\r\nDialogue: 0,1:02:13.72,1:02:15.57,yin,,0,0,0,,包括重力行为和碰撞行为\\N{\\fs12}that's going to have the gravity and the collider\r\nDialogue: 0,1:02:15.58,1:02:18.67,yin,,0,0,0,,以及其他行为等子行为\\N{\\fs12}and eventually some more things as child behaviors.\r\nDialogue: 0,1:02:18.95,1:02:21.87,yin,,0,0,0,,点击下一步 选择保存位置\\N{\\fs12}Okay? So let's hit next, where we want to put it,\r\nDialogue: 0,1:02:21.89,1:02:24.68,yin,,0,0,0,,很好 出来了\\N{\\fs12}this is all good, here it is.\r\nDialogue: 0,1:02:24.69,1:02:26.39,yin,,0,0,0,,这就是我的DropitBehavior\\N{\\fs12}Okay? Here's my DropitBehavior,\r\nDialogue: 0,1:02:26.91,1:02:29.96,yin,,0,0,0,,在这个DropitBehavior中\\N{\\fs12}and all I'm going to do in this DropitBehavior\r\nDialogue: 0,1:02:29.98,1:02:32.08,yin,,0,0,0,,我要定义两个方法\\N{\\fs12}is I'm going to define a couple of methods here,\r\nDialogue: 0,1:02:32.09,1:02:35.91,yin,,0,0,0,,addItem方法允许添加UIDynamicItem\\N{\\fs12}addItem, which allows you to add UIDynamicItem,\r\nDialogue: 0,1:02:37.70,1:02:40.71,yin,,0,0,0,,注意这里我用了协议的语法\\N{\\fs12}notice I'm using this protocol syntax,\r\nDialogue: 0,1:02:41.11,1:02:43.10,yin,,0,0,0,,还要添加一个移除动力项的方法\\N{\\fs12}and then I'm also going to let you remove an item.\r\nDialogue: 0,1:02:45.58,1:02:47.72,yin,,0,0,0,,在DropitBehavior中 我就要实现这些方法\\N{\\fs12}And that's all I'm gonna implement in my DropitBehavior\r\nDialogue: 0,1:02:47.73,1:02:49.95,yin,,0,0,0,,但我要重写它的初始化方法\\N{\\fs12}except for I'm going to override its init.\r\nDialogue: 0,1:02:50.52,1:02:52.98,yin,,0,0,0,,我要在init中做什么呢\\N{\\fs12}Okay, so what am I going to do in its init?\r\nDialogue: 0,1:02:52.98,1:02:56.10,yin,,0,0,0,,instancetype init\\N{\\fs12}So instancetype, init,\r\nDialogue: 0,1:02:56.71,1:02:58.65,yin,,0,0,0,,self=[super init]\\N{\\fs12}I'm going to do self equals super init,\r\nDialogue: 0,1:02:58.66,1:03:02.03,yin,,0,0,0,,这是UIDynamicBehavior的init方法\\N{\\fs12}so that's UIDynamicBehavior's init.\r\nDialogue: 0,1:03:03.64,1:03:08.23,yin,,0,0,0,,然后是return self\\N{\\fs12}Alright? And then return self,\r\nDialogue: 0,1:03:09.69,1:03:10.84,yin,,0,0,0,,在中间这里\\N{\\fs12}and then in between here\r\nDialogue: 0,1:03:10.86,1:03:15.36,yin,,0,0,0,,我只要添加子行为\\N{\\fs12}all I'm gonna do is add child behaviors\r\nDialogue: 0,1:03:16.46,1:03:17.99,yin,,0,0,0,,重力行为gravity和碰撞行为collider\\N{\\fs12}for the gravity and the collider,\r\nDialogue: 0,1:03:17.99,1:03:19.64,yin,,0,0,0,,我就直接复制粘贴了\\N{\\fs12}which I'm actually going to copy and paste.\r\nDialogue: 0,1:03:20.05,1:03:21.10,yin,,0,0,0,,省点时间\\N{\\fs12}Save ourselves a little time,\r\nDialogue: 0,1:03:21.10,1:03:26.83,yin,,0,0,0,,这是它们的延迟实例化\\N{\\fs12}here's nice little lazy instantiation of these,\r\nDialogue: 0,1:03:27.18,1:03:30.21,yin,,0,0,0,,我们... 点错了\\N{\\fs12}and let's go grab the-- oops,\r\nDialogue: 0,1:03:30.98,1:03:36.49,yin,,0,0,0,,复制它们的输出口 加到这里\\N{\\fs12}let's grab the outlets for these, add those.\r\nDialogue: 0,1:03:37.17,1:03:39.62,yin,,0,0,0,,抱歉 我一直点错\\N{\\fs12}Oops, sorry, I keep clicking on the wrong button.\r\nDialogue: 0,1:03:39.62,1:03:43.75,yin,,0,0,0,,这里加上@interface DropitBehavior()\\N{\\fs12}Okay, so this is at sign interface, DropitBehavior,\r\nDialogue: 0,1:03:44.57,1:03:46.64,yin,,0,0,0,,粘贴到这里\\N{\\fs12}oops, paste, hello, paste.\r\nDialogue: 0,1:03:47.38,1:03:49.24,yin,,0,0,0,,粘贴好了 很好\\N{\\fs12}And okay so we've got those, that's good.\r\nDialogue: 0,1:03:49.32,1:03:51.59,yin,,0,0,0,,至于这行代码 我们不用再将它添加到动画者中了\\N{\\fs12}These lines, we're not going to add it to the animator\r\nDialogue: 0,1:03:51.70,1:03:54.12,yin,,0,0,0,,因为我们要把整个行为添加到动画者中\\N{\\fs12}because we're going to add this whole behavior to the animator,\r\nDialogue: 0,1:03:54.12,1:03:55.21,yin,,0,0,0,,所以我们可以删掉这两行代码\\N{\\fs12}so we can get rid of those.\r\nDialogue: 0,1:03:56.30,1:03:59.67,yin,,0,0,0,,把addItem放到这里\\N{\\fs12}And in addItem, which we'll put right here.\r\nDialogue: 0,1:03:59.79,1:04:02.07,yin,,0,0,0,,我们就直接复制粘贴\\N{\\fs12}Actually let's go ahead and copy and paste\r\nDialogue: 0,1:04:02.08,1:04:03.39,yin,,0,0,0,,这两个方法\\N{\\fs12}these two things that we want.\r\nDialogue: 0,1:04:04.09,1:04:05.61,yin,,0,0,0,,addItem和removeItem\\N{\\fs12}AddItem and removeItem.\r\nDialogue: 0,1:04:07.53,1:04:09.06,yin,,0,0,0,,这里我要做的就是\\N{\\fs12}Okay, all I need to do here\r\nDialogue: 0,1:04:09.23,1:04:12.56,yin,,0,0,0,,将它们添加到子行为中\\N{\\fs12}is add them to each of my sub behaviors,\r\nDialogue: 0,1:04:12.77,1:04:15.36,yin,,0,0,0,,用addItem将动力项添加到gravity中\\N{\\fs12}so I'll do addItem to my gravity\r\nDialogue: 0,1:04:15.44,1:04:18.71,yin,,0,0,0,,添加到collider中\\N{\\fs12}and addItem to my collider.\r\nDialogue: 0,1:04:19.80,1:04:21.67,yin,,0,0,0,,移除动力项也是一样的\\N{\\fs12}And I'll do the same thing for remove.\r\nDialogue: 0,1:04:24.95,1:04:27.34,yin,,0,0,0,,但是这里要改成remove\\N{\\fs12}Okay, except we want this to be remove.\r\nDialogue: 0,1:04:28.75,1:04:31.94,yin,,0,0,0,,这是一个常见的模式\\N{\\fs12}Okay. So this s a common pattern here, you know,\r\nDialogue: 0,1:04:31.94,1:04:36.64,yin,,0,0,0,,你创建一个动力行为\\N{\\fs12}you create basically a dynamic behavior\r\nDialogue: 0,1:04:36.72,1:04:39.35,yin,,0,0,0,,添加子行为等等\\N{\\fs12}that has child behaviors and in the add,\r\nDialogue: 0,1:04:39.37,1:04:41.27,yin,,0,0,0,,可以用addItem\\N{\\fs12}I mean you also have addItems,\r\nDialogue: 0,1:04:41.29,1:04:43.17,yin,,0,0,0,,或者initWithItem等等\\N{\\fs12}you might have initWithItem, whatever,\r\nDialogue: 0,1:04:43.43,1:04:46.33,yin,,0,0,0,,然后在这里 添加子行为\\N{\\fs12}and then here, we're going to add child behaviors,\r\nDialogue: 0,1:04:46.94,1:04:52.85,yin,,0,0,0,,gravity和collider\\N{\\fs12}the gravity and the collider.\r\nDialogue: 0,1:04:53.55,1:04:56.26,yin,,0,0,0,,我们新建了一个类\\N{\\fs12}Okay? So we've created a new class here,\r\nDialogue: 0,1:04:56.50,1:04:58.87,yin,,0,0,0,,它是UIDynamicBehavior的一个子类\\N{\\fs12}it's a sub-class of UIDynamicBehavior.\r\nDialogue: 0,1:04:58.95,1:05:00.40,yin,,0,0,0,,我们可以向其添加动力项\\N{\\fs12}We can add items to it,\r\nDialogue: 0,1:05:00.46,1:05:03.21,yin,,0,0,0,,与向gravity和collider添加动力项是一样的\\N{\\fs12}just like we added items to our gravity and our collider,\r\nDialogue: 0,1:05:03.43,1:05:07.03,yin,,0,0,0,,它的实现就是添加子行为\\N{\\fs12}and its implementation is merely to have a sub,\r\nDialogue: 0,1:05:07.07,1:05:10.61,yin,,0,0,0,,这些子行为\\N{\\fs12}these little sub behaviors.\r\nDialogue: 0,1:05:11.39,1:05:12.68,yin,,0,0,0,,非常简单\\N{\\fs12}Okay? Very, very simple.\r\nDialogue: 0,1:05:12.69,1:05:14.52,yin,,0,0,0,,回到控制器\\N{\\fs12}And we go back to our controller here,\r\nDialogue: 0,1:05:14.64,1:05:17.66,yin,,0,0,0,,这里不再需要用单独的行为\\N{\\fs12}we need to, instead of having the individual ones,\r\nDialogue: 0,1:05:17.67,1:05:19.96,yin,,0,0,0,,只要添加一个自定义行为就可以了\\N{\\fs12}now we're just going to have a drop it--\r\nDialogue: 0,1:05:21.61,1:05:25.25,yin,,0,0,0,,#import DropitBehavior\\N{\\fs12}sorry, pound sign import, DropitBehavior.\r\nDialogue: 0,1:05:26.60,1:05:28.31,yin,,0,0,0,,添加一个DropitBehavior\\N{\\fs12}It's going to have a DropitBehavior,\r\nDialogue: 0,1:05:32.60,1:05:35.92,yin,,0,0,0,,这里也用延迟实例化\\N{\\fs12}okay, we'll put a little lazy instantiation for this one too.\r\nDialogue: 0,1:05:48.90,1:05:49.88,yin,,0,0,0,,这里的alloc/init\\N{\\fs12}so there's alloc init,\r\nDialogue: 0,1:05:49.90,1:05:52.12,yin,,0,0,0,,会调用我们刚才编写的那个init方法\\N{\\fs12}that's going to call that other init that we just did.\r\nDialogue: 0,1:05:52.43,1:05:57.11,yin,,0,0,0,,self.animator addBehavior:_dropitBehavior\\N{\\fs12}We'll do self dot animator addBehavior our dropitBehavior,\r\nDialogue: 0,1:05:58.56,1:06:01.54,yin,,0,0,0,,然后只要返回_dropitBehavior\\N{\\fs12}alright, and then we'll just return our dropitBehavior\r\nDialogue: 0,1:06:01.54,1:06:02.28,yin,,0,0,0,,就像这样\\N{\\fs12}like that.\r\nDialogue: 0,1:06:02.66,1:06:06.24,yin,,0,0,0,,这里不用再两次添加动力项了\\N{\\fs12}And now, down here, we don't have to add these separately,\r\nDialogue: 0,1:06:06.24,1:06:10.46,yin,,0,0,0,,直接像这样用dropitBehavior addItem就可以了\\N{\\fs12}we're just gonna say dropitBehavior addItem like that.\r\nDialogue: 0,1:06:11.17,1:06:12.39,yin,,0,0,0,,大家明白了吗\\N{\\fs12}Okay? So everyone understand how we kind of\r\nDialogue: 0,1:06:12.41,1:06:13.83,yin,,0,0,0,,我们是如何组合行为的\\N{\\fs12}grouped all that stuff over there?\r\nDialogue: 0,1:06:13.96,1:06:17.42,yin,,0,0,0,,随着演示的进行 我们还会向这个dropitBehavior中\\N{\\fs12}And we're going to add more things as this demo goes on\r\nDialogue: 0,1:06:17.60,1:06:20.24,yin,,0,0,0,,添加更多内容\\N{\\fs12}to this kind of general dropitBehavior,\r\nDialogue: 0,1:06:20.32,1:06:22.51,yin,,0,0,0,,现在我们会将它们都加到另一个类中\\N{\\fs12}and we're going to add them over in that other class now.\r\nDialogue: 0,1:06:22.61,1:06:24.87,yin,,0,0,0,,我们还会添加这里的其他行为\\N{\\fs12}We're still going to add other behaviors that we add here,\r\nDialogue: 0,1:06:24.88,1:06:26.47,yin,,0,0,0,,并不是另一个类的内容\\N{\\fs12}that really aren't part of that other thing,\r\nDialogue: 0,1:06:26.80,1:06:29.88,yin,,0,0,0,,但是现在我们把它们都放到一起了\\N{\\fs12}but now we collected that into a nice space over there.\r\nDialogue: 0,1:06:30.41,1:06:32.79,yin,,0,0,0,,希望没出什么问题\\N{\\fs12}So hopefully that didn't break anything,\r\nDialogue: 0,1:06:34.17,1:06:35.45,yin,,0,0,0,,试一下 没有\\N{\\fs12}let's see, it didn't.\r\nDialogue: 0,1:06:35.47,1:06:37.87,yin,,0,0,0,,运行正常 很好\\N{\\fs12}Okay, it's all still working, which is awesome.\r\nDialogue: 0,1:06:38.13,1:06:40.88,yin,,0,0,0,,现在我想做的是\\N{\\fs12}Okay, so now what I want to do is,\r\nDialogue: 0,1:06:40.89,1:06:42.85,yin,,0,0,0,,如果像这样填满一行\\N{\\fs12}when I get a full row like that,\r\nDialogue: 0,1:06:42.85,1:06:44.98,yin,,0,0,0,,就炸掉这一行\\N{\\fs12}I want it to blow up, okay?\r\nDialogue: 0,1:06:45.16,1:06:48.59,yin,,0,0,0,,我不会用动力动画者来实现这个效果\\N{\\fs12}And I'm going to do the blow up not using a dynamic animator.\r\nDialogue: 0,1:06:48.99,1:06:51.82,yin,,0,0,0,,我要用UIView动画来实现\\N{\\fs12}Okay? I'm going to do that with that UIView animation business.\r\nDialogue: 0,1:06:51.82,1:06:55.08,yin,,0,0,0,,因为我想演示一下 这二者可以混合使用\\N{\\fs12}Because I want to show you how you can mix the two together\r\nDialogue: 0,1:06:55.09,1:06:56.68,yin,,0,0,0,,运行正常\\N{\\fs12}and they'll work fine, okay?\r\nDialogue: 0,1:06:56.69,1:06:57.52,yin,,0,0,0,,我们来做一下\\N{\\fs12}So let's do that.\r\nDialogue: 0,1:06:58.39,1:06:59.99,yin,,0,0,0,,我们要怎么做呢\\N{\\fs12}So how are we going to do that?\r\nDialogue: 0,1:07:00.29,1:07:03.94,yin,,0,0,0,,一个问题是 什么时候\\N{\\fs12}Well, one question is when can I start thinking\r\nDialogue: 0,1:07:03.94,1:07:05.06,yin,,0,0,0,,可以开始考虑执行其他动画\\N{\\fs12}about doing other animation\r\nDialogue: 0,1:07:05.06,1:07:07.13,yin,,0,0,0,,现在动力动画者正在运行\\N{\\fs12}when I've got this dynamic animator going off\r\nDialogue: 0,1:07:07.13,1:07:08.23,yin,,0,0,0,,掌管一切动画\\N{\\fs12}and doing all these things\r\nDialogue: 0,1:07:08.24,1:07:09.98,yin,,0,0,0,,弹跳 碰撞等等\\N{\\fs12}bouncing and colliding and all this stuff.\r\nDialogue: 0,1:07:10.18,1:07:12.39,yin,,0,0,0,,答案是 可以找到\\N{\\fs12}The answer is you can find out\r\nDialogue: 0,1:07:12.59,1:07:16.27,yin,,0,0,0,,动画者处于静止状态的时刻\\N{\\fs12}when an animator reaches quiescent state,\r\nDialogue: 0,1:07:16.29,1:07:19.11,yin,,0,0,0,,没有弹跳 一切动画都完成了\\N{\\fs12}when nothing is bouncing, everything is resolved.\r\nDialogue: 0,1:07:19.11,1:07:20.82,yin,,0,0,0,,一切安静下来的时候\\N{\\fs12}Okay? When everything is quiet. Okay?\r\nDialogue: 0,1:07:21.12,1:07:24.86,yin,,0,0,0,,方法是使用动画者的委托属性\\N{\\fs12}And you do that using a delegate for the animator.\r\nDialogue: 0,1:07:25.43,1:07:27.06,yin,,0,0,0,,如果我转到动画者\\N{\\fs12}So if I go to animator here,\r\nDialogue: 0,1:07:27.15,1:07:29.78,yin,,0,0,0,,它有一个属性叫做delegate委托\\N{\\fs12}there is a property on animator called delegate.\r\nDialogue: 0,1:07:30.36,1:07:33.09,yin,,0,0,0,,delegate可以发现\\N{\\fs12}And the delegate is an object that's going to find out\r\nDialogue: 0,1:07:33.20,1:07:36.40,yin,,0,0,0,,动画者何时停止 何时再次开始\\N{\\fs12}when the animator stops and when it starts up again.\r\nDialogue: 0,1:07:36.91,1:07:38.54,yin,,0,0,0,,我要将它设为self\\N{\\fs12}And I'm going to set that to be self.\r\nDialogue: 0,1:07:39.13,1:07:40.34,yin,,0,0,0,,这样做之后\\N{\\fs12}Now when I do that,\r\nDialogue: 0,1:07:40.35,1:07:42.11,yin,,0,0,0,,编译器会在这里发出一个警告\\N{\\fs12}I'm going to get a warning from the compiler here.\r\nDialogue: 0,1:07:42.27,1:07:42.96,yin,,0,0,0,,为什么会这样\\N{\\fs12}Why is that?\r\nDialogue: 0,1:07:43.36,1:07:46.23,yin,,0,0,0,,警告说 你将self\\N{\\fs12}It says \"You are assigning self,\"\r\nDialogue: 0,1:07:46.39,1:07:48.06,yin,,0,0,0,,也就是dropit视图控制器\\N{\\fs12}which is a dropit view controller,\r\nDialogue: 0,1:07:48.13,1:07:49.11,yin,,0,0,0,,赋值给了\\N{\\fs12}\"To something that's supposed\r\nDialogue: 0,1:07:49.12,1:07:52.02,yin,,0,0,0,,一个id类型UIDynamicAnimatorDelegate\\N{\\fs12}to be an ID UIDynamicAnimatorDelegate\",\r\nDialogue: 0,1:07:52.28,1:07:53.50,yin,,0,0,0,,换句话说\\N{\\fs12}in other words, you're supposed\r\nDialogue: 0,1:07:53.50,1:07:56.08,yin,,0,0,0,,你应该实现这个动画者委托\\N{\\fs12}to be implementing this UI animator delegate.\r\nDialogue: 0,1:07:56.08,1:07:59.01,yin,,0,0,0,,所以我们要在上面这里说\\N{\\fs12}So we have to go up here and say\r\nDialogue: 0,1:07:59.08,1:08:03.04,yin,,0,0,0,,我们实现了这个UIDynamicAnimatorDelegate\\N{\\fs12}that we implement this UIDynamicAnimatorDelegate.\r\nDialogue: 0,1:08:03.09,1:08:04.69,yin,,0,0,0,,这是我们刚才讲过的协议\\N{\\fs12}This is what we're talking about, protocols\r\nDialogue: 0,1:08:04.86,1:08:06.50,yin,,0,0,0,,表示我们保证做什么\\N{\\fs12}saying that we promised to do something.\r\nDialogue: 0,1:08:07.04,1:08:08.97,yin,,0,0,0,,现在没有警告了\\N{\\fs12}Okay? Now, I'm not getting any more warnings,\r\nDialogue: 0,1:08:08.97,1:08:11.63,yin,,0,0,0,,说明这里没有必须实现的方法\\N{\\fs12}so there must not be any required methods in this,\r\nDialogue: 0,1:08:11.74,1:08:12.91,yin,,0,0,0,,肯定都是可选的\\N{\\fs12}they must all be optional.\r\nDialogue: 0,1:08:13.25,1:08:14.86,yin,,0,0,0,,实际上 它们确实是可选的\\N{\\fs12}And in fact they are all optional,\r\nDialogue: 0,1:08:14.90,1:08:16.20,yin,,0,0,0,,有两个方法\\N{\\fs12}and there's only two of them,\r\nDialogue: 0,1:08:16.23,1:08:20.05,yin,,0,0,0,,我需要的那个叫做dynamicAnimatorDidPause\\N{\\fs12}and the one I want is called dynamicAnimatorDidPause,\r\nDialogue: 0,1:08:20.06,1:08:25.76,yin,,0,0,0,,可以看到 有两个动力动画者委托方法\\N{\\fs12}you can see there's the two dynamic animator delegate methods,\r\nDialogue: 0,1:08:25.79,1:08:29.76,yin,,0,0,0,,dynamicAnimatorDidPause和dynamicAnimatorWillResume\\N{\\fs12}dynamicAnimatorDidPause and dynamicAnimatorWillResume.\r\nDialogue: 0,1:08:30.24,1:08:32.95,yin,,0,0,0,,分别告诉你动画者什么时候停止\\N{\\fs12}Okay, so that's telling you when it reaches a settle state\r\nDialogue: 0,1:08:32.96,1:08:36.23,yin,,0,0,0,,什么时候又出现变化 增加了行为或动力项\\N{\\fs12}and when something changed, a behavior or an item got added,\r\nDialogue: 0,1:08:36.23,1:08:38.34,yin,,0,0,0,,这时动画者又重新开始\\N{\\fs12}and now it's going back active again.\r\nDialogue: 0,1:08:38.80,1:08:41.59,yin,,0,0,0,,在这个例子中 我们想要知道它何时暂停\\N{\\fs12}Okay? So in this case, we want to know the pause.\r\nDialogue: 0,1:08:41.84,1:08:43.79,yin,,0,0,0,,当出现暂停时\\N{\\fs12}Okay? When the pause happens,\r\nDialogue: 0,1:08:43.82,1:08:47.35,yin,,0,0,0,,我会检查最底下一行是否被填满\\N{\\fs12}I'm gonna look at that bottom row and see if it's complete.\r\nDialogue: 0,1:08:47.36,1:08:48.59,yin,,0,0,0,,实际上 我要检查所有行\\N{\\fs12}Actually I'm going to look at all the rows\r\nDialogue: 0,1:08:48.59,1:08:49.75,yin,,0,0,0,,看是否有哪行被填满\\N{\\fs12}and see if any of them are complete.\r\nDialogue: 0,1:08:50.15,1:08:52.42,yin,,0,0,0,,如果填满一行 就炸掉这行\\N{\\fs12}Okay? And if they are, I'm gonna blast them out of there.\r\nDialogue: 0,1:08:53.08,1:08:56.03,yin,,0,0,0,,方法是调用一个方法\\N{\\fs12}So I'm gonna do that by calling a method\r\nDialogue: 0,1:08:56.04,1:08:59.34,yin,,0,0,0,,叫做removeCompletedRows\\N{\\fs12}called removeCompletedRows,\r\nDialogue: 0,1:08:59.93,1:09:02.75,yin,,0,0,0,,我提前做好了 节省点时间\\N{\\fs12}and I have a little snippet for that to speed us up here.\r\nDialogue: 0,1:09:05.11,1:09:07.51,yin,,0,0,0,,就是这个方法\\N{\\fs12}Okay. Here it is right here.\r\nDialogue: 0,1:09:07.72,1:09:09.11,yin,,0,0,0,,我没有全加进来\\N{\\fs12}Okay? I didn't put it all in here.\r\nDialogue: 0,1:09:09.19,1:09:10.96,yin,,0,0,0,,这里写成了removeCompletedRow\\N{\\fs12}Actually removeCompletedRow, I call it,\r\nDialogue: 0,1:09:10.97,1:09:12.06,yin,,0,0,0,,应该是removeCompletedRows\\N{\\fs12}but really should be rows.\r\nDialogue: 0,1:09:13.65,1:09:15.60,yin,,0,0,0,,它是如何工作的呢\\N{\\fs12}And so how does this work?\r\nDialogue: 0,1:09:15.61,1:09:17.51,yin,,0,0,0,,你们可以先听我的\\N{\\fs12}Well, you can take my word for it\r\nDialogue: 0,1:09:17.51,1:09:19.48,yin,,0,0,0,,课下再仔细看\\N{\\fs12}that this little snippet of code,\r\nDialogue: 0,1:09:19.49,1:09:20.65,yin,,0,0,0,,这段代码\\N{\\fs12}and you can go look at it later,\r\nDialogue: 0,1:09:20.75,1:09:24.14,yin,,0,0,0,,基本上是填充了这个可变数组dropsToRemove\\N{\\fs12}it basically just fills this mutable array, dropsToRemove\r\nDialogue: 0,1:09:24.37,1:09:27.64,yin,,0,0,0,,填充的是完整的一行中掉落的方块\\N{\\fs12}with all the drops that are in a completed row,\r\nDialogue: 0,1:09:28.28,1:09:30.11,yin,,0,0,0,,即便有多行\\N{\\fs12}even if there's multiple rows, okay?\r\nDialogue: 0,1:09:30.26,1:09:32.48,yin,,0,0,0,,用的是这个方法hitTest\\N{\\fs12}It does this using this method hitTest.\r\nDialogue: 0,1:09:32.57,1:09:35.84,yin,,0,0,0,,我先检测全部对象\\N{\\fs12}I'm actually looking at all these things\r\nDialogue: 0,1:09:35.85,1:09:38.20,yin,,0,0,0,,看是否有视图 如果有就抓住\\N{\\fs12}and seeing if there's a view there, and if it is, I'm okay.\r\nDialogue: 0,1:09:38.25,1:09:40.30,yin,,0,0,0,,如果得到一整行\\N{\\fs12}And if I get all the way across a row I'm like, okay,\r\nDialogue: 0,1:09:40.31,1:09:42.01,yin,,0,0,0,,就要把这一整行都保存下来\\N{\\fs12}I've got a whole row and I'll keep them all.\r\nDialogue: 0,1:09:42.28,1:09:43.83,yin,,0,0,0,,这就是要移除的方块\\N{\\fs12}So that's what drops to remove.\r\nDialogue: 0,1:09:43.95,1:09:46.42,yin,,0,0,0,,这段代码会用这些信息\\N{\\fs12}This code right here is going to fill in\r\nDialogue: 0,1:09:46.43,1:09:48.08,yin,,0,0,0,,填写dropsToRemove数组\\N{\\fs12}dropsToRemove with all the things.\r\nDialogue: 0,1:09:48.08,1:09:50.95,yin,,0,0,0,,现在我们有了这个数组\\N{\\fs12}Okay, so now we have an array\r\nDialogue: 0,1:09:50.96,1:09:52.62,yin,,0,0,0,,里面是我们想要移除的方块\\N{\\fs12}of the drops that we want to remove.\r\nDialogue: 0,1:09:52.74,1:09:54.32,yin,,0,0,0,,接下来是我们要学习的内容\\N{\\fs12}Now, let's talk about what we're trying to learn here,\r\nDialogue: 0,1:09:54.32,1:09:56.28,yin,,0,0,0,,也就是动画 要怎样移除它们呢\\N{\\fs12}which is animation, how do I remove them?\r\nDialogue: 0,1:09:57.00,1:09:59.50,yin,,0,0,0,,这里我要做的\\N{\\fs12}And what I'm going to do, to do that,\r\nDialogue: 0,1:09:59.52,1:10:02.44,yin,,0,0,0,,分为两步\\N{\\fs12}it's kind of a two-part deal here,\r\nDialogue: 0,1:10:02.62,1:10:06.23,yin,,0,0,0,,首先判断是否有要移除的方块\\N{\\fs12}the first thing I'm gonna say if I have any drops to remove,\r\nDialogue: 0,1:10:08.21,1:10:12.11,yin,,0,0,0,,如果有 就移除全部方块\\N{\\fs12}okay, then I am going to remove all of the drops\r\nDialogue: 0,1:10:12.12,1:10:18.41,yin,,0,0,0,,我要将视图从动画者中移除\\N{\\fs12}that I'm gonna be taking out of this view from the animator,\r\nDialogue: 0,1:10:18.67,1:10:20.40,yin,,0,0,0,,从动力动画者中移除\\N{\\fs12}from the dynamic animator,\r\nDialogue: 0,1:10:20.40,1:10:23.31,yin,,0,0,0,,因为我不希望动力动画者阻挡我的操作\\N{\\fs12}because I don't want the dynamic animator fighting me.\r\nDialogue: 0,1:10:23.95,1:10:27.55,yin,,0,0,0,,我要用UIView动画移除它们\\N{\\fs12}Okay? I'm gonna remove these things using UIView animation,\r\nDialogue: 0,1:10:27.55,1:10:29.49,yin,,0,0,0,,我不希望动画者把它们拉回去\\N{\\fs12}I don't want it trying to pull them back\r\nDialogue: 0,1:10:29.49,1:10:31.10,yin,,0,0,0,,或者重力拉动它\\N{\\fs12}or the gravity pulling on it,\r\nDialogue: 0,1:10:31.38,1:10:32.48,yin,,0,0,0,,我要移除它们\\N{\\fs12}so I'm going to take them out,\r\nDialogue: 0,1:10:32.49,1:10:33.63,yin,,0,0,0,,非常简单\\N{\\fs12}and I'm going to do that very simply\r\nDialogue: 0,1:10:33.64,1:10:38.92,yin,,0,0,0,,self.dropitBehavior removeItem:drop\\N{\\fs12}by just saying self dot dropitBehavior, removeItem, drop.\r\nDialogue: 0,1:10:39.03,1:10:41.07,yin,,0,0,0,,遍历dropsToRemove\\N{\\fs12}Okay? So I'm going through all the drops to remove,\r\nDialogue: 0,1:10:41.18,1:10:43.49,yin,,0,0,0,,将它们逐个从dropitBehavior中移除\\N{\\fs12}and I'm removing them from my dropitBehavior.\r\nDialogue: 0,1:10:43.66,1:10:45.46,yin,,0,0,0,,现在它们不在任何行为中\\N{\\fs12}Now they're not in any behavior,\r\nDialogue: 0,1:10:45.63,1:10:47.50,yin,,0,0,0,,就不会受到动画者的影响\\N{\\fs12}so they're not going to be affected by the animator.\r\nDialogue: 0,1:10:48.50,1:10:51.77,yin,,0,0,0,,现在... 就是这样了\\N{\\fs12}Okay? Now, I'm going to-- so that's that.\r\nDialogue: 0,1:10:51.95,1:10:54.50,yin,,0,0,0,,现在我要添加动画将它们炸掉\\N{\\fs12}Now I'm going to animate the blowing them up.\r\nDialogue: 0,1:10:54.51,1:10:55.38,yin,,0,0,0,,方法是\\N{\\fs12}Okay? And let me do that\r\nDialogue: 0,1:10:55.39,1:11:00.00,yin,,0,0,0,,animateRemovingDrops dropsToRemove\\N{\\fs12}with animateRemovingDrops, dropsToRemove.\r\nDialogue: 0,1:11:00.75,1:11:01.98,yin,,0,0,0,,这是一个新方法\\N{\\fs12}Okay? So this is a new method\r\nDialogue: 0,1:11:02.09,1:11:03.49,yin,,0,0,0,,放到这里 写在一起\\N{\\fs12}that we're going to write together here,\r\nDialogue: 0,1:11:04.05,1:11:07.85,yin,,0,0,0,,animateRemovingDrops\\N{\\fs12}animateRemovingDrops,\r\nDialogue: 0,1:11:08.22,1:11:11.78,yin,,0,0,0,,参数是数组dropsToRemove\\N{\\fs12}it takes an array of drops to remove,\r\nDialogue: 0,1:11:12.49,1:11:14.02,yin,,0,0,0,,要怎么做呢\\N{\\fs12}okay, how are we going to do this?\r\nDialogue: 0,1:11:15.04,1:11:20.58,yin,,0,0,0,,UIView animateWithDuration\\N{\\fs12}Well, I'm just going to do UIView, animateWithDuration.\r\nDialogue: 0,1:11:21.16,1:11:23.27,yin,,0,0,0,,它有好几个版本\\N{\\fs12}Okay? So I want-- there's a few versions of this,\r\nDialogue: 0,1:11:23.27,1:11:25.64,yin,,0,0,0,,有些有delay 有些没有\\N{\\fs12}some of them have delay, some don't have delay,\r\nDialogue: 0,1:11:26.26,1:11:28.02,yin,,0,0,0,,我想要哪个呢\\N{\\fs12}so I want the one-- which one do I want?\r\nDialogue: 0,1:11:28.31,1:11:32.45,yin,,0,0,0,,只要completion就够了 就是这个\\N{\\fs12}I think I want the one with just completion, so that's this one.\r\nDialogue: 0,1:11:32.93,1:11:34.79,yin,,0,0,0,,我需要的是这个\\N{\\fs12}Okay? So I want this one right here.\r\nDialogue: 0,1:11:34.80,1:11:36.12,yin,,0,0,0,,要多长时间呢\\N{\\fs12}How long is this going to take?\r\nDialogue: 0,1:11:36.32,1:11:39.30,yin,,0,0,0,,我要用一秒钟炸掉它们\\N{\\fs12}I'm going to take about a second to blow those things up.\r\nDialogue: 0,1:11:39.47,1:11:41.40,yin,,0,0,0,,这最好是一个常量\\N{\\fs12}This probably wants to be a constant,\r\nDialogue: 0,1:11:41.41,1:11:43.54,yin,,0,0,0,,你可以调整数值以达到最好效果\\N{\\fs12}and you want to tweak it to look good, right?\r\nDialogue: 0,1:11:43.67,1:11:46.07,yin,,0,0,0,,如果消除得太慢 看起来会很可笑\\N{\\fs12}If it blows up too slowly it looks ridiculous,\r\nDialogue: 0,1:11:46.14,1:11:47.83,yin,,0,0,0,,如果太快 用户会看不清楚\\N{\\fs12}if it blows up too fast, people can't tell\r\nDialogue: 0,1:11:48.06,1:11:49.75,yin,,0,0,0,,所以我们设为一秒钟\\N{\\fs12}that it did it, so we'll do that.\r\nDialogue: 0,1:11:49.86,1:11:52.25,yin,,0,0,0,,然后是animations 就是一个block\\N{\\fs12}And then here's the animations, which is just a block,\r\nDialogue: 0,1:11:52.53,1:11:54.08,yin,,0,0,0,,然后是completion\\N{\\fs12}and here's the completion,\r\nDialogue: 0,1:11:54.16,1:11:55.63,yin,,0,0,0,,我不会在completion中做任何操作\\N{\\fs12}which I'm not going to do anything on completion\r\nDialogue: 0,1:11:55.86,1:11:57.35,yin,,0,0,0,,实际上 我还是做点什么吧\\N{\\fs12}actually I am going to do something on completion,\r\nDialogue: 0,1:11:57.37,1:11:59.79,yin,,0,0,0,,我们加些内容 演示一下\\N{\\fs12}let's do something on completion just to show here.\r\nDialogue: 0,1:12:00.01,1:12:02.14,yin,,0,0,0,,加一个finished\\N{\\fs12}So finished, okay?\r\nDialogue: 0,1:12:02.42,1:12:03.16,yin,,0,0,0,,就是这样\\N{\\fs12}And that's it.\r\nDialogue: 0,1:12:03.17,1:12:04.95,yin,,0,0,0,,这就是animateWithDuration\\N{\\fs12}So that's this entire animateWithDuration,\r\nDialogue: 0,1:12:04.95,1:12:07.62,yin,,0,0,0,,我们只要加上这两个block就行了\\N{\\fs12}all we need to do is fill in these two blocks, right?\r\nDialogue: 0,1:12:07.62,1:12:08.97,yin,,0,0,0,,先来做这个block\\N{\\fs12}So let's do this block first.\r\nDialogue: 0,1:12:08.97,1:12:10.14,yin,,0,0,0,,这个animations\\N{\\fs12}This is the animations.\r\nDialogue: 0,1:12:10.38,1:12:11.85,yin,,0,0,0,,这里是实际移动操作\\N{\\fs12}This is the actual moving.\r\nDialogue: 0,1:12:11.87,1:12:15.00,yin,,0,0,0,,我只要将这些方块移走\\N{\\fs12}So all I need to do here is move these things out of the way.\r\nDialogue: 0,1:12:15.26,1:12:17.16,yin,,0,0,0,,我要让它们炸飞\\N{\\fs12}So I'm going to have them kind of explode up\r\nDialogue: 0,1:12:17.44,1:12:18.93,yin,,0,0,0,,从视图顶部出去\\N{\\fs12}and off the top of my view.\r\nDialogue: 0,1:12:19.09,1:12:21.82,yin,,0,0,0,,所以我要将它们移动到我的视图上面\\N{\\fs12}So I'm going to move each one to a random location\r\nDialogue: 0,1:12:21.84,1:12:24.74,yin,,0,0,0,,外部的某个随机位置\\N{\\fs12}somewhere off screen above my view, okay,\r\nDialogue: 0,1:12:24.76,1:12:26.35,yin,,0,0,0,,让它们从上面出去\\N{\\fs12}kind of just out there somewhere.\r\nDialogue: 0,1:12:26.74,1:12:28.76,yin,,0,0,0,,怎么做呢\\N{\\fs12}And so how am I going to do that,\r\nDialogue: 0,1:12:28.77,1:12:34.90,yin,,0,0,0,,for (UIView *drop in dropsToRemove)\\N{\\fs12}by saying for, UIView drop in dropsToRemove,\r\nDialogue: 0,1:12:35.89,1:12:40.27,yin,,0,0,0,,随机选取一个x轴坐标\\N{\\fs12}I'm gonna have the x be some random location\r\nDialogue: 0,1:12:40.89,1:12:45.36,yin,,0,0,0,,范围是从向左宽度大小的两倍\\N{\\fs12}that is between two times my width to the left\r\nDialogue: 0,1:12:45.82,1:12:47.57,yin,,0,0,0,,到向右宽度大小的两倍\\N{\\fs12}to two times above my width.\r\nDialogue: 0,1:12:47.71,1:12:50.18,yin,,0,0,0,,像一个漏斗\\N{\\fs12}So it's gonna be kind of going out like this in a funnel.\r\nDialogue: 0,1:12:50.32,1:12:53.74,yin,,0,0,0,,x的范围是从向左两倍宽度\\N{\\fs12}Okay? So the x has to be from two times my width to the left\r\nDialogue: 0,1:12:53.74,1:12:55.24,yin,,0,0,0,,到向右两倍宽度\\N{\\fs12}to two times my width to the right,\r\nDialogue: 0,1:12:55.50,1:12:56.81,yin,,0,0,0,,这里也就是\\N{\\fs12}so I'm going to make that be\r\nDialogue: 0,1:12:56.82,1:13:01.34,yin,,0,0,0,,self.gameView.bounds.size.width*5\\N{\\fs12}self dot gameView dot bounds dot size dot width times five,\r\nDialogue: 0,1:13:02.11,1:13:04.82,yin,,0,0,0,,这样可以得到随机x轴点\\N{\\fs12}okay, so that's going to get me there,\r\nDialogue: 0,1:13:05.18,1:13:12.25,yin,,0,0,0,,减去self.gameView.bounds.size.width*2\\N{\\fs12}minus self dot gameView dot bounds dot size dot width times two.\r\nDialogue: 0,1:13:14.56,1:13:18.05,yin,,0,0,0,,把这段代码移到前面来\\N{\\fs12}Okay. And actually I'm going to move this all back here\r\nDialogue: 0,1:13:18.05,1:13:19.63,yin,,0,0,0,,看得更清楚\\N{\\fs12}so we can see it better,\r\nDialogue: 0,1:13:20.55,1:13:21.91,yin,,0,0,0,,这个也移到前面来\\N{\\fs12}move this back too.\r\nDialogue: 0,1:13:23.29,1:13:26.55,yin,,0,0,0,,增大点空间\\N{\\fs12}Okay. So let's do that, okay,\r\nDialogue: 0,1:13:26.89,1:13:29.35,yin,,0,0,0,,可以看到 我将五倍宽度\\N{\\fs12}so you see I'm just going five wide\r\nDialogue: 0,1:13:29.36,1:13:30.62,yin,,0,0,0,,转变为了两倍\\N{\\fs12}and I'm shifting it over two.\r\nDialogue: 0,1:13:30.98,1:13:32.65,yin,,0,0,0,,在上面创建它\\N{\\fs12}So I'm just creating this thing above.\r\nDialogue: 0,1:13:32.91,1:13:35.60,yin,,0,0,0,,y轴坐标就简单了\\N{\\fs12}And then the y, I'm going to make y easy,\r\nDialogue: 0,1:13:35.61,1:13:36.42,yin,,0,0,0,,让它等于\\N{\\fs12}I'm just going to have it\r\nDialogue: 0,1:13:36.43,1:13:40.80,yin,,0,0,0,,self.gameView.bounds.size.height\\N{\\fs12}be self dot gameView dot bounds dot size dot height,\r\nDialogue: 0,1:13:41.00,1:13:43.76,yin,,0,0,0,,移动方块的时候 让y轴坐标为负\\N{\\fs12}and then when I move it there, I'm going to make it negative,\r\nDialogue: 0,1:13:43.76,1:13:46.92,yin,,0,0,0,,所以我要让drop.center等于\\N{\\fs12}so I'm gonna say drop dot center equals\r\nDialogue: 0,1:13:46.93,1:13:51.80,yin,,0,0,0,,CGPoint(x, -y)\\N{\\fs12}CGPoint x comma minus y. Alright?\r\nDialogue: 0,1:13:51.82,1:13:55.99,yin,,0,0,0,,在这个duration block中 如果我修改了center\\N{\\fs12}So inside this duration block, if I change the center,\r\nDialogue: 0,1:13:55.99,1:13:57.70,yin,,0,0,0,,它是神奇的触发点之一\\N{\\fs12}it's one of the magic things.\r\nDialogue: 0,1:13:57.75,1:13:58.76,yin,,0,0,0,,它就会运行动画\\N{\\fs12}This will get animated.\r\nDialogue: 0,1:13:59.90,1:14:03.40,yin,,0,0,0,,center frame alpha和transform\\N{\\fs12}Okay? Center, and frame, and alpha, and transform,\r\nDialogue: 0,1:14:03.40,1:14:08.07,yin,,0,0,0,,都能够触发自动动画\\N{\\fs12}those are all the magic things that automatically will animate,\r\nDialogue: 0,1:14:08.49,1:14:11.21,yin,,0,0,0,,我打错了什么吗\\N{\\fs12}and what did I type wrong here?\r\nDialogue: 0,1:14:12.92,1:14:14.17,yin,,0,0,0,,CGPointMake 对\\N{\\fs12}Oh CGPointMake, yeah.\r\nDialogue: 0,1:14:14.94,1:14:16.97,yin,,0,0,0,,忘了Make 好样的\\N{\\fs12}Make. Good job.\r\nDialogue: 0,1:14:16.99,1:14:18.08,yin,,0,0,0,,就是这样\\N{\\fs12}Okay, so that's it.\r\nDialogue: 0,1:14:18.08,1:14:19.95,yin,,0,0,0,,现在方块们就会炸飞了\\N{\\fs12}So now they're all going to blow up.\r\nDialogue: 0,1:14:20.21,1:14:21.61,yin,,0,0,0,,completion中做什么呢\\N{\\fs12}What am I going to do on completion?\r\nDialogue: 0,1:14:21.62,1:14:25.22,yin,,0,0,0,,当它们成功炸飞之后\\N{\\fs12}Well, after they blow up, if they successfully blow up,\r\nDialogue: 0,1:14:26.52,1:14:29.90,yin,,0,0,0,,我就要将它们从父视图中移除\\N{\\fs12}I'm going to remove them all from the super view, right?\r\nDialogue: 0,1:14:29.93,1:14:30.84,yin,,0,0,0,,因为我不需要它们了\\N{\\fs12}Because I don't want them anymore,\r\nDialogue: 0,1:14:30.84,1:14:32.22,yin,,0,0,0,,我炸掉了它们 它们没有了\\N{\\fs12}I just blew them up, they're gone.\r\nDialogue: 0,1:14:32.48,1:14:34.01,yin,,0,0,0,,有什么好办法来实现呢\\N{\\fs12}So what's a cool way to do that?\r\nDialogue: 0,1:14:34.02,1:14:34.79,yin,,0,0,0,,看这个\\N{\\fs12}Watch this.\r\nDialogue: 0,1:14:34.92,1:14:39.54,yin,,0,0,0,,dropsToRemove makeObjectsPerformSelector:\\N{\\fs12}Let's go dropsToRemove, makeObjectsPerformSelector,\r\nDialogue: 0,1:14:39.65,1:14:42.74,yin,,0,0,0,,@selector(removeRromSuperview)\\N{\\fs12}at sign selector, removeRromSuperview.\r\nDialogue: 0,1:14:44.02,1:14:46.39,yin,,0,0,0,,我说了 这类方法\\N{\\fs12}Okay, I told you that methods like this\r\nDialogue: 0,1:14:46.41,1:14:49.35,yin,,0,0,0,,会很好用 确实很好用\\N{\\fs12}would come in familiar, come in handy, and they are,\r\nDialogue: 0,1:14:49.37,1:14:52.29,yin,,0,0,0,,这比用for-in循环好多了\\N{\\fs12}it's better than having to do for, in, you know, all that stuff.\r\nDialogue: 0,1:14:52.30,1:14:53.06,yin,,0,0,0,,这要用这个方法\\N{\\fs12}Boom, just do this,\r\nDialogue: 0,1:14:53.14,1:14:55.31,yin,,0,0,0,,它就会向所有目标视图发送removeFromSuperview\\N{\\fs12}it's gonna send removeFromSuperview to all of them.\r\nDialogue: 0,1:14:56.08,1:14:58.22,yin,,0,0,0,,明白吗\\N{\\fs12}Okay? Make sense?\r\nDialogue: 0,1:14:59.01,1:15:00.47,yin,,0,0,0,,我们来看看是否运行正常\\N{\\fs12}Alright, let's see if this works.\r\nDialogue: 0,1:15:02.72,1:15:04.70,yin,,0,0,0,,我们加一些方块\\N{\\fs12}Alright, so let's add some of these guys\r\nDialogue: 0,1:15:04.85,1:15:08.95,yin,,0,0,0,,等它凑满一行 还差一个\\N{\\fs12}until we get a whole row, almost there, almost there.\r\nDialogue: 0,1:15:09.65,1:15:11.54,yin,,0,0,0,,快出来 来了\\N{\\fs12}Oh, come on, oh, there it is!\r\nDialogue: 0,1:15:13.34,1:15:15.11,yin,,0,0,0,,这里要注意两件事\\N{\\fs12}Okay, now, two things there.\r\nDialogue: 0,1:15:15.40,1:15:18.10,yin,,0,0,0,,炸飞动画执行了\\N{\\fs12}Notice that we got the animation of the thing happening,\r\nDialogue: 0,1:15:18.11,1:15:19.71,yin,,0,0,0,,其他方块怎样了\\N{\\fs12}but what happened to all the other blocks?\r\nDialogue: 0,1:15:19.97,1:15:22.36,yin,,0,0,0,,它们向下移了\\N{\\fs12}They moved down, because they're all still\r\nDialogue: 0,1:15:22.36,1:15:23.65,yin,,0,0,0,,因为它们依旧受动画者的影响\\N{\\fs12}under the influence of the animator.\r\nDialogue: 0,1:15:23.88,1:15:25.41,yin,,0,0,0,,重力依旧作用于它们\\N{\\fs12}Gravity is still pulling on them,\r\nDialogue: 0,1:15:25.41,1:15:26.94,yin,,0,0,0,,碰撞依旧起作用\\N{\\fs12}the collider is still working.\r\nDialogue: 0,1:15:27.30,1:15:29.62,yin,,0,0,0,,如果我再增加一些方块\\N{\\fs12}So if I put a whole bunch of things in here, okay,\r\nDialogue: 0,1:15:29.62,1:15:32.44,yin,,0,0,0,,它们有点倾斜了 再看一遍\\N{\\fs12}and also okay they're kind of tilting, watch this again.\r\nDialogue: 0,1:15:33.43,1:15:34.05,yin,,0,0,0,,糟糕\\N{\\fs12}Oop...\r\nDialogue: 0,1:15:35.50,1:15:36.42,yin,,0,0,0,,没错\\N{\\fs12}Yeah, I did.\r\nDialogue: 0,1:15:36.42,1:15:37.91,yin,,0,0,0,,hitTest确实不太靠谱\\N{\\fs12}I did get unlucky with the hitTest there,\r\nDialogue: 0,1:15:37.91,1:15:39.35,yin,,0,0,0,,再重新运行一下吧\\N{\\fs12}here let me show you a different way.\r\nDialogue: 0,1:15:39.87,1:15:41.47,yin,,0,0,0,,用hitTest来实现这个效果\\N{\\fs12}The hitTest is kind of a questionable way\r\nDialogue: 0,1:15:41.47,1:15:42.50,yin,,0,0,0,,不是一个可靠的方法\\N{\\fs12}to do that, by the way.\r\nDialogue: 0,1:15:43.50,1:15:45.28,yin,,0,0,0,,我来演示一下\\N{\\fs12}But, here, let's show you.\r\nDialogue: 0,1:15:45.28,1:15:47.16,yin,,0,0,0,,再重新看一遍\\N{\\fs12}I'll just show you this again.\r\nDialogue: 0,1:15:48.22,1:15:50.77,yin,,0,0,0,,而且 我应该让它们不这样倾斜\\N{\\fs12}Also, I should make it so that they're not tilting like that.\r\nDialogue: 0,1:15:50.77,1:15:52.05,yin,,0,0,0,,我们下次再做\\N{\\fs12}We'll do that next time.\r\nDialogue: 0,1:15:52.05,1:15:54.05,yin,,0,0,0,,又不出来吗 来了\\N{\\fs12}But...wow, I'm getting-- There we go.\r\nDialogue: 0,1:15:54.55,1:15:57.00,yin,,0,0,0,,喂 怎么回事\\N{\\fs12}Okay. Hello.\r\nDialogue: 0,1:15:58.31,1:15:59.15,yin,,0,0,0,,动一下 动一下\\N{\\fs12}Knock, knock, knock.\r\nDialogue: 0,1:15:59.45,1:16:01.59,yin,,0,0,0,,我不知道为什么不行\\N{\\fs12}Well, I don't know why it's not working now,\r\nDialogue: 0,1:16:01.60,1:16:03.85,yin,,0,0,0,,但好歹你们刚才看到了 该下课了\\N{\\fs12}but anyway you got to see it work and time's up,\r\nDialogue: 0,1:16:03.87,1:16:05.83,yin,,0,0,0,,我们会再看一下\\N{\\fs12}but we'll look at that,\r\nDialogue: 0,1:16:05.83,1:16:06.58,yin,,0,0,0,,后面会再看一下\\N{\\fs12}we'll look at that later\r\nDialogue: 0,1:16:06.60,1:16:08.11,yin,,0,0,0,,看看问题出在哪\\N{\\fs12}and try and find out what our problem was.\r\nDialogue: 0,1:16:08.28,1:16:12.09,yin,,0,0,0,,但是 这里主要要注意 我们让方块飞走了\\N{\\fs12}But anyway, the main thing there to notice, we did the fly away,\r\nDialogue: 0,1:16:12.17,1:16:15.40,yin,,0,0,0,,但是动画者依旧作用于其他对象\\N{\\fs12}but we also had the animator still working on the other things,\r\nDialogue: 0,1:16:15.41,1:16:16.37,yin,,0,0,0,,要知道这一点很重要\\N{\\fs12}and that's important to know,\r\nDialogue: 0,1:16:16.37,1:16:18.10,yin,,0,0,0,,这二者可以这样互相作用\\N{\\fs12}that the two things can interact like that.\r\nDialogue: 0,1:16:18.10,1:16:19.55,yin,,0,0,0,,如果你将某些元素移走\\N{\\fs12}If you move things out of the way,\r\nDialogue: 0,1:16:19.75,1:16:21.97,yin,,0,0,0,,动画者会重新开始\\N{\\fs12}the animator is going to go back to life\r\nDialogue: 0,1:16:22.02,1:16:24.42,yin,,0,0,0,,继续拉动物体\\N{\\fs12}and start pulling down on things, okay?\r\nDialogue: 0,1:16:24.50,1:16:26.36,yin,,0,0,0,,下次我们会继续完成这个动画\\N{\\fs12}So next time, we'll continue to do the animation,\r\nDialogue: 0,1:16:26.37,1:16:28.55,yin,,0,0,0,,我们不会再让它这么摇晃了\\N{\\fs12}we'll make it so it's not so rickety, okay,\r\nDialogue: 0,1:16:28.56,1:16:29.91,yin,,0,0,0,,避免出现\\N{\\fs12}so we don't have this problem\r\nDialogue: 0,1:16:29.91,1:16:31.79,yin,,0,0,0,,底部无法对齐的问题\\N{\\fs12}where the bottom load doesn't line up,\r\nDialogue: 0,1:16:32.34,1:16:33.83,yin,,0,0,0,,我们还会增加一个吸附行为\\N{\\fs12}and we'll also do an attachment,\r\nDialogue: 0,1:16:33.91,1:16:36.81,yin,,0,0,0,,吸附到某个元素上\\N{\\fs12}where we attach to something and, you know,\r\nDialogue: 0,1:16:36.82,1:16:39.13,yin,,0,0,0,,用吸附行为\\N{\\fs12}have it swing from an attachment,\r\nDialogue: 0,1:16:39.84,1:16:42.52,yin,,0,0,0,,让它挂到某个吸附对象上\\N{\\fs12}with a little attachment behavior.\r\nDialogue: 0,1:16:43.01,1:16:44.10,yin,,0,0,0,,好了 下次见\\N{\\fs12}Alright, we'll see you next time.\r\nDialogue: 0,1:16:45.24,1:16:48.74,yin,,0,0,0,,更多内容 请访问斯坦福网站\\N{\\fs12}For more, please visit us at Stanford.edu.\r\n"
  },
  {
    "path": "Subtitles/9. Animation and Autolayout.ass",
    "content": "﻿[Script Info]\r\n; Script generated by Aegisub 3.2.0\r\n; http://www.aegisub.org/\r\nTitle: Default Aegisub file\r\nScriptType: v4.00+\r\nWrapStyle: 0\r\nScaledBorderAndShadow: yes\r\nYCbCr Matrix: None\r\n\r\n[Aegisub Project Garbage]\r\nLast Style Storage: Default\r\nActive Line: 1\r\n\r\n[V4+ Styles]\r\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\r\nStyle: yin,冬青黑体简体中文 W3,20,&H00FFFFFF,&HF0000000,&H00000000,&H32000000,0,0,0,0,100,100,0,0,1,1,0,2,5,5,5,134\r\n\r\n[Events]\r\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\nDialogue: 0,0:00:05.34,0:00:06.83,yin,,0,0,0,,斯坦福大学\\N{\\fs12}Stanford University.\r\nDialogue: 0,0:00:08.59,0:00:14.03,yin,,0,0,0,,欢迎来到2013至2014秋季学期CS193P第九讲\\N{\\fs12}Alright. Well, welcome to Lecture number 9 of CS193P, fall of 2013/14.\r\nDialogue: 0,0:00:14.32,0:00:16.79,yin,,0,0,0,,今天我会先完成周一开始的\\N{\\fs12}Today I'm going to finish the animation demo\r\nDialogue: 0,0:00:16.79,0:00:18.39,yin,,0,0,0,,那个动画示例演示\\N{\\fs12}that we started on Monday,\r\nDialogue: 0,0:00:18.39,0:00:21.15,yin,,0,0,0,,然后这节课的主要内容是autolayout自动布局\\N{\\fs12}and then the lecture's going to be about autolayout,\r\nDialogue: 0,0:00:21.17,0:00:23.86,yin,,0,0,0,,这是一套非常棒的系统\\N{\\fs12}which is a really cool system for making it\r\nDialogue: 0,0:00:23.88,0:00:27.06,yin,,0,0,0,,可以让你的用户界面适应变化的环境\\N{\\fs12}so that your user interface can adapt to changing conditions.\r\nDialogue: 0,0:00:27.40,0:00:31.07,yin,,0,0,0,,最后我会做一个简单的自动布局演示\\N{\\fs12}And then I'll do a brief autolayout demo at the end,\r\nDialogue: 0,0:00:31.08,0:00:32.98,yin,,0,0,0,,让大家看看实际操作是怎样的\\N{\\fs12}just so you can kind of see it in action.\r\nDialogue: 0,0:00:33.00,0:00:35.70,yin,,0,0,0,,眼见为实 尤其是自动布局这部分\\N{\\fs12}Seeing is believing, especially with autolayout.\r\nDialogue: 0,0:00:37.40,0:00:39.62,yin,,0,0,0,,这个示例 我们上次实现了\\N{\\fs12}So this demo, where we left off\r\nDialogue: 0,0:00:39.63,0:00:43.05,yin,,0,0,0,,让方块在重力作用下掉落\\N{\\fs12}is the blocks would come down due to gravity\r\nDialogue: 0,0:00:43.06,0:00:44.52,yin,,0,0,0,,在底部碰撞\\N{\\fs12}and they would collide at the bottom\r\nDialogue: 0,0:00:44.52,0:00:46.23,yin,,0,0,0,,方块相互之间会碰撞\\N{\\fs12}and they'd kind of run into each other,\r\nDialogue: 0,0:00:46.41,0:00:48.84,yin,,0,0,0,,当底部的一行拼满之后\\N{\\fs12}and then when a bottom row was full\r\nDialogue: 0,0:00:48.86,0:00:52.10,yin,,0,0,0,,这一行就会飞出去\\N{\\fs12}they would all kind of fly off into outer space.\r\nDialogue: 0,0:00:53.15,0:00:56.30,yin,,0,0,0,,还留下一个问题就是 它们能够堆积起来\\N{\\fs12}And I think where we left off too was they would stack up\r\nDialogue: 0,0:00:56.31,0:00:58.44,yin,,0,0,0,,但是不会飞出去\\N{\\fs12}and they weren't flying off, okay?\r\nDialogue: 0,0:00:58.44,0:01:00.26,yin,,0,0,0,,为什么最后不飞出去呢\\N{\\fs12}And so why weren't they flying off at the end?\r\nDialogue: 0,0:01:00.26,0:01:02.47,yin,,0,0,0,,部分是因为\\N{\\fs12}Well, part of the reason they weren't flying off was\r\nDialogue: 0,0:01:02.47,0:01:06.30,yin,,0,0,0,,方块搭成的塔太不稳了\\N{\\fs12}because they were, those towers of blocks were so tippy,\r\nDialogue: 0,0:01:06.47,0:01:10.35,yin,,0,0,0,,一直在晃动 不会停下来\\N{\\fs12}they were kind of wiggling, they were never coming to rest, okay?\r\nDialogue: 0,0:01:10.49,0:01:13.31,yin,,0,0,0,,动画永远都不会停下来\\N{\\fs12}So they were never, the animation was never stopping.\r\nDialogue: 0,0:01:13.42,0:01:15.58,yin,,0,0,0,,始终会小幅度移动着\\N{\\fs12}It was always continuing to move them a little bit,\r\nDialogue: 0,0:01:15.84,0:01:17.61,yin,,0,0,0,,我们先要对示例进行修改\\N{\\fs12}and so we're going to start off our demo\r\nDialogue: 0,0:01:17.76,0:01:22.31,yin,,0,0,0,,让方块堆得更稳固一些\\N{\\fs12}by making those stacks a little more solid,\r\nDialogue: 0,0:01:22.31,0:01:23.51,yin,,0,0,0,,减少摇晃\\N{\\fs12}a little less tippy,\r\nDialogue: 0,0:01:23.69,0:01:26.41,yin,,0,0,0,,方法是禁止方块旋转\\N{\\fs12}by making it so that the blocks can't rotate.\r\nDialogue: 0,0:01:26.68,0:01:27.74,yin,,0,0,0,,如果方块不能旋转\\N{\\fs12}So since they can't rotate,\r\nDialogue: 0,0:01:27.75,0:01:29.53,yin,,0,0,0,,相互叠加得就会更稳固一些\\N{\\fs12}they'll sit on top of each other much nicer\r\nDialogue: 0,0:01:29.68,0:01:31.96,yin,,0,0,0,,我还要把重力大小设回为1\\N{\\fs12}and I'm gonna turn gravity back up to 1.0,\r\nDialogue: 0,0:01:31.97,0:01:34.33,yin,,0,0,0,,我之前将它设为了0.9\\N{\\fs12}I think I had typed in .9 at some point,\r\nDialogue: 0,0:01:34.94,0:01:35.90,yin,,0,0,0,,只应用于这个示例\\N{\\fs12}just as far as the demo,\r\nDialogue: 0,0:01:35.90,0:01:36.90,yin,,0,0,0,,我们再把它改回去\\N{\\fs12}but let's crank it back up\r\nDialogue: 0,0:01:36.90,0:01:40.12,yin,,0,0,0,,让方块坐得更稳 完全不会浮起来\\N{\\fs12}so that they will sit a little bit so they don't float at all,\r\nDialogue: 0,0:01:40.12,0:01:42.93,yin,,0,0,0,,重重地放在其他方块顶部\\N{\\fs12}you know, so they sit down strongly on top of each other.\r\nDialogue: 0,0:01:43.22,0:01:47.09,yin,,0,0,0,,然后我要使用一个吸附行为\\N{\\fs12}Then what I'm gonna do is use an attachment behavior\r\nDialogue: 0,0:01:47.24,0:01:51.00,yin,,0,0,0,,这样当方块掉落时 我们就能抓住它了\\N{\\fs12}so as the block falls, we can grab onto it, okay?\r\nDialogue: 0,0:01:51.34,0:01:54.34,yin,,0,0,0,,然后我们可以让它摆动\\N{\\fs12}And then we can kind of swing it around\r\nDialogue: 0,0:01:54.44,0:01:56.87,yin,,0,0,0,,选择掉落的堆叠位置\\N{\\fs12}and pick which stack we want to drop it in\r\nDialogue: 0,0:01:56.88,0:01:57.97,yin,,0,0,0,,然后再让它掉下去\\N{\\fs12}and then let it go.\r\nDialogue: 0,0:01:58.71,0:02:02.03,yin,,0,0,0,,最后要做的是\\N{\\fs12}And then the last thing I'm gonna do is\r\nDialogue: 0,0:02:02.04,0:02:06.16,yin,,0,0,0,,使用吸附行为的action block\\N{\\fs12}we're gonna use the action block of that attachment behavior\r\nDialogue: 0,0:02:06.34,0:02:09.01,yin,,0,0,0,,添加并显示出吸附效果\\N{\\fs12}to animate that and show the attachment,\r\nDialogue: 0,0:02:09.10,0:02:12.19,yin,,0,0,0,,我要画一条线来显示它\\N{\\fs12}I'm just gonna actually draw a little line to show it.\r\nDialogue: 0,0:02:12.19,0:02:13.49,yin,,0,0,0,,今天有很多要演示的内容\\N{\\fs12}So it's quite a bit to show there.\r\nDialogue: 0,0:02:13.61,0:02:14.73,yin,,0,0,0,,我觉得我们没时间\\N{\\fs12}I don't think we're going to have time\r\nDialogue: 0,0:02:14.73,0:02:17.37,yin,,0,0,0,,演示碰撞委托这部分\\N{\\fs12}to do this collision delegate thing,\r\nDialogue: 0,0:02:17.38,0:02:18.70,yin,,0,0,0,,但我会上传这部分的代码\\N{\\fs12}but I'll post the code for that\r\nDialogue: 0,0:02:18.71,0:02:20.33,yin,,0,0,0,,帮助大家学习这部分是怎样实现的\\N{\\fs12}so you can see what that's all about.\r\nDialogue: 0,0:02:20.90,0:02:25.75,yin,,0,0,0,,好了 我们回到Xcode\\N{\\fs12}Alright, so, let's get back over to Xcode here\r\nDialogue: 0,0:02:25.75,0:02:28.28,yin,,0,0,0,,回到Dropit中\\N{\\fs12}and go back into Dropit and--\r\nDialogue: 0,0:02:29.70,0:02:36.37,yin,,0,0,0,,记得吗 我们把示例中的全部行为\\N{\\fs12}Okay, so, remember that we moved all of the behavior\r\nDialogue: 0,0:02:36.66,0:02:40.71,yin,,0,0,0,,都移到了它自己的一个UIDynamicBehavior子类中\\N{\\fs12}of this thing out into its own subclass of UIDynamicBehavior,\r\nDialogue: 0,0:02:40.71,0:02:42.17,yin,,0,0,0,,叫做dropitBehavior\\N{\\fs12}called dropitBehavior.\r\nDialogue: 0,0:02:42.18,0:02:43.62,yin,,0,0,0,,这边这个\\N{\\fs12}Right over here, this guy,\r\nDialogue: 0,0:02:44.33,0:02:46.86,yin,,0,0,0,,重力和碰撞行为就在这里面\\N{\\fs12}and so that's where the gravity and the collision is.\r\nDialogue: 0,0:02:47.03,0:02:48.06,yin,,0,0,0,,我要做的是\\N{\\fs12}And so what I'm gonna do there is\r\nDialogue: 0,0:02:48.07,0:02:51.50,yin,,0,0,0,,向自定义行为中再增加一个行为\\N{\\fs12}I'm gonna add another behavior to that customer behavior,\r\nDialogue: 0,0:02:51.78,0:02:55.31,yin,,0,0,0,,我们可以通过它控制是否允许方块旋转\\N{\\fs12}which let us control things like whether the blocks rotate.\r\nDialogue: 0,0:02:55.32,0:02:58.63,yin,,0,0,0,,还可以控制其摩擦力 阻力 密度\\N{\\fs12}Okay? We can also control friction, resistance, density,\r\nDialogue: 0,0:02:58.63,0:02:59.94,yin,,0,0,0,,这类属性\\N{\\fs12}those kind of things in there.\r\nDialogue: 0,0:03:00.57,0:03:04.38,yin,,0,0,0,,控制这些属性设置的行为\\N{\\fs12}The kind of behavior that is that controls those things\r\nDialogue: 0,0:03:04.56,0:03:08.73,yin,,0,0,0,,叫做UIDynamicItemBehavior\\N{\\fs12}is called a UIDynamicItemBehavior,\r\nDialogue: 0,0:03:08.89,0:03:11.19,yin,,0,0,0,,因为它指定的是动力项的行为\\N{\\fs12}because it's specifying the behavior of that item\r\nDialogue: 0,0:03:11.43,0:03:14.02,yin,,0,0,0,,这里我们叫它\\N{\\fs12}Okay? So we'll call that,\r\nDialogue: 0,0:03:14.77,0:03:18.70,yin,,0,0,0,,比如animationOptions\\N{\\fs12}maybe something like animationOptions,\r\nDialogue: 0,0:03:18.71,0:03:19.78,yin,,0,0,0,,或者类似的名字\\N{\\fs12}or something like that,\r\nDialogue: 0,0:03:19.78,0:03:23.25,yin,,0,0,0,,你可以叫它itemBehaviors\\N{\\fs12}you can call them itemBehaviors, some,\r\nDialogue: 0,0:03:23.49,0:03:26.26,yin,,0,0,0,,或者physicalCharacteristics之类的\\N{\\fs12}you might call them physicalCharacteristics almost,\r\nDialogue: 0,0:03:26.49,0:03:27.60,yin,,0,0,0,,但这里我们就用这个名字了\\N{\\fs12}but that's, we'll do that.\r\nDialogue: 0,0:03:27.62,0:03:31.51,yin,,0,0,0,,在下面这里添加延迟实例化\\N{\\fs12}And let's go down here and lazy instantiate that,\r\nDialogue: 0,0:03:31.62,0:03:35.50,yin,,0,0,0,,UIDynamicItemBehavior animationOptions\\N{\\fs12}so dynamic behavior animationOptions.\r\nDialogue: 0,0:03:36.07,0:03:38.58,yin,,0,0,0,,如果没有animationOptions\\N{\\fs12}If not animationOptions,\r\nDialogue: 0,0:03:39.02,0:03:44.57,yin,,0,0,0,,animationOptions=[[UIDynamicItemBehavior alloc] init]\\N{\\fs12}then animationOptions equals UIDynamicItemBehavior alloc init.\r\nDialogue: 0,0:03:44.76,0:03:46.90,yin,,0,0,0,,对它进行配置\\N{\\fs12}So I'm just allocating this thing\r\nDialogue: 0,0:03:47.38,0:03:52.62,yin,,0,0,0,,将allowRotation设为NO\\N{\\fs12}and I'm going to allowRotation, no.\r\nDialogue: 0,0:03:52.93,0:03:56.43,yin,,0,0,0,,不允许这些动力项旋转\\N{\\fs12}So I'm not gonna allow these items to rotate.\r\nDialogue: 0,0:03:56.73,0:03:58.87,yin,,0,0,0,,方块必须保持稳定状态\\N{\\fs12}Okay? So the blocks will have to stay\r\nDialogue: 0,0:03:59.00,0:04:00.71,yin,,0,0,0,,在互相碰撞 反弹的时候\\N{\\fs12}as they bounce on each other and collide,\r\nDialogue: 0,0:04:00.72,0:04:03.33,yin,,0,0,0,,不可以旋转\\N{\\fs12}they'll have to stay nonrotated.\r\nDialogue: 0,0:04:04.45,0:04:07.49,yin,,0,0,0,,然后返回animationOptions\\N{\\fs12}Alright? And return animationOptions.\r\nDialogue: 0,0:04:07.49,0:04:09.18,yin,,0,0,0,,我们还可以在这里设置\\N{\\fs12}And, again, we can do other things in here\r\nDialogue: 0,0:04:09.20,0:04:12.27,yin,,0,0,0,,摩擦力和密度等等\\N{\\fs12}like dot friction equals dot density equals whatever,\r\nDialogue: 0,0:04:12.27,0:04:13.31,yin,,0,0,0,,省点事 我们就不做了\\N{\\fs12}but we'll keep it simple.\r\nDialogue: 0,0:04:13.80,0:04:17.10,yin,,0,0,0,,当然 要将全部动力项\\N{\\fs12}I obviously want all items to be added\r\nDialogue: 0,0:04:17.48,0:04:21.44,yin,,0,0,0,,都添加到这个animationOptions中\\N{\\fs12}also to this animationOptions thing\r\nDialogue: 0,0:04:21.45,0:04:28.32,yin,,0,0,0,,移除动力项也是一样\\N{\\fs12}and we clearly want to remove all items, as well.\r\nDialogue: 0,0:04:29.03,0:04:34.79,yin,,0,0,0,,最后添加子行为animationOptions\\N{\\fs12}And let's finally add our child behavior animationOptions.\r\nDialogue: 0,0:04:34.80,0:04:38.35,yin,,0,0,0,,animationOption和其他行为是一样的\\N{\\fs12}So the animationOptions act like any other behavior, okay?\r\nDialogue: 0,0:04:38.56,0:04:42.34,yin,,0,0,0,,只不过它是在指定属性\\N{\\fs12}They just specify attributes instead of, you know,\r\nDialogue: 0,0:04:42.34,0:04:44.47,yin,,0,0,0,,而不是应用作用力等\\N{\\fs12}applying the forces or whatever,\r\nDialogue: 0,0:04:44.48,0:04:47.47,yin,,0,0,0,,但其实你也可以把它们看做是在应用作用力\\N{\\fs12}but you can actually think of them somewhat as applying forces too,\r\nDialogue: 0,0:04:48.22,0:04:51.17,yin,,0,0,0,,比如 用作用力阻止物体旋转\\N{\\fs12}it's just, you know, like forces to keep them from rotating\r\nDialogue: 0,0:04:51.18,0:04:53.48,yin,,0,0,0,,或者用作用力增加物体的摩擦力\\N{\\fs12}or forces to make them have higher friction,\r\nDialogue: 0,0:04:53.50,0:04:54.56,yin,,0,0,0,,可以这样理解\\N{\\fs12}those kind of things.\r\nDialogue: 0,0:04:55.45,0:04:55.99,yin,,0,0,0,,有问题吗\\N{\\fs12}Okay. Question?\r\nDialogue: 0,0:04:56.62,0:04:59.84,yin,,0,0,0,,[学生提问]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,0:04:59.85,0:05:00.82,yin,,0,0,0,,好问题\\N{\\fs12}What a great question.\r\nDialogue: 0,0:05:00.88,0:05:03.91,yin,,0,0,0,,你是问 如果有多个动力项行为\\N{\\fs12}You mean if, if you had multiple item behaviors\r\nDialogue: 0,0:05:03.93,0:05:06.49,yin,,0,0,0,,密度等属性设置有冲突会怎样 是吗\\N{\\fs12}that had different conflicting densities or whatever?\r\nDialogue: 0,0:05:06.59,0:05:08.24,yin,,0,0,0,,这是个好问题\\N{\\fs12}So that's a great question.\r\nDialogue: 0,0:05:08.54,0:05:09.68,yin,,0,0,0,,有对应的规则\\N{\\fs12}There are rules for that\r\nDialogue: 0,0:05:09.70,0:05:12.74,yin,,0,0,0,,如果你有一个行为树\\N{\\fs12}if you have, you know, a tree of behaviors\r\nDialogue: 0,0:05:12.76,0:05:14.95,yin,,0,0,0,,里面有一些动力项行为\\N{\\fs12}and you had some item behaviors in there.\r\nDialogue: 0,0:05:14.99,0:05:16.50,yin,,0,0,0,,规则会规定哪个动力项行为起决定作用\\N{\\fs12}There are rules for which one wins,\r\nDialogue: 0,0:05:16.50,0:05:17.96,yin,,0,0,0,,可能是最后一个\\N{\\fs12}it's kind of the last one wins\r\nDialogue: 0,0:05:17.96,0:05:19.96,yin,,0,0,0,,是如何发生的\\N{\\fs12}and how that's happens\r\nDialogue: 0,0:05:19.96,0:05:22.30,yin,,0,0,0,,这些都在文档中定义了\\N{\\fs12}is all defined in the documentation for it,\r\nDialogue: 0,0:05:22.31,0:05:24.75,yin,,0,0,0,,所以如果你要构建复杂的树形结构\\N{\\fs12}so if you're gonna build a tree so complicated\r\nDialogue: 0,0:05:24.75,0:05:26.66,yin,,0,0,0,,里面有动力项使用了两次\\N{\\fs12}that you have the items in there twice\r\nDialogue: 0,0:05:26.66,0:05:28.95,yin,,0,0,0,,两个不同的行为等等\\N{\\fs12}with two different behaviors and different things,\r\nDialogue: 0,0:05:28.95,0:05:31.38,yin,,0,0,0,,如果你要这样做\\N{\\fs12}I mean, that's pretty, I mean, if you're doing that,\r\nDialogue: 0,0:05:31.43,0:05:32.84,yin,,0,0,0,,你真的需要清楚自己在做什么\\N{\\fs12}you really got to know what you're doing\r\nDialogue: 0,0:05:33.24,0:05:34.66,yin,,0,0,0,,你需要查阅文档\\N{\\fs12}and so you really want to read the documentation,\r\nDialogue: 0,0:05:34.66,0:05:38.23,yin,,0,0,0,,这是行为的高级用法\\N{\\fs12}that would be considered advanced behavior to do that,\r\nDialogue: 0,0:05:38.24,0:05:39.08,yin,,0,0,0,,但是可以这样做\\N{\\fs12}but it can be done.\r\nDialogue: 0,0:05:39.18,0:05:39.94,yin,,0,0,0,,是合法的\\N{\\fs12}It is legal.\r\nDialogue: 0,0:05:41.12,0:05:43.47,yin,,0,0,0,,这样就设置好了\\N{\\fs12}Okay. So, now we'll have that.\r\nDialogue: 0,0:05:43.47,0:05:45.02,yin,,0,0,0,,现在我们再运行一下\\N{\\fs12}So now when we run this,\r\nDialogue: 0,0:05:47.40,0:05:51.03,yin,,0,0,0,,这回堆积的方块就不会那么摇晃了\\N{\\fs12}we'll get a little less of the tippy stack thing,\r\nDialogue: 0,0:05:51.92,0:05:54.97,yin,,0,0,0,,但是我没有修改重力大小\\N{\\fs12}although I didn't change the gravity,\r\nDialogue: 0,0:05:54.97,0:05:56.14,yin,,0,0,0,,我们先看看目前的效果\\N{\\fs12}but we'll see what happens here,\r\nDialogue: 0,0:05:56.14,0:05:57.82,yin,,0,0,0,,可以看到 它们没有转动\\N{\\fs12}but you can see they're definitely not twisting,\r\nDialogue: 0,0:05:57.82,0:05:58.56,yin,,0,0,0,,垂直落在其他方块顶部\\N{\\fs12}they're staying.\r\nDialogue: 0,0:05:58.76,0:06:01.46,yin,,0,0,0,,它们可能还是会稍微弹向一边\\N{\\fs12}They still might bounce slightly to the side if they--\r\nDialogue: 0,0:06:02.13,0:06:04.00,yin,,0,0,0,,比如当我快速点击时\\N{\\fs12}for example, if I clicked too fast\r\nDialogue: 0,0:06:04.01,0:06:06.19,yin,,0,0,0,,方块下落时就可能会相撞\\N{\\fs12}they might crash into each other on the way down,\r\nDialogue: 0,0:06:07.15,0:06:08.50,yin,,0,0,0,,如果它们都在同一列的话\\N{\\fs12}once that they are in the same column.\r\nDialogue: 0,0:06:08.50,0:06:09.10,yin,,0,0,0,,拼满一行了\\N{\\fs12}So here we go.\r\nDialogue: 0,0:06:09.10,0:06:10.68,yin,,0,0,0,,现在 就能更可靠地\\N{\\fs12}So now, they're gonna\r\nDialogue: 0,0:06:10.93,0:06:13.25,yin,,0,0,0,,显示飞走的效果了\\N{\\fs12}to be flying away a little more reliably.\r\nDialogue: 0,0:06:13.99,0:06:15.45,yin,,0,0,0,,我们再试试快速点击\\N{\\fs12}Let's try going really fast,\r\nDialogue: 0,0:06:15.45,0:06:17.09,yin,,0,0,0,,看看能不能让它们倾斜一点\\N{\\fs12}see if we can get them to tip a little.\r\nDialogue: 0,0:06:18.53,0:06:22.26,yin,,0,0,0,,如果拼满多行 这几行会一块飞出去\\N{\\fs12}Now I, if I have multiple rows, they should all go together.\r\nDialogue: 0,0:06:22.50,0:06:24.30,yin,,0,0,0,,还要注意 随着方块数量的增加\\N{\\fs12}Notice also I'm starting to get a lot of blocks\r\nDialogue: 0,0:06:24.30,0:06:27.03,yin,,0,0,0,,应用开始变得磕磕绊绊的了\\N{\\fs12}and it's the performance that's starting to get a little jerky.\r\nDialogue: 0,0:06:27.38,0:06:30.03,yin,,0,0,0,,这是需要大家理解的一点\\N{\\fs12}Okay? And that's something you have to understand\r\nDialogue: 0,0:06:30.21,0:06:32.22,yin,,0,0,0,,在动画时 如果要为很多对象添加动画\\N{\\fs12}when animation, if you have a lot of things animated,\r\nDialogue: 0,0:06:32.24,0:06:33.02,yin,,0,0,0,,并非免费的\\N{\\fs12}it's not free.\r\nDialogue: 0,0:06:33.36,0:06:34.92,yin,,0,0,0,,动画是要占用资源的\\N{\\fs12}Okay? Animation is not free.\r\nDialogue: 0,0:06:35.04,0:06:37.05,yin,,0,0,0,,如果你的应用像这里一样\\N{\\fs12}And if you had an application like this\r\nDialogue: 0,0:06:37.05,0:06:38.28,yin,,0,0,0,,让方块掉落下来\\N{\\fs12}where you were dropping these blocks\r\nDialogue: 0,0:06:38.30,0:06:40.22,yin,,0,0,0,,允许用户掉落很多方块\\N{\\fs12}and you allowed the user to drop a lot of them,\r\nDialogue: 0,0:06:40.24,0:06:41.92,yin,,0,0,0,,你可能需要进行一些其他处理\\N{\\fs12}you might have to start doing some other things,\r\nDialogue: 0,0:06:41.93,0:06:46.34,yin,,0,0,0,,比如 修改碰撞边界\\N{\\fs12}like, for example, instead of having the collision boundary,\r\nDialogue: 0,0:06:46.35,0:06:48.66,yin,,0,0,0,,不让所有动力项相互碰撞\\N{\\fs12}instead of having all the items collide with each other,\r\nDialogue: 0,0:06:48.77,0:06:52.04,yin,,0,0,0,,而是沿着顶部绘制一条边界\\N{\\fs12}what if you just drew a boundary around the top\r\nDialogue: 0,0:06:52.66,0:06:55.13,yin,,0,0,0,,让顶部的方块进行碰撞\\N{\\fs12}that they top ones could collide to.\r\nDialogue: 0,0:06:55.39,0:06:57.30,yin,,0,0,0,,这样 底部的方块\\N{\\fs12}You see? Then you would keep all those bottom ones\r\nDialogue: 0,0:06:57.31,0:06:59.58,yin,,0,0,0,,就不用再一直计算自己的移动位置\\N{\\fs12}from having to calculate where they're going to go,\r\nDialogue: 0,0:06:59.79,0:07:00.40,yin,,0,0,0,,因为你会注意到\\N{\\fs12}because you'll notice that\r\nDialogue: 0,0:07:00.41,0:07:02.08,yin,,0,0,0,,当它们被压在底下之后\\N{\\fs12}after they get tamped down a little bit,\r\nDialogue: 0,0:07:02.09,0:07:03.74,yin,,0,0,0,,就不会出现太多的弹跳了\\N{\\fs12}they don't bounce so much at the bottom anyways,\r\nDialogue: 0,0:07:03.75,0:07:06.36,yin,,0,0,0,,所以你可以取消弹跳 放置一个边界\\N{\\fs12}so you could take away that bounce and put a boundary,\r\nDialogue: 0,0:07:06.37,0:07:08.37,yin,,0,0,0,,边界是一个UIBezierPath\\N{\\fs12}because your boundary is a UIBezierPath,\r\nDialogue: 0,0:07:08.39,0:07:09.34,yin,,0,0,0,,可以是任意形状\\N{\\fs12}it can be anything you want.\r\nDialogue: 0,0:07:09.85,0:07:12.38,yin,,0,0,0,,如果要处理的动画对象太多\\N{\\fs12}Okay? So you have to think about that only, you know,\r\nDialogue: 0,0:07:12.38,0:07:14.82,yin,,0,0,0,,你就要考虑这个问题\\N{\\fs12}when you start getting to extreme cases there.\r\nDialogue: 0,0:07:15.82,0:07:16.50,yin,,0,0,0,,好了 同学们\\N{\\fs12}Okay, everyone.\r\nDialogue: 0,0:07:16.76,0:07:17.40,yin,,0,0,0,,有问题吗\\N{\\fs12}Cool with that?\r\nDialogue: 0,0:07:17.90,0:07:18.47,yin,,0,0,0,,都明白了吗\\N{\\fs12}Make sense?\r\nDialogue: 0,0:07:18.80,0:07:20.54,yin,,0,0,0,,我们最后要做的是\\N{\\fs12}Alright, so, the last thing we're gonna do\r\nDialogue: 0,0:07:20.55,0:07:22.13,yin,,0,0,0,,吸附行为\\N{\\fs12}is this attachment behavior.\r\nDialogue: 0,0:07:22.44,0:07:25.06,yin,,0,0,0,,就是吸附一条杆\\N{\\fs12}So this is just attaching that bar,\r\nDialogue: 0,0:07:25.14,0:07:27.26,yin,,0,0,0,,可以是有弹性的或者是一条铁杆\\N{\\fs12}which can be a springy bar or an iron bar,\r\nDialogue: 0,0:07:27.27,0:07:29.10,yin,,0,0,0,,我要用一条铁杆\\N{\\fs12}I'm going to leave mine be an iron bar,\r\nDialogue: 0,0:07:29.10,0:07:33.33,yin,,0,0,0,,既不会塌陷 也不会伸长\\N{\\fs12}you know, a bar that doesn't collapse and expand.\r\nDialogue: 0,0:07:33.90,0:07:39.22,yin,,0,0,0,,我们要用这条杆抓住掉落的方块\\N{\\fs12}And, we will use that bar to grab onto one that's coming down\r\nDialogue: 0,0:07:39.24,0:07:40.85,yin,,0,0,0,,这样就能将其摆动至目标列中\\N{\\fs12}so I can swing it into the right column,\r\nDialogue: 0,0:07:40.86,0:07:42.85,yin,,0,0,0,,目前是方块出现在哪一列\\N{\\fs12}because right now it's just whatever column it comes down in,\r\nDialogue: 0,0:07:42.86,0:07:44.69,yin,,0,0,0,,就落在那一列\\N{\\fs12}that's the column it goes in\r\nDialogue: 0,0:07:44.69,0:07:47.13,yin,,0,0,0,,感觉有点限制性\\N{\\fs12}and that's a little bit restrictive,\r\nDialogue: 0,0:07:47.85,0:07:51.77,yin,,0,0,0,,影响我的游戏的竞争力\\N{\\fs12}it makes it hard for my game to play very, very competitively.\r\nDialogue: 0,0:07:52.32,0:07:54.56,yin,,0,0,0,,我们要做的是\\N{\\fs12}And so, what we're gonna do to do this,\r\nDialogue: 0,0:07:54.57,0:07:57.35,yin,,0,0,0,,我们需要在视图控制器中增加一些东西\\N{\\fs12}we need a couple of things here, in our view controller.\r\nDialogue: 0,0:07:57.35,0:08:00.90,yin,,0,0,0,,首先我们显然需要一个吸附行为\\N{\\fs12}One is we're gonna clearly need an attachment behavior,\r\nDialogue: 0,0:08:00.91,0:08:04.12,yin,,0,0,0,,我要新建一个UIAttachmentBehavior\\N{\\fs12}so I'm gonna create a new UIAttachmentBehavior.\r\nDialogue: 0,0:08:04.24,0:08:07.27,yin,,0,0,0,,我就叫它attachment\\N{\\fs12}I'm just going to call it attachment, okay?\r\nDialogue: 0,0:08:07.70,0:08:15.01,yin,,0,0,0,,我还需要知道掉落的是哪个视图\\N{\\fs12}And, I'm also gonna need to know which view is dropping.\r\nDialogue: 0,0:08:16.56,0:08:18.87,yin,,0,0,0,,当前正在掉落的视图\\N{\\fs12}Okay? The view that's currently falling down\r\nDialogue: 0,0:08:18.89,0:08:20.33,yin,,0,0,0,,因为我要抓住的就是这个视图\\N{\\fs12}because that's the one I'm going to grab on.\r\nDialogue: 0,0:08:20.34,0:08:23.15,yin,,0,0,0,,游戏中有一大堆视图\\N{\\fs12}Because there's a whole bunch of views in my game, right?\r\nDialogue: 0,0:08:23.16,0:08:24.78,yin,,0,0,0,,这些视图都堆在那里\\N{\\fs12}Tons of them, all of them are stacked up there,\r\nDialogue: 0,0:08:24.97,0:08:28.04,yin,,0,0,0,,当我开始抓取时 我要抓住哪个\\N{\\fs12}which one, when I start grabbing, am I gonna grab onto?\r\nDialogue: 0,0:08:28.04,0:08:29.18,yin,,0,0,0,,就是这个droppingView\\N{\\fs12}It's gonna be the droppingView,\r\nDialogue: 0,0:08:29.19,0:08:31.88,yin,,0,0,0,,所以我要追踪正在掉落的视图\\N{\\fs12}so I'm gonna have to keep track of the dropping view\r\nDialogue: 0,0:08:31.89,0:08:33.61,yin,,0,0,0,,实际上 很容易追踪\\N{\\fs12}and, in fact, that's easy to keep track of,\r\nDialogue: 0,0:08:33.62,0:08:35.94,yin,,0,0,0,,就写在下面这里 每次掉落一个新的视图时\\N{\\fs12}I'll just write down here, every time I drop a new one,\r\nDialogue: 0,0:08:36.01,0:08:39.83,yin,,0,0,0,,就让droppingView等于dropView\\N{\\fs12}I'm gonna say the droppingView equals the dropView.\r\nDialogue: 0,0:08:40.14,0:08:41.99,yin,,0,0,0,,这样每次新视图掉落时\\N{\\fs12}Okay? So every time a new one comes down,\r\nDialogue: 0,0:08:42.00,0:08:43.59,yin,,0,0,0,,这个视图就是被抓取的视图\\N{\\fs12}it's gonna become the one that gets grabbed.\r\nDialogue: 0,0:08:43.75,0:08:45.90,yin,,0,0,0,,如果同时掉落多个视图\\N{\\fs12}So if I have multiple of them coming down at once,\r\nDialogue: 0,0:08:45.98,0:08:47.90,yin,,0,0,0,,那么就是最后一个掉落的视图\\N{\\fs12}it's the last one that started coming down\r\nDialogue: 0,0:08:47.90,0:08:49.09,yin,,0,0,0,,成为被抓取的对象\\N{\\fs12}is gonna be the one that gets grabbed,\r\nDialogue: 0,0:08:49.10,0:08:50.73,yin,,0,0,0,,用这个吸附行为进行抓取\\N{\\fs12}if I grab onto it with this attachment.\r\nDialogue: 0,0:08:51.38,0:08:53.47,yin,,0,0,0,,现在我得到了droppingView\\N{\\fs12}Okay? So now I have the droppingView.\r\nDialogue: 0,0:08:54.70,0:08:58.41,yin,,0,0,0,,我要用一个拖动手势实现吸附操作\\N{\\fs12}So, I'm gonna do the attachment with a pan gesture.\r\nDialogue: 0,0:08:58.45,0:09:00.96,yin,,0,0,0,,所以这里我们会见到另一个手势识别器\\N{\\fs12}Okay? So we're gonna see another gesture recognizer here,\r\nDialogue: 0,0:09:01.49,0:09:03.45,yin,,0,0,0,,我要抓住它\\N{\\fs12}because I'm gonna grab it\r\nDialogue: 0,0:09:03.46,0:09:06.14,yin,,0,0,0,,然后随着手指在屏幕上的移动\\N{\\fs12}and then as I move my finger around on the screen,\r\nDialogue: 0,0:09:06.15,0:09:09.54,yin,,0,0,0,,让吸附对象吸附着我的手指\\N{\\fs12}I'm gonna keep the attachment attached to my finger.\r\nDialogue: 0,0:09:09.84,0:09:12.90,yin,,0,0,0,,所以被抓住的那个方块\\N{\\fs12}So the block that's being grabbed onto it\r\nDialogue: 0,0:09:12.91,0:09:15.61,yin,,0,0,0,,会随着我的手指移动\\N{\\fs12}it will kind of follow my finger around, right?\r\nDialogue: 0,0:09:15.62,0:09:17.55,yin,,0,0,0,,二者中间有一条杆连着\\N{\\fs12}With the bar behind it.\r\nDialogue: 0,0:09:18.19,0:09:19.51,yin,,0,0,0,,很有意思\\N{\\fs12}So, that'll be kind of fun.\r\nDialogue: 0,0:09:20.00,0:09:20.89,yin,,0,0,0,,我们来做一下\\N{\\fs12}So let's do that.\r\nDialogue: 0,0:09:21.01,0:09:23.36,yin,,0,0,0,,大家还记得如何设置手势吧\\N{\\fs12}So you'll remember the gestures we set up, right,\r\nDialogue: 0,0:09:23.38,0:09:25.62,yin,,0,0,0,,在storyboard中进行设置 这是storyboard\\N{\\fs12}from our storyboard, right, here's the storyboard.\r\nDialogue: 0,0:09:25.86,0:09:27.91,yin,,0,0,0,,我要到这边抓取一个手势\\N{\\fs12}I'm gonna go over and grab a gesture,\r\nDialogue: 0,0:09:28.38,0:09:31.76,yin,,0,0,0,,拖动手势 代表随着手指移动\\N{\\fs12}it's a pan gesture, which means follow the finger around,\r\nDialogue: 0,0:09:31.77,0:09:32.94,yin,,0,0,0,,拖动手势在这里\\N{\\fs12}so here's a pan gesture.\r\nDialogue: 0,0:09:33.19,0:09:35.72,yin,,0,0,0,,拖出它  直接放在gameView上面\\N{\\fs12}Drag this out, I'm just gonna drag it on top of my gameView,\r\nDialogue: 0,0:09:35.80,0:09:36.85,yin,,0,0,0,,就放在上面这里\\N{\\fs12}right on top here.\r\nDialogue: 0,0:09:37.05,0:09:39.41,yin,,0,0,0,,这是我的点击手势和拖动手势\\N{\\fs12}Here's my tap gesture, here's my pan gesture,\r\nDialogue: 0,0:09:39.62,0:09:41.01,yin,,0,0,0,,我要把它拖出来\\N{\\fs12}so I'm gonna drag it out,\r\nDialogue: 0,0:09:41.04,0:09:44.53,yin,,0,0,0,,放到点击手势这边\\N{\\fs12}I'm gonna put it down near where my tap gesture is.\r\nDialogue: 0,0:09:44.53,0:09:45.89,yin,,0,0,0,,点击手势在这里\\N{\\fs12}Here's my tap gesture right here,\r\nDialogue: 0,0:09:45.90,0:09:48.38,yin,,0,0,0,,我就把拖动手势放在它下面\\N{\\fs12}so I'm gonna put my pan gesture right next to it.\r\nDialogue: 0,0:09:48.66,0:09:49.74,yin,,0,0,0,,我要叫它pan\\N{\\fs12}I'm going to call it pan,\r\nDialogue: 0,0:09:49.74,0:09:52.32,yin,,0,0,0,,我可能示范了不好的命名样式\\N{\\fs12}I'm probably teaching a bad style here\r\nDialogue: 0,0:09:52.33,0:09:53.68,yin,,0,0,0,,直接叫它们pan和tap\\N{\\fs12}to call these pan and tap,\r\nDialogue: 0,0:09:53.70,0:09:55.84,yin,,0,0,0,,我用这种名字是为了让大家明白\\N{\\fs12}I call them that so that when you see them you realize,\r\nDialogue: 0,0:09:55.86,0:09:57.43,yin,,0,0,0,,这是拖动手势处理器\\N{\\fs12}oh yeah, that's the pan gesture handler,\r\nDialogue: 0,0:09:57.65,0:10:00.37,yin,,0,0,0,,也可以叫做grabDrop等类似的名字\\N{\\fs12}but again, this could be something like grabDrop,\r\nDialogue: 0,0:10:00.71,0:10:03.42,yin,,0,0,0,,这种名字可能更适合这个拖动手势\\N{\\fs12}that might be a better name for this than pan.\r\nDialogue: 0,0:10:03.65,0:10:04.13,yin,,0,0,0,,明白吗\\N{\\fs12}Okay?\r\nDialogue: 0,0:10:05.22,0:10:08.60,yin,,0,0,0,,这就是我们的手势\\N{\\fs12}So, there's our gesture and--\r\nDialogue: 0,0:10:09.76,0:10:11.48,yin,,0,0,0,,扩大点空间\\N{\\fs12}let's make some more space\r\nDialogue: 0,0:10:11.49,0:10:13.31,yin,,0,0,0,,实际上 我们不需要...\\N{\\fs12}and actually we don't even need to see--\r\nDialogue: 0,0:10:13.32,0:10:15.02,yin,,0,0,0,,回到这里\\N{\\fs12}actually let's go back here.\r\nDialogue: 0,0:10:15.07,0:10:20.23,yin,,0,0,0,,这里我们不需要查看storyboard\\N{\\fs12}We don't need to see our storyboard for this.\r\nDialogue: 0,0:10:20.70,0:10:22.47,yin,,0,0,0,,拖动手势在这里\\N{\\fs12}Okay? So I've got my pan right here.\r\nDialogue: 0,0:10:22.54,0:10:24.42,yin,,0,0,0,,这个拖动手势中会发生什么呢\\N{\\fs12}So what's gonna happen in this pan?\r\nDialogue: 0,0:10:24.83,0:10:27.63,yin,,0,0,0,,拖动手势和捏合手势\\N{\\fs12}Okay, pan gestures, like pinch gestures,\r\nDialogue: 0,0:10:27.63,0:10:29.16,yin,,0,0,0,,以及其他类似连续手势\\N{\\fs12}and continuous gestures like that,\r\nDialogue: 0,0:10:29.29,0:10:34.22,yin,,0,0,0,,事件执行顺序类似\\N{\\fs12}they kind of have a similar sequence of events that goes on,\r\nDialogue: 0,0:10:34.23,0:10:35.63,yin,,0,0,0,,我有一小段代码\\N{\\fs12}so I have a little snippet\r\nDialogue: 0,0:10:35.64,0:10:38.04,yin,,0,0,0,,适用于所有这类手势\\N{\\fs12}that I do the same thing for all these kind of gestures,\r\nDialogue: 0,0:10:38.05,0:10:40.55,yin,,0,0,0,,开始时状态为Began\\N{\\fs12}which is they start out, they begin,\r\nDialogue: 0,0:10:40.74,0:10:42.59,yin,,0,0,0,,随着移动 状态变为Changed\\N{\\fs12}then they change as they move around\r\nDialogue: 0,0:10:42.61,0:10:43.28,yin,,0,0,0,,然后结束时状态为Ended\\N{\\fs12}and then they end.\r\nDialogue: 0,0:10:43.57,0:10:45.44,yin,,0,0,0,,执行吸附行为时\\N{\\fs12}So what are the three things we're going to do\r\nDialogue: 0,0:10:45.58,0:10:48.01,yin,,0,0,0,,拖动手势要做的三件事是什么呢\\N{\\fs12}for our pan gesture when we do our attachment?\r\nDialogue: 0,0:10:48.01,0:10:50.53,yin,,0,0,0,,首先 我要做的是\\N{\\fs12}Well, the first thing I'm going to do,\r\nDialogue: 0,0:10:50.53,0:10:51.75,yin,,0,0,0,,实际上 我要做的第一件事是\\N{\\fs12}actually the first thing I'm going to do\r\nDialogue: 0,0:10:51.76,0:10:54.12,yin,,0,0,0,,找到拖动手势的位置\\N{\\fs12}is I'm going to find out where is that pan gesture?\r\nDialogue: 0,0:10:54.37,0:10:56.40,yin,,0,0,0,,发生在gameView的什么位置呢\\N{\\fs12}Where did that happen in my gameView?\r\nDialogue: 0,0:10:56.59,0:10:57.27,yin,,0,0,0,,方法是\\N{\\fs12}And I'm going to do that with\r\nDialogue: 0,0:10:57.28,0:11:05.35,yin,,0,0,0,,CGPoint gesturePoint=[sender locationInView:gameView]\\N{\\fs12}CGPoint, gesturePoint equals sender locationInView, my gameView.\r\nDialogue: 0,0:11:06.33,0:11:08.90,yin,,0,0,0,,这样我就可以知道手势在gameView中发生的位置\\N{\\fs12}Okay, so now I know where in my gameView that happens.\r\nDialogue: 0,0:11:08.90,0:11:10.93,yin,,0,0,0,,这是个手势识别器 对吧\\N{\\fs12}So this is a gesture recognizer, right?\r\nDialogue: 0,0:11:10.93,0:11:14.80,yin,,0,0,0,,这是sender 这是拖动手势处理器的一个方法\\N{\\fs12}This sender is and this's a method in pan gesture recognizer,\r\nDialogue: 0,0:11:14.81,0:11:17.20,yin,,0,0,0,,能够告诉你拖动手势发生的位置\\N{\\fs12}which tells you the location the pan happened\r\nDialogue: 0,0:11:17.21,0:11:18.96,yin,,0,0,0,,如果手势正在移动\\N{\\fs12}or is happening if it's moving around,\r\nDialogue: 0,0:11:18.97,0:11:20.02,yin,,0,0,0,,它会告诉你最新的当前位置\\N{\\fs12}it tells you the new position.\r\nDialogue: 0,0:11:20.90,0:11:22.35,yin,,0,0,0,,这里我先要做的是\\N{\\fs12}So, the first thing I'm going to do\r\nDialogue: 0,0:11:22.36,0:11:25.35,yin,,0,0,0,,将刚才说过的droppingView\\N{\\fs12}is I'm going to attach the droppingView,\r\nDialogue: 0,0:11:25.35,0:11:27.92,yin,,0,0,0,,吸附到发生手势的那个点上\\N{\\fs12}that thing we just said, to that point.\r\nDialogue: 0,0:11:28.27,0:11:29.12,yin,,0,0,0,,gesturePoint这个点\\N{\\fs12}The gesturePoint.\r\nDialogue: 0,0:11:29.58,0:11:32.31,yin,,0,0,0,,这个方法我们要实现一下\\N{\\fs12}Okay? So this is a method we're going to have to write,\r\nDialogue: 0,0:11:32.47,0:11:35.52,yin,,0,0,0,,放到下面这里 这样我们就不会忘记实现它了\\N{\\fs12}so we'll put it down here so that we remember to do it.\r\nDialogue: 0,0:11:36.77,0:11:38.60,yin,,0,0,0,,但是如果我们不在这里增加这个方法\\N{\\fs12}Though we might, we might remember better\r\nDialogue: 0,0:11:38.60,0:11:40.47,yin,,0,0,0,,可能更不会忘\\N{\\fs12}if we don't put this down here, but,\r\nDialogue: 0,0:11:41.16,0:11:42.30,yin,,0,0,0,,因为系统会不断提示\\N{\\fs12}because it'll keep complaining.\r\nDialogue: 0,0:11:42.49,0:11:43.12,yin,,0,0,0,,这里先加上了\\N{\\fs12}We'll do that.\r\nDialogue: 0,0:11:43.13,0:11:44.87,yin,,0,0,0,,我要让它与droppingView吸附\\N{\\fs12}So I'm going to have this attached to droppingView,\r\nDialogue: 0,0:11:44.87,0:11:48.07,yin,,0,0,0,,这是使用吸附行为的主要内容\\N{\\fs12}that's going to the guts of doing an attachment thing.\r\nDialogue: 0,0:11:48.49,0:11:52.01,yin,,0,0,0,,当拖动手势变化时 当它移动到一个新位置时\\N{\\fs12}Here, when the pan changes, when it moves to a new spot,\r\nDialogue: 0,0:11:52.14,0:11:56.98,yin,,0,0,0,,我要将吸附行为的anchorPoint...\\N{\\fs12}I'm just going to have my attachment behavior anchorPoint,\r\nDialogue: 0,0:11:57.29,0:11:58.83,yin,,0,0,0,,还记得锚点吗\\N{\\fs12}okay, anchor point, remember,\r\nDialogue: 0,0:11:58.91,0:12:01.05,yin,,0,0,0,,吸附行为可以是两个动力项吸附\\N{\\fs12}the attachment can be either attachment between two items\r\nDialogue: 0,0:12:01.05,0:12:02.78,yin,,0,0,0,,或者是动力项和锚点吸附\\N{\\fs12}or between an anchor point in an item.\r\nDialogue: 0,0:12:02.80,0:12:04.33,yin,,0,0,0,,这里是动力项与锚点吸附\\N{\\fs12}This is going to be between an anchor point,\r\nDialogue: 0,0:12:04.39,0:12:07.00,yin,,0,0,0,,锚点会随着我的手指移动\\N{\\fs12}that anchor point is going to be following my finger around.\r\nDialogue: 0,0:12:07.38,0:12:10.40,yin,,0,0,0,,我要将它设为gesturePoint\\N{\\fs12}I'm going to set that to be the gesturePoint, okay?\r\nDialogue: 0,0:12:10.42,0:12:12.73,yin,,0,0,0,,这就是手势发生变化时 我要做的操作\\N{\\fs12}So that's all I'm going to do when it changes.\r\nDialogue: 0,0:12:13.19,0:12:14.97,yin,,0,0,0,,然后 当它完成时\\N{\\fs12}And then, when it's done,\r\nDialogue: 0,0:12:14.98,0:12:18.64,yin,,0,0,0,,我要移除这个吸附行为\\N{\\fs12}I'm going to do remove this attachment,\r\nDialogue: 0,0:12:19.53,0:12:24.05,yin,,0,0,0,,用removeBehavior将attachment从animator中移除\\N{\\fs12}removeBehavior, this attachment from my animator.\r\nDialogue: 0,0:12:24.07,0:12:27.68,yin,,0,0,0,,动画者会停止继续执行这个动画\\N{\\fs12}So my animator is gonna stop doing that animation anymore.\r\nDialogue: 0,0:12:28.34,0:12:29.62,yin,,0,0,0,,就是这样\\N{\\fs12}Okay? So that's it.\r\nDialogue: 0,0:12:30.01,0:12:32.75,yin,,0,0,0,,可以看到 这些都很简单\\N{\\fs12}You can see this is all pretty easy to do, all this stuff.\r\nDialogue: 0,0:12:32.75,0:12:35.12,yin,,0,0,0,,这个attach方法也非常简单\\N{\\fs12}Even this attach is going to be really straightforward.\r\nDialogue: 0,0:12:35.12,0:12:36.36,yin,,0,0,0,,我们来看一下这个方法\\N{\\fs12}So let's look at that attach.\r\nDialogue: 0,0:12:36.69,0:12:39.07,yin,,0,0,0,,如何在一个锚点和某个动力项之间\\N{\\fs12}How do we create an attachment behavior\r\nDialogue: 0,0:12:39.07,0:12:41.79,yin,,0,0,0,,创建吸附行为呢\\N{\\fs12}between an anchor point and some item?\r\nDialogue: 0,0:12:42.19,0:12:43.22,yin,,0,0,0,,非常简单\\N{\\fs12}And it's very simple.\r\nDialogue: 0,0:12:43.35,0:12:46.24,yin,,0,0,0,,如果有一个正在掉落的动力项\\N{\\fs12}If we have an item that's currently dropping, okay,\r\nDialogue: 0,0:12:46.24,0:12:47.22,yin,,0,0,0,,希望有一个\\N{\\fs12}hopefully we do,\r\nDialogue: 0,0:12:47.60,0:12:52.01,yin,,0,0,0,,然后我们只要新建一个吸附行为\\N{\\fs12}then we're just gonna create a new attachment behavior\r\nDialogue: 0,0:12:52.41,0:12:56.23,yin,,0,0,0,,用UIAttachmentBehavior alloc init\\N{\\fs12}with UIAttachmentBehavior alloc, and its init,\r\nDialogue: 0,0:12:56.24,0:12:58.98,yin,,0,0,0,,有四个不同的init方法\\N{\\fs12}it has, remember, four different kinds of inits here,\r\nDialogue: 0,0:12:58.98,0:13:00.89,yin,,0,0,0,,取决于你要创建的是锚点与动力项的吸附行为\\N{\\fs12}depending on whether you're attaching the points\r\nDialogue: 0,0:13:00.89,0:13:02.77,yin,,0,0,0,,还是两个动力项的吸附行为\\N{\\fs12}or between two items.\r\nDialogue: 0,0:13:02.93,0:13:05.49,yin,,0,0,0,,还可以吸附到一个偏移位置上\\N{\\fs12}It also has some ways to attach with an offset\r\nDialogue: 0,0:13:05.50,0:13:08.65,yin,,0,0,0,,这样连接铁杆就不会连接到物体中心\\N{\\fs12}so that the iron bar is not connected to the center of the thing,\r\nDialogue: 0,0:13:08.66,0:13:10.27,yin,,0,0,0,,中心会偏移一点\\N{\\fs12}maybe it's centered a little offset,\r\nDialogue: 0,0:13:10.43,0:13:11.65,yin,,0,0,0,,物体会略微倾斜\\N{\\fs12}it'll tilt a little bit.\r\nDialogue: 0,0:13:12.56,0:13:17.04,yin,,0,0,0,,我要用的是initWithItem attachedToAnchor\\N{\\fs12}So I'm gonna do the one which is initWithItem attachedToAnchor,\r\nDialogue: 0,0:13:17.51,0:13:20.75,yin,,0,0,0,,应该是这个\\N{\\fs12}which is this one I guess,\r\nDialogue: 0,0:13:21.64,0:13:24.30,yin,,0,0,0,,动力项就是那个droppingView\\N{\\fs12}and the item is going to be that droppingView.\r\nDialogue: 0,0:13:25.55,0:13:27.54,yin,,0,0,0,,错了 不是吸附到动力项上\\N{\\fs12}Oops, sorry, attach to item, no,\r\nDialogue: 0,0:13:27.55,0:13:30.29,yin,,0,0,0,,我想要的是吸附到锚点上\\N{\\fs12}I wanted a different one, I want attach to anchor.\r\nDialogue: 0,0:13:30.64,0:13:33.58,yin,,0,0,0,,锚点就是刚才的那个点\\N{\\fs12}And the anchor is going to be that point, right,\r\nDialogue: 0,0:13:33.65,0:13:35.63,yin,,0,0,0,,拖动手势触摸的位置\\N{\\fs12}where my tap pan gesture went down.\r\nDialogue: 0,0:13:36.22,0:13:37.54,yin,,0,0,0,,就是这些 就是这么简单\\N{\\fs12}So that's it, it's as simple as that,\r\nDialogue: 0,0:13:37.57,0:13:38.68,yin,,0,0,0,,我创建了一个吸附行为\\N{\\fs12}and now I have an attachment\r\nDialogue: 0,0:13:38.70,0:13:41.12,yin,,0,0,0,,吸附了那个点和掉落视图droppingView\\N{\\fs12}between that point and this droppingView,\r\nDialogue: 0,0:13:41.14,0:13:43.45,yin,,0,0,0,,锚点随着手势的移动而移动\\N{\\fs12}I'm gonna be moving that point as the gesture moves,\r\nDialogue: 0,0:13:43.75,0:13:45.81,yin,,0,0,0,,droppingView会跟在它后面移动\\N{\\fs12}and the droppingView is just gonna follow around.\r\nDialogue: 0,0:13:47.11,0:13:49.54,yin,,0,0,0,,吸附行为发生以后\\N{\\fs12}After that attachment happens, by the way,\r\nDialogue: 0,0:13:49.57,0:13:52.07,yin,,0,0,0,,就不允许再次操作了\\N{\\fs12}I'm not going to allow you to do it again,\r\nDialogue: 0,0:13:52.18,0:13:53.73,yin,,0,0,0,,所以我要将droppingView设为nil\\N{\\fs12}so I'm going to set the droppingView to nil.\r\nDialogue: 0,0:13:54.89,0:13:55.89,yin,,0,0,0,,换句话说\\N{\\fs12}Okay? So in other words,\r\nDialogue: 0,0:13:55.90,0:13:57.50,yin,,0,0,0,,不允许你抓住一个方块\\N{\\fs12}I'm not going to let you grab onto that thing,\r\nDialogue: 0,0:13:57.51,0:14:00.96,yin,,0,0,0,,移动一点 掉了 然后再次抓住移动\\N{\\fs12}move it a little, oops, grab onto it again, move it again,\r\nDialogue: 0,0:14:00.96,0:14:02.46,yin,,0,0,0,,不行 你只能移动一次\\N{\\fs12}nope, you get one try, okay\r\nDialogue: 0,0:14:02.47,0:14:03.48,yin,,0,0,0,,这是游戏规则的一部分\\N{\\fs12}that's just part of the game play,\r\nDialogue: 0,0:14:03.49,0:14:05.74,yin,,0,0,0,,只允许对掉落方块操作一次\\N{\\fs12}I only want you to get one try dropping that thing.\r\nDialogue: 0,0:14:06.32,0:14:09.60,yin,,0,0,0,,然后只要用animator addBehavior\\N{\\fs12}And then I just say, animator, addBehavior,\r\nDialogue: 0,0:14:09.61,0:14:14.18,yin,,0,0,0,,这样做之后 就会开始动画\\N{\\fs12}and instantly I do this it's going to start animating that.\r\nDialogue: 0,0:14:14.76,0:14:17.19,yin,,0,0,0,,为那个锚点和视图之间的连接\\N{\\fs12}Okay? Animating an anchor, a connection\r\nDialogue: 0,0:14:17.19,0:14:21.52,yin,,0,0,0,,添加动画\\N{\\fs12}between that point and that, that view.\r\nDialogue: 0,0:14:21.84,0:14:25.78,yin,,0,0,0,,这就是我要做的全部内容\\N{\\fs12}Okay? So, I think that's all that I have to do.\r\nDialogue: 0,0:14:26.17,0:14:27.72,yin,,0,0,0,,运行一下 看是否运行正常\\N{\\fs12}So let's run and see if this works.\r\nDialogue: 0,0:14:30.56,0:14:31.93,yin,,0,0,0,,一个方块掉下来了\\N{\\fs12}Alright, so we have them dropping down,\r\nDialogue: 0,0:14:31.94,0:14:34.88,yin,,0,0,0,,我抓住它 可以看到鼠标的移动\\N{\\fs12}I grabbed onto it, you see how, you see my mouse,\r\nDialogue: 0,0:14:34.88,0:14:36.87,yin,,0,0,0,,我好像抓住了它的手柄\\N{\\fs12}you can see how I kind of have a hold of it\r\nDialogue: 0,0:14:36.88,0:14:39.97,yin,,0,0,0,,像是一条杆 我甚至可以将它顶在上面\\N{\\fs12}and it's like a bar, I can even, whoa, balance it on top?\r\nDialogue: 0,0:14:39.97,0:14:42.31,yin,,0,0,0,,有点不容易看清楚\\N{\\fs12}You see? It's a little hard to see, right?\r\nDialogue: 0,0:14:42.32,0:14:43.73,yin,,0,0,0,,我们应该画一条线\\N{\\fs12}So maybe we'll draw a line\r\nDialogue: 0,0:14:43.73,0:14:47.98,yin,,0,0,0,,连接吸附点和方块\\N{\\fs12}between the attachment point and the little thing.\r\nDialogue: 0,0:14:49.62,0:14:50.23,yin,,0,0,0,,懂吗\\N{\\fs12}Okay?\r\nDialogue: 0,0:14:55.18,0:14:56.41,yin,,0,0,0,,所以这就是我下面要做的事情\\N{\\fs12}So that's the next thing I'm going to do\r\nDialogue: 0,0:14:56.41,0:15:01.45,yin,,0,0,0,,绘制一条线\\N{\\fs12}is I'm gonna draw a line between where I'm panning and the--\r\nDialogue: 0,0:15:02.11,0:15:03.43,yin,,0,0,0,,连接拖动手势位置和掉落项\\N{\\fs12}and the item that I'm dropping.\r\nDialogue: 0,0:15:03.43,0:15:04.22,yin,,0,0,0,,我们来做一下\\N{\\fs12}So let's do that.\r\nDialogue: 0,0:15:04.27,0:15:05.88,yin,,0,0,0,,这样做的原因\\N{\\fs12}And I'm doing that not as much,\r\nDialogue: 0,0:15:06.23,0:15:08.69,yin,,0,0,0,,不仅是为了演示吸附行为的工作原理\\N{\\fs12}partially to show you how the attachment is working,\r\nDialogue: 0,0:15:08.87,0:15:11.41,yin,,0,0,0,,还是为了演示action的使用方法\\N{\\fs12}but also because I want to show you how to use this action,\r\nDialogue: 0,0:15:11.41,0:15:15.63,yin,,0,0,0,,大家可以使用的这个action block\\N{\\fs12}this little action block that you can use.\r\nDialogue: 0,0:15:15.65,0:15:17.81,yin,,0,0,0,,我要如何绘制呢\\N{\\fs12}So, how am I going to draw that?\r\nDialogue: 0,0:15:17.91,0:15:23.40,yin,,0,0,0,,要如何绘制这条线呢\\N{\\fs12}Okay? How am I going to draw this line?\r\nDialogue: 0,0:15:23.66,0:15:25.13,yin,,0,0,0,,我要做的是\\N{\\fs12}Well, what I'm gonna do is\r\nDialogue: 0,0:15:25.38,0:15:30.25,yin,,0,0,0,,将这里的storyboard的gameView\\N{\\fs12}I'm going to make the gameView of my storyboard here\r\nDialogue: 0,0:15:30.58,0:15:33.76,yin,,0,0,0,,变为UIBezierPath绘制视图\\N{\\fs12}be a UIBezierPath Drawing view.\r\nDialogue: 0,0:15:34.98,0:15:37.47,yin,,0,0,0,,我要新建一种视图\\N{\\fs12}Okay? So I'm going to create a new kind of view,\r\nDialogue: 0,0:15:38.41,0:15:40.71,yin,,0,0,0,,选择新建文件\\N{\\fs12}oops, new file.\r\nDialogue: 0,0:15:41.23,0:15:44.73,yin,,0,0,0,,它是UIView的一个子类\\N{\\fs12}And it's going to be a UIView, subclass a UIView,\r\nDialogue: 0,0:15:44.96,0:15:48.75,yin,,0,0,0,,我要叫它BezierPathView\\N{\\fs12}I'm going to call it BezierPathView,\r\nDialogue: 0,0:15:49.33,0:15:51.75,yin,,0,0,0,,它会是一个完全通用的\\N{\\fs12}okay? And this is going to be a totally generic,\r\nDialogue: 0,0:15:51.98,0:15:54.33,yin,,0,0,0,,贝塞尔曲线绘制视图\\N{\\fs12}Bezier path drawing view,\r\nDialogue: 0,0:15:54.62,0:15:56.65,yin,,0,0,0,,所以在它的公有API中\\N{\\fs12}so it's public API is,\r\nDialogue: 0,0:15:56.65,0:15:59.68,yin,,0,0,0,,有一个公有属性\\N{\\fs12}it is going to have one property, public property,\r\nDialogue: 0,0:15:59.85,0:16:02.83,yin,,0,0,0,,是一个UIBezierPath 叫做path\\N{\\fs12}which is a UIBezierPath, called path.\r\nDialogue: 0,0:16:04.11,0:16:06.25,yin,,0,0,0,,这就是它的整个公有API\\N{\\fs12}Alright? That's its entire public API,\r\nDialogue: 0,0:16:06.36,0:16:09.18,yin,,0,0,0,,它只要在drawRect中\\N{\\fs12}and all its gonna do is in its drawRect,\r\nDialogue: 0,0:16:09.70,0:16:15.12,yin,,0,0,0,,用path stroke\\N{\\fs12}it is going to say path stroke.\r\nDialogue: 0,0:16:16.99,0:16:20.16,yin,,0,0,0,,我只要再...\\N{\\fs12}Okay? And the only other thing I'm going to do is--\r\nDialogue: 0,0:16:20.29,0:16:21.42,yin,,0,0,0,,是self.path\\N{\\fs12}self dot path,\r\nDialogue: 0,0:16:21.76,0:16:25.44,yin,,0,0,0,,我只要再做一件事 就是在setPath中\\N{\\fs12}and the only other thing I'm gonna do here is in setPath,\r\nDialogue: 0,0:16:25.51,0:16:27.15,yin,,0,0,0,,这是它的setter\\N{\\fs12}the setter for that thing,\r\nDialogue: 0,0:16:27.48,0:16:29.29,yin,,0,0,0,,在里面写_path=path\\N{\\fs12}I'm going to do underline path equals path,\r\nDialogue: 0,0:16:29.49,0:16:31.59,yin,,0,0,0,,self setNeedsDisplay\\N{\\fs12}and I'm going to say self setNeedsDisplay.\r\nDialogue: 0,0:16:31.61,0:16:34.74,yin,,0,0,0,,只要有人修改了path 就会重绘\\N{\\fs12}So anytime someone changes the path, it's going to redraw it.\r\nDialogue: 0,0:16:35.92,0:16:37.88,yin,,0,0,0,,大家明白这个类是做什么的了吗\\N{\\fs12}Okay? Everyone understand what this class does?\r\nDialogue: 0,0:16:37.89,0:16:38.94,yin,,0,0,0,,希望大家都明白了\\N{\\fs12}I hope, right?\r\nDialogue: 0,0:16:38.95,0:16:40.63,yin,,0,0,0,,这将大家知道的全部绘制的内容\\N{\\fs12}It combines everything you know\r\nDialogue: 0,0:16:40.64,0:16:42.33,yin,,0,0,0,,都结合在了一起\\N{\\fs12}about drawing, right, in one thing.\r\nDialogue: 0,0:16:42.67,0:16:45.97,yin,,0,0,0,,DrawRect BezierPath描边 setNeedsDisplay\\N{\\fs12}DrawRect, BezierPath stroking, setNeedsDisplay,\r\nDialogue: 0,0:16:45.97,0:16:47.15,yin,,0,0,0,,全部内容 就是这样\\N{\\fs12}the whole thing, so that's it.\r\nDialogue: 0,0:16:47.37,0:16:49.26,yin,,0,0,0,,现在我要回到storyboard\\N{\\fs12}Now, I'm going to go back to my storyboard\r\nDialogue: 0,0:16:49.40,0:16:54.41,yin,,0,0,0,,这个gameView现在是UIView类\\N{\\fs12}and I'm gona have this gameView, instead of being a UIView,\r\nDialogue: 0,0:16:54.51,0:16:58.25,yin,,0,0,0,,我要将它的类变为BezierPathView\\N{\\fs12}I'm going to change its class to be BezierPathView.\r\nDialogue: 0,0:16:58.84,0:17:01.12,yin,,0,0,0,,大家都记得吧 我讲过的\\N{\\fs12}Okay? So everyone remember what I told you about,\r\nDialogue: 0,0:17:01.13,0:17:02.63,yin,,0,0,0,,如果你有一个这样的自定义视图\\N{\\fs12}if you have a custom view like this,\r\nDialogue: 0,0:17:03.07,0:17:05.61,yin,,0,0,0,,刚拖出来时 它是一个通用视图\\N{\\fs12}it starts out generic when you drag it out,\r\nDialogue: 0,0:17:05.70,0:17:06.87,yin,,0,0,0,,最开始是通用的\\N{\\fs12}right, it starts out generic,\r\nDialogue: 0,0:17:07.02,0:17:09.19,yin,,0,0,0,,你可以修改它的类 就像控制器一样\\N{\\fs12}and you can change its class, just like with the controller.\r\nDialogue: 0,0:17:09.92,0:17:13.36,yin,,0,0,0,,为了让控制器中代码匹配\\N{\\fs12}Okay? Now, to match this up in my controller,\r\nDialogue: 0,0:17:13.48,0:17:19.00,yin,,0,0,0,,我最好将上面这里修改一下\\N{\\fs12}I better go up here and say that this is a--\r\nDialogue: 0,0:17:19.01,0:17:21.18,yin,,0,0,0,,我的gameView在哪呢\\N{\\fs12}where is that thing, my gameView,\r\nDialogue: 0,0:17:21.32,0:17:24.19,yin,,0,0,0,,将它改为BezierPathView\\N{\\fs12}is a BezierPathView,\r\nDialogue: 0,0:17:24.21,0:17:24.94,yin,,0,0,0,,这里要加一下\\N{\\fs12}so let's do that.\r\nDialogue: 0,0:17:25.15,0:17:26.56,yin,,0,0,0,,BezierPathView\\N{\\fs12}BezierPathView.\r\nDialogue: 0,0:17:29.02,0:17:31.57,yin,,0,0,0,,这里是BezierPathView\\N{\\fs12}Alright. So it's BezierPathView,\r\nDialogue: 0,0:17:31.65,0:17:34.82,yin,,0,0,0,,这样我就可以向它发送贝塞尔曲线消息了\\N{\\fs12}so that I can send it BezierPath messages, okay?\r\nDialogue: 0,0:17:35.30,0:17:38.28,yin,,0,0,0,,现在我的gameView可以显示任意贝塞尔曲线\\N{\\fs12}Alright, so now my gameView can display an arbitrary BezierPath,\r\nDialogue: 0,0:17:38.29,0:17:41.72,yin,,0,0,0,,现在我只要计算贝塞尔曲线\\N{\\fs12}so now all I have to do is calculate the BezierPath between--\r\nDialogue: 0,0:17:42.07,0:17:43.59,yin,,0,0,0,,吸附行为要显示的贝赛尔曲线\\N{\\fs12}that the attachment shows,\r\nDialogue: 0,0:17:43.60,0:17:45.67,yin,,0,0,0,,也就是锚点和掉落视图间的连线\\N{\\fs12}basically, between the anchor point and the dropping view,\r\nDialogue: 0,0:17:45.84,0:17:49.31,yin,,0,0,0,,每次吸附视图变化时\\N{\\fs12}and then every time that attachment view changes,\r\nDialogue: 0,0:17:49.67,0:17:52.01,yin,,0,0,0,,我都要对其重绘 重置路径\\N{\\fs12}I have to redraw, I have to reset that path,\r\nDialogue: 0,0:17:52.01,0:17:53.30,yin,,0,0,0,,每次都要重新计算\\N{\\fs12}recalculate it every time.\r\nDialogue: 0,0:17:53.38,0:17:54.97,yin,,0,0,0,,这也就是action block\\N{\\fs12}Okay, so that's where this action block\r\nDialogue: 0,0:17:55.65,0:17:56.70,yin,,0,0,0,,要起作用的地方\\N{\\fs12}is going to come into play.\r\nDialogue: 0,0:17:57.32,0:17:59.55,yin,,0,0,0,,我们要怎么做呢\\N{\\fs12}Alright? So, how are we going to do that?\r\nDialogue: 0,0:17:59.90,0:18:03.32,yin,,0,0,0,,我们在这个方法中实现\\N{\\fs12}Let's do it right in here, okay?\r\nDialogue: 0,0:18:03.64,0:18:07.27,yin,,0,0,0,,当我们在这里创建这个吸附行为时\\N{\\fs12}When we attach, when we create this attachment right here,\r\nDialogue: 0,0:18:07.96,0:18:13.61,yin,,0,0,0,,我们要使用它的action block\\N{\\fs12}we are going to use the little action block of this guy,\r\nDialogue: 0,0:18:14.84,0:18:17.98,yin,,0,0,0,,来更新它\\N{\\fs12}action, to update that thing,\r\nDialogue: 0,0:18:18.00,0:18:21.69,yin,,0,0,0,,首先是脱字符号^ 然后是大括号\\N{\\fs12}so, let's go caret, curly brace, curly brace,\r\nDialogue: 0,0:18:21.80,0:18:25.54,yin,,0,0,0,,这是声明block的方法\\N{\\fs12}okay, this is how we specify a block.\r\nDialogue: 0,0:18:25.78,0:18:30.38,yin,,0,0,0,,我们要将这段代码传递给attachment\\N{\\fs12}So we're gonna pass this block of code off to this attachment,\r\nDialogue: 0,0:18:30.97,0:18:31.97,yin,,0,0,0,,每次动画时\\N{\\fs12}and every time it animates,\r\nDialogue: 0,0:18:31.99,0:18:33.27,yin,,0,0,0,,就会调用这段代码\\N{\\fs12}it's gonna call this block of code,\r\nDialogue: 0,0:18:33.28,0:18:34.55,yin,,0,0,0,,我们要在这段代码中做什么呢\\N{\\fs12}and what are we going to do in this block of code?\r\nDialogue: 0,0:18:34.56,0:18:36.21,yin,,0,0,0,,我们要创建一个贝赛尔曲线\\N{\\fs12}Well, we're going to create a BezierPath.\r\nDialogue: 0,0:18:38.72,0:18:41.04,yin,,0,0,0,,[[UIBezierPath alloc] init]\\N{\\fs12}Just using UIBezierPath alloc init.\r\nDialogue: 0,0:18:42.59,0:18:44.84,yin,,0,0,0,,这个贝塞尔曲线需要有一个目标移动位置\\N{\\fs12}And this BezierPath needs to have a move to,\r\nDialogue: 0,0:18:44.84,0:18:51.43,yin,,0,0,0,,我们就让它移动到吸附行为的锚点\\N{\\fs12}so let's have it move to the anchor point of the attachment,\r\nDialogue: 0,0:18:51.43,0:18:56.54,yin,,0,0,0,,也就是self.attachment.anchorPoint\\N{\\fs12}so that's self dot attachment dot anchorPoint.\r\nDialogue: 0,0:18:57.22,0:19:00.49,yin,,0,0,0,,然后用path addLineToPoint\\N{\\fs12}And then we're gonna path add line to,\r\nDialogue: 0,0:19:00.88,0:19:03.99,yin,,0,0,0,,向掉落视图的位置添加连线\\N{\\fs12}we need to go to where the dropping view is.\r\nDialogue: 0,0:19:04.08,0:19:09.81,yin,,0,0,0,,也就是self.droppingView.center\\N{\\fs12}That's self dot droppingView dot center.\r\nDialogue: 0,0:19:10.99,0:19:13.61,yin,,0,0,0,,现在我们有了路径\\N{\\fs12}Alright? And now we have that path\r\nDialogue: 0,0:19:13.61,0:19:17.20,yin,,0,0,0,,我只要用self.gameView.path=path\\N{\\fs12}so I can just say self dot gameView dot path equals path.\r\nDialogue: 0,0:19:19.29,0:19:21.67,yin,,0,0,0,,有问题吗\\N{\\fs12}Okay? Any questions about this?\r\nDialogue: 0,0:19:21.90,0:19:22.28,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,0:19:22.46,0:19:28.02,yin,,0,0,0,,[学生提问]\\N{\\fs12}Student:[inaudible]\r\nDialogue: 0,0:19:28.04,0:19:28.87,yin,,0,0,0,,问题是\\N{\\fs12}Yeah, so the question is\r\nDialogue: 0,0:19:28.89,0:19:31.46,yin,,0,0,0,,不可以直接在这里用anchorPoint吗\\N{\\fs12}couldn't I just say right here anchorPoint?\r\nDialogue: 0,0:19:31.46,0:19:32.97,yin,,0,0,0,,因为我在这里传递了anchorPoint\\N{\\fs12}Because I'm passing anchorPoint right here.\r\nDialogue: 0,0:19:33.45,0:19:35.91,yin,,0,0,0,,答案是不行 不能这样做\\N{\\fs12}And the answer is no, I can't do that,\r\nDialogue: 0,0:19:36.15,0:19:39.60,yin,,0,0,0,,因为anchorPoint一直在变化\\N{\\fs12}because I'm changing the anchorPoint, right?\r\nDialogue: 0,0:19:39.80,0:19:42.90,yin,,0,0,0,,每次拖动手势移动时 都会修改锚点\\N{\\fs12}Every time you move that pan, I'm changing that anchor point.\r\nDialogue: 0,0:19:43.29,0:19:46.94,yin,,0,0,0,,每次发生时 这段代码都会被执行\\N{\\fs12}So, this block of code gets executed every time it happens,\r\nDialogue: 0,0:19:46.99,0:19:48.71,yin,,0,0,0,,所以我不能使用这个anchorPoint\\N{\\fs12}so I can't use this anchorPoint,\r\nDialogue: 0,0:19:48.72,0:19:51.31,yin,,0,0,0,,它只在第一次吸附时被传递进来\\N{\\fs12}which was only passed in here when I first attached it.\r\nDialogue: 0,0:19:51.57,0:19:55.96,yin,,0,0,0,,我得用self.attachment.anchorPoint\\N{\\fs12}I have to use self dot attachment dot anchorPoint.\r\nDialogue: 0,0:19:55.96,0:19:57.42,yin,,0,0,0,,也就是\\N{\\fs12}In other words, the anchor,\r\nDialogue: 0,0:19:57.54,0:19:59.98,yin,,0,0,0,,锚点当前吸附的那一点\\N{\\fs12}the anchor point's current attachment point.\r\nDialogue: 0,0:20:00.11,0:20:01.76,yin,,0,0,0,,所以我必须不断调用它\\N{\\fs12}Right? So that's why I have to keep calling that.\r\nDialogue: 0,0:20:01.76,0:20:02.11,yin,,0,0,0,,请讲\\N{\\fs12}Yeah?\r\nDialogue: 0,0:20:03.15,0:20:05.89,yin,,0,0,0,,你在设置block之后\\N{\\fs12}Since you setting self dot droppingView to nil\r\nDialogue: 0,0:20:05.91,0:20:08.33,yin,,0,0,0,,将self.droppingView设为了nil\\N{\\fs12}after you set that block\r\nDialogue: 0,0:20:10.04,0:20:11.87,yin,,0,0,0,,这会影响block内的操作吗\\N{\\fs12}will that affect what happens in the block?\r\nDialogue: 0,0:20:11.96,0:20:13.38,yin,,0,0,0,,非常好的问题\\N{\\fs12}Yeah. Excellent question.\r\nDialogue: 0,0:20:13.58,0:20:16.10,yin,,0,0,0,,我将这个self.droppingView设为了nil\\N{\\fs12}So, I'm setting this self dot droppingView to nil\r\nDialogue: 0,0:20:16.12,0:20:18.25,yin,,0,0,0,,我还在里面使用了self.droppingView\\N{\\fs12}and I'm using self dot droppingView in here.\r\nDialogue: 0,0:20:18.36,0:20:19.59,yin,,0,0,0,,不会出问题吗\\N{\\fs12}Isn't that going to break it?\r\nDialogue: 0,0:20:19.59,0:20:21.32,yin,,0,0,0,,答案是 当然会的\\N{\\fs12}And the answer is absolutely it is.\r\nDialogue: 0,0:20:21.59,0:20:22.96,yin,,0,0,0,,我是故意这样做的\\N{\\fs12}Okay, I did this intentionally,\r\nDialogue: 0,0:20:23.09,0:20:24.27,yin,,0,0,0,,因为我想告诉大家\\N{\\fs12}because I wanted to show you\r\nDialogue: 0,0:20:24.41,0:20:26.18,yin,,0,0,0,,这里面的内容\\N{\\fs12}that the things that are in here\r\nDialogue: 0,0:20:26.27,0:20:28.00,yin,,0,0,0,,每次都会被重新评估\\N{\\fs12}get reevaluated every time,\r\nDialogue: 0,0:20:28.01,0:20:31.03,yin,,0,0,0,,每次动画发生时 这个block都会被执行\\N{\\fs12}this block gets executed each time animation happens.\r\nDialogue: 0,0:20:31.05,0:20:32.68,yin,,0,0,0,,那要怎么办呢\\N{\\fs12}So how can I deal with that?\r\nDialogue: 0,0:20:32.87,0:20:34.00,yin,,0,0,0,,可以直接\\N{\\fs12}Well, I can just,\r\nDialogue: 0,0:20:34.02,0:20:36.55,yin,,0,0,0,,在这里新建一个局部变量\\N{\\fs12}how about create a little local variable here\r\nDialogue: 0,0:20:36.75,0:20:40.24,yin,,0,0,0,,叫做droppingView 让它等于self.droppingView\\N{\\fs12}called droppingView equals self dot droppingView,\r\nDialogue: 0,0:20:41.35,0:20:43.85,yin,,0,0,0,,然后在这里用这个局部变量\\N{\\fs12}and then I will use that right here.\r\nDialogue: 0,0:20:45.01,0:20:48.72,yin,,0,0,0,,这样我是在这里用局部变量抓取了droppingView\\N{\\fs12}Okay? So now I've captured the droppingView, here,\r\nDialogue: 0,0:20:48.86,0:20:51.48,yin,,0,0,0,,然后在这里使用\\N{\\fs12}in a local variable, and I'm using it here.\r\nDialogue: 0,0:20:51.52,0:20:53.62,yin,,0,0,0,,所以这里用的是这个局部变量\\N{\\fs12}So this is referring to this local variable,\r\nDialogue: 0,0:20:53.64,0:20:55.62,yin,,0,0,0,,而不再是self.droppingView了\\N{\\fs12}not to self dot droppingView anymore,\r\nDialogue: 0,0:20:55.82,0:20:57.86,yin,,0,0,0,,我将它设为nil也没关系\\N{\\fs12}and the fact that I set this to nil doesn't matter.\r\nDialogue: 0,0:20:57.86,0:20:59.71,yin,,0,0,0,,它还是会指向目标对象\\N{\\fs12}This one's still going to be pointing to that thing.\r\nDialogue: 0,0:21:00.39,0:21:02.71,yin,,0,0,0,,我只是想演示一下\\N{\\fs12}Okay? So that, I just wanted to kind of show you\r\nDialogue: 0,0:21:02.72,0:21:05.22,yin,,0,0,0,,block是如何获取\\N{\\fs12}how blocks capture the local variables\r\nDialogue: 0,0:21:05.57,0:21:07.35,yin,,0,0,0,,范围之外的局部变量的\\N{\\fs12}that are just outside their scope.\r\nDialogue: 0,0:21:08.47,0:21:10.55,yin,,0,0,0,,实际上 这里还有个问题\\N{\\fs12}Now, we have another problem in here, in fact,\r\nDialogue: 0,0:21:10.57,0:21:12.53,yin,,0,0,0,,编译器警告我们了 看到了吗\\N{\\fs12}the compiler's warning us about it, you see?\r\nDialogue: 0,0:21:12.62,0:21:14.58,yin,,0,0,0,,在此block中对self使用强引用\\N{\\fs12}Capturing self strongly in this block\r\nDialogue: 0,0:21:14.60,0:21:16.82,yin,,0,0,0,,可能会导致保留循环\\N{\\fs12}is likely to lead to a retain cycle.\r\nDialogue: 0,0:21:17.00,0:21:18.85,yin,,0,0,0,,就是我们说过的存储循环\\N{\\fs12}That's a memory cycle like we were talking about.\r\nDialogue: 0,0:21:19.02,0:21:20.22,yin,,0,0,0,,实际上 确实会的\\N{\\fs12}And, in fact, it's going to.\r\nDialogue: 0,0:21:20.57,0:21:25.39,yin,,0,0,0,,因为这个action block是在这个attachment中的\\N{\\fs12}Because this action, this block, is inside this attachment,\r\nDialogue: 0,0:21:25.39,0:21:28.44,yin,,0,0,0,,被attachment强引用 而attachment又被self强引用\\N{\\fs12}strongly held by it, which is strongly held by us,\r\nDialogue: 0,0:21:28.44,0:21:30.36,yin,,0,0,0,,所以我们有一个指向block的强指针\\N{\\fs12}so we have a strong pointer to the block,\r\nDialogue: 0,0:21:30.57,0:21:31.87,yin,,0,0,0,,如果在这里使用self\\N{\\fs12}and if I put self in here,\r\nDialogue: 0,0:21:31.88,0:21:33.95,yin,,0,0,0,,block就会有一个指向self的强指针\\N{\\fs12}the block is going to have a strong pointer to us,\r\nDialogue: 0,0:21:34.26,0:21:35.23,yin,,0,0,0,,这样就不好了\\N{\\fs12}and that's no good.\r\nDialogue: 0,0:21:35.58,0:21:36.81,yin,,0,0,0,,所以我们要使用这个技巧\\N{\\fs12}So we're going to do this trick,\r\nDialogue: 0,0:21:36.83,0:21:41.47,yin,,0,0,0,,双下划线weak 叫什么来着\\N{\\fs12}underbar, underbar weak UI-- what do we call,\r\nDialogue: 0,0:21:41.48,0:21:42.61,yin,,0,0,0,,它叫什么\\N{\\fs12}what is the name of this thing?\r\nDialogue: 0,0:21:42.62,0:21:46.12,yin,,0,0,0,,DropitViewController 这就是self\\N{\\fs12}DropitViewController, that's our self.\r\nDialogue: 0,0:21:46.83,0:21:49.39,yin,,0,0,0,,weakSelf=self\\N{\\fs12}WeakSelf equals self.\r\nDialogue: 0,0:21:49.56,0:21:52.68,yin,,0,0,0,,这样我就创建了一个指向self的弱指针\\N{\\fs12}So now I've created a weak pointer to myself,\r\nDialogue: 0,0:21:53.04,0:21:54.45,yin,,0,0,0,,然后我就可以在这里使用它了\\N{\\fs12}and now I can use that here.\r\nDialogue: 0,0:21:54.55,0:21:55.33,yin,,0,0,0,,weakSelf\\N{\\fs12}WeakSelf.\r\nDialogue: 0,0:21:56.12,0:21:57.62,yin,,0,0,0,,还有下面这里\\N{\\fs12}Okay? Also down here.\r\nDialogue: 0,0:21:58.01,0:22:01.18,yin,,0,0,0,,weakSelf 明白吗\\N{\\fs12}WeakSelf. Alright?\r\nDialogue: 0,0:22:02.04,0:22:04.59,yin,,0,0,0,,如果我从堆中被释放\\N{\\fs12}So if I ever got dropped out of the heap,\r\nDialogue: 0,0:22:04.99,0:22:06.75,yin,,0,0,0,,没有强指针指向我了\\N{\\fs12}and no one had a strong pointer to me,\r\nDialogue: 0,0:22:06.92,0:22:09.00,yin,,0,0,0,,weakSelf指针就会变为nil\\N{\\fs12}these weakSelf pointers would all go to nil,\r\nDialogue: 0,0:22:09.00,0:22:09.87,yin,,0,0,0,,但这是没问题的\\N{\\fs12}but that would be fine,\r\nDialogue: 0,0:22:09.88,0:22:11.14,yin,,0,0,0,,因为如果我不在\\N{\\fs12}because if I'm not around,\r\nDialogue: 0,0:22:11.15,0:22:13.44,yin,,0,0,0,,那这个action也没什么意义了 对吧\\N{\\fs12}then this action doesn't mean anything anyway, right?\r\nDialogue: 0,0:22:13.44,0:22:14.43,yin,,0,0,0,,我是控制器\\N{\\fs12}I'm the controller.\r\nDialogue: 0,0:22:14.98,0:22:17.72,yin,,0,0,0,,所以这样做完全没问题\\N{\\fs12}So, so it's all perfectly fine to do that.\r\nDialogue: 0,0:22:18.93,0:22:21.05,yin,,0,0,0,,对刚才这部分有问题吗\\N{\\fs12}Okay? Any questions about what we did there?\r\nDialogue: 0,0:22:21.07,0:22:23.49,yin,,0,0,0,,这也是需要理解的重要内容\\N{\\fs12}Because that's an important thing to understand, as well.\r\nDialogue: 0,0:22:24.98,0:22:27.74,yin,,0,0,0,,我们要做的最后一件事是\\N{\\fs12}Alright. One last thing we have to do is\r\nDialogue: 0,0:22:27.91,0:22:31.74,yin,,0,0,0,,当这个拖动手势结束时\\N{\\fs12}when the gesture ends, the pan gesture ends,\r\nDialogue: 0,0:22:31.75,0:22:33.35,yin,,0,0,0,,移除动画者\\N{\\fs12}and we remove the animator,\r\nDialogue: 0,0:22:33.53,0:22:34.63,yin,,0,0,0,,具体代码是\\N{\\fs12}we're going to want to say\r\nDialogue: 0,0:22:34.64,0:22:36.99,yin,,0,0,0,,self.gameView.path=nil\\N{\\fs12}self dot gameView dot path equals nil.\r\nDialogue: 0,0:22:37.68,0:22:40.58,yin,,0,0,0,,因为这个action...\\N{\\fs12}Okay? Because this action--\r\nDialogue: 0,0:22:40.59,0:22:43.24,yin,,0,0,0,,当这里移除之后\\N{\\fs12}once this thing is removed from here,\r\nDialogue: 0,0:22:43.37,0:22:45.27,yin,,0,0,0,,这个action就不会再执行了\\N{\\fs12}this action is not going to execute anymore,\r\nDialogue: 0,0:22:45.28,0:22:47.36,yin,,0,0,0,,不会再执行一次action\\N{\\fs12}so we're not gonna get that last action\r\nDialogue: 0,0:22:47.36,0:22:48.93,yin,,0,0,0,,什么都不绘制 对吧\\N{\\fs12}that draws nothing, right?\r\nDialogue: 0,0:22:48.93,0:22:50.88,yin,,0,0,0,,我们不希望把那条线留在屏幕上\\N{\\fs12}We don't want that line to be left there.\r\nDialogue: 0,0:22:51.89,0:22:54.58,yin,,0,0,0,,为了让大家理解\\N{\\fs12}Okay? In fact, here, just to make sure you understand this,\r\nDialogue: 0,0:22:54.59,0:22:56.91,yin,,0,0,0,,我把它先注释掉 看会发生什么\\N{\\fs12}I'll leave this out and we'll see what happens.\r\nDialogue: 0,0:22:58.74,0:23:00.61,yin,,0,0,0,,方块掉下来了 看\\N{\\fs12}Okay, so I'm dropping here and now, see,\r\nDialogue: 0,0:23:00.62,0:23:01.62,yin,,0,0,0,,我撑住了这条杆\\N{\\fs12}look, I've got my bar.\r\nDialogue: 0,0:23:03.32,0:23:05.61,yin,,0,0,0,,可以来回移动 掉落在目标位置\\N{\\fs12}Dance this thing around, drop it where I want.\r\nDialogue: 0,0:23:05.61,0:23:07.21,yin,,0,0,0,,看到了吗 这条线没有消失\\N{\\fs12}Oh, see the bar didn't go away.\r\nDialogue: 0,0:23:07.85,0:23:09.28,yin,,0,0,0,,因为action没被调用\\N{\\fs12}Okay? Because that action never called,\r\nDialogue: 0,0:23:09.29,0:23:10.51,yin,,0,0,0,,因为这行代码\\N{\\fs12}that's because of this line of codes,\r\nDialogue: 0,0:23:10.51,0:23:13.27,yin,,0,0,0,,取消注释 再运行一次\\N{\\fs12}so let's put this back, now we'll run.\r\nDialogue: 0,0:23:15.19,0:23:18.07,yin,,0,0,0,,掉下来一个 抓住它 又掉下来一个\\N{\\fs12}Okay, now we drop one, we got it, drop another one,\r\nDialogue: 0,0:23:18.07,0:23:21.11,yin,,0,0,0,,又掉下来一个 从旁边抓住 又一个\\N{\\fs12}another one, grab onto the side, another one,\r\nDialogue: 0,0:23:21.92,0:23:23.58,yin,,0,0,0,,可以让它旋转\\N{\\fs12}try and swing it around.\r\nDialogue: 0,0:23:24.28,0:23:26.60,yin,,0,0,0,,如果我们让它转起来 撞到这里\\N{\\fs12}Okay, if we swing it around and smash it in there,\r\nDialogue: 0,0:23:26.61,0:23:27.61,yin,,0,0,0,,它们依旧会产生碰撞效果\\N{\\fs12}they'll still collide.\r\nDialogue: 0,0:23:27.96,0:23:31.42,yin,,0,0,0,,碰撞依然发生\\N{\\fs12}Okay? These are still collision, still happening,\r\nDialogue: 0,0:23:32.18,0:23:33.96,yin,,0,0,0,,还可以看到\\N{\\fs12}and you can see also that our game\r\nDialogue: 0,0:23:34.07,0:23:35.94,yin,,0,0,0,,游戏目前有点问题\\N{\\fs12}has a little bit of a problem right now,\r\nDialogue: 0,0:23:35.96,0:23:38.22,yin,,0,0,0,,对了 它不能旋转\\N{\\fs12}by the way, this not being able to rotate\r\nDialogue: 0,0:23:38.24,0:23:39.87,yin,,0,0,0,,所以不会翻下来\\N{\\fs12}is why it didn't tip off there.\r\nDialogue: 0,0:23:40.11,0:23:42.37,yin,,0,0,0,,因为它...\\N{\\fs12}Okay? Because it kind of got, with being,\r\nDialogue: 0,0:23:42.37,0:23:46.10,yin,,0,0,0,,某个动力项行为阻止了它翻下来\\N{\\fs12}some item behavior is keeping it from tipping off, okay?\r\nDialogue: 0,0:23:47.73,0:23:50.18,yin,,0,0,0,,目前不是个好游戏\\N{\\fs12}So, this is, by a bad far, game,\r\nDialogue: 0,0:23:50.18,0:23:52.87,yin,,0,0,0,,因为很难让这些方块排列在底部\\N{\\fs12}because how are we ever gonna line these blocks up here, right?\r\nDialogue: 0,0:23:53.25,0:23:55.10,yin,,0,0,0,,下面我们要做的呢\\N{\\fs12}So the next thing we would want to do,\r\nDialogue: 0,0:23:55.36,0:23:58.39,yin,,0,0,0,,我没时间做了\\N{\\fs12}and this is what I'm not gonna do because time here\r\nDialogue: 0,0:23:58.57,0:24:01.64,yin,,0,0,0,,就是碰撞 当碰撞发生时\\N{\\fs12}is in the collisions, okay, when collisions happen,\r\nDialogue: 0,0:24:01.66,0:24:03.51,yin,,0,0,0,,碰撞也有一个委托\\N{\\fs12}collisions have a delegate, as well.\r\nDialogue: 0,0:24:03.98,0:24:06.75,yin,,0,0,0,,在委托中 你要做的是每次...\\N{\\fs12}And in that delegate, what could you do is every time--\r\nDialogue: 0,0:24:06.99,0:24:09.59,yin,,0,0,0,,碰撞委托可以告诉你碰撞何时开始\\N{\\fs12}and the collision delegate tells you when a collision starts\r\nDialogue: 0,0:24:09.60,0:24:12.18,yin,,0,0,0,,何时不再处理\\N{\\fs12}and when the collision is ended being processed.\r\nDialogue: 0,0:24:12.57,0:24:15.05,yin,,0,0,0,,在结束处理程序中\\N{\\fs12}Okay? And in that ending handler,\r\nDialogue: 0,0:24:15.06,0:24:17.78,yin,,0,0,0,,碰撞向碰撞委托\\N{\\fs12}the ending message that gets sent by the collision\r\nDialogue: 0,0:24:18.71,0:24:19.81,yin,,0,0,0,,发送的结束消息中\\N{\\fs12}to this collision delegate,\r\nDialogue: 0,0:24:19.81,0:24:22.55,yin,,0,0,0,,在那个方法中 你要将方块进行排列\\N{\\fs12}in that ending thing, you would then grid the thing up.\r\nDialogue: 0,0:24:23.20,0:24:25.04,yin,,0,0,0,,也许可以检查一下它的线速度\\N{\\fs12}Probably look at its linear velocity,\r\nDialogue: 0,0:24:25.05,0:24:26.12,yin,,0,0,0,,如果它在向右移动\\N{\\fs12}if it's moving to the right,\r\nDialogue: 0,0:24:26.19,0:24:28.39,yin,,0,0,0,,就向右多移一些 让它排列对齐\\N{\\fs12}move it to the right a little more until it lines up.\r\nDialogue: 0,0:24:28.44,0:24:29.59,yin,,0,0,0,,如果它向左移动\\N{\\fs12}If it's moving to the left,\r\nDialogue: 0,0:24:29.59,0:24:31.49,yin,,0,0,0,,就向左多移一些 让它排列对齐\\N{\\fs12}move it to the left a little more until it lines up.\r\nDialogue: 0,0:24:31.71,0:24:34.45,yin,,0,0,0,,代码不多\\N{\\fs12}See? So, not too many lines of code,\r\nDialogue: 0,0:24:34.45,0:24:37.50,yin,,0,0,0,,但我今天想把自动布局讲完\\N{\\fs12}but I want to make sure we cover autolayout today\r\nDialogue: 0,0:24:37.50,0:24:38.82,yin,,0,0,0,,所以课上就不继续演示了\\N{\\fs12}so we won't do it, but--\r\nDialogue: 0,0:24:38.98,0:24:42.74,yin,,0,0,0,,刚才的演示有什么问题吗\\N{\\fs12}any questions about what we did so far or what we did here?\r\nDialogue: 0,0:24:50.17,0:24:50.75,yin,,0,0,0,,好的\\N{\\fs12}Okay.\r\nDialogue: 0,0:24:50.92,0:24:55.43,yin,,0,0,0,,那我们就来讲一下自动布局\\N{\\fs12}Alright, so let's get on to the lecture about autolayout.\r\nDialogue: 0,0:24:55.76,0:24:57.95,yin,,0,0,0,,keynote在哪呢 这呢\\N{\\fs12}Where is my keynote, there it is.\r\nDialogue: 0,0:25:01.49,0:25:03.78,yin,,0,0,0,,什么是自动布局呢\\N{\\fs12}So what is autolayout?\r\nDialogue: 0,0:25:04.25,0:25:07.38,yin,,0,0,0,,自动布局是设置所有视图框架的\\N{\\fs12}So autolayout is a way of setting the frame\r\nDialogue: 0,0:25:07.57,0:25:09.42,yin,,0,0,0,,一种方法\\N{\\fs12}of all your views, okay?\r\nDialogue: 0,0:25:09.42,0:25:12.79,yin,,0,0,0,,可以是用代码创建的视图框架\\N{\\fs12}And these can be frames of views that you make in code\r\nDialogue: 0,0:25:13.07,0:25:16.71,yin,,0,0,0,,也可以是拖进storyboard中的框架\\N{\\fs12}or frames that you drag out into your storyboard, okay?\r\nDialogue: 0,0:25:16.71,0:25:18.40,yin,,0,0,0,,但是我要提醒一下\\N{\\fs12}Although I'll warn you for your homework,\r\nDialogue: 0,0:25:18.52,0:25:22.70,yin,,0,0,0,,作业中用代码创建的卡牌的框架\\N{\\fs12}the frames of the cards that you make in code,\r\nDialogue: 0,0:25:22.77,0:25:24.96,yin,,0,0,0,,最好不要使用自动布局\\N{\\fs12}you're probably not gonna wanna use autolayout\r\nDialogue: 0,0:25:25.09,0:25:26.13,yin,,0,0,0,,来进行布局\\N{\\fs12}to lay those out,\r\nDialogue: 0,0:25:26.15,0:25:27.11,yin,,0,0,0,,你要使用\\N{\\fs12}you're going to want to use, like,\r\nDialogue: 0,0:25:27.12,0:25:29.48,yin,,0,0,0,,我提供的grid类或你自己编写的类\\N{\\fs12}that grid class I gave you or some class you write.\r\nDialogue: 0,0:25:29.56,0:25:31.67,yin,,0,0,0,,因为它们的布局规则\\N{\\fs12}Okay? Because the rules for laying them out\r\nDialogue: 0,0:25:31.83,0:25:34.50,yin,,0,0,0,,超出了自动布局的功能范围\\N{\\fs12}are kind of beyond even what autolayout can do.\r\nDialogue: 0,0:25:35.34,0:25:37.34,yin,,0,0,0,,这只是一点提醒\\N{\\fs12}Okay? So that's just a little hint there.\r\nDialogue: 0,0:25:37.56,0:25:40.69,yin,,0,0,0,,但是全部其他视图\\N{\\fs12}But all the other views, every other, every single other view,\r\nDialogue: 0,0:25:40.70,0:25:43.04,yin,,0,0,0,,包括容纳卡牌的那个视图\\N{\\fs12}including the view that contains your cards,\r\nDialogue: 0,0:25:43.24,0:25:44.75,yin,,0,0,0,,都要使用自动布局\\N{\\fs12}you'll want to use autolayout\r\nDialogue: 0,0:25:45.22,0:25:47.48,yin,,0,0,0,,来决定其在屏幕上的显示位置\\N{\\fs12}to decide where it gets put on screen.\r\nDialogue: 0,0:25:47.54,0:25:49.81,yin,,0,0,0,,框架的位置将取决于规则\\N{\\fs12}So we're going to decide where to put these frames\r\nDialogue: 0,0:25:49.82,0:25:52.63,yin,,0,0,0,,而不再是数字\\N{\\fs12}using rules instead of using numbers,\r\nDialogue: 0,0:25:52.63,0:25:57.19,yin,,0,0,0,,不用再说 将它放到20,20的位置 180宽200高\\N{\\fs12}instead of saying, putting it 20, 20, 180 wide by 200 high,\r\nDialogue: 0,0:25:57.24,0:26:01.23,yin,,0,0,0,,我们要用规则来决定框架的位置\\N{\\fs12}we're going to use rules to decide where it goes, okay?\r\nDialogue: 0,0:26:01.41,0:26:03.67,yin,,0,0,0,,这些规则灵活又强大\\N{\\fs12}And these rules are really flexible and powerful,\r\nDialogue: 0,0:26:03.75,0:26:05.76,yin,,0,0,0,,大部分是关于\\N{\\fs12}and the rules are mostly about the relationship\r\nDialogue: 0,0:26:05.76,0:26:07.70,yin,,0,0,0,,两个视图间的关系\\N{\\fs12}between one view to another view\r\nDialogue: 0,0:26:07.72,0:26:09.67,yin,,0,0,0,,或者视图与其父视图之间的关系\\N{\\fs12}or between a view to its superview.\r\nDialogue: 0,0:26:10.41,0:26:12.37,yin,,0,0,0,,为什么我们要用规则而不是数字\\N{\\fs12}Okay, now why do we want to specify these frames\r\nDialogue: 0,0:26:12.37,0:26:14.13,yin,,0,0,0,,来指定这些框架的位置呢\\N{\\fs12}as rules instead of as numbers?\r\nDialogue: 0,0:26:14.26,0:26:16.66,yin,,0,0,0,,因为包含全部视图的矩形边框\\N{\\fs12}Because sometimes the bounding rectangle\r\nDialogue: 0,0:26:16.66,0:26:19.07,yin,,0,0,0,,有时会变化\\N{\\fs12}that contains all our views is changing.\r\nDialogue: 0,0:26:19.24,0:26:21.19,yin,,0,0,0,,可能是因为设备旋转了\\N{\\fs12}Either because device rotated,\r\nDialogue: 0,0:26:21.30,0:26:24.04,yin,,0,0,0,,iPhone屏幕高度不同\\N{\\fs12}we're on a tall iPhone versus a short iPhone,\r\nDialogue: 0,0:26:24.15,0:26:27.26,yin,,0,0,0,,是否嵌入导航控制器\\N{\\fs12}we're embedded inside of a navigation controller or not,\r\nDialogue: 0,0:26:27.40,0:26:29.04,yin,,0,0,0,,是否有选项卡栏\\N{\\fs12}we're in a tab view bar or not,\r\nDialogue: 0,0:26:29.13,0:26:32.48,yin,,0,0,0,,或者是在iPad的弹出窗口控制器视图中\\N{\\fs12}we're on an iPad in some popover controller view\r\nDialogue: 0,0:26:32.49,0:26:33.12,yin,,0,0,0,,等类似情况\\N{\\fs12}or something like that,\r\nDialogue: 0,0:26:33.13,0:26:35.73,yin,,0,0,0,,有很多原因可能会导致边框大小变化\\N{\\fs12}there's a lot of reasons that are bounds would change size,\r\nDialogue: 0,0:26:35.73,0:26:38.05,yin,,0,0,0,,所以我们想要让视图\\N{\\fs12}so we want to build our views\r\nDialogue: 0,0:26:38.48,0:26:41.53,yin,,0,0,0,,能够对其内容自动调整\\N{\\fs12}so that what's inside of them adjust automatically.\r\nDialogue: 0,0:26:41.53,0:26:44.13,yin,,0,0,0,,这是作业中很重要的一部分\\N{\\fs12}Okay? And that's part of, a big part of your assignment,\r\nDialogue: 0,0:26:44.22,0:26:47.83,yin,,0,0,0,,你的卡牌视图\\N{\\fs12}although, your views want to, in terms of your card view,\r\nDialogue: 0,0:26:47.84,0:26:49.45,yin,,0,0,0,,本来就是要自动调整的\\N{\\fs12}want to adjust automatically anyway,\r\nDialogue: 0,0:26:49.49,0:26:51.35,yin,,0,0,0,,因为你一直在添加和移除卡牌\\N{\\fs12}because you're adding and removing cards from them\r\nDialogue: 0,0:26:51.40,0:26:52.53,yin,,0,0,0,,所以它们必须要调整布局\\N{\\fs12}and so they have to adjust anyway,\r\nDialogue: 0,0:26:52.54,0:26:54.88,yin,,0,0,0,,这里的自动布局有点像是白得的\\N{\\fs12}so you kind of get, probably get that for free,\r\nDialogue: 0,0:26:55.16,0:26:56.21,yin,,0,0,0,,但是所有其他视图\\N{\\fs12}but all the rest of your views,\r\nDialogue: 0,0:26:56.23,0:26:58.60,yin,,0,0,0,,重新发牌和得分等等\\N{\\fs12}the one that says redeal and score and all that,\r\nDialogue: 0,0:26:58.62,0:27:00.63,yin,,0,0,0,,在旋转设备时 要使用自动布局\\N{\\fs12}you're going to want to use autolayout to make those\r\nDialogue: 0,0:27:00.77,0:27:02.60,yin,,0,0,0,,让它们正确显示在合适位置上\\N{\\fs12}fit in the right place when you rotate the phone.\r\nDialogue: 0,0:27:03.30,0:27:05.30,yin,,0,0,0,,这些规则\\N{\\fs12}Now, there, these rules,\r\nDialogue: 0,0:27:05.31,0:27:08.07,yin,,0,0,0,,我们叫做constraints约束 布局约束\\N{\\fs12}by the way, we call them constraints, layout constraints,\r\nDialogue: 0,0:27:08.23,0:27:09.42,yin,,0,0,0,,我说约束时\\N{\\fs12}so that, when I use the word constraints,\r\nDialogue: 0,0:27:09.42,0:27:10.69,yin,,0,0,0,,指的就是\\N{\\fs12}that's what I'm talking about the rules\r\nDialogue: 0,0:27:10.70,0:27:12.62,yin,,0,0,0,,设置所有视图框架的规则\\N{\\fs12}for how to set the frames of all these views.\r\nDialogue: 0,0:27:13.18,0:27:16.50,yin,,0,0,0,,iOS中有一个很强大的API\\N{\\fs12}There's a really powerful API in iOS for this,\r\nDialogue: 0,0:27:16.51,0:27:18.37,yin,,0,0,0,,也就是一个程序接口 包含对象\\N{\\fs12}in other word, a program interface with object\r\nDialogue: 0,0:27:18.39,0:27:21.03,yin,,0,0,0,,布局约束等等全套机制\\N{\\fs12}and its layout constrained and all these mechanisms,\r\nDialogue: 0,0:27:21.05,0:27:24.22,yin,,0,0,0,,但是绝大部分自动布局的操作\\N{\\fs12}but really, almost all of what we do with autolayout,\r\nDialogue: 0,0:27:24.23,0:27:26.10,yin,,0,0,0,,都是在Xcode可视化界面中实现的\\N{\\fs12}we do in Xcode, visually,\r\nDialogue: 0,0:27:26.45,0:27:28.74,yin,,0,0,0,,通常不会使用代码实现\\N{\\fs12}we don't usually go to the code.\r\nDialogue: 0,0:27:28.96,0:27:29.96,yin,,0,0,0,,如果你要用代码实现\\N{\\fs12}If you're going to the code,\r\nDialogue: 0,0:27:29.97,0:27:32.36,yin,,0,0,0,,那就是非常高级的布局了\\N{\\fs12}you're doing some pretty advanced layout, okay?\r\nDialogue: 0,0:27:32.50,0:27:34.35,yin,,0,0,0,,我相信 使用代码\\N{\\fs12}I'm sure it's possible, actually with the code,\r\nDialogue: 0,0:27:34.37,0:27:36.82,yin,,0,0,0,,可以使用自动布局处理卡牌布局\\N{\\fs12}you could lay your cards out using autolayout,\r\nDialogue: 0,0:27:37.04,0:27:38.56,yin,,0,0,0,,但在Xcode中可能不行\\N{\\fs12}but Xcode, probably not.\r\nDialogue: 0,0:27:39.18,0:27:42.74,yin,,0,0,0,,因为全部都是Xcode中的图形化操作\\N{\\fs12}Okay? So since it's all Xcode and it's all graphically,\r\nDialogue: 0,0:27:42.76,0:27:45.67,yin,,0,0,0,,我就用屏幕截图来讲解\\N{\\fs12}I'm going to do this entire lecture about autolayout\r\nDialogue: 0,0:27:46.23,0:27:48.06,yin,,0,0,0,,自动布局这部分了\\N{\\fs12}with screen shots, okay?\r\nDialogue: 0,0:27:48.47,0:27:50.10,yin,,0,0,0,,就直接串讲一遍\\N{\\fs12}And we'll just kind of walk through it,\r\nDialogue: 0,0:27:50.77,0:27:52.25,yin,,0,0,0,,前面几步我就直接跳过去了\\N{\\fs12}I'm actually going to skip these first few here\r\nDialogue: 0,0:27:52.26,0:27:53.56,yin,,0,0,0,,我会在示例中演示\\N{\\fs12}because I'll show you that in the demo.\r\nDialogue: 0,0:27:54.86,0:27:58.71,yin,,0,0,0,,我要新建一个视图\\N{\\fs12}So what I'm gonna do it I'm going to start with a view,\r\nDialogue: 0,0:27:58.76,0:28:00.15,yin,,0,0,0,,这里的这个控制器的视图\\N{\\fs12}controller's view, right here,\r\nDialogue: 0,0:28:00.24,0:28:01.59,yin,,0,0,0,,里边有两个Thing\\N{\\fs12}with a couple of things in it.\r\nDialogue: 0,0:28:01.60,0:28:02.71,yin,,0,0,0,,Thing 1和Thing 2\\N{\\fs12}Thing one and thing two,\r\nDialogue: 0,0:28:02.73,0:28:04.30,yin,,0,0,0,,苏斯博士抱歉了\\N{\\fs12}with apologies to Dr. Seuss,\r\nDialogue: 0,0:28:04.57,0:28:07.18,yin,,0,0,0,,Thing 1和Thing 2可以是任意视图\\N{\\fs12}things one and thing two, they can be any kind of view,\r\nDialogue: 0,0:28:07.24,0:28:08.68,yin,,0,0,0,,这里它们是UILabel\\N{\\fs12}they're UILabels in this case,\r\nDialogue: 0,0:28:08.68,0:28:09.76,yin,,0,0,0,,但也可以是按钮\\N{\\fs12}but they could be buttons,\r\nDialogue: 0,0:28:09.77,0:28:11.30,yin,,0,0,0,,可以是自定义视图等等\\N{\\fs12}they could be custom views, whatever,\r\nDialogue: 0,0:28:11.32,0:28:12.64,yin,,0,0,0,,它们就是Thing 1和Thing 2\\N{\\fs12}they're just thing one and thing two,\r\nDialogue: 0,0:28:12.98,0:28:16.28,yin,,0,0,0,,我们想让Thing 1和Thing 2\\N{\\fs12}and we want thing one and thing two to\r\nDialogue: 0,0:28:16.41,0:28:20.41,yin,,0,0,0,,在边界改变时 显示在正确的位置\\N{\\fs12}be in the right place when this bounds changes.\r\nDialogue: 0,0:28:20.47,0:28:22.39,yin,,0,0,0,,现在如果我让它横屏显示\\N{\\fs12}Okay? So what happens right now,\r\nDialogue: 0,0:28:22.89,0:28:25.09,yin,,0,0,0,,会发生什么呢\\N{\\fs12}if we go and try and show this in landscape,\r\nDialogue: 0,0:28:25.11,0:28:26.97,yin,,0,0,0,,我可以运行它\\N{\\fs12}well, I could run this\r\nDialogue: 0,0:28:27.06,0:28:30.41,yin,,0,0,0,,然后再将模拟器翻转到横屏模式\\N{\\fs12}and then flip the simulator to landscape to see,\r\nDialogue: 0,0:28:30.51,0:28:33.62,yin,,0,0,0,,但其实还可以将视图控制器场景\\N{\\fs12}but it's actually possible to take your view controller scene,\r\nDialogue: 0,0:28:33.75,0:28:37.30,yin,,0,0,0,,在Xcode中翻转为横屏模式\\N{\\fs12}and flip it to landscape in Xcode, okay?\r\nDialogue: 0,0:28:37.96,0:28:38.94,yin,,0,0,0,,有两种方法可以实现\\N{\\fs12}Now there are two ways to do,\r\nDialogue: 0,0:28:38.95,0:28:41.28,yin,,0,0,0,,一是Xcode中有一个预览器\\N{\\fs12}one is Xcode actually has a previewer,\r\nDialogue: 0,0:28:41.34,0:28:42.64,yin,,0,0,0,,可以预览\\N{\\fs12}a previewer that will preview\r\nDialogue: 0,0:28:42.65,0:28:44.01,yin,,0,0,0,,UI在不同情况下的显示效果\\N{\\fs12}what your UI's going to look like\r\nDialogue: 0,0:28:44.18,0:28:46.82,yin,,0,0,0,,不同的旋转方向 不同的iPhone版本\\N{\\fs12}on different rotations, different iPhones,\r\nDialogue: 0,0:28:46.83,0:28:48.81,yin,,0,0,0,,甚至iOS7和iOS6的显示效果\\N{\\fs12}even between iOS 7 and iOS 6,\r\nDialogue: 0,0:28:48.81,0:28:50.72,yin,,0,0,0,,如果你的应用是要兼容两版iOS的话\\N{\\fs12}if you're writing an app that's compatible for both.\r\nDialogue: 0,0:28:51.78,0:28:55.20,yin,,0,0,0,,另一种方法是直接检查控制器\\N{\\fs12}But another way to do it is just to inspect your controller,\r\nDialogue: 0,0:28:55.20,0:28:57.72,yin,,0,0,0,,这里我选中了控制器\\N{\\fs12}so here I've selected my controller, right,\r\nDialogue: 0,0:28:57.74,0:29:00.21,yin,,0,0,0,,蓝色边框表示我已经选中了它\\N{\\fs12}it's got a blue boundary around it and I've selected it,\r\nDialogue: 0,0:29:00.37,0:29:02.74,yin,,0,0,0,,然后转到属性检查器\\N{\\fs12}and I went to the attributes inspector, you see?\r\nDialogue: 0,0:29:02.75,0:29:03.58,yin,,0,0,0,,在右上方\\N{\\fs12}Upper right there.\r\nDialogue: 0,0:29:03.66,0:29:04.75,yin,,0,0,0,,检查它\\N{\\fs12}And I'm inspecting it.\r\nDialogue: 0,0:29:04.85,0:29:06.77,yin,,0,0,0,,控制器检查器中\\N{\\fs12}And if you look at the inspector for controller,\r\nDialogue: 0,0:29:06.78,0:29:10.71,yin,,0,0,0,,最上面五项是Simulated Metrics模拟选项\\N{\\fs12}the top five things there are called simulated metrics.\r\nDialogue: 0,0:29:11.16,0:29:13.77,yin,,0,0,0,,可以在这里设置模拟用户界面\\N{\\fs12}And this is a way to simulate your user interface\r\nDialogue: 0,0:29:13.77,0:29:19.53,yin,,0,0,0,,选择不同的方向或大小 或者是否有选项卡栏\\N{\\fs12}in different orientations or sizes or with tab bars or not,\r\nDialogue: 0,0:29:19.54,0:29:20.69,yin,,0,0,0,,通过这样来确认\\N{\\fs12}so that you kind of make sure\r\nDialogue: 0,0:29:20.69,0:29:22.62,yin,,0,0,0,,UI在自动布局条件下显示正常\\N{\\fs12}your UI is working with autolayout,\r\nDialogue: 0,0:29:22.80,0:29:25.50,yin,,0,0,0,,这里我们选择切换方向\\N{\\fs12}so we're gonna go and switch the orientation,\r\nDialogue: 0,0:29:25.51,0:29:28.00,yin,,0,0,0,,选择Orientation方向选项\\N{\\fs12}alright, so I'm picking on this thing orientation,\r\nDialogue: 0,0:29:28.09,0:29:29.63,yin,,0,0,0,,切换为Landscape横屏模式\\N{\\fs12}and I'm switching it to landscape.\r\nDialogue: 0,0:29:29.98,0:29:31.00,yin,,0,0,0,,这样做之后\\N{\\fs12}And when I do that,\r\nDialogue: 0,0:29:31.19,0:29:34.25,yin,,0,0,0,,场景切换为横屏模式 Thing 2没了\\N{\\fs12}my scene changes to landscape and I lost thing two.\r\nDialogue: 0,0:29:34.64,0:29:36.16,yin,,0,0,0,,Thing 2怎么了\\N{\\fs12}Okay? What happened to thing two?\r\nDialogue: 0,0:29:36.17,0:29:38.75,yin,,0,0,0,,实际上 Thing 2还在那呢 留在那了\\N{\\fs12}Well, thing two is actually there, I left it there,\r\nDialogue: 0,0:29:38.77,0:29:40.29,yin,,0,0,0,,变灰了 看到了吗\\N{\\fs12}it's kind of grayed out, you see it?\r\nDialogue: 0,0:29:40.46,0:29:41.77,yin,,0,0,0,,但是没有显示在屏幕上\\N{\\fs12}But it's not on screen\r\nDialogue: 0,0:29:41.84,0:29:43.51,yin,,0,0,0,,因为很不幸\\N{\\fs12}because unfortunately in landscape\r\nDialogue: 0,0:29:43.73,0:29:46.82,yin,,0,0,0,,横屏模式不够长 够不到Thing 2\\N{\\fs12}it doesn't go down far enough to reach thing two.\r\nDialogue: 0,0:29:47.60,0:29:49.37,yin,,0,0,0,,我把方向切换回去\\N{\\fs12}Okay? So I'm going to switch back.\r\nDialogue: 0,0:29:49.38,0:29:51.83,yin,,0,0,0,,还要注意 方向选项中\\N{\\fs12}By the way, you notice that the orientation there,\r\nDialogue: 0,0:29:51.83,0:29:54.36,yin,,0,0,0,,不仅有横屏竖屏 还有一个Inferred推断\\N{\\fs12}there's portrait landscape and there's also inferred.\r\nDialogue: 0,0:29:54.66,0:29:55.90,yin,,0,0,0,,当修改场景边界时\\N{\\fs12}Okay, for all of these things\r\nDialogue: 0,0:29:55.92,0:29:59.04,yin,,0,0,0,,对应的这些内容\\N{\\fs12}where you change the bounds of your scene,\r\nDialogue: 0,0:29:59.15,0:30:01.75,yin,,0,0,0,,Inferred推断表示\\N{\\fs12}inferred means inferred from\r\nDialogue: 0,0:30:01.76,0:30:03.54,yin,,0,0,0,,从storyboard中进行推断\\N{\\fs12}what's going on in your storyboard.\r\nDialogue: 0,0:30:03.78,0:30:07.19,yin,,0,0,0,,如果这个场景是在导航控制器中\\N{\\fs12}So this's the thing that makes a bar come across the top\r\nDialogue: 0,0:30:07.20,0:30:09.56,yin,,0,0,0,,它就会在顶部添加一条导航栏\\N{\\fs12}if this scene is in a navigation controller,\r\nDialogue: 0,0:30:09.70,0:30:10.74,yin,,0,0,0,,如果是一个选项卡栏控制器\\N{\\fs12}or a bar across the bottom\r\nDialogue: 0,0:30:10.75,0:30:12.94,yin,,0,0,0,,就在底部添加一条选项卡栏\\N{\\fs12}if this scene is a tab bar controller, okay?\r\nDialogue: 0,0:30:13.63,0:30:16.89,yin,,0,0,0,,竖屏是默认的推断方向\\N{\\fs12}Portrait is the default inferred orientation,\r\nDialogue: 0,0:30:17.02,0:30:18.52,yin,,0,0,0,,所以如果你选择推断选项\\N{\\fs12}so if you pick inferred,\r\nDialogue: 0,0:30:18.80,0:30:20.20,yin,,0,0,0,,就像其他选项选择推断一样\\N{\\fs12}just like you pick inferred for the other things,\r\nDialogue: 0,0:30:20.32,0:30:21.88,yin,,0,0,0,,它会推断你指的是竖屏\\N{\\fs12}it will infer that you mean portrait.\r\nDialogue: 0,0:30:22.13,0:30:24.01,yin,,0,0,0,,如果你选择竖屏...\\N{\\fs12}So whether you say portrait landscape,\r\nDialogue: 0,0:30:24.42,0:30:26.95,yin,,0,0,0,,竖屏和推断选项的方向一样的\\N{\\fs12}portrait or inferred are the same for orientation.\r\nDialogue: 0,0:30:27.36,0:30:28.64,yin,,0,0,0,,横屏就代表横屏\\N{\\fs12}Landscape means landscape.\r\nDialogue: 0,0:30:29.07,0:30:31.35,yin,,0,0,0,,我们再将方向设回为推断或竖屏\\N{\\fs12}So let's go back to inferred, or to portrait.\r\nDialogue: 0,0:30:31.56,0:30:32.75,yin,,0,0,0,,Thing 2又回来了\\N{\\fs12}We get thing two back.\r\nDialogue: 0,0:30:33.00,0:30:34.46,yin,,0,0,0,,Thing 2哪都没去\\N{\\fs12}Okay, thing two didn't go anywhere,\r\nDialogue: 0,0:30:34.48,0:30:36.86,yin,,0,0,0,,它之前还在那 只不过不显示在屏幕上了\\N{\\fs12}it was there before, it just wasn't on screen.\r\nDialogue: 0,0:30:37.90,0:30:41.36,yin,,0,0,0,,我想将Thing 1和Thing 2放在更合适的位置上\\N{\\fs12}So, I want to put thing one and thing two in better places.\r\nDialogue: 0,0:30:41.37,0:30:42.84,yin,,0,0,0,,它们现在是随机放置的\\N{\\fs12}They're kind of in random places,\r\nDialogue: 0,0:30:42.90,0:30:44.72,yin,,0,0,0,,我想将它们放在某个特定位置\\N{\\fs12}I want to put them in places\r\nDialogue: 0,0:30:44.73,0:30:47.15,yin,,0,0,0,,这样就可以为它们的显示位置设定规则了\\N{\\fs12}where I can have a rule that says where they are,\r\nDialogue: 0,0:30:47.28,0:30:48.23,yin,,0,0,0,,我要做的是\\N{\\fs12}and then what I'm going to do is\r\nDialogue: 0,0:30:48.24,0:30:50.54,yin,,0,0,0,,将Thing 1放到左上角\\N{\\fs12}I'm gonna put thing one in the upper left corner\r\nDialogue: 0,0:30:50.55,0:30:52.62,yin,,0,0,0,,将Thing 2放到右下角\\N{\\fs12}and I'm gonna put thing two in the lower right corner,\r\nDialogue: 0,0:30:52.79,0:30:54.44,yin,,0,0,0,,让Thing 1和Thing2\\N{\\fs12}and I always want thing one and thing two\r\nDialogue: 0,0:30:54.45,0:30:55.68,yin,,0,0,0,,始终位于这两个角上\\N{\\fs12}to stay in those corners,\r\nDialogue: 0,0:30:55.77,0:30:57.56,yin,,0,0,0,,无论这两个角的位置如何移动\\N{\\fs12}no matter where those corners move.\r\nDialogue: 0,0:30:58.05,0:31:00.47,yin,,0,0,0,,如果转为横屏模式 下角上移\\N{\\fs12}Okay? If those corners move up in the landscape\r\nDialogue: 0,0:31:00.48,0:31:03.83,yin,,0,0,0,,或者因为iPhone版本不同 下角下移\\N{\\fs12}or down because it's an iPhone, the tall iPhone,\r\nDialogue: 0,0:31:04.36,0:31:06.21,yin,,0,0,0,,比如更长的iPhone 5等等\\N{\\fs12}like an iPhone 5, or up, or whatever,\r\nDialogue: 0,0:31:06.22,0:31:07.89,yin,,0,0,0,,我想让这两个Thing始终显示在两个角上\\N{\\fs12}I want those things to stick to their corners,\r\nDialogue: 0,0:31:07.89,0:31:10.27,yin,,0,0,0,,所以我要的规则就是始终显示在两个角上\\N{\\fs12}so the rules I want is stick in the corners, okay,\r\nDialogue: 0,0:31:10.70,0:31:13.39,yin,,0,0,0,,我要演示三种设置规则的方法\\N{\\fs12}I'm gonna show you three ways to set rules,\r\nDialogue: 0,0:31:13.61,0:31:15.74,yin,,0,0,0,,这节课上会讲三种不同的方法\\N{\\fs12}over the course of this lecture, three different ways.\r\nDialogue: 0,0:31:15.84,0:31:18.39,yin,,0,0,0,,第一种方法 大家已经用过了\\N{\\fs12}The first way, you have already been doing.\r\nDialogue: 0,0:31:18.99,0:31:21.15,yin,,0,0,0,,无意间用过了 也不是完全无意\\N{\\fs12}Unwittingly, well, not really unwittingly\r\nDialogue: 0,0:31:21.15,0:31:22.46,yin,,0,0,0,,因为是我告诉大家这样做的\\N{\\fs12}because I've been telling you to do it,\r\nDialogue: 0,0:31:22.63,0:31:25.26,yin,,0,0,0,,就是使用蓝色辅助线\\N{\\fs12}which is to use those blue guidelines, okay?\r\nDialogue: 0,0:31:25.40,0:31:27.23,yin,,0,0,0,,当拖出对象时\\N{\\fs12}When you drag things around\r\nDialogue: 0,0:31:27.24,0:31:31.32,yin,,0,0,0,,借助蓝线将其放置到特定位置\\N{\\fs12}and you let the blue guidelines snap to certain locations,\r\nDialogue: 0,0:31:31.41,0:31:34.68,yin,,0,0,0,,就是告诉了Xcode你想要怎样\\N{\\fs12}you're basically telling Xcode what you want.\r\nDialogue: 0,0:31:35.24,0:31:37.69,yin,,0,0,0,,当我将Thing 1拖到左上角时\\N{\\fs12}So when I drag thing one up into this upper left-hand corner\r\nDialogue: 0,0:31:37.69,0:31:39.34,yin,,0,0,0,,出现这两条蓝线\\N{\\fs12}and these two blue lines appear,\r\nDialogue: 0,0:31:39.46,0:31:40.75,yin,,0,0,0,,就是告诉Xcode\\N{\\fs12}it's really telling Xcode, yeah,\r\nDialogue: 0,0:31:40.77,0:31:42.95,yin,,0,0,0,,我想让它跟着这两条线\\N{\\fs12}I want it to be stuck to this line and stuck to this line,\r\nDialogue: 0,0:31:42.95,0:31:44.48,yin,,0,0,0,,也就是左上角\\N{\\fs12}in other words, upper left there.\r\nDialogue: 0,0:31:44.69,0:31:46.75,yin,,0,0,0,,Thing 2也是一样的\\N{\\fs12}And same thing when I do that for thing two.\r\nDialogue: 0,0:31:47.02,0:31:48.51,yin,,0,0,0,,我告诉了Xcode要怎样处理\\N{\\fs12}Okay? I'm kind of telling Xcode.\r\nDialogue: 0,0:31:48.93,0:31:51.66,yin,,0,0,0,,但是我这样拖动放置之后\\N{\\fs12}But if I drag these two things then, right,\r\nDialogue: 0,0:31:51.76,0:31:53.82,yin,,0,0,0,,再次切换至横屏模式\\N{\\fs12}and then I switch over to landscape again,\r\nDialogue: 0,0:31:54.05,0:31:55.32,yin,,0,0,0,,Thing 2依旧无法显示出来\\N{\\fs12}I still don't get thing two.\r\nDialogue: 0,0:31:55.83,0:31:58.08,yin,,0,0,0,,为什么不行呢 我用了蓝线\\N{\\fs12}Why not? Okay, I did the blue lines,\r\nDialogue: 0,0:31:58.26,0:31:59.76,yin,,0,0,0,,为什么不能用呢\\N{\\fs12}how come it doesn't work?\r\nDialogue: 0,0:32:00.02,0:32:02.40,yin,,0,0,0,,答案是 借助蓝线可以告诉Xcode\\N{\\fs12}And the answer is, all the blue lines are\r\nDialogue: 0,0:32:02.41,0:32:04.74,yin,,0,0,0,,你想要什么\\N{\\fs12}is telling Xcode what you intend.\r\nDialogue: 0,0:32:04.96,0:32:06.78,yin,,0,0,0,,你还得要求Xcode\\N{\\fs12}You still have to ask Xcode,\r\nDialogue: 0,0:32:06.98,0:32:10.06,yin,,0,0,0,,为我执行这些规则 这些约束\\N{\\fs12}make those rules for me, make those constraints.\r\nDialogue: 0,0:32:10.58,0:32:14.09,yin,,0,0,0,,我们回到竖屏方向\\N{\\fs12}Okay? So let's go back to, to the portrait orientation,\r\nDialogue: 0,0:32:14.58,0:32:15.66,yin,,0,0,0,,实现方法是\\N{\\fs12}and the way you do that,\r\nDialogue: 0,0:32:15.88,0:32:17.32,yin,,0,0,0,,通过底部的这些小按钮\\N{\\fs12}is the little buttons at the bottom,\r\nDialogue: 0,0:32:17.33,0:32:18.70,yin,,0,0,0,,看到底部的按钮了吗\\N{\\fs12}you see these buttons at the bottom,\r\nDialogue: 0,0:32:19.39,0:32:21.74,yin,,0,0,0,,我点击了一个\\N{\\fs12}those, here I'll click on one.\r\nDialogue: 0,0:32:22.19,0:32:24.89,yin,,0,0,0,,它们都与自动布局有关\\N{\\fs12}Those all have to do with autolayout, okay?\r\nDialogue: 0,0:32:25.04,0:32:26.24,yin,,0,0,0,,表示你要如何布局视图\\N{\\fs12}And how you're going to layout the view.\r\nDialogue: 0,0:32:26.25,0:32:28.77,yin,,0,0,0,,这个像钛战机的按钮\\N{\\fs12}And this one, that looked kind of like a TIE fighter,\r\nDialogue: 0,0:32:28.85,0:32:30.57,yin,,0,0,0,,星球大战里面的钛战机\\N{\\fs12}a Star Wars TIE fighter there,\r\nDialogue: 0,0:32:31.32,0:32:33.64,yin,,0,0,0,,是用于重置的\\N{\\fs12}that one is kind of for resetting,\r\nDialogue: 0,0:32:33.65,0:32:36.62,yin,,0,0,0,,清除整个视图的约束\\N{\\fs12}clearing constraints for the entire view,\r\nDialogue: 0,0:32:36.80,0:32:39.87,yin,,0,0,0,,或是你选中的\\N{\\fs12}okay, or for a specific view or number of views\r\nDialogue: 0,0:32:40.15,0:32:41.35,yin,,0,0,0,,某个或某些视图的约束\\N{\\fs12}that you have selected.\r\nDialogue: 0,0:32:41.75,0:32:44.24,yin,,0,0,0,,菜单底部是整个视图\\N{\\fs12}So the bottom part of this menu is the entire view,\r\nDialogue: 0,0:32:44.37,0:32:45.62,yin,,0,0,0,,顶部也是一样的\\N{\\fs12}the top part is the same things,\r\nDialogue: 0,0:32:45.62,0:32:47.95,yin,,0,0,0,,但针对的是某些选定视图\\N{\\fs12}but for specific clicked on views, okay?\r\nDialogue: 0,0:32:48.39,0:32:50.05,yin,,0,0,0,,我们会讲讲其中几个\\N{\\fs12}So, we'll go through a few of these things,\r\nDialogue: 0,0:32:50.05,0:32:55.48,yin,,0,0,0,,有一个很酷 就是这个重置为建议约束\\N{\\fs12}but a really cool one is reset to suggested constraints, okay?\r\nDialogue: 0,0:32:55.58,0:32:59.36,yin,,0,0,0,,建议约束代表\\N{\\fs12}Suggested constraints means Xcode is going to suggest\r\nDialogue: 0,0:32:59.36,0:33:01.90,yin,,0,0,0,,Xcode会向你推荐最好的约束 最好的规则\\N{\\fs12}to you the best constraints, the best rules,\r\nDialogue: 0,0:33:02.18,0:33:05.02,yin,,0,0,0,,而且只有在你使用了蓝色辅助线的条件下\\N{\\fs12}and it's only going to be very good at that\r\nDialogue: 0,0:33:05.12,0:33:06.54,yin,,0,0,0,,才会好用\\N{\\fs12}if you use the blue guidelines.\r\nDialogue: 0,0:33:06.54,0:33:07.94,yin,,0,0,0,,因为如果你没有使用蓝色辅助线\\N{\\fs12}Because if you don't use the blue guidelines,\r\nDialogue: 0,0:33:07.95,0:33:09.12,yin,,0,0,0,,它就不知道要建议什么\\N{\\fs12}it doesn't really know what to suggest.\r\nDialogue: 0,0:33:09.12,0:33:10.10,yin,,0,0,0,,它会推荐一些约束\\N{\\fs12}It'll suggest something,\r\nDialogue: 0,0:33:10.11,0:33:11.55,yin,,0,0,0,,但并不好用 我们会看到\\N{\\fs12}but it's not gonna be good as we'll see.\r\nDialogue: 0,0:33:11.93,0:33:12.65,yin,,0,0,0,,但在这个例子中\\N{\\fs12}But in this case,\r\nDialogue: 0,0:33:12.66,0:33:15.61,yin,,0,0,0,,因为Thing 1和Thing 2都明确使用了蓝色辅助线\\N{\\fs12}since both thing one and thing two clearly have blue guidelines\r\nDialogue: 0,0:33:15.62,0:33:16.79,yin,,0,0,0,,来表示它们的位置\\N{\\fs12}to say where they want to be,\r\nDialogue: 0,0:33:16.89,0:33:19.16,yin,,0,0,0,,这里我们使用重置为建议约束\\N{\\fs12}when we do reset to suggested constraints,\r\nDialogue: 0,0:33:19.43,0:33:20.15,yin,,0,0,0,,就可以起作用了\\N{\\fs12}it's going to work.\r\nDialogue: 0,0:33:20.55,0:33:23.11,yin,,0,0,0,,什么都没有发生\\N{\\fs12}Now, nothing appears to happen, right?\r\nDialogue: 0,0:33:23.16,0:33:25.37,yin,,0,0,0,,我设置了重置为建议约束 什么都没发生\\N{\\fs12}I did reset suggest content and nothing happened.\r\nDialogue: 0,0:33:25.59,0:33:26.86,yin,,0,0,0,,但确实有变化\\N{\\fs12}But something did happen,\r\nDialogue: 0,0:33:27.10,0:33:29.71,yin,,0,0,0,,我们可以点击Thing 1\\N{\\fs12}and we can see that by clicking on thing one\r\nDialogue: 0,0:33:29.89,0:33:32.93,yin,,0,0,0,,然后转到尺寸检查器\\N{\\fs12}and going over to the size inspector.\r\nDialogue: 0,0:33:33.03,0:33:35.41,yin,,0,0,0,,右边检查器这里 我切换到了尺寸检查器\\N{\\fs12}Okay, so in the inspector there, I've switched over to size,\r\nDialogue: 0,0:33:35.41,0:33:37.04,yin,,0,0,0,,点击那个像尺子一样的图标\\N{\\fs12}that thing looks kind of like a ruler,\r\nDialogue: 0,0:33:37.97,0:33:39.41,yin,,0,0,0,,尺寸检查器中可以看到\\N{\\fs12}and size inspector has, you know,\r\nDialogue: 0,0:33:39.42,0:33:41.43,yin,,0,0,0,,当前框架的位置等等\\N{\\fs12}where the current frame is and all that,\r\nDialogue: 0,0:33:41.44,0:33:43.59,yin,,0,0,0,,但在底部 看到Constraints约束这部分了吗\\N{\\fs12}but at the bottom, do you see where it says constraints?\r\nDialogue: 0,0:33:43.70,0:33:45.01,yin,,0,0,0,,有两个约束\\N{\\fs12}And I have two constraints.\r\nDialogue: 0,0:33:45.17,0:33:47.27,yin,,0,0,0,,第一个是Leading Space前置间距\\N{\\fs12}My leading space, okay,\r\nDialogue: 0,0:33:47.27,0:33:50.17,yin,,0,0,0,,这里用前置间距而不是左间距\\N{\\fs12}the reason that says leading space instead of left space\r\nDialogue: 0,0:33:50.25,0:33:54.79,yin,,0,0,0,,是因为在某些语言中 文字是从右边开始的\\N{\\fs12}is because some languages, leading is on the right.\r\nDialogue: 0,0:33:55.53,0:33:58.56,yin,,0,0,0,,希伯来语等语言是从右向左的\\N{\\fs12}Okay? So Hebrew, a language like that, it's on the right\r\nDialogue: 0,0:33:58.57,0:34:00.77,yin,,0,0,0,,所以你或许想让你的整个用户界面\\N{\\fs12}so you might want your entire user interface\r\nDialogue: 0,0:34:00.78,0:34:03.52,yin,,0,0,0,,都从右边开始\\N{\\fs12}oriented towards coming from the right, okay,\r\nDialogue: 0,0:34:03.53,0:34:04.55,yin,,0,0,0,,而不是从左边开始\\N{\\fs12}instead of coming from the left,\r\nDialogue: 0,0:34:04.56,0:34:06.20,yin,,0,0,0,,因为你的文字是从右向左的\\N{\\fs12}because all your text is going to be going that way,\r\nDialogue: 0,0:34:06.22,0:34:08.27,yin,,0,0,0,,所以整个用户界面最好也是这个方向的\\N{\\fs12}so you might want all your user interface to flow from that way.\r\nDialogue: 0,0:34:08.58,0:34:12.69,yin,,0,0,0,,前置指的就是文字开始的方向\\N{\\fs12}So anyway, so leading means whichever leading you're talking about,\r\nDialogue: 0,0:34:13.10,0:34:16.11,yin,,0,0,0,,我想让前置间距与父视图绑定\\N{\\fs12}and I want the leading space to be tied to my superview,\r\nDialogue: 0,0:34:16.12,0:34:17.40,yin,,0,0,0,,与父视图的边缘\\N{\\fs12}the edge of my superview,\r\nDialogue: 0,0:34:17.62,0:34:22.18,yin,,0,0,0,,间距为某个固定值 这个值是默认的\\N{\\fs12}by some fixed amount, and that fixed amount is default.\r\nDialogue: 0,0:34:22.60,0:34:23.38,yin,,0,0,0,,Default\\N{\\fs12}Default. Okay?\r\nDialogue: 0,0:34:23.38,0:34:25.56,yin,,0,0,0,,不是个魔术数字 是由系统决定的\\N{\\fs12}It's not a magic number, its default, it's by the system,\r\nDialogue: 0,0:34:25.56,0:34:27.73,yin,,0,0,0,,系统决定默认值是多少\\N{\\fs12}the system decides what that default amount is.\r\nDialogue: 0,0:34:28.11,0:34:30.18,yin,,0,0,0,,还可以看到 上间距也和父视图的上边缘绑定\\N{\\fs12}And then you can see my top space is also tied\r\nDialogue: 0,0:34:30.18,0:34:33.60,yin,,0,0,0,,间距为默认值Default\\N{\\fs12}to my superview's top edge with the default space.\r\nDialogue: 0,0:34:34.08,0:34:37.22,yin,,0,0,0,,这两个约束决定了\\N{\\fs12}So those two constraints determine exactly\r\nDialogue: 0,0:34:37.22,0:34:38.71,yin,,0,0,0,,Thing 1的准确位置\\N{\\fs12}where thing one's going to be.\r\nDialogue: 0,0:34:39.11,0:34:41.27,yin,,0,0,0,,Thing 1的大小是怎样的呢\\N{\\fs12}Now what about thing one's size.\r\nDialogue: 0,0:34:42.11,0:34:43.56,yin,,0,0,0,,Thing 1会始终保持\\N{\\fs12}Okay? Is thing one always going\r\nDialogue: 0,0:34:43.56,0:34:45.41,yin,,0,0,0,,当前宽度吗\\N{\\fs12}to be exactly the width it is right now?\r\nDialogue: 0,0:34:45.63,0:34:49.65,yin,,0,0,0,,Thing 1和所有标签及按钮一样\\N{\\fs12}No. Thing one, like all labels and buttons,\r\nDialogue: 0,0:34:49.97,0:34:52.51,yin,,0,0,0,,有一个内置大小\\N{\\fs12}it has what's called an intrinsic size.\r\nDialogue: 0,0:34:52.84,0:34:56.70,yin,,0,0,0,,也就是它的文本需要的尺寸\\N{\\fs12}Okay? That's the size that its text demands that it be.\r\nDialogue: 0,0:34:56.96,0:34:57.84,yin,,0,0,0,,这是可以修改的\\N{\\fs12}And that could change.\r\nDialogue: 0,0:34:57.84,0:35:01.85,yin,,0,0,0,,如果你修改了Thing 1的文字 它就会变宽\\N{\\fs12}If you change the text in thing one, it needs to be wider\r\nDialogue: 0,0:35:01.85,0:35:04.48,yin,,0,0,0,,如果你减少了文字 它就会缩短\\N{\\fs12}or it could be shorter if you change it to something shorter.\r\nDialogue: 0,0:35:04.70,0:35:08.14,yin,,0,0,0,,所以它的尺寸会随着文本的变化而变化\\N{\\fs12}And so, it will change its size as you change its text.\r\nDialogue: 0,0:35:08.25,0:35:11.38,yin,,0,0,0,,因为你没有向其添加尺寸约束\\N{\\fs12}Okay? Because you haven't put a constraint on its size.\r\nDialogue: 0,0:35:12.04,0:35:13.67,yin,,0,0,0,,如果你增加了一个尺寸约束\\N{\\fs12}If you put a constraint on its size,\r\nDialogue: 0,0:35:13.72,0:35:16.27,yin,,0,0,0,,它就会始终保持那个大小 这样不好\\N{\\fs12}it would then be stuck to that size and that is bad.\r\nDialogue: 0,0:35:16.38,0:35:19.07,yin,,0,0,0,,通常情况下 我们不会为具有内置大小的控件\\N{\\fs12}We do not put size constraints, generally,\r\nDialogue: 0,0:35:19.30,0:35:23.27,yin,,0,0,0,,设置尺寸约束 比如标签和按钮\\N{\\fs12}on intrinsically sizable items like labels and buttons,\r\nDialogue: 0,0:35:23.28,0:35:24.34,yin,,0,0,0,,我会在示例中演示\\N{\\fs12}and I'm going to show you, hopefully,\r\nDialogue: 0,0:35:24.35,0:35:27.88,yin,,0,0,0,,为什么这样不好 希望有时间演示\\N{\\fs12}if we have time in the demo, why that's bad, okay?\r\nDialogue: 0,0:35:28.70,0:35:30.48,yin,,0,0,0,,总之 Thing 1只有这两个约束\\N{\\fs12}So anyway, thing one only has those two constraints,\r\nDialogue: 0,0:35:30.48,0:35:33.36,yin,,0,0,0,,但这两个约束完全可以决定Thing 1的位置\\N{\\fs12}but those two constraints completely determine thing one's location\r\nDialogue: 0,0:35:33.37,0:35:35.71,yin,,0,0,0,,无论父视图是怎样的\\N{\\fs12}no matter what the superview does.\r\nDialogue: 0,0:35:36.01,0:35:37.30,yin,,0,0,0,,Thing 2也是一样的\\N{\\fs12}Same thing with thing two,\r\nDialogue: 0,0:35:37.38,0:35:39.73,yin,,0,0,0,,可以设置下间距和后置间距\\N{\\fs12}bottom space and the trailing space.\r\nDialogue: 0,0:35:40.26,0:35:42.30,yin,,0,0,0,,现在我们来看一下横屏模式\\N{\\fs12}Okay? So now let's go look in landscape.\r\nDialogue: 0,0:35:42.31,0:35:44.15,yin,,0,0,0,,我要切换到横屏 看看效果如何\\N{\\fs12}I'm going to switch over to landscape and see what happens.\r\nDialogue: 0,0:35:44.69,0:35:47.90,yin,,0,0,0,,可以看到 Thing 2始终显示在右下角\\N{\\fs12}And you can see, thing two sticks to that corner,\r\nDialogue: 0,0:35:47.90,0:35:49.35,yin,,0,0,0,,就是我们想要的效果\\N{\\fs12}kind of exactly what we want.\r\nDialogue: 0,0:35:50.25,0:35:52.59,yin,,0,0,0,,这是因为Thing 2的位置\\N{\\fs12}Alright? And that's because thing two's position\r\nDialogue: 0,0:35:52.60,0:35:55.88,yin,,0,0,0,,现在完全由那些规则决定\\N{\\fs12}is totally determined by those rules now, okay?\r\nDialogue: 0,0:35:57.25,0:35:58.60,yin,,0,0,0,,再回到竖屏\\N{\\fs12}Okay, so let's go back to portrait.\r\nDialogue: 0,0:35:59.08,0:36:02.00,yin,,0,0,0,,我要再加一个Bad Thing\\N{\\fs12}So, I'm going to put a bad thing in there, okay?\r\nDialogue: 0,0:36:02.00,0:36:04.97,yin,,0,0,0,,这个Bad Thing会演示可能会发生的不好的事情\\N{\\fs12}So this bad thing is going to show bad things that can happen,\r\nDialogue: 0,0:36:05.24,0:36:07.91,yin,,0,0,0,,我想将Bad Thing放到中间\\N{\\fs12}and I tried to put bad thing in the middle,\r\nDialogue: 0,0:36:08.00,0:36:09.86,yin,,0,0,0,,但是我没用蓝色辅助线\\N{\\fs12}but I didn't use the blue guidelines.\r\nDialogue: 0,0:36:10.04,0:36:12.63,yin,,0,0,0,,这其实挺难做到的 但是我做到了\\N{\\fs12}That's actually difficult to do, but I did.\r\nDialogue: 0,0:36:12.87,0:36:13.69,yin,,0,0,0,,我增加了一个Bad Thing\\N{\\fs12}Okay, I put a bad thing in.\r\nDialogue: 0,0:36:13.69,0:36:16.87,yin,,0,0,0,,而且这个Bad Thing的尺寸太大了\\N{\\fs12}Also, you know, this bad thing size, it's too big for itself,\r\nDialogue: 0,0:36:16.87,0:36:18.72,yin,,0,0,0,,不需要那么大\\N{\\fs12}it really doesn't want to be that big,\r\nDialogue: 0,0:36:19.00,0:36:21.57,yin,,0,0,0,,如果用内置大小的话 会小得多\\N{\\fs12}it could be a lot smaller if it was just an intrinsic size.\r\nDialogue: 0,0:36:21.79,0:36:25.95,yin,,0,0,0,,我只是将它拖出来 移动缩放控点\\N{\\fs12}So, I just dragged it out and moved the sizing handles.\r\nDialogue: 0,0:36:26.49,0:36:29.52,yin,,0,0,0,,它没有约束 因为我刚把它拖出来\\N{\\fs12}It has no constraints, because I just dragged it out, okay?\r\nDialogue: 0,0:36:29.52,0:36:32.63,yin,,0,0,0,,看右边的尺寸检查器 写着无约束\\N{\\fs12}See how its size inspector there says no constraints, right?\r\nDialogue: 0,0:36:32.68,0:36:33.53,yin,,0,0,0,,没有约束\\N{\\fs12}You have no constraints.\r\nDialogue: 0,0:36:34.01,0:36:37.51,yin,,0,0,0,,如果我向Xcode请求\\N{\\fs12}So, what happens if I try to ask Xcode,\r\nDialogue: 0,0:36:37.66,0:36:41.00,yin,,0,0,0,,请为Bad Thing提供一些建议约束 会怎样\\N{\\fs12}please give me some suggested constraints for bad thing.\r\nDialogue: 0,0:36:41.09,0:36:42.77,yin,,0,0,0,,要记得 拖放Bad Thing时\\N{\\fs12}Remember, I didn't use the blue guidelines\r\nDialogue: 0,0:36:42.77,0:36:44.02,yin,,0,0,0,,我没有使用蓝色辅助线\\N{\\fs12}when I dragged bad thing out.\r\nDialogue: 0,0:36:44.64,0:36:46.88,yin,,0,0,0,,还要注意 我使用的是菜单的上半部分\\N{\\fs12}And notice, also, I'm using the top half of that menu\r\nDialogue: 0,0:36:46.88,0:36:48.52,yin,,0,0,0,,是针对Bad Thing的\\N{\\fs12}which is just, just for bad thing.\r\nDialogue: 0,0:36:48.67,0:36:50.38,yin,,0,0,0,,并没有重置Thing 1和Thing 2\\N{\\fs12}Okay? I'm not resetting thing one and thing two,\r\nDialogue: 0,0:36:50.38,0:36:53.21,yin,,0,0,0,,但我可以一直重置Thing 1和Thing2\\N{\\fs12}although I could reset thing one and thing two all day long,\r\nDialogue: 0,0:36:53.21,0:36:55.92,yin,,0,0,0,,因为它们始终会被重置为合适约束\\N{\\fs12}because they're always gonna reset to the proper constraints\r\nDialogue: 0,0:36:55.92,0:36:58.10,yin,,0,0,0,,因为我对它们使用了建议约束\\N{\\fs12}because I'm using the suggested constraints for them.\r\nDialogue: 0,0:36:58.11,0:37:01.38,yin,,0,0,0,,这里我就只重置Bad Thing的约束\\N{\\fs12}But anyway, so I'm just gonna reset bad things constraints\r\nDialogue: 0,0:37:01.40,0:37:02.43,yin,,0,0,0,,出来了\\N{\\fs12}and, boom!\r\nDialogue: 0,0:37:02.44,0:37:06.52,yin,,0,0,0,,Xcode尽力了 这很难\\N{\\fs12}Xcode gives it the old college try, but it's hard, okay?\r\nDialogue: 0,0:37:06.64,0:37:08.19,yin,,0,0,0,,实际上 看一下它给出的\\N{\\fs12}And, in fact, look at the constraints\r\nDialogue: 0,0:37:08.20,0:37:09.22,yin,,0,0,0,,这些约束\\N{\\fs12}it came up with there.\r\nDialogue: 0,0:37:09.36,0:37:13.79,yin,,0,0,0,,高度为62 前置间距为89 后置间距为68\\N{\\fs12}Height equals 62, leading space equals 89, trailing space 68,\r\nDialogue: 0,0:37:13.81,0:37:15.34,yin,,0,0,0,,换句话说 这些都是魔术数字\\N{\\fs12}in other words, these are all magic numbers.\r\nDialogue: 0,0:37:15.63,0:37:18.32,yin,,0,0,0,,这很糟糕 是很差的约束条件\\N{\\fs12}Okay? This is horrible, these are terrible constraints.\r\nDialogue: 0,0:37:18.42,0:37:21.52,yin,,0,0,0,,带有魔术数字的约束几乎都很糟糕\\N{\\fs12}Constraints with magic numbers are almost always bad.\r\nDialogue: 0,0:37:21.78,0:37:23.46,yin,,0,0,0,,少数情况下可以使用\\N{\\fs12}There's a few cases where they're okay,\r\nDialogue: 0,0:37:23.56,0:37:24.91,yin,,0,0,0,,但通常都很糟糕\\N{\\fs12}but it's almost always bad,\r\nDialogue: 0,0:37:25.00,0:37:27.25,yin,,0,0,0,,如果我切换到横屏模式\\N{\\fs12}and, in fact, if I go and try to switch to landscape,\r\nDialogue: 0,0:37:27.72,0:37:29.88,yin,,0,0,0,,这些数字都不变\\N{\\fs12}all of those number stay exactly the same, okay?\r\nDialogue: 0,0:37:29.88,0:37:31.95,yin,,0,0,0,,上边距依旧为198\\N{\\fs12}It stays 198 pixels from the top,\r\nDialogue: 0,0:37:31.96,0:37:33.55,yin,,0,0,0,,左边距也不变\\N{\\fs12}and whatever it was from the left,\r\nDialogue: 0,0:37:33.56,0:37:34.99,yin,,0,0,0,,完全不是我想要的效果\\N{\\fs12}it's totally not what I want.\r\nDialogue: 0,0:37:35.19,0:37:36.98,yin,,0,0,0,,我是要将Bad Thing放在中间\\N{\\fs12}Okay? I tried to put bad thing in the middle.\r\nDialogue: 0,0:37:36.99,0:37:38.40,yin,,0,0,0,,我想让它始终显示在中间\\N{\\fs12}I want it to stay in the middle,\r\nDialogue: 0,0:37:38.42,0:37:40.11,yin,,0,0,0,,现在离中间还差得远呢\\N{\\fs12}that's not even close to being in the middle.\r\nDialogue: 0,0:37:40.31,0:37:43.51,yin,,0,0,0,,所以如果你不使用蓝色辅助线\\N{\\fs12}So suggested constraints aren't gonna work\r\nDialogue: 0,0:37:43.51,0:37:44.90,yin,,0,0,0,,建议约束就不会起作用\\N{\\fs12}if you don't use the blue guidelines\r\nDialogue: 0,0:37:44.90,0:37:46.46,yin,,0,0,0,,因为它不确定你想要什么效果\\N{\\fs12}because it's not really sure what you want.\r\nDialogue: 0,0:37:46.68,0:37:49.67,yin,,0,0,0,,我们删掉这些约束\\N{\\fs12}Okay? So, so let's get rid of these constraints.\r\nDialogue: 0,0:37:49.67,0:37:51.32,yin,,0,0,0,,方法是回到刚才那个菜单\\N{\\fs12}I'm going to go back to that same menu\r\nDialogue: 0,0:37:51.86,0:37:53.99,yin,,0,0,0,,选择另外一项 也就是Clear Constraints清除约束\\N{\\fs12}and pick a different item, which is clear constraints,\r\nDialogue: 0,0:37:53.99,0:37:55.23,yin,,0,0,0,,这样就清除了全部约束\\N{\\fs12}and that clears all the constraints,\r\nDialogue: 0,0:37:55.23,0:37:57.43,yin,,0,0,0,,回到最初状态\\N{\\fs12}and goes back to this thing.\r\nDialogue: 0,0:37:57.43,0:38:00.36,yin,,0,0,0,,还要注意 全部约束都会被绘制出来\\N{\\fs12}Notice, by the way, all the constraints draw,\r\nDialogue: 0,0:38:00.37,0:38:01.59,yin,,0,0,0,,看到蓝线了吗\\N{\\fs12}you see the blue bars?\r\nDialogue: 0,0:38:02.15,0:38:05.01,yin,,0,0,0,,每个约束都会被绘制出来\\N{\\fs12}See them? Every single constraint is drawn.\r\nDialogue: 0,0:38:05.02,0:38:06.90,yin,,0,0,0,,它们不仅会被绘制出来\\N{\\fs12}And not only does it draw those constraints,\r\nDialogue: 0,0:38:06.92,0:38:08.74,yin,,0,0,0,,你还可以点击它们 然后进行编辑\\N{\\fs12}you can click on them, and edit them.\r\nDialogue: 0,0:38:08.93,0:38:10.83,yin,,0,0,0,,很多约束都有属性\\N{\\fs12}A lot of the constraints have attributes,\r\nDialogue: 0,0:38:10.85,0:38:13.16,yin,,0,0,0,,很可惜 今天我没时间讲了\\N{\\fs12}which I'm not gonna have time to talk about today, unfortunately,\r\nDialogue: 0,0:38:13.86,0:38:15.91,yin,,0,0,0,,这些约束是storyboard的\\N{\\fs12}but those constraints are first-class objects\r\nDialogue: 0,0:38:15.92,0:38:18.69,yin,,0,0,0,,一类对象\\N{\\fs12}inside of your, your storyboard.\r\nDialogue: 0,0:38:19.39,0:38:21.07,yin,,0,0,0,,好的 我们清除掉这些约束\\N{\\fs12}Alright. So we're gonna clear those out of there.\r\nDialogue: 0,0:38:21.45,0:38:24.58,yin,,0,0,0,,我们换一种方法来添加约束\\N{\\fs12}And let's put in some constraints in a different way.\r\nDialogue: 0,0:38:24.59,0:38:26.66,yin,,0,0,0,,这是添加约束的第二种方法\\N{\\fs12}So this is way number two to add constraints.\r\nDialogue: 0,0:38:26.66,0:38:30.22,yin,,0,0,0,,第一种方法是使用蓝色辅助线 然后选择建议约束\\N{\\fs12}And way number one was use blue guidelines and say suggested.\r\nDialogue: 0,0:38:30.38,0:38:32.32,yin,,0,0,0,,这是添加约束的第一种方法\\N{\\fs12}That's way number one to put constraints on.\r\nDialogue: 0,0:38:32.52,0:38:33.63,yin,,0,0,0,,第二种方法是\\N{\\fs12}Number two is you can use\r\nDialogue: 0,0:38:33.63,0:38:35.06,yin,,0,0,0,,可以使用底部的这些按钮\\N{\\fs12}some of these other buttons at the bottom.\r\nDialogue: 0,0:38:35.24,0:38:37.93,yin,,0,0,0,,比如这个按钮就是用来设置对齐的\\N{\\fs12}Like this particular button here for aligning things.\r\nDialogue: 0,0:38:38.25,0:38:39.48,yin,,0,0,0,,看这个菜单\\N{\\fs12}So if you look in this,\r\nDialogue: 0,0:38:39.48,0:38:41.48,yin,,0,0,0,,上面有很多对齐选项\\N{\\fs12}there's a lot of choices of how to align things,\r\nDialogue: 0,0:38:41.48,0:38:43.28,yin,,0,0,0,,如果我选择多个视图\\N{\\fs12}if I selected multiple views,\r\nDialogue: 0,0:38:43.39,0:38:44.64,yin,,0,0,0,,那么上部的这些选项\\N{\\fs12}then all of those things at the top,\r\nDialogue: 0,0:38:44.66,0:38:46.95,yin,,0,0,0,,比如前边缘 后边缘 上边缘\\N{\\fs12}like leading edges, trailing edges, top edges,\r\nDialogue: 0,0:38:47.06,0:38:48.04,yin,,0,0,0,,我可以选择它们\\N{\\fs12}I'd be able to pick those\r\nDialogue: 0,0:38:48.05,0:38:50.45,yin,,0,0,0,,对齐视图的前边缘或者后边缘等等\\N{\\fs12}and I could line up the leading edges or trailing edges\r\nDialogue: 0,0:38:50.45,0:38:53.18,yin,,0,0,0,,让它们对齐\\N{\\fs12}or whatever, of views, make them line up.\r\nDialogue: 0,0:38:53.38,0:38:54.34,yin,,0,0,0,,就是对齐\\N{\\fs12}Okay? It's just alignment things,\r\nDialogue: 0,0:38:54.35,0:38:56.66,yin,,0,0,0,,和绘图程序等是一样的\\N{\\fs12}just like if you're in some drawing program or something.\r\nDialogue: 0,0:38:57.42,0:39:01.26,yin,,0,0,0,,我要选择底下的两个\\N{\\fs12}I'm gonna pick the bottom two, which lines this thing up\r\nDialogue: 0,0:39:01.43,0:39:03.86,yin,,0,0,0,,在父视图中水平居中对齐\\N{\\fs12}with the horizontal center in the superview.\r\nDialogue: 0,0:39:04.42,0:39:06.99,yin,,0,0,0,,所以它会在父视图中居中\\N{\\fs12}So it's gonna be centered in my superview,\r\nDialogue: 0,0:39:07.00,0:39:08.27,yin,,0,0,0,,水平居中 垂直居中\\N{\\fs12}both horizontally and vertically,\r\nDialogue: 0,0:39:08.28,0:39:09.54,yin,,0,0,0,,所以我要在这里增加两个约束\\N{\\fs12}so I'm going to add two constraints here,\r\nDialogue: 0,0:39:09.54,0:39:11.60,yin,,0,0,0,,一个是水平约束 一个是垂直约束\\N{\\fs12}one for horizontal, one for vertical.\r\nDialogue: 0,0:39:11.72,0:39:13.75,yin,,0,0,0,,还可以指定中心的偏移量\\N{\\fs12}And I can also specify an offset from the center,\r\nDialogue: 0,0:39:13.76,0:39:16.09,yin,,0,0,0,,就是现在选中的那个0的含义\\N{\\fs12}that's what that zero is right there that's selected,\r\nDialogue: 0,0:39:16.35,0:39:17.95,yin,,0,0,0,,我要让它显示在正中心\\N{\\fs12}but I'm going to have the exact in the center,\r\nDialogue: 0,0:39:17.95,0:39:18.93,yin,,0,0,0,,所以这里设为0\\N{\\fs12}so I'm going to say zero.\r\nDialogue: 0,0:39:19.36,0:39:21.34,yin,,0,0,0,,还有一个Update Frames更新框架\\N{\\fs12}And there's also update frames,\r\nDialogue: 0,0:39:21.35,0:39:23.03,yin,,0,0,0,,看到底部的Update Frames了吗\\N{\\fs12}you see the update frames at the bottom there\r\nDialogue: 0,0:39:23.04,0:39:24.88,yin,,0,0,0,,就在\"添加两条约束\"上面\\N{\\fs12}right above where it says add two constraints.\r\nDialogue: 0,0:39:25.02,0:39:27.75,yin,,0,0,0,,可以在这里的弹出菜单中设置\\N{\\fs12}That popup, you can go in there and say,\r\nDialogue: 0,0:39:28.22,0:39:29.90,yin,,0,0,0,,当添加约束时\\N{\\fs12}and when you add these constraints,\r\nDialogue: 0,0:39:29.98,0:39:32.72,yin,,0,0,0,,移动视图以匹配这些约束\\N{\\fs12}move my view to fit those constraints,\r\nDialogue: 0,0:39:32.95,0:39:34.06,yin,,0,0,0,,但这里我就不设置了\\N{\\fs12}but I'm not going to set that\r\nDialogue: 0,0:39:34.07,0:39:35.15,yin,,0,0,0,,因为我想为大家演示一下\\N{\\fs12}because I want to show you what happens\r\nDialogue: 0,0:39:35.17,0:39:37.04,yin,,0,0,0,,如果这里不设置会怎样\\N{\\fs12}if you don't do that, okay?\r\nDialogue: 0,0:39:37.23,0:39:38.62,yin,,0,0,0,,我们添加这两个约束\\N{\\fs12}So let's add these two constraints,\r\nDialogue: 0,0:39:38.63,0:39:39.83,yin,,0,0,0,,水平和垂直居中\\N{\\fs12}horizontal and vertical centering.\r\nDialogue: 0,0:39:40.30,0:39:41.43,yin,,0,0,0,,它们显示出来了\\N{\\fs12}Okay. There they are.\r\nDialogue: 0,0:39:41.51,0:39:43.49,yin,,0,0,0,,在父视图中X轴居中\\N{\\fs12}You see them, align center X to superview,\r\nDialogue: 0,0:39:43.50,0:39:45.48,yin,,0,0,0,,在父视图中Y轴居中 很好\\N{\\fs12}align center Y to superview, awesome.\r\nDialogue: 0,0:39:45.48,0:39:47.10,yin,,0,0,0,,可以看到这两个约束\\N{\\fs12}You can see them, they're there.\r\nDialogue: 0,0:39:47.25,0:39:48.77,yin,,0,0,0,,注意 它们是黄色的\\N{\\fs12}Notice that they're yellow.\r\nDialogue: 0,0:39:49.30,0:39:51.90,yin,,0,0,0,,黄色代表警告\\N{\\fs12}Okay, yellow is like a warning, okay?\r\nDialogue: 0,0:39:52.33,0:39:53.44,yin,,0,0,0,,出现黄色不是什么好事\\N{\\fs12}Yellow is not good.\r\nDialogue: 0,0:39:53.45,0:39:56.54,yin,,0,0,0,,蓝色很好 黄色不是那么好 红色很糟糕\\N{\\fs12}Blue is good, yellow not so good, red is really bad.\r\nDialogue: 0,0:39:56.72,0:39:58.56,yin,,0,0,0,,有时约束会显示为红色\\N{\\fs12}Okay? Sometimes your constraints will be red,\r\nDialogue: 0,0:39:58.56,0:39:59.62,yin,,0,0,0,,那就是发生冲突了\\N{\\fs12}that's if they conflict.\r\nDialogue: 0,0:39:59.89,0:40:02.39,yin,,0,0,0,,有两个约束是完全相反的\\N{\\fs12}You got two constraints sitting, doing opposite things.\r\nDialogue: 0,0:40:02.92,0:40:04.87,yin,,0,0,0,,我们会讲到如何解决这个问题\\N{\\fs12}And we'll talk about how we resolve all this.\r\nDialogue: 0,0:40:05.95,0:40:06.48,yin,,0,0,0,,这里是黄色的\\N{\\fs12}So it's yellow.\r\nDialogue: 0,0:40:06.49,0:40:08.17,yin,,0,0,0,,如果仔细看\\N{\\fs12}Also, if you look really closely,\r\nDialogue: 0,0:40:08.19,0:40:11.13,yin,,0,0,0,,可以看到有一个虚线框\\N{\\fs12}you see there's a dashed box, kind of right,\r\nDialogue: 0,0:40:11.60,0:40:16.11,yin,,0,0,0,,穿过Bad Thing\\N{\\fs12}it goes right through the word bad over to the thing,\r\nDialogue: 0,0:40:16.13,0:40:16.82,yin,,0,0,0,,看到了吗\\N{\\fs12}you see it right there,\r\nDialogue: 0,0:40:16.83,0:40:19.11,yin,,0,0,0,,在大矩形中的虚线框\\N{\\fs12}dashed box inside of the bigger box?\r\nDialogue: 0,0:40:19.36,0:40:22.70,yin,,0,0,0,,大家能看清这个虚线框吗\\N{\\fs12}That dashed box, I don't know how well you can see that there,\r\nDialogue: 0,0:40:22.70,0:40:25.04,yin,,0,0,0,,能看清 这个虚线框代表\\N{\\fs12}yeah you can see it, that dashed box is\r\nDialogue: 0,0:40:25.05,0:40:27.75,yin,,0,0,0,,约束条件认为的该控件的所在位置\\N{\\fs12}where you constraints say this thing should be.\r\nDialogue: 0,0:40:28.81,0:40:31.43,yin,,0,0,0,,换句话说就是 如果只看约束\\N{\\fs12}Okay? In other words, if you just looked at your constraints,\r\nDialogue: 0,0:40:31.48,0:40:32.68,yin,,0,0,0,,Bad Thing应该在哪\\N{\\fs12}where should bad thing be?\r\nDialogue: 0,0:40:32.69,0:40:34.23,yin,,0,0,0,,它应该显示在那个小虚线框中\\N{\\fs12}Well, it should be in that little dashed box,\r\nDialogue: 0,0:40:34.95,0:40:38.13,yin,,0,0,0,,因为我们刚才没有勾选底部的\\N{\\fs12}but since we didn't click that thing at the bottom there\r\nDialogue: 0,0:40:38.13,0:40:42.24,yin,,0,0,0,,将框架更新至约束位置\\N{\\fs12}that said update my frame to where my constraints are\r\nDialogue: 0,0:40:42.48,0:40:43.41,yin,,0,0,0,,Bad Thing就没有移动\\N{\\fs12}it didn't do it.\r\nDialogue: 0,0:40:43.42,0:40:44.87,yin,,0,0,0,,所以Bad Thing还在原来的位置\\N{\\fs12}So bad thing is still where it was,\r\nDialogue: 0,0:40:44.89,0:40:46.36,yin,,0,0,0,,这也就是为什么它们是黄色的原因\\N{\\fs12}and that's why these are yellow.\r\nDialogue: 0,0:40:47.11,0:40:50.12,yin,,0,0,0,,如何知道约束变为黄色的原因呢\\N{\\fs12}Okay? How can I know why my constraints are yellow?\r\nDialogue: 0,0:40:50.22,0:40:53.10,yin,,0,0,0,,一个地方就是右上角的小三角形那里\\N{\\fs12}Well, one place is that little triangle in the upper corner,\r\nDialogue: 0,0:40:53.11,0:40:54.96,yin,,0,0,0,,就是看应用中其他警告的\\N{\\fs12}the normal triangle where you would look at\r\nDialogue: 0,0:40:54.97,0:40:56.62,yin,,0,0,0,,三角形那里\\N{\\fs12}any other warning in your app,\r\nDialogue: 0,0:40:56.74,0:40:57.71,yin,,0,0,0,,这里的警告是\\N{\\fs12}and you can see this\r\nDialogue: 0,0:40:57.72,0:41:00.95,yin,,0,0,0,,Bad Thing的框架在运行时会不同\\N{\\fs12}as the frame for bad thing will be different at run time.\r\nDialogue: 0,0:41:00.96,0:41:01.88,yin,,0,0,0,,因为在运行时\\N{\\fs12}That's because at run time\r\nDialogue: 0,0:41:01.89,0:41:03.37,yin,,0,0,0,,约束会被应用\\N{\\fs12}the constraints are going to be applied\r\nDialogue: 0,0:41:03.38,0:41:05.23,yin,,0,0,0,,它就会被移动到那个小虚线框中\\N{\\fs12}and it's gonna be moved into that little dashed box.\r\nDialogue: 0,0:41:06.05,0:41:08.58,yin,,0,0,0,,如果约束为黄色\\N{\\fs12}Okay? Another place you can see these warnings,\r\nDialogue: 0,0:41:08.58,0:41:11.50,yin,,0,0,0,,还有一个地方可以查看警告 就是在文档大纲中\\N{\\fs12}if you're constraints are yellow is in the document outline.\r\nDialogue: 0,0:41:11.67,0:41:12.82,yin,,0,0,0,,我们在课上还没有机会\\N{\\fs12}Now we have not had a chance\r\nDialogue: 0,0:41:12.83,0:41:15.56,yin,,0,0,0,,讲到文档大纲\\N{\\fs12}to talk about the document outline in this class,\r\nDialogue: 0,0:41:15.76,0:41:17.30,yin,,0,0,0,,但其实也没什么要讲的\\N{\\fs12}but there's not really a lot to say about\r\nDialogue: 0,0:41:17.31,0:41:20.03,yin,,0,0,0,,除了一点 就是它很棒 是什么呢\\N{\\fs12}except for that it's really great and what is it?\r\nDialogue: 0,0:41:20.04,0:41:22.59,yin,,0,0,0,,是以大纲的形式列出storyboard中\\N{\\fs12}It's every single object in your storyboard\r\nDialogue: 0,0:41:22.60,0:41:24.94,yin,,0,0,0,,每一个对象\\N{\\fs12}that matters in an outline form.\r\nDialogue: 0,0:41:25.75,0:41:29.02,yin,,0,0,0,,全部视图 全部手势\\N{\\fs12}Okay? So that's all your views, all your gestures,\r\nDialogue: 0,0:41:29.19,0:41:32.28,yin,,0,0,0,,全部约束 布局向导\\N{\\fs12}all your constraints, things like layout guides,\r\nDialogue: 0,0:41:32.28,0:41:34.12,yin,,0,0,0,,我们还没有机会讲呢\\N{\\fs12}which we're really not getting a chance to talk about,\r\nDialogue: 0,0:41:34.13,0:41:36.57,yin,,0,0,0,,也和自动布局系统有关\\N{\\fs12}but has to do with auto layout system, as well.\r\nDialogue: 0,0:41:36.72,0:41:40.19,yin,,0,0,0,,这些都列在大纲中\\N{\\fs12}Those are all listed in this outline,\r\nDialogue: 0,0:41:40.30,0:41:43.13,yin,,0,0,0,,特别棒的一点是 你可以通过点击选中它们\\N{\\fs12}and what's really cool is you can click on them to select.\r\nDialogue: 0,0:41:43.26,0:41:44.79,yin,,0,0,0,,因为有时视图中对象很多\\N{\\fs12}Because sometimes your view's very crowded\r\nDialogue: 0,0:41:44.80,0:41:46.31,yin,,0,0,0,,很难通过点击选择你想要的对象\\N{\\fs12}and it's hard to click on the thing you want\r\nDialogue: 0,0:41:46.33,0:41:49.69,yin,,0,0,0,,即便使用了我教大家的Control Shift技巧也一样\\N{\\fs12}even using the control shift trick that I showed you,\r\nDialogue: 0,0:41:49.90,0:41:52.11,yin,,0,0,0,,你还可以从这里进行control拖拽\\N{\\fs12}and also you can control drag from them.\r\nDialogue: 0,0:41:52.67,0:41:54.64,yin,,0,0,0,,可以从一个手势进行control拖拽\\N{\\fs12}Okay? You can control drag from a gesture,\r\nDialogue: 0,0:41:54.64,0:41:55.94,yin,,0,0,0,,可以从一个视图进行control拖拽\\N{\\fs12}you control drag from a view.\r\nDialogue: 0,0:41:55.99,0:41:58.99,yin,,0,0,0,,在这里进行control拖拽非常方便\\N{\\fs12}It's a really great place to control drag things from, okay?\r\nDialogue: 0,0:41:59.39,0:42:00.71,yin,,0,0,0,,入门指导第一条\\N{\\fs12}That's pro-tip number one.\r\nDialogue: 0,0:42:01.07,0:42:03.16,yin,,0,0,0,,从文档大纲中进行control拖拽\\N{\\fs12}Drag, control drag from document outline.\r\nDialogue: 0,0:42:03.74,0:42:05.30,yin,,0,0,0,,文档大纲还可以显示出\\N{\\fs12}The document online, also,\r\nDialogue: 0,0:42:05.40,0:42:07.89,yin,,0,0,0,,自动布局的全部问题\\N{\\fs12}will show you all the problems with your autolayout\r\nDialogue: 0,0:42:08.10,0:42:11.76,yin,,0,0,0,,看到上面那个小黄色圆形图标了吗\\N{\\fs12}and you see the tiny, little, yellow circle up there\r\nDialogue: 0,0:42:11.77,0:42:13.10,yin,,0,0,0,,在文档大纲顶部\\N{\\fs12}where it says view controller scene\r\nDialogue: 0,0:42:13.10,0:42:14.34,yin,,0,0,0,,视图控制器场景右侧\\N{\\fs12}at the top of the document outline\r\nDialogue: 0,0:42:14.36,0:42:15.51,yin,,0,0,0,,那里有一个小的黄色圆形图标\\N{\\fs12}and then there's that little yellow circle,\r\nDialogue: 0,0:42:15.53,0:42:17.09,yin,,0,0,0,,点击它\\N{\\fs12}I'm going to click on that circle,\r\nDialogue: 0,0:42:17.37,0:42:20.31,yin,,0,0,0,,就会显示出这个控制器中 这个场景中\\N{\\fs12}and it's going to show me all the autolayout problems\r\nDialogue: 0,0:42:20.49,0:42:22.92,yin,,0,0,0,,自动布局的全部问题\\N{\\fs12}in this controller, in this scene.\r\nDialogue: 0,0:42:23.56,0:42:25.43,yin,,0,0,0,,可以看到有Bad Thing\\N{\\fs12}And you can see the bad thing,\r\nDialogue: 0,0:42:25.61,0:42:29.03,yin,,0,0,0,,它预期框架是上面的值 实际框架是不同的\\N{\\fs12}it expects a certain frame and the actual frame is different.\r\nDialogue: 0,0:42:29.38,0:42:30.99,yin,,0,0,0,,可以看到右边有一个小三角形\\N{\\fs12}And you see the little triangle there,\r\nDialogue: 0,0:42:30.99,0:42:35.00,yin,,0,0,0,,如果点击它 就会提供...\\N{\\fs12}if I click on that triangle, it will offer me to,\r\nDialogue: 0,0:42:35.05,0:42:37.30,yin,,0,0,0,,会为我提供问题的解决方案\\N{\\fs12}offer to solve the problem for me.\r\nDialogue: 0,0:42:37.89,0:42:39.74,yin,,0,0,0,,我如何才能解决这个问题呢\\N{\\fs12}Okay? Now, how can I solve the problem?\r\nDialogue: 0,0:42:39.75,0:42:41.32,yin,,0,0,0,,有几种解决方法\\N{\\fs12}Well, there's a number of ways it could solve the problem.\r\nDialogue: 0,0:42:41.47,0:42:44.03,yin,,0,0,0,,可以将Bad Thing的框架\\N{\\fs12}It could change the frame of bad thing\r\nDialogue: 0,0:42:44.04,0:42:45.74,yin,,0,0,0,,修改为约束的值\\N{\\fs12}to be what the constraints say,\r\nDialogue: 0,0:42:45.75,0:42:47.12,yin,,0,0,0,,这就是Update Frame更新框架的作用\\N{\\fs12}that's what update frame is.\r\nDialogue: 0,0:42:47.67,0:42:50.64,yin,,0,0,0,,还可以修改约束\\N{\\fs12}It could update the constraints instead of being\r\nDialogue: 0,0:42:50.85,0:42:53.59,yin,,0,0,0,,不再是我刚才设置的水平垂直居中\\N{\\fs12}the vertical and horizontal center that I just set it to,\r\nDialogue: 0,0:42:53.59,0:42:56.13,yin,,0,0,0,,可以将其设回为\\N{\\fs12}it could set them back to being something that would make,\r\nDialogue: 0,0:42:56.57,0:42:59.59,yin,,0,0,0,,某个能让Bad Thing框架使用的约束\\N{\\fs12}you know, the bad things frame work,\r\nDialogue: 0,0:43:00.29,0:43:03.06,yin,,0,0,0,,还可以将其设为建议约束\\N{\\fs12}or it could try to set it to the suggested constraints,\r\nDialogue: 0,0:43:03.07,0:43:04.44,yin,,0,0,0,,我们已经知道这行不通了\\N{\\fs12}which we already know don't work.\r\nDialogue: 0,0:43:04.73,0:43:07.25,yin,,0,0,0,,所以在这个例子中 我们需要的当然是更新框架\\N{\\fs12}So we definitely want update frame in this case.\r\nDialogue: 0,0:43:07.39,0:43:09.19,yin,,0,0,0,,我们喜欢我们的约束\\N{\\fs12}We know we like our constraints,\r\nDialogue: 0,0:43:09.19,0:43:11.04,yin,,0,0,0,,也就是水平垂直居中\\N{\\fs12}that's the horizontal, vertical centering.\r\nDialogue: 0,0:43:11.49,0:43:12.51,yin,,0,0,0,,所以我们要选择这一项\\N{\\fs12}So we're going to pick that.\r\nDialogue: 0,0:43:12.68,0:43:14.27,yin,,0,0,0,,选择Update Frame选项\\N{\\fs12}So I'm going to leave update frame suggested\r\nDialogue: 0,0:43:14.28,0:43:16.33,yin,,0,0,0,,点击Fix Misplacement修复错位\\N{\\fs12}and click where it says fix misplacement,\r\nDialogue: 0,0:43:16.46,0:43:18.04,yin,,0,0,0,,看看Bad Thing会怎样\\N{\\fs12}and watch what's going to happen to bad thing.\r\nDialogue: 0,0:43:18.73,0:43:22.66,yin,,0,0,0,,它移动了 现在没有黄色警告了\\N{\\fs12}It moved. Okay, now, everything is no longer yellow,\r\nDialogue: 0,0:43:22.81,0:43:24.52,yin,,0,0,0,,Bad Thing框架被设置为了\\N{\\fs12}bad things frame has been set\r\nDialogue: 0,0:43:24.52,0:43:26.97,yin,,0,0,0,,约束要求的值\\N{\\fs12}to what the constraints demand of it. Okay?\r\nDialogue: 0,0:43:27.60,0:43:30.79,yin,,0,0,0,,我点击了返回 回到文档大纲中\\N{\\fs12}And I just hit back to go back to, in the document online.\r\nDialogue: 0,0:43:30.85,0:43:32.39,yin,,0,0,0,,现在我们回到横屏模式\\N{\\fs12}So now let's go look in landscape\r\nDialogue: 0,0:43:32.39,0:43:33.77,yin,,0,0,0,,看看Bad Thing会怎样\\N{\\fs12}and see what happens to bad thing.\r\nDialogue: 0,0:43:33.88,0:43:34.87,yin,,0,0,0,,它始终显示在中间\\N{\\fs12}It stays centered.\r\nDialogue: 0,0:43:35.30,0:43:37.35,yin,,0,0,0,,Bad Thing始终很好地显示在中间\\N{\\fs12}Okay? Bad thing properly stays centered,\r\nDialogue: 0,0:43:37.35,0:43:38.83,yin,,0,0,0,,因为它只有一条规则\\N{\\fs12}because the only rules it has,\r\nDialogue: 0,0:43:39.10,0:43:41.59,yin,,0,0,0,,就是让它显示在中间\\N{\\fs12}is for it to be in the center.\r\nDialogue: 0,0:43:42.52,0:43:44.60,yin,,0,0,0,,好了 回到这里\\N{\\fs12}Okay? Alright, so back here.\r\nDialogue: 0,0:43:45.48,0:43:48.19,yin,,0,0,0,,我刚才说过了\\N{\\fs12}Okay. You can also click on, I told you,\r\nDialogue: 0,0:43:48.19,0:43:49.94,yin,,0,0,0,,你还可以点击这些约束\\N{\\fs12}you could click on these constraints.\r\nDialogue: 0,0:43:49.94,0:43:51.97,yin,,0,0,0,,这里我点击了垂直约束\\N{\\fs12}So here I clicked on the vertical constraint there,\r\nDialogue: 0,0:43:51.98,0:43:53.78,yin,,0,0,0,,我刚点了它\\N{\\fs12}you can see, I just clicked on it,\r\nDialogue: 0,0:43:53.87,0:43:56.46,yin,,0,0,0,,可以看到 它被突出显示出来了\\N{\\fs12}and you see how it's kind of highlighted.\r\nDialogue: 0,0:43:56.58,0:44:00.12,yin,,0,0,0,,还要注意 属性检查器\\N{\\fs12}Also notice that the attribute inspector started being an inspector\r\nDialogue: 0,0:44:00.13,0:44:03.03,yin,,0,0,0,,现在检查的是X轴居中约束\\N{\\fs12}that's inspecting the center X alignment constraint.\r\nDialogue: 0,0:44:03.36,0:44:05.57,yin,,0,0,0,,有很多关于约束的选项\\N{\\fs12}Okay? And there's a lot of things\r\nDialogue: 0,0:44:05.58,0:44:06.56,yin,,0,0,0,,可以在这里进行设置\\N{\\fs12}you can set about constraints.\r\nDialogue: 0,0:44:06.56,0:44:07.87,yin,,0,0,0,,注意这里有一个Priority优先级选项\\N{\\fs12}Notice there's a priority there,\r\nDialogue: 0,0:44:07.87,0:44:11.13,yin,,0,0,0,,因为在复杂布局中可能会有两个约束\\N{\\fs12}because you might have two constraints in a complicated layout,\r\nDialogue: 0,0:44:11.46,0:44:12.57,yin,,0,0,0,,只会出现于复杂布局的情况\\N{\\fs12}only complicated ones,\r\nDialogue: 0,0:44:12.73,0:44:15.01,yin,,0,0,0,,你的约束之间可能会有冲突\\N{\\fs12}you might have conflicting constraints.\r\nDialogue: 0,0:44:15.08,0:44:17.24,yin,,0,0,0,,你想让某个控件显示在另一个控件的下面\\N{\\fs12}You want something to be underneath something else,\r\nDialogue: 0,0:44:17.26,0:44:19.64,yin,,0,0,0,,但你还想让它显示在屏幕的中间\\N{\\fs12}but you want it to try and be in the middle of the screen,\r\nDialogue: 0,0:44:19.64,0:44:21.08,yin,,0,0,0,,但如果屏幕变得很小\\N{\\fs12}but if the screen gets really small,\r\nDialogue: 0,0:44:21.21,0:44:22.51,yin,,0,0,0,,这时你就想将它移出来\\N{\\fs12}then you want it to just move down\r\nDialogue: 0,0:44:22.52,0:44:24.05,yin,,0,0,0,,不被上面的控件遮挡\\N{\\fs12}out of the way of the thing on top,\r\nDialogue: 0,0:44:24.24,0:44:26.90,yin,,0,0,0,,可以为这种冲突约束设置优先级\\N{\\fs12}those kind of conflicting constraints you can set priorities,\r\nDialogue: 0,0:44:26.91,0:44:27.96,yin,,0,0,0,,哪个更重要呢\\N{\\fs12}to say which is more important?\r\nDialogue: 0,0:44:27.96,0:44:29.04,yin,,0,0,0,,在中间显示\\N{\\fs12}Is it more important to be in the middle\r\nDialogue: 0,0:44:29.04,0:44:31.27,yin,,0,0,0,,还是在另一个视图下面更加重要\\N{\\fs12}or is it more important to be underneath this other view?\r\nDialogue: 0,0:44:31.56,0:44:32.36,yin,,0,0,0,,明白我的意思吗\\N{\\fs12}You see what I'm saying?\r\nDialogue: 0,0:44:32.58,0:44:34.78,yin,,0,0,0,,优先级范围可以是1到1000\\N{\\fs12}So you can set your priorities between zero and a thousand,\r\nDialogue: 0,0:44:34.78,0:44:37.95,yin,,0,0,0,,1000个控件可以有各自不同的优先级\\N{\\fs12}so you, up to thousand items could have varying priorities\r\nDialogue: 0,0:44:37.95,0:44:39.47,yin,,0,0,0,,通常情况下  整个应用中\\N{\\fs12}and generally you're gonna only use two or three\r\nDialogue: 0,0:44:39.48,0:44:41.65,yin,,0,0,0,,只会用到两三个不同的优先级\\N{\\fs12}different priorities in your entire application, but--\r\nDialogue: 0,0:44:41.96,0:44:43.57,yin,,0,0,0,,选中约束时 还可以做一件事情\\N{\\fs12}anyway, the other thing you can do\r\nDialogue: 0,0:44:43.58,0:44:45.94,yin,,0,0,0,,就是点击删除键\\N{\\fs12}when you have this selected is hit delete.\r\nDialogue: 0,0:44:46.64,0:44:48.04,yin,,0,0,0,,删除选中的约束\\N{\\fs12}And that deletes that constraint.\r\nDialogue: 0,0:44:48.05,0:44:49.36,yin,,0,0,0,,可以看到 这时Bad Thing\\N{\\fs12}And now you can see the bad thing\r\nDialogue: 0,0:44:49.37,0:44:53.08,yin,,0,0,0,,只有这个Y轴居中约束\\N{\\fs12}only has this center Y constraint.\r\nDialogue: 0,0:44:53.08,0:44:57.67,yin,,0,0,0,,现在就没有指定它的水平位置了\\N{\\fs12}So it no longer specifies where it is horizontally,\r\nDialogue: 0,0:44:58.01,0:44:59.93,yin,,0,0,0,,这真的很糟糕\\N{\\fs12}and that is really bad\r\nDialogue: 0,0:45:00.09,0:45:01.89,yin,,0,0,0,,现在再看文档大纲\\N{\\fs12}and now if you look at the document outline,\r\nDialogue: 0,0:45:01.92,0:45:05.58,yin,,0,0,0,,右上不仅出现了圆形图标 它还是红色的\\N{\\fs12}I not only have a little dot up there, but its red.\r\nDialogue: 0,0:45:06.18,0:45:09.36,yin,,0,0,0,,如果这里有一个不太好的约束\\N{\\fs12}Okay? And if I had a constraint that was bad here,\r\nDialogue: 0,0:45:09.53,0:45:11.22,yin,,0,0,0,,问题是缺少约束\\N{\\fs12}the problem is I have a lack of constraint,\r\nDialogue: 0,0:45:11.22,0:45:12.41,yin,,0,0,0,,没有足够的约束\\N{\\fs12}I don't have enough constraints\r\nDialogue: 0,0:45:12.42,0:45:14.72,yin,,0,0,0,,指定Bad Thing的水平位置\\N{\\fs12}to specify where bad thing is horizontally,\r\nDialogue: 0,0:45:14.86,0:45:16.85,yin,,0,0,0,,但如果有两个约束冲突了 就会是红色的\\N{\\fs12}but if I had two that conflicted, they would be red.\r\nDialogue: 0,0:45:17.46,0:45:17.91,yin,,0,0,0,,明白吗\\N{\\fs12}Okay?\r\nDialogue: 0,0:45:18.06,0:45:20.08,yin,,0,0,0,,显示在屏幕上的约束线会是红色的\\N{\\fs12}The constraint, the lines on screen would be red\r\nDialogue: 0,0:45:20.09,0:45:21.55,yin,,0,0,0,,大纲右上角会出现红色的圆形图标\\N{\\fs12}and I would have this little red circle.\r\nDialogue: 0,0:45:21.80,0:45:24.43,yin,,0,0,0,,点击文档大纲中的红色圆形图标\\N{\\fs12}So let's click on that red circle in the document outline\r\nDialogue: 0,0:45:24.95,0:45:27.57,yin,,0,0,0,,这里说它缺失约束\\N{\\fs12}and here it's saying missing constraints, okay,\r\nDialogue: 0,0:45:27.62,0:45:30.94,yin,,0,0,0,,Bad Thing需要X轴位置的约束\\N{\\fs12}bad thing needs constraints for X position, it's saying,\r\nDialogue: 0,0:45:30.95,0:45:31.77,yin,,0,0,0,,确实需要\\N{\\fs12}which it does.\r\nDialogue: 0,0:45:31.91,0:45:34.72,yin,,0,0,0,,不然它怎么知道要把Bad Thing放在哪里呢\\N{\\fs12}Because how else is it gonna know where to put X, bad thing,\r\nDialogue: 0,0:45:34.73,0:45:36.10,yin,,0,0,0,,没有规则说明它应该放在哪里\\N{\\fs12}there's nothing that says where to put it\r\nDialogue: 0,0:45:36.11,0:45:37.65,yin,,0,0,0,,因为我删掉了\\N{\\fs12}because I took that constraint\r\nDialogue: 0,0:45:37.66,0:45:39.33,yin,,0,0,0,,那个要求它显示在中间的约束\\N{\\fs12}that was telling it to be in the middle away.\r\nDialogue: 0,0:45:39.66,0:45:41.23,yin,,0,0,0,,我们点击红色圆形图标\\N{\\fs12}So let's click on that red thing,\r\nDialogue: 0,0:45:41.38,0:45:43.67,yin,,0,0,0,,点击之后 系统会提供解决方案\\N{\\fs12}and when we do, it's going to offer to fix that.\r\nDialogue: 0,0:45:43.86,0:45:46.83,yin,,0,0,0,,它说 让我试着加一个缺失的约束\\N{\\fs12}And it says let me try and add a missing constraint,\r\nDialogue: 0,0:45:46.84,0:45:48.55,yin,,0,0,0,,它会尽己所能\\N{\\fs12}and it's going to do the best it can\r\nDialogue: 0,0:45:48.72,0:45:51.96,yin,,0,0,0,,添加一个或多个约束\\N{\\fs12}to add a constraint or a number of constraints\r\nDialogue: 0,0:45:52.05,0:45:54.38,yin,,0,0,0,,让它至少不缺少约束\\N{\\fs12}to make it so that at least there's not a missing constraint.\r\nDialogue: 0,0:45:54.40,0:45:57.52,yin,,0,0,0,,可能并不是你想要的约束\\N{\\fs12}This might not be the constraint you want, but, you know,\r\nDialogue: 0,0:45:57.53,0:45:59.99,yin,,0,0,0,,很可能就是建议约束\\N{\\fs12}it's probably gonna be mostly suggested constraints,\r\nDialogue: 0,0:46:00.09,0:46:02.21,yin,,0,0,0,,但是添加这个约束之后\\N{\\fs12}but it's gonna be some kind of constraint so that there--\r\nDialogue: 0,0:46:02.83,0:46:05.34,yin,,0,0,0,,该元素的位置和大小\\N{\\fs12}so the position of this thing, and its size,\r\nDialogue: 0,0:46:05.64,0:46:07.17,yin,,0,0,0,,就能够完全确定了\\N{\\fs12}are completely specified.\r\nDialogue: 0,0:46:07.59,0:46:08.96,yin,,0,0,0,,在这个例子中\\N{\\fs12}So, in this case,\r\nDialogue: 0,0:46:08.98,0:46:11.29,yin,,0,0,0,,因为我们已经用蓝线将其居中对齐\\N{\\fs12}since we already blue guidelined this thing to the middle,\r\nDialogue: 0,0:46:11.30,0:46:13.37,yin,,0,0,0,,我们知道它就在正中\\N{\\fs12}and we know it's exactly in the middle,\r\nDialogue: 0,0:46:13.71,0:46:15.56,yin,,0,0,0,,当我们点击增加缺失约束时\\N{\\fs12}when we hit add missing constraints,\r\nDialogue: 0,0:46:15.58,0:46:16.95,yin,,0,0,0,,它会把那个约束再加回来\\N{\\fs12}it's going to put that thing back.\r\nDialogue: 0,0:46:17.52,0:46:19.07,yin,,0,0,0,,也不是恢复之前那个约束\\N{\\fs12}Okay? Now it's not putting it back\r\nDialogue: 0,0:46:19.08,0:46:20.18,yin,,0,0,0,,因为系统知道我删掉了它\\N{\\fs12}because it knows I deleted it,\r\nDialogue: 0,0:46:20.19,0:46:23.62,yin,,0,0,0,,只不过它认为这是最适合这里的约束\\N{\\fs12}it's just thinking that's the best constraint that goes here.\r\nDialogue: 0,0:46:23.94,0:46:25.57,yin,,0,0,0,,它知道这个元素在正中间\\N{\\fs12}Because it knows this thing is dead center,\r\nDialogue: 0,0:46:25.58,0:46:27.57,yin,,0,0,0,,它就会想 正中间 好吧\\N{\\fs12}so it's like, hmm, dead center thing,\r\nDialogue: 0,0:46:27.58,0:46:28.31,yin,,0,0,0,,我也许应该添加一个这样的约束\\N{\\fs12}I'm probably going to do that.\r\nDialogue: 0,0:46:28.33,0:46:29.31,yin,,0,0,0,,系统真的很聪明\\N{\\fs12}So it's really smart\r\nDialogue: 0,0:46:29.50,0:46:31.80,yin,,0,0,0,,知道要增加哪个缺失约束\\N{\\fs12}about what missing constraints it will put in there.\r\nDialogue: 0,0:46:31.91,0:46:33.54,yin,,0,0,0,,大多数情况下都会用建议约束\\N{\\fs12}Mostly it's going to use suggested constraints,\r\nDialogue: 0,0:46:33.54,0:46:36.30,yin,,0,0,0,,但是它很聪明 并不会只用建议约束\\N{\\fs12}but it's even smarter than just the suggested system.\r\nDialogue: 0,0:46:37.29,0:46:39.66,yin,,0,0,0,,现在自动布局就没有问题了\\N{\\fs12}Okay? So now we have no autolayout issues,\r\nDialogue: 0,0:46:39.67,0:46:42.13,yin,,0,0,0,,Bad Thing又位于很好的位置了\\N{\\fs12}we're back to having bad thing in a good spot.\r\nDialogue: 0,0:46:42.39,0:46:45.10,yin,,0,0,0,,如果我不想让Bad Thing显示在中间了呢\\N{\\fs12}Now what if I decided I don't want bad thing in the middle,\r\nDialogue: 0,0:46:45.10,0:46:46.32,yin,,0,0,0,,我想让Bad Thing始终显示在\\N{\\fs12}I want bad thing to be stacked\r\nDialogue: 0,0:46:46.33,0:46:47.69,yin,,0,0,0,,Thing 2的上面\\N{\\fs12}on top of thing two all the time?\r\nDialogue: 0,0:46:48.36,0:46:51.78,yin,,0,0,0,,我只要拾取Bad Thing 向下拖动\\N{\\fs12}So I just pick up bad thing and drag it down,\r\nDialogue: 0,0:46:52.03,0:46:55.05,yin,,0,0,0,,可以选择是否使用蓝色辅助线 这里要用\\N{\\fs12}I'll use the blue guidelines or not, but I'm using the--\r\nDialogue: 0,0:46:55.12,0:46:57.34,yin,,0,0,0,,将它拖动到那里 然后松开鼠标\\N{\\fs12}I'm just going to drag it down there and I drop it.\r\nDialogue: 0,0:46:57.65,0:46:58.59,yin,,0,0,0,,发生了什么\\N{\\fs12}And what happens?\r\nDialogue: 0,0:46:58.60,0:47:00.43,yin,,0,0,0,,又一次出现了黄色辅助线\\N{\\fs12}Well, I get the yellow guidelines again,\r\nDialogue: 0,0:47:00.44,0:47:03.72,yin,,0,0,0,,因为Bad Thing又被放到了错误的位置\\N{\\fs12}because bad thing, once again, is misplaced.\r\nDialogue: 0,0:47:04.00,0:47:07.08,yin,,0,0,0,,这是因为当你将控件拖动到新位置时\\N{\\fs12}That's because when you drag things to new positions,\r\nDialogue: 0,0:47:07.08,0:47:09.15,yin,,0,0,0,,并不会改变其约束\\N{\\fs12}it does not change the constraints.\r\nDialogue: 0,0:47:09.48,0:47:10.66,yin,,0,0,0,,这一点很重要 需要大家理解\\N{\\fs12}That's important to understand.\r\nDialogue: 0,0:47:10.66,0:47:12.33,yin,,0,0,0,,将控件拖至新位置时\\N{\\fs12}When you drag things somewhere new,\r\nDialogue: 0,0:47:12.46,0:47:13.73,yin,,0,0,0,,约束不变\\N{\\fs12}the constraints stay the same.\r\nDialogue: 0,0:47:13.75,0:47:15.70,yin,,0,0,0,,Bad Thing的约束\\N{\\fs12}So bad thing's constraints are still\r\nDialogue: 0,0:47:15.71,0:47:17.79,yin,,0,0,0,,依旧是水平垂直居中\\N{\\fs12}align center X and align Y, you see?\r\nDialogue: 0,0:47:17.80,0:47:18.61,yin,,0,0,0,,看到了吗\\N{\\fs12}See them right there?\r\nDialogue: 0,0:47:19.69,0:47:20.76,yin,,0,0,0,,这样不好\\N{\\fs12}And that's no good.\r\nDialogue: 0,0:47:20.76,0:47:23.03,yin,,0,0,0,,我们能做什么呢\\N{\\fs12}So, what can we do about that?\r\nDialogue: 0,0:47:23.04,0:47:25.43,yin,,0,0,0,,我们也许想要删掉这些约束\\N{\\fs12}Well, we probably want to delete these constraints,\r\nDialogue: 0,0:47:25.43,0:47:26.77,yin,,0,0,0,,因为它们不再适用了\\N{\\fs12}because they no longer apply,\r\nDialogue: 0,0:47:26.91,0:47:30.27,yin,,0,0,0,,我演示了使用清除约束删掉它们的方法\\N{\\fs12}and I showed you how to delete them by doing clear constraints,\r\nDialogue: 0,0:47:30.28,0:47:31.44,yin,,0,0,0,,我还讲了如何选中它们\\N{\\fs12}and I told you how to delete them\r\nDialogue: 0,0:47:31.45,0:47:32.91,yin,,0,0,0,,然后点击删除的方法\\N{\\fs12}by clicking on them and hit delete.\r\nDialogue: 0,0:47:33.00,0:47:34.37,yin,,0,0,0,,还有一种删除方法\\N{\\fs12}Here's another way to delete them,\r\nDialogue: 0,0:47:34.37,0:47:36.16,yin,,0,0,0,,看到那个小齿轮了吗\\N{\\fs12}you see the little cog, right there,\r\nDialogue: 0,0:47:36.17,0:47:38.23,yin,,0,0,0,,在Y轴居中和X轴居中约束线上\\N{\\fs12}where it says align center Y and align center X,\r\nDialogue: 0,0:47:38.24,0:47:39.22,yin,,0,0,0,,有一个小齿轮\\N{\\fs12}there's a little cog,\r\nDialogue: 0,0:47:39.34,0:47:41.65,yin,,0,0,0,,如果点击它 会出现一个小菜单\\N{\\fs12}if you click on that, there's a little menu,\r\nDialogue: 0,0:47:41.78,0:47:42.62,yin,,0,0,0,,你可以对它进行编辑\\N{\\fs12}you can edit it,\r\nDialogue: 0,0:47:42.63,0:47:45.67,yin,,0,0,0,,和属性检查器是完全一样的\\N{\\fs12}which is exactly the same as attributes inspector on it,\r\nDialogue: 0,0:47:45.90,0:47:47.13,yin,,0,0,0,,你还可以选择删除它\\N{\\fs12}or you can delete it.\r\nDialogue: 0,0:47:47.49,0:47:49.31,yin,,0,0,0,,我要删除这两个约束\\N{\\fs12}So I'll delete that one and I'll delete that one.\r\nDialogue: 0,0:47:49.32,0:47:50.72,yin,,0,0,0,,这样我就删掉了这些约束\\N{\\fs12}So now I got rid of those constraints,\r\nDialogue: 0,0:47:50.89,0:47:52.48,yin,,0,0,0,,Bad Thing又回到了没有约束的状态\\N{\\fs12}bad things back to having no constraints.\r\nDialogue: 0,0:47:52.48,0:47:53.71,yin,,0,0,0,,我这样做只是为了给大家演示\\N{\\fs12}I just did that because I wanted to show you\r\nDialogue: 0,0:47:53.71,0:47:56.50,yin,,0,0,0,,有多种删除方法\\N{\\fs12}that there's multiple ways to get at this thing.\r\nDialogue: 0,0:47:56.51,0:47:58.43,yin,,0,0,0,,还可以在文档大纲中选中它们\\N{\\fs12}You can also delete them by selecting them\r\nDialogue: 0,0:47:58.44,0:48:00.88,yin,,0,0,0,,然后点击删除\\N{\\fs12}in the document outline and hitting delete. Okay?\r\nDialogue: 0,0:48:01.61,0:48:04.46,yin,,0,0,0,,现在Bad Thing显示在那里\\N{\\fs12}So now I have bad thing, but where it is there,\r\nDialogue: 0,0:48:04.46,0:48:05.99,yin,,0,0,0,,但它并没有和Thing 2绑定\\N{\\fs12}it's not tied to thing two.\r\nDialogue: 0,0:48:05.99,0:48:07.86,yin,,0,0,0,,如果现在切换为横屏模式\\N{\\fs12}If I were to go landscape right now,\r\nDialogue: 0,0:48:07.93,0:48:09.66,yin,,0,0,0,,它不会随着Thing 2移动\\N{\\fs12}it would not stick with thing two\r\nDialogue: 0,0:48:09.68,0:48:12.36,yin,,0,0,0,,因为没有约束将其与Thing 2绑定\\N{\\fs12}because there's no constraint that ties it to thing two.\r\nDialogue: 0,0:48:12.49,0:48:14.62,yin,,0,0,0,,那我们就添加一个约束\\N{\\fs12}Okay? So, let's put a constraint.\r\nDialogue: 0,0:48:14.69,0:48:17.45,yin,,0,0,0,,这是第三种方法\\N{\\fs12}Here's way number three, okay,\r\nDialogue: 0,0:48:17.45,0:48:19.20,yin,,0,0,0,,大家还记得第一种方法是什么吗\\N{\\fs12}do you remember what ways number one are?\r\nDialogue: 0,0:48:19.32,0:48:22.26,yin,,0,0,0,,第一种方法是使用蓝色辅助线 选择建议约束\\N{\\fs12}Number one is blue guideline suggested constraint,\r\nDialogue: 0,0:48:22.28,0:48:23.79,yin,,0,0,0,,这是第一种方法 对吧\\N{\\fs12}that's way number one, alright?\r\nDialogue: 0,0:48:24.50,0:48:25.12,yin,,0,0,0,,大家还记得吗\\N{\\fs12}Everybody got that?\r\nDialogue: 0,0:48:25.52,0:48:28.31,yin,,0,0,0,,第二种方法是使用底部的菜单按钮\\N{\\fs12}Number two is to use the little menu things at the bottom.\r\nDialogue: 0,0:48:28.47,0:48:30.36,yin,,0,0,0,,点击按钮 弹出菜单 输入数值\\N{\\fs12}Click, bring up the little thing, type in,\r\nDialogue: 0,0:48:30.39,0:48:33.04,yin,,0,0,0,,选择水平约束等等 点击你需要的约束\\N{\\fs12}click horizontal, whatever, click the things that you want.\r\nDialogue: 0,0:48:33.29,0:48:37.57,yin,,0,0,0,,第三种方法是使用control拖拽\\N{\\fs12}Way number three is to control drag, control drag,\r\nDialogue: 0,0:48:37.58,0:48:38.74,yin,,0,0,0,,和添加输出口的操作是一样的\\N{\\fs12}just like you're making an outlet,\r\nDialogue: 0,0:48:38.91,0:48:41.36,yin,,0,0,0,,在两个目标对象之间进行拖拽\\N{\\fs12}between two items that you want\r\nDialogue: 0,0:48:41.56,0:48:43.94,yin,,0,0,0,,添加约束关系\\N{\\fs12}to have some sort of constrained relationship.\r\nDialogue: 0,0:48:44.16,0:48:47.71,yin,,0,0,0,,我要从Bad Thing按住control键拖拽到Thing 2\\N{\\fs12}So I'm gonna control drag from bad thing to thing two.\r\nDialogue: 0,0:48:48.37,0:48:51.01,yin,,0,0,0,,这样做之后 会弹出一个黑色菜单\\N{\\fs12}Okay? And when I do, I get a little black box\r\nDialogue: 0,0:48:51.02,0:48:52.54,yin,,0,0,0,,类似于添加输出口的菜单\\N{\\fs12}just like if I was making an outlet,\r\nDialogue: 0,0:48:52.64,0:48:55.84,yin,,0,0,0,,但是这里要选择的是\\N{\\fs12}but this time it's saying what do you want to tie\r\nDialogue: 0,0:48:56.12,0:48:57.71,yin,,0,0,0,,要怎样绑定两个对象\\N{\\fs12}between these two items?\r\nDialogue: 0,0:48:57.72,0:49:00.50,yin,,0,0,0,,你想让这两个对象间的什么值固定\\N{\\fs12}What do you want to be fixed between these two?\r\nDialogue: 0,0:49:00.79,0:49:04.72,yin,,0,0,0,,实际上 你可以按住shift键进行多选\\N{\\fs12}So, you can actually select multiple of these using shift,\r\nDialogue: 0,0:49:04.73,0:49:05.92,yin,,0,0,0,,底下提示的就是这个\\N{\\fs12}that's what it says at the bottom there,\r\nDialogue: 0,0:49:05.93,0:49:07.09,yin,,0,0,0,,按住shift键选择多项\\N{\\fs12}hold shift to select multiple.\r\nDialogue: 0,0:49:07.26,0:49:08.88,yin,,0,0,0,,我要选择垂直间距\\N{\\fs12}So I'm going to pick the vertical spacing,\r\nDialogue: 0,0:49:08.89,0:49:12.20,yin,,0,0,0,,我想让Bad Thing以固定的垂直间距\\N{\\fs12}I want bad thing to always be a fixed vertical space\r\nDialogue: 0,0:49:12.21,0:49:13.87,yin,,0,0,0,,始终显示在Thing 2的上方\\N{\\fs12}above thing two,\r\nDialogue: 0,0:49:13.98,0:49:16.96,yin,,0,0,0,,我还要选择右边缘\\N{\\fs12}and I'm also gonna pick right edge, okay?\r\nDialogue: 0,0:49:17.32,0:49:18.59,yin,,0,0,0,,这里说的是左边缘和右边缘\\N{\\fs12}And this is saying left and right,\r\nDialogue: 0,0:49:18.60,0:49:20.29,yin,,0,0,0,,实际上是前边缘和后边缘\\N{\\fs12}but it's really trailing and leading,\r\nDialogue: 0,0:49:20.30,0:49:22.71,yin,,0,0,0,,只不过系统现在知道你的左右方向\\N{\\fs12}it just right now it knows which is your left and right\r\nDialogue: 0,0:49:22.73,0:49:24.35,yin,,0,0,0,,用右边缘是为了更方便你\\N{\\fs12}so it's saying right to be nice to you.\r\nDialogue: 0,0:49:24.70,0:49:26.19,yin,,0,0,0,,所以我要选择垂直间距\\N{\\fs12}So I'm gonna pick both vertical spacing\r\nDialogue: 0,0:49:26.19,0:49:27.63,yin,,0,0,0,,和右边缘这两项\\N{\\fs12}and the right edges, okay?\r\nDialogue: 0,0:49:27.81,0:49:31.14,yin,,0,0,0,,这样做之后 可以看到添加了两个约束\\N{\\fs12}When I do that, you can see I get two constraints.\r\nDialogue: 0,0:49:31.21,0:49:34.23,yin,,0,0,0,,可以在屏幕上看到 IB上出现了两条蓝线\\N{\\fs12}You can see them on screen, two little blue lines in the IB,\r\nDialogue: 0,0:49:34.25,0:49:35.89,yin,,0,0,0,,在Bad Thing和Thing 2之间\\N{\\fs12}between bad thing and thing two,\r\nDialogue: 0,0:49:36.34,0:49:38.50,yin,,0,0,0,,代表二者右边缘对齐\\N{\\fs12}that is lining up the right edges\r\nDialogue: 0,0:49:38.63,0:49:42.52,yin,,0,0,0,,将二者间距设为固定的默认值\\N{\\fs12}and fixing the space between them to the default space.\r\nDialogue: 0,0:49:42.80,0:49:44.44,yin,,0,0,0,,这是因为我用了蓝色辅助线\\N{\\fs12}Okay, that's because I used the blue guidelines.\r\nDialogue: 0,0:49:44.72,0:49:46.18,yin,,0,0,0,,如果我没用蓝色辅助线\\N{\\fs12}If I hadn't used the blue guidelines\r\nDialogue: 0,0:49:46.19,0:49:49.06,yin,,0,0,0,,而是将Bad Thing放在Thing 2上面40像素处\\N{\\fs12}and had put bad thing, you know, 40 pixels above,\r\nDialogue: 0,0:49:49.19,0:49:50.80,yin,,0,0,0,,那么间距就固定为40像素\\N{\\fs12}then it would have fixed it to 40 pixels,\r\nDialogue: 0,0:49:50.82,0:49:53.24,yin,,0,0,0,,但我们会在约束中看到40\\N{\\fs12}but we would have seen in the constraints 40,\r\nDialogue: 0,0:49:53.24,0:49:55.23,yin,,0,0,0,,约束中有魔术数字\\N{\\fs12}and we said a magic number is in constraints,\r\nDialogue: 0,0:49:55.24,0:49:56.24,yin,,0,0,0,,我们最好改一下\\N{\\fs12}we better fix that.\r\nDialogue: 0,0:49:56.75,0:49:59.24,yin,,0,0,0,,你可以编辑约束\\N{\\fs12}Okay? Which you could do by editing the constraint and just--\r\nDialogue: 0,0:49:59.26,0:50:00.18,yin,,0,0,0,,会有一个按钮\\N{\\fs12}there's a button actually\r\nDialogue: 0,0:50:00.20,0:50:01.80,yin,,0,0,0,,可以将其设为默认值\\N{\\fs12}that says put it, make it the default.\r\nDialogue: 0,0:50:02.53,0:50:03.04,yin,,0,0,0,,明白吗\\N{\\fs12}Alright?\r\nDialogue: 0,0:50:03.55,0:50:06.04,yin,,0,0,0,,现在我将这两个控件这样绑定起来了\\N{\\fs12}So now I have these two things tied in that way,\r\nDialogue: 0,0:50:06.05,0:50:07.53,yin,,0,0,0,,这些约束\\N{\\fs12}again, this is totally enough\r\nDialogue: 0,0:50:07.54,0:50:10.00,yin,,0,0,0,,可以准确指定它们的位置\\N{\\fs12}to specify all of their positions exactly,\r\nDialogue: 0,0:50:10.01,0:50:11.86,yin,,0,0,0,,因为Thing 2绑定在了右下角\\N{\\fs12}because thing two is tied to the corner\r\nDialogue: 0,0:50:12.02,0:50:13.78,yin,,0,0,0,,Bad Thing与Thing 2右边缘对齐\\N{\\fs12}and bad thing is tied to the right edge\r\nDialogue: 0,0:50:13.80,0:50:15.06,yin,,0,0,0,,绑定在它的上方\\N{\\fs12}and just above thing two.\r\nDialogue: 0,0:50:15.33,0:50:17.31,yin,,0,0,0,,如果我们再转为横屏模式\\N{\\fs12}So, if we go to landscape again,\r\nDialogue: 0,0:50:17.48,0:50:20.26,yin,,0,0,0,,Bad Thing会始终和Thing 2保持这个距离\\N{\\fs12}bad thing will always stay that distance\r\nDialogue: 0,0:50:20.52,0:50:22.14,yin,,0,0,0,,且始终与Thing 2右边缘对齐\\N{\\fs12}and always to the right edge of thing two.\r\nDialogue: 0,0:50:23.26,0:50:27.04,yin,,0,0,0,,这是吸附对象的第三种方法\\N{\\fs12}Okay? So that's way number three to attach things\r\nDialogue: 0,0:50:27.05,0:50:28.66,yin,,0,0,0,,就是在二者之间进行control拖拽\\N{\\fs12}is to control drag between them\r\nDialogue: 0,0:50:28.80,0:50:32.98,yin,,0,0,0,,可以在两个控件 两个视图之间进行control拖拽\\N{\\fs12}and you control drag between items, between views,\r\nDialogue: 0,0:50:33.03,0:50:36.68,yin,,0,0,0,,还可以从某个视图向其父视图进行control拖拽\\N{\\fs12}you can also control drag from a view to its superview,\r\nDialogue: 0,0:50:36.91,0:50:37.98,yin,,0,0,0,,就是我现在做的这个操作\\N{\\fs12}that's what I'm doing here.\r\nDialogue: 0,0:50:38.01,0:50:39.68,yin,,0,0,0,,从Bad Thing拖拽到它的父视图\\N{\\fs12}Bad thing to its superview\r\nDialogue: 0,0:50:39.69,0:50:41.56,yin,,0,0,0,,会弹出另外一组选项\\N{\\fs12}and you'll get a different set of options,\r\nDialogue: 0,0:50:41.57,0:50:43.89,yin,,0,0,0,,比如容器内水平垂直居中\\N{\\fs12}like horizontal and vertical container.\r\nDialogue: 0,0:50:44.57,0:50:47.48,yin,,0,0,0,,还可以向自己进行control拖拽\\N{\\fs12}Or you could also control drag to yourself.\r\nDialogue: 0,0:50:48.67,0:50:51.19,yin,,0,0,0,,为什么要向自己进行control拖拽呢\\N{\\fs12}Okay? Why would you ever control drag to yourself?\r\nDialogue: 0,0:50:51.20,0:50:52.00,yin,,0,0,0,,我有一个Bad Thing\\N{\\fs12}I have a bad thing,\r\nDialogue: 0,0:50:52.01,0:50:54.52,yin,,0,0,0,,为什么要从Bad Thing control拖拽到它自己呢\\N{\\fs12}why would I control drag bad thing to itself?\r\nDialogue: 0,0:50:55.11,0:50:56.68,yin,,0,0,0,,这样弹出的选项是\\N{\\fs12}Well, then I'll get the option to do things\r\nDialogue: 0,0:50:56.68,0:50:59.70,yin,,0,0,0,,将Bad Thing的宽度设为固定值\\N{\\fs12}like fix bad thing's width, okay?\r\nDialogue: 0,0:50:59.74,0:51:02.33,yin,,0,0,0,,如果你要处理的是按钮或标签这种有内置大小的元素\\N{\\fs12}Which I told you was bad anytime you have a button or a label\r\nDialogue: 0,0:51:02.33,0:51:05.47,yin,,0,0,0,,我说了这样处理很不好\\N{\\fs12}or anything that has, you know, an intrinsic size like that.\r\nDialogue: 0,0:51:05.75,0:51:08.23,yin,,0,0,0,,如果附近有可以依附的对象的话\\N{\\fs12}It'll also, if there's some nearby thing it could do,\r\nDialogue: 0,0:51:08.23,0:51:10.81,yin,,0,0,0,,还会有将容器的后置间距设为固定值等选项\\N{\\fs12}like fix the trailing space to its container,\r\nDialogue: 0,0:51:10.82,0:51:11.90,yin,,0,0,0,,它也可以为你完成这类操作\\N{\\fs12}it could do that for you too,\r\nDialogue: 0,0:51:11.92,0:51:13.78,yin,,0,0,0,,反正是可以向自己进行control拖拽的\\N{\\fs12}but you can control drag to yourself too,\r\nDialogue: 0,0:51:14.34,0:51:16.39,yin,,0,0,0,,听起来很疯狂 但是你们会习惯的\\N{\\fs12}which sounds crazy, but you'll get used to doing that.\r\nDialogue: 0,0:51:16.61,0:51:19.76,yin,,0,0,0,,所以control是设置约束的第三种方法\\N{\\fs12}So control drag is way number three to set up constraints.\r\nDialogue: 0,0:51:20.67,0:51:24.71,yin,,0,0,0,,这套系统中有很多内容\\N{\\fs12}Okay? So, there is a lot to this system.\r\nDialogue: 0,0:51:24.72,0:51:26.16,yin,,0,0,0,,我只是尽可能多地为大家演示\\N{\\fs12}I've just tried to kind of show you\r\nDialogue: 0,0:51:26.17,0:51:27.40,yin,,0,0,0,,到哪里查看各种内容\\N{\\fs12}where to look for everything.\r\nDialogue: 0,0:51:27.70,0:51:30.19,yin,,0,0,0,,如何点击 如何检查\\N{\\fs12}How to click on things, where to inspect them,\r\nDialogue: 0,0:51:30.37,0:51:31.66,yin,,0,0,0,,怎样查看约束\\N{\\fs12}where to see the constraints,\r\nDialogue: 0,0:51:31.72,0:51:34.40,yin,,0,0,0,,怎样在文档大纲中解决问题\\N{\\fs12}how to go on the document outline to resolve problems,\r\nDialogue: 0,0:51:34.41,0:51:35.95,yin,,0,0,0,,无论警告是红色的还是黄色的\\N{\\fs12}whether they'd be red or yellow,\r\nDialogue: 0,0:51:36.53,0:51:38.19,yin,,0,0,0,,要想将全部可设的\\N{\\fs12}it would take me many lectures\r\nDialogue: 0,0:51:38.19,0:51:41.08,yin,,0,0,0,,不同的约束都讲一遍\\N{\\fs12}to cover all the different kinds of constraints\r\nDialogue: 0,0:51:41.08,0:51:42.29,yin,,0,0,0,,要很多节课才能讲完\\N{\\fs12}that you can set up, and--\r\nDialogue: 0,0:51:42.60,0:51:43.51,yin,,0,0,0,,比如说\\N{\\fs12}you know, for example,\r\nDialogue: 0,0:51:43.51,0:51:45.20,yin,,0,0,0,,看到右侧检查器中\\N{\\fs12}do you see on the, in the inspector there\r\nDialogue: 0,0:51:45.20,0:51:47.38,yin,,0,0,0,,有一项是Content Hugging Priority\\N{\\fs12}where it says content hugging priority,\r\nDialogue: 0,0:51:47.66,0:51:49.95,yin,,0,0,0,,还有一个Content Compression Resistance Priority\\N{\\fs12}and content compression resistance priority?\r\nDialogue: 0,0:51:50.63,0:51:51.52,yin,,0,0,0,,\"拥抱\"优先级[压缩优先级]\\N{\\fs12}That hugging priority,\r\nDialogue: 0,0:51:51.53,0:51:53.51,yin,,0,0,0,,并不是因为视图们互相喜欢\\N{\\fs12}that's not because these views love each other,\r\nDialogue: 0,0:51:53.51,0:51:54.74,yin,,0,0,0,,有时确实是的\\N{\\fs12}but sometimes they do,\r\nDialogue: 0,0:51:54.75,0:51:57.06,yin,,0,0,0,,但是大部分情况下 用压缩优先级\\N{\\fs12}but mostly the hugging priority is\r\nDialogue: 0,0:51:57.07,0:51:58.73,yin,,0,0,0,,是因为有时有些视图\\N{\\fs12}because you have sometimes views\r\nDialogue: 0,0:51:58.73,0:52:02.00,yin,,0,0,0,,会共享某个水平或垂直的空间\\N{\\fs12}that are sharing some horizontal or vertical space.\r\nDialogue: 0,0:52:02.38,0:52:03.61,yin,,0,0,0,,当它们共享空间时\\N{\\fs12}And when they share,\r\nDialogue: 0,0:52:03.69,0:52:06.54,yin,,0,0,0,,有的视图会被减小空间\\N{\\fs12}and that space gets removed from them, or gets taken away,\r\nDialogue: 0,0:52:06.65,0:52:10.80,yin,,0,0,0,,有的会被增加空间\\N{\\fs12}or they get more space added to them,\r\nDialogue: 0,0:52:11.00,0:52:11.73,yin,,0,0,0,,系统需要知道\\N{\\fs12}they need to know\r\nDialogue: 0,0:52:11.74,0:52:15.20,yin,,0,0,0,,哪个视图最想保持自己的大小\\N{\\fs12}which of those views wants to keep its size the most\r\nDialogue: 0,0:52:15.28,0:52:17.54,yin,,0,0,0,,哪个想要得到更多的空间\\N{\\fs12}and which of them wants to get extra,\r\nDialogue: 0,0:52:17.60,0:52:19.41,yin,,0,0,0,,哪一个视图愿意被压缩\\N{\\fs12}and which is willing to be compressed\r\nDialogue: 0,0:52:19.41,0:52:21.33,yin,,0,0,0,,哪一个不愿意被压缩\\N{\\fs12}and which is not willing to get compressed,\r\nDialogue: 0,0:52:21.34,0:52:23.27,yin,,0,0,0,,所以就要用到内容抗压缩优先级\\N{\\fs12}thus you have compression resistance priority\r\nDialogue: 0,0:52:23.35,0:52:25.55,yin,,0,0,0,,和内容压缩优先级\\N{\\fs12}and content hugging priority. Okay?\r\nDialogue: 0,0:52:26.22,0:52:28.12,yin,,0,0,0,,关于这部分 我要讲的就是这些\\N{\\fs12}So, that's as much as I'm going to say about those,\r\nDialogue: 0,0:52:28.14,0:52:29.83,yin,,0,0,0,,如果大家要用的话 要自己查阅文档\\N{\\fs12}you've got to read up on those if you're gonna do that.\r\nDialogue: 0,0:52:29.98,0:52:31.76,yin,,0,0,0,,在作业中\\N{\\fs12}You don't need, you're not gonna be building UIs,\r\nDialogue: 0,0:52:31.77,0:52:33.59,yin,,0,0,0,,大家应该不用构建这样的UI\\N{\\fs12}I don't think, like that in your homework,\r\nDialogue: 0,0:52:34.14,0:52:37.31,yin,,0,0,0,,如果要的话 大家就自行查看内容压缩优先级\\N{\\fs12}if you are, more power to you to go look up content hugging\r\nDialogue: 0,0:52:37.32,0:52:38.81,yin,,0,0,0,,和内容抗压缩优先级的内容\\N{\\fs12}and content compression resistances.\r\nDialogue: 0,0:52:39.81,0:52:42.77,yin,,0,0,0,,最后还剩一个选项就是Intrinsic Size内置大小\\N{\\fs12}Okay? The last thing there you see is intrinsic size.\r\nDialogue: 0,0:52:43.57,0:52:46.04,yin,,0,0,0,,很多iOS对象都有内置大小\\N{\\fs12}Again, a bunch of iOS things have an intrinsic size,\r\nDialogue: 0,0:52:46.06,0:52:47.18,yin,,0,0,0,,比如标签和按钮\\N{\\fs12}like labels and buttons,\r\nDialogue: 0,0:52:47.37,0:52:49.41,yin,,0,0,0,,但其实你可以对自定义视图进行设置\\N{\\fs12}but you could actually have your own custom views,\r\nDialogue: 0,0:52:49.53,0:52:50.59,yin,,0,0,0,,这也不是作业的要求\\N{\\fs12}again, not for your homework,\r\nDialogue: 0,0:52:51.03,0:52:52.23,yin,,0,0,0,,你可以让自定义视图\\N{\\fs12}you could have your own custom views\r\nDialogue: 0,0:52:52.24,0:52:54.15,yin,,0,0,0,,具有内置大小\\N{\\fs12}that have their own intrinsic size,\r\nDialogue: 0,0:52:54.16,0:52:56.02,yin,,0,0,0,,只要实现一个小API\\N{\\fs12}they just have to implement a little API\r\nDialogue: 0,0:52:56.03,0:52:57.46,yin,,0,0,0,,用来返回它们的内置大小\\N{\\fs12}that reports their intrinsic size,\r\nDialogue: 0,0:52:57.67,0:52:58.87,yin,,0,0,0,,在弹出的菜单上\\N{\\fs12}and that little popup there\r\nDialogue: 0,0:52:58.89,0:53:01.80,yin,,0,0,0,,可以告诉Xcode如何处理自定义视图\\N{\\fs12}let you tell Xcode how to handle that,\r\nDialogue: 0,0:53:01.81,0:53:02.63,yin,,0,0,0,,因为它只知道\\N{\\fs12}because it doesn't really know\r\nDialogue: 0,0:53:02.64,0:53:05.86,yin,,0,0,0,,系统对象的处理方法\\N{\\fs12}how to handle that for non system objects,\r\nDialogue: 0,0:53:05.88,0:53:06.95,yin,,0,0,0,,比如标签和按钮\\N{\\fs12}like labels and buttons.\r\nDialogue: 0,0:53:07.91,0:53:08.57,yin,,0,0,0,,明白了吗\\N{\\fs12}Okay?\r\nDialogue: 0,0:53:09.35,0:53:10.56,yin,,0,0,0,,我要做的演示\\N{\\fs12}So the demo I'm gonna do\r\nDialogue: 0,0:53:10.57,0:53:11.94,yin,,0,0,0,,要使用Attributor这个示例\\N{\\fs12}is I'm gonna take Attributor,\r\nDialogue: 0,0:53:13.08,0:53:15.11,yin,,0,0,0,,希望大家还记得Attributor\\N{\\fs12}which I, hopefully, you still remember Attributor\r\nDialogue: 0,0:53:15.12,0:53:17.29,yin,,0,0,0,,大概是三节课以前的内容了\\N{\\fs12}from three lectures ago, or whatever it was.\r\nDialogue: 0,0:53:18.38,0:53:19.95,yin,,0,0,0,,我们要让Attributor\\N{\\fs12}And we're going to make Attributor\r\nDialogue: 0,0:53:19.96,0:53:21.65,yin,,0,0,0,,实现自动旋转且旋转后布局正常\\N{\\fs12}so it auto-rotates and looks good.\r\nDialogue: 0,0:53:21.66,0:53:22.91,yin,,0,0,0,,Attributor就是那个显示文本\\N{\\fs12}Attributor is the thing that had the text\r\nDialogue: 0,0:53:22.93,0:53:25.15,yin,,0,0,0,,我们可以为其添加轮廓和设置颜色的应用 记得吗\\N{\\fs12}and we could outline it and pick the colors, remember that?\r\nDialogue: 0,0:53:25.25,0:53:26.55,yin,,0,0,0,,我们要让它实现自动旋转\\N{\\fs12}So we're going to make that do that.\r\nDialogue: 0,0:53:27.38,0:53:29.96,yin,,0,0,0,,构建Attributor时 我们使用了辅助线\\N{\\fs12}We used the guidelines when we built Attributor,\r\nDialogue: 0,0:53:30.03,0:53:32.14,yin,,0,0,0,,所以很容易实现\\N{\\fs12}so it's going to be really easy to make this work.\r\nDialogue: 0,0:53:32.23,0:53:33.87,yin,,0,0,0,,但我要演示一遍\\N{\\fs12}Okay? But I just want to show you what it all looks like,\r\nDialogue: 0,0:53:34.00,0:53:34.79,yin,,0,0,0,,其实现过程\\N{\\fs12}to make it go.\r\nDialogue: 0,0:53:35.12,0:53:37.81,yin,,0,0,0,,先讲这一页 等会演示完就下课了\\N{\\fs12}And I'll do this slide because we'll finish with the demo.\r\nDialogue: 0,0:53:37.98,0:53:39.22,yin,,0,0,0,,周五的时候\\N{\\fs12}On Friday, I'm still hoping\r\nDialogue: 0,0:53:39.24,0:53:41.35,yin,,0,0,0,,希望大学开发者计划能够正常使用\\N{\\fs12}to get this university developer thing going,\r\nDialogue: 0,0:53:41.36,0:53:43.09,yin,,0,0,0,,在我将大家加入到计划中之前\\N{\\fs12}again, I'm not going to require any of you\r\nDialogue: 0,0:53:43.10,0:53:45.04,yin,,0,0,0,,我不会要求大家\\N{\\fs12}to get the thing working on your device\r\nDialogue: 0,0:53:45.05,0:53:47.22,yin,,0,0,0,,在设备上运行应用\\N{\\fs12}until I can get you into this program,\r\nDialogue: 0,0:53:47.24,0:53:49.04,yin,,0,0,0,,不用担心\\N{\\fs12}so, no worries there.\r\nDialogue: 0,0:53:49.96,0:53:52.45,yin,,0,0,0,,加入99美元开发者计划的同学\\N{\\fs12}And those of you who are doing the 99 dollar program,\r\nDialogue: 0,0:53:52.46,0:53:53.56,yin,,0,0,0,,可以开始使用了\\N{\\fs12}you're all good to go,\r\nDialogue: 0,0:53:53.57,0:53:55.10,yin,,0,0,0,,希望大家都能在设备上正常运行\\N{\\fs12}hopefully it's all just working for you.\r\nDialogue: 0,0:53:55.34,0:53:57.60,yin,,0,0,0,,作业截止日期为周一\\N{\\fs12}Your homework, as you know, is due on Monday,\r\nDialogue: 0,0:53:57.68,0:54:00.15,yin,,0,0,0,,下周我们会讲解滚动视图和表视图\\N{\\fs12}and next week we're going to do scroll view and table view,\r\nDialogue: 0,0:54:00.21,0:54:01.97,yin,,0,0,0,,我想了一下\\N{\\fs12}actually we probably won't do collection view,\r\nDialogue: 0,0:54:01.97,0:54:03.03,yin,,0,0,0,,可能不会讲集合视图\\N{\\fs12}the more I think about it,\r\nDialogue: 0,0:54:03.19,0:54:05.25,yin,,0,0,0,,下周要讲的另外一个内容是iPad\\N{\\fs12}and the other thing we're gonna do next week is iPad.\r\nDialogue: 0,0:54:05.51,0:54:07.24,yin,,0,0,0,,因为我们到目前为止讲过的都是针对iPhone的\\N{\\fs12}Because everything we've done so far is iPhone,\r\nDialogue: 0,0:54:07.61,0:54:09.18,yin,,0,0,0,,现在应该讲一讲iPad的内容了\\N{\\fs12}it's time to start doing some iPad.\r\nDialogue: 0,0:54:09.98,0:54:13.50,yin,,0,0,0,,我们回到Attributor\\N{\\fs12}Okay? So let's go back to Attributor.\r\nDialogue: 0,0:54:13.87,0:54:19.52,yin,,0,0,0,,在这里打开Xcode 关掉Dropit\\N{\\fs12}So I'm gonna get Xcode up here and let's close Dropit.\r\nDialogue: 0,0:54:19.72,0:54:21.15,yin,,0,0,0,,停止任务\\N{\\fs12}Stop that task,\r\nDialogue: 0,0:54:23.73,0:54:25.78,yin,,0,0,0,,回到这里\\N{\\fs12}and so let's go back here,\r\nDialogue: 0,0:54:27.15,0:54:29.01,yin,,0,0,0,,打开Attributor\\N{\\fs12}and I'm just gonna bring up Attributor, as--\r\nDialogue: 0,0:54:29.04,0:54:30.89,yin,,0,0,0,,回到上次结束的地方\\N{\\fs12}as we last left it here.\r\nDialogue: 0,0:54:31.22,0:54:33.75,yin,,0,0,0,,还记得Attributor的界面吗\\N{\\fs12}Remember this is what Attributor's user interface\r\nDialogue: 0,0:54:33.82,0:54:34.64,yin,,0,0,0,,是这样的\\N{\\fs12}looks like here,\r\nDialogue: 0,0:54:34.65,0:54:36.86,yin,,0,0,0,,我们今天完全不用看代码\\N{\\fs12}we don't need to see the code at all today,\r\nDialogue: 0,0:54:36.87,0:54:40.73,yin,,0,0,0,,因为自动布局的全部操作都会在Xcode中完成\\N{\\fs12}because we're gonna do all of this autolayout stuff in Xcode.\r\nDialogue: 0,0:54:41.36,0:54:43.37,yin,,0,0,0,,我们来看看Attributor现在能做什么\\N{\\fs12}And let's see what Attributor does right now.\r\nDialogue: 0,0:54:43.37,0:54:46.48,yin,,0,0,0,,运行Attributor 和上次最后一样\\N{\\fs12}So let's run Attributor, just as we left it off.\r\nDialogue: 0,0:54:46.49,0:54:47.70,yin,,0,0,0,,这就是Attributor\\N{\\fs12}And here it is, here's Attributor,\r\nDialogue: 0,0:54:47.98,0:54:52.42,yin,,0,0,0,,我们可以做这样的操作 点击这些按钮\\N{\\fs12}remember we can do this kind of stuff, pick these things,\r\nDialogue: 0,0:54:52.67,0:54:55.46,yin,,0,0,0,,如果对其进行旋转...\\N{\\fs12}and if we rotate, and everyone saw on--\r\nDialogue: 0,0:54:55.46,0:54:58.15,yin,,0,0,0,,旋转的方法是按住command键\\N{\\fs12}ps the way we rotate it is we hold down the command key,\r\nDialogue: 0,0:54:58.16,0:54:59.39,yin,,0,0,0,,就是这里这个\\N{\\fs12}it's basically this right here.\r\nDialogue: 0,0:54:59.69,0:55:00.93,yin,,0,0,0,,command键加箭头键\\N{\\fs12}Command, arrow.\r\nDialogue: 0,0:55:01.32,0:55:02.88,yin,,0,0,0,,我按下command键加箭头键\\N{\\fs12}Okay? So I'm going to do command arrow.\r\nDialogue: 0,0:55:03.43,0:55:04.38,yin,,0,0,0,,看起来很糟糕\\N{\\fs12}That looks pretty bad.\r\nDialogue: 0,0:55:04.85,0:55:05.23,yin,,0,0,0,,对吧\\N{\\fs12}Okay?\r\nDialogue: 0,0:55:05.45,0:55:06.56,yin,,0,0,0,,实际上是太可怕了\\N{\\fs12}In fact, that's horrible.\r\nDialogue: 0,0:55:06.57,0:55:08.32,yin,,0,0,0,,因为我们完全不可操控了\\N{\\fs12}Because we've lost all of our control\r\nDialogue: 0,0:55:08.34,0:55:10.29,yin,,0,0,0,,不能增加轮廓 不能改变颜色\\N{\\fs12}no outline, no colors,\r\nDialogue: 0,0:55:10.30,0:55:12.46,yin,,0,0,0,,我们在这里什么都不能做\\N{\\fs12}we can't really do anything here.\r\nDialogue: 0,0:55:12.91,0:55:16.27,yin,,0,0,0,,统计数据这里看起来还好 但是缺失内容了\\N{\\fs12}Stats still looks okay, but it's kind of cutoff,\r\nDialogue: 0,0:55:16.28,0:55:17.78,yin,,0,0,0,,后面显示的是三个点 这不太好\\N{\\fs12}that's not so good, dot, dot, dot,\r\nDialogue: 0,0:55:17.80,0:55:21.30,yin,,0,0,0,,所以整个UI的应对措施并不好\\N{\\fs12}so, really this whole UI did not react well,\r\nDialogue: 0,0:55:22.29,0:55:26.40,yin,,0,0,0,,我们修改一下 让它不要再这样了\\N{\\fs12}and so, let's try and fix it so that it stops doing that,\r\nDialogue: 0,0:55:27.01,0:55:30.66,yin,,0,0,0,,从某种程度上来说 这有点太简单了\\N{\\fs12}and this is gonna be in some ways almost too easy,\r\nDialogue: 0,0:55:30.71,0:55:33.73,yin,,0,0,0,,因为我们在拖放这些对象时使用了辅助线\\N{\\fs12}because we dragged all these things out using the guidelines,\r\nDialogue: 0,0:55:33.84,0:55:36.96,yin,,0,0,0,,我只要点击下面这个像钛战机一样的按钮\\N{\\fs12}so I'm just going to go down here, to the TIE fighter,\r\nDialogue: 0,0:55:37.03,0:55:40.15,yin,,0,0,0,,然后选择重置为建议约束\\N{\\fs12}and I'm gonna say reset to suggested constraints.\r\nDialogue: 0,0:55:41.21,0:55:42.77,yin,,0,0,0,,基本上这样就行了\\N{\\fs12}And pretty much that's gonna do it.\r\nDialogue: 0,0:55:43.00,0:55:44.20,yin,,0,0,0,,再运行一次\\N{\\fs12}So let's just rerun.\r\nDialogue: 0,0:55:44.26,0:55:46.88,yin,,0,0,0,,我们可以快速浏览一下这些约束\\N{\\fs12}Okay, we could make a quick look at some of these constraints\r\nDialogue: 0,0:55:46.89,0:55:48.99,yin,,0,0,0,,看看它做了什么\\N{\\fs12}just to see what's it doing, but like this--\r\nDialogue: 0,0:55:49.32,0:55:51.36,yin,,0,0,0,,把对象面板移开\\N{\\fs12}let's get this out of the way in here.\r\nDialogue: 0,0:55:51.70,0:55:53.77,yin,,0,0,0,,可以看到文本区域\\N{\\fs12}So, you can see that this thing\r\nDialogue: 0,0:55:53.78,0:55:56.09,yin,,0,0,0,,与父视图的左边缘绑定\\N{\\fs12}is tied to the superview on the left,\r\nDialogue: 0,0:55:56.10,0:55:57.48,yin,,0,0,0,,与按钮对齐\\N{\\fs12}it's lined up with the buttons.\r\nDialogue: 0,0:55:57.48,0:55:59.77,yin,,0,0,0,,与按钮间保持一定间距\\N{\\fs12}It makes a little space in between the buttons,\r\nDialogue: 0,0:55:59.91,0:56:01.24,yin,,0,0,0,,与顶部保持一定间距\\N{\\fs12}a little space at the top,\r\nDialogue: 0,0:56:01.50,0:56:04.05,yin,,0,0,0,,基本上添加了我们想要的约束\\N{\\fs12}so it's pretty much doing what we want.\r\nDialogue: 0,0:56:04.48,0:56:06.42,yin,,0,0,0,,现在再旋转 看看会怎样\\N{\\fs12}Let's see what happens when we rotate now.\r\nDialogue: 0,0:56:06.43,0:56:09.56,yin,,0,0,0,,这些都还可以正常运行\\N{\\fs12}So we got this, it's still all working, nothing has broken\r\nDialogue: 0,0:56:09.57,0:56:11.74,yin,,0,0,0,,没有因为增加约束而破坏功能\\N{\\fs12}because of our, putting those constraints in,\r\nDialogue: 0,0:56:11.98,0:56:14.97,yin,,0,0,0,,旋转一下 看起来很不错\\N{\\fs12}and so we'll rotate, ooh, that looks pretty good!\r\nDialogue: 0,0:56:15.01,0:56:17.65,yin,,0,0,0,,我还可以添加轮廓\\N{\\fs12}I can still, for example, set my outline,\r\nDialogue: 0,0:56:17.67,0:56:19.68,yin,,0,0,0,,设置颜色 很好\\N{\\fs12}I can set colors, that's great,\r\nDialogue: 0,0:56:19.92,0:56:21.95,yin,,0,0,0,,统计数据呢 好多了\\N{\\fs12}stats, ooh, much better.\r\nDialogue: 0,0:56:22.58,0:56:24.42,yin,,0,0,0,,但是紫色这块不太好\\N{\\fs12}However, this is not so good.\r\nDialogue: 0,0:56:25.14,0:56:28.38,yin,,0,0,0,,我喜欢紫色 但是没有到这种程度\\N{\\fs12}Okay? I like purple, but not that much. Okay?\r\nDialogue: 0,0:56:28.56,0:56:31.07,yin,,0,0,0,,所以我们要让它们大小一致\\N{\\fs12}So we've got to make these things all the same size,\r\nDialogue: 0,0:56:31.21,0:56:34.47,yin,,0,0,0,,让这四个按钮大小一致\\N{\\fs12}we want these four buttons to be the same size, okay?\r\nDialogue: 0,0:56:34.75,0:56:37.52,yin,,0,0,0,,显然 我们将它们拖进来时没有任何操作\\N{\\fs12}Nothing that we did when we dragged it in, evidently,\r\nDialogue: 0,0:56:37.52,0:56:39.44,yin,,0,0,0,,能够告诉Xcode这样做\\N{\\fs12}was enough to let Xcode know that.\r\nDialogue: 0,0:56:39.66,0:56:41.95,yin,,0,0,0,,不过想要实现这条约束特别简单\\N{\\fs12}However, so simple to make that happen,\r\nDialogue: 0,0:56:41.96,0:56:44.24,yin,,0,0,0,,只要选中这四个按钮\\N{\\fs12}I'm just gonna select these four buttons,\r\nDialogue: 0,0:56:44.69,0:56:45.99,yin,,0,0,0,,到下面这里\\N{\\fs12}I'm going to go down here\r\nDialogue: 0,0:56:46.30,0:56:51.48,yin,,0,0,0,,在这个约束添加栏这里\\N{\\fs12}to this little constraint adder right here,\r\nDialogue: 0,0:56:51.55,0:56:52.84,yin,,0,0,0,,只要点击这个按钮选项\\N{\\fs12}and I'm going to just click this button\r\nDialogue: 0,0:56:52.86,0:56:55.77,yin,,0,0,0,,将四个按钮设为相同宽度\\N{\\fs12}that says I want these four buttons to have equal widths.\r\nDialogue: 0,0:56:55.93,0:56:57.65,yin,,0,0,0,,换句话说 我加了约束\\N{\\fs12}In other words, I'm adding the constraint\r\nDialogue: 0,0:56:57.73,0:56:59.12,yin,,0,0,0,,让它们的宽度相等\\N{\\fs12}that their widths be the same.\r\nDialogue: 0,0:56:59.78,0:57:03.30,yin,,0,0,0,,我点击\"添加三条约束\"之后\\N{\\fs12}Okay? So, I just, when I hit add three constraints,\r\nDialogue: 0,0:57:03.31,0:57:05.61,yin,,0,0,0,,可能会为每一个按钮添加一条约束\\N{\\fs12}it's gonna add one constraint to each of them, probably,\r\nDialogue: 0,0:57:05.63,0:57:07.03,yin,,0,0,0,,在前面三个按钮上\\N{\\fs12}each of these first three,\r\nDialogue: 0,0:57:07.33,0:57:10.66,yin,,0,0,0,,让它们和下一个按钮同宽\\N{\\fs12}saying, be the same as the next one over.\r\nDialogue: 0,0:57:11.11,0:57:11.82,yin,,0,0,0,,我们这样做\\N{\\fs12}We'll do that.\r\nDialogue: 0,0:57:12.33,0:57:13.57,yin,,0,0,0,,可以看到\\N{\\fs12}You can even see the, see,\r\nDialogue: 0,0:57:13.57,0:57:15.83,yin,,0,0,0,,就是这样的 宽度相等 看到了吗\\N{\\fs12}here's what they look like, equals. See?\r\nDialogue: 0,0:57:16.58,0:57:18.24,yin,,0,0,0,,我们运行一下 看行不行\\N{\\fs12}So let's go and run and see if that fixed it.\r\nDialogue: 0,0:57:19.67,0:57:20.31,yin,,0,0,0,,可以了\\N{\\fs12}And it did.\r\nDialogue: 0,0:57:20.79,0:57:23.01,yin,,0,0,0,,两种方向都可以\\N{\\fs12}Okay? So, whichever way,\r\nDialogue: 0,0:57:23.25,0:57:24.81,yin,,0,0,0,,为什么这里不旋转呢\\N{\\fs12}by the way, why does it not rotate here?\r\nDialogue: 0,0:57:24.81,0:57:27.23,yin,,0,0,0,,因为现在是倒立竖屏\\N{\\fs12}Because this is the upside down, portrait upside down,\r\nDialogue: 0,0:57:27.47,0:57:30.84,yin,,0,0,0,,在项目设置中\\N{\\fs12}and in our project settings,\r\nDialogue: 0,0:57:30.84,0:57:32.74,yin,,0,0,0,,我们设置了不支持倒立竖屏\\N{\\fs12}we said we don't support portrait upside down,\r\nDialogue: 0,0:57:32.76,0:57:34.09,yin,,0,0,0,,所以这里没有旋转\\N{\\fs12}so that's why it just does nothing.\r\nDialogue: 0,0:57:34.09,0:57:35.86,yin,,0,0,0,,转为倒立竖屏时 什么都不会发生\\N{\\fs12}When you go to portrait upside down, it does nothing.\r\nDialogue: 0,0:57:36.38,0:57:38.31,yin,,0,0,0,,但是在正向竖屏\\N{\\fs12}But when we stay with portrait right-side up,\r\nDialogue: 0,0:57:38.33,0:57:40.40,yin,,0,0,0,,和两个横屏模式时\\N{\\fs12}or between either the two of the landscapes,\r\nDialogue: 0,0:57:40.97,0:57:44.34,yin,,0,0,0,,视图的效果和我们想要的一样\\N{\\fs12}it seems to be doing exactly what we want here in this view.\r\nDialogue: 0,0:57:45.94,0:57:50.90,yin,,0,0,0,,只有一个问题 如果看一下控制台\\N{\\fs12}And, the only problem is, if we look at our console,\r\nDialogue: 0,0:57:50.91,0:57:52.88,yin,,0,0,0,,得到了各种错误\\N{\\fs12}we're getting all kinds of errors here.\r\nDialogue: 0,0:57:53.57,0:57:55.12,yin,,0,0,0,,这看起来可不太好\\N{\\fs12}Okay? This doesn't look too good.\r\nDialogue: 0,0:57:55.70,0:57:58.37,yin,,0,0,0,,最主要的错误是什么\\N{\\fs12}Okay? And what is this primary error we're getting.\r\nDialogue: 0,0:57:58.77,0:58:02.67,yin,,0,0,0,,无法同时满足约束\\N{\\fs12}Unable to simultaneously satisfy constraints.\r\nDialogue: 0,0:58:03.59,0:58:07.98,yin,,0,0,0,,这里看起来很好 没有不对的地方\\N{\\fs12}Okay? So, this looked all good over here, there was no--\r\nDialogue: 0,0:58:07.99,0:58:10.64,yin,,0,0,0,,没有看到黄色的警告\\N{\\fs12}I don't see anything, there's no yellow things.\r\nDialogue: 0,0:58:10.64,0:58:12.48,yin,,0,0,0,,如果打开文档大纲\\N{\\fs12}If I bring up my document outline,\r\nDialogue: 0,0:58:12.94,0:58:14.46,yin,,0,0,0,,这里也没有黄色圆形图标\\N{\\fs12}there's nothing yellow here.\r\nDialogue: 0,0:58:14.60,0:58:16.76,yin,,0,0,0,,自动布局约束没问题\\N{\\fs12}My autolayout constraints are good!\r\nDialogue: 0,0:58:16.93,0:58:18.06,yin,,0,0,0,,实际上并不是这样的\\N{\\fs12}Well, actually they're not.\r\nDialogue: 0,0:58:18.49,0:58:20.59,yin,,0,0,0,,因为它不能\\N{\\fs12}Okay? Because it's unable\r\nDialogue: 0,0:58:20.60,0:58:23.13,yin,,0,0,0,,在运行时满足约束\\N{\\fs12}to satisfy the constraints at run time.\r\nDialogue: 0,0:58:23.15,0:58:24.82,yin,,0,0,0,,为什么会这样呢\\N{\\fs12}Okay? Well, why is that happening?\r\nDialogue: 0,0:58:24.85,0:58:27.37,yin,,0,0,0,,实际上 这里提供了很多信息\\N{\\fs12}Well, it'd actually give you a lot of help\r\nDialogue: 0,0:58:27.47,0:58:29.02,yin,,0,0,0,,帮助你明白出现错误的原因\\N{\\fs12}as to why that's happening,\r\nDialogue: 0,0:58:29.46,0:58:30.58,yin,,0,0,0,,把这栏拉宽一点\\N{\\fs12}Make this wider.\r\nDialogue: 0,0:58:31.68,0:58:35.50,yin,,0,0,0,,这里甚至还给出了ASCII文本\\N{\\fs12}Here, and it gives you even kind of ASCII text,\r\nDialogue: 0,0:58:35.84,0:58:38.80,yin,,0,0,0,,描述了布局的信息\\N{\\fs12}kind of descriptions of the layouts.\r\nDialogue: 0,0:58:39.19,0:58:41.01,yin,,0,0,0,,看到了吗 各种对象的布局\\N{\\fs12}You see? How everything's laid out?\r\nDialogue: 0,0:58:41.30,0:58:43.56,yin,,0,0,0,,我大概已经可以猜到了\\N{\\fs12}But I can probably guess already\r\nDialogue: 0,0:58:43.73,0:58:45.75,yin,,0,0,0,,因为我刚引发了这个错误\\N{\\fs12}that since I just introduced this error,\r\nDialogue: 0,0:58:45.77,0:58:48.34,yin,,0,0,0,,所以肯定和我刚做过的操作相关\\N{\\fs12}it has something to do with what I just did.\r\nDialogue: 0,0:58:48.83,0:58:51.64,yin,,0,0,0,,也就是让按钮的宽度相等\\N{\\fs12}Okay? Which is to make those widths be the same.\r\nDialogue: 0,0:58:51.92,0:58:54.87,yin,,0,0,0,,我们看一下这些按钮的约束\\N{\\fs12}So, let's take a look at the constraints of these buttons\r\nDialogue: 0,0:58:54.87,0:58:56.52,yin,,0,0,0,,看看是否能看出来明显的问题\\N{\\fs12}and see if we can see something obvious.\r\nDialogue: 0,0:58:56.72,0:58:59.78,yin,,0,0,0,,有谁看出来了吗\\N{\\fs12}Okay? Anyone see anything obvious in here?\r\nDialogue: 0,0:59:00.29,0:59:01.73,yin,,0,0,0,,哪里看起来不太好\\N{\\fs12}That doesn't look very good?\r\nDialogue: 0,0:59:04.33,0:59:04.96,yin,,0,0,0,,大声说\\N{\\fs12}Speak up.\r\nDialogue: 0,0:59:05.20,0:59:07.06,yin,,0,0,0,,因为宽度为64是硬编码吗\\N{\\fs12}The width equals 64 is hard coded?\r\nDialogue: 0,0:59:07.08,0:59:07.50,yin,,0,0,0,,没错\\N{\\fs12}Yeah,\r\nDialogue: 0,0:59:07.51,0:59:10.54,yin,,0,0,0,,宽度为64 这里是硬编码\\N{\\fs12}the width equals 64 here is hard coded, okay,\r\nDialogue: 0,0:59:10.54,0:59:12.82,yin,,0,0,0,,这是个魔术数字 不好\\N{\\fs12}that's a magic number, that's bad.\r\nDialogue: 0,0:59:12.98,0:59:15.10,yin,,0,0,0,,而且 我们知道横屏模式中\\N{\\fs12}And, in fact, we know that when we go to landscape,\r\nDialogue: 0,0:59:15.23,0:59:17.14,yin,,0,0,0,,宽度不会再是64了\\N{\\fs12}the width's not going to be 64 anyway!\r\nDialogue: 0,0:59:17.44,0:59:19.42,yin,,0,0,0,,会变宽一些\\N{\\fs12}Right? They all get a little wider in landscape.\r\nDialogue: 0,0:59:19.83,0:59:21.30,yin,,0,0,0,,这就是问题所在\\N{\\fs12}So this is the problem.\r\nDialogue: 0,0:59:21.35,0:59:23.82,yin,,0,0,0,,系统想让这些按钮同宽\\N{\\fs12}It's trying to make those buttons all the same width,\r\nDialogue: 0,0:59:23.98,0:59:26.15,yin,,0,0,0,,而你要让它们的宽度都为64\\N{\\fs12}but you're trying to keep them all 64,\r\nDialogue: 0,0:59:26.16,0:59:29.79,yin,,0,0,0,,至少是让前三个按钮的宽度都为64\\N{\\fs12}or at least to keep this one and this one and this one 64,\r\nDialogue: 0,0:59:29.79,0:59:32.77,yin,,0,0,0,,最后一个按钮没有宽度64的约束 不错\\N{\\fs12}this one seems to not have that 64, which is nice.\r\nDialogue: 0,0:59:33.66,0:59:35.29,yin,,0,0,0,,很容易改好\\N{\\fs12}So this is easy to fix.\r\nDialogue: 0,0:59:35.31,0:59:39.09,yin,,0,0,0,,只要删除这些宽度64的约束\\N{\\fs12}I'm just gonna delete these width equals 64s,\r\nDialogue: 0,0:59:39.09,0:59:40.19,yin,,0,0,0,,不是高度64\\N{\\fs12}not the height equals 64.\r\nDialogue: 0,0:59:40.62,0:59:42.56,yin,,0,0,0,,删掉宽度64这个约束\\N{\\fs12}So let's delete the width equals 64,\r\nDialogue: 0,0:59:42.86,0:59:46.67,yin,,0,0,0,,删掉这个宽度64约束 还有这个\\N{\\fs12}let's delete this width equals 64, and we'll delete this one.\r\nDialogue: 0,0:59:47.40,0:59:51.46,yin,,0,0,0,,没有对象变为黄色\\N{\\fs12}Okay? So, this height, nothing turned yellow, okay?\r\nDialogue: 0,0:59:51.46,0:59:53.94,yin,,0,0,0,,不缺少约束\\N{\\fs12}Nothing was like missing constraints, okay,\r\nDialogue: 0,0:59:53.95,0:59:57.92,yin,,0,0,0,,全部都有约束指定了 现在再运行\\N{\\fs12}it's all completely still specified, and now if we run.\r\nDialogue: 0,0:59:59.97,1:00:01.75,yin,,0,0,0,,左右旋转\\N{\\fs12}Okay, and we rotate back and forth.\r\nDialogue: 0,1:00:02.79,1:00:05.19,yin,,0,0,0,,依旧可以正常运行 按钮会变宽\\N{\\fs12}Still working, still making the buttons wider,\r\nDialogue: 0,1:00:05.19,1:00:07.68,yin,,0,0,0,,控制台也没有错误提示了\\N{\\fs12}and we're not getting anything in our console here.\r\nDialogue: 0,1:00:08.57,1:00:10.56,yin,,0,0,0,,有时你的约束\\N{\\fs12}Okay? So sometimes you'll get the constraints,\r\nDialogue: 0,1:00:10.57,1:00:12.87,yin,,0,0,0,,在Xcode中不会出现什么问题\\N{\\fs12}they won't have any problems in Xcode,\r\nDialogue: 0,1:00:12.87,1:00:14.68,yin,,0,0,0,,但约束间也可能会有冲突\\N{\\fs12}but you still might have some conflicts,\r\nDialogue: 0,1:00:14.68,1:00:16.05,yin,,0,0,0,,所以大家应该检查控制台\\N{\\fs12}so you should be looking at your console\r\nDialogue: 0,1:00:16.05,1:00:17.26,yin,,0,0,0,,看是否有冲突\\N{\\fs12}to see if there's conflicts.\r\nDialogue: 0,1:00:17.27,1:00:17.65,yin,,0,0,0,,有问题吗\\N{\\fs12}Question?\r\nDialogue: 0,1:00:18.03,1:00:20.43,yin,,0,0,0,,为什么要保留高度64约束中的魔术数字\\N{\\fs12}why did you keep the height equals 64 magic number?\r\nDialogue: 0,1:00:20.44,1:00:21.07,yin,,0,0,0,,好的 问题是\\N{\\fs12}Okay, so the question,\r\nDialogue: 0,1:00:21.07,1:00:24.29,yin,,0,0,0,,为什么要保留高度64约束中的魔术数字\\N{\\fs12}why did I keep the height equals 64 magic number,\r\nDialogue: 0,1:00:24.29,1:00:25.38,yin,,0,0,0,,非常好的问题\\N{\\fs12}and that's a super good question.\r\nDialogue: 0,1:00:25.38,1:00:27.98,yin,,0,0,0,,这里使用魔术数字是可以的\\N{\\fs12}Now, it's okay that I have a magic number here.\r\nDialogue: 0,1:00:28.30,1:00:29.72,yin,,0,0,0,,为什么这里可以呢\\N{\\fs12}And why is that okay here?\r\nDialogue: 0,1:00:30.10,1:00:32.15,yin,,0,0,0,,因为按钮中没有文本\\N{\\fs12}That's because there's no text in that button.\r\nDialogue: 0,1:00:32.57,1:00:34.57,yin,,0,0,0,,几乎就像是图像\\N{\\fs12}It's almost like an image, right?\r\nDialogue: 0,1:00:34.83,1:00:37.40,yin,,0,0,0,,不然的话 它的大小应该是什么\\N{\\fs12}So, what size would it be otherwise?\r\nDialogue: 0,1:00:37.65,1:00:38.69,yin,,0,0,0,,这里没有\\N{\\fs12}There's nothing--\r\nDialogue: 0,1:00:38.70,1:00:40.92,yin,,0,0,0,,如果从上到下看看这个视图\\N{\\fs12}if you look from top to bottom in this view,\r\nDialogue: 0,1:00:40.97,1:00:43.19,yin,,0,0,0,,没有能够指定它的大小的约束\\N{\\fs12}there's nothing that would specify what size is,\r\nDialogue: 0,1:00:43.20,1:00:46.12,yin,,0,0,0,,文本视图的宽不固定 或者说高不固定\\N{\\fs12}because this is not a fixed width, or height rather,\r\nDialogue: 0,1:00:46.53,1:00:49.18,yin,,0,0,0,,它有固定高度 上下间距也是\\N{\\fs12}this is a fixed height and so is this and this,\r\nDialogue: 0,1:00:49.40,1:00:52.26,yin,,0,0,0,,那么它们俩的空间分别是多少呢\\N{\\fs12}but then how much space goes to this and how much goes to this?\r\nDialogue: 0,1:00:52.50,1:00:56.11,yin,,0,0,0,,将按钮的高度设为64 剩下的空间就是文本视图的\\N{\\fs12}By fixing this one at 64, this one gets the rest.\r\nDialogue: 0,1:00:56.47,1:00:58.35,yin,,0,0,0,,实际上 我还可以换一种方法\\N{\\fs12}Now, I actually could do this another way.\r\nDialogue: 0,1:00:58.35,1:01:00.19,yin,,0,0,0,,如果我想让文本视图\\N{\\fs12}If I kind of wanted, you know,\r\nDialogue: 0,1:01:00.22,1:01:03.21,yin,,0,0,0,,占据大部分空间\\N{\\fs12}the text view to have most of the space\r\nDialogue: 0,1:01:03.22,1:01:07.60,yin,,0,0,0,,让这些按钮控制在最小尺寸\\N{\\fs12}and this, some of it, and I want it to be a minimum size,\r\nDialogue: 0,1:01:07.64,1:01:10.09,yin,,0,0,0,,我可以将它的大小\\N{\\fs12}I could actually set the size here to be\r\nDialogue: 0,1:01:10.63,1:01:12.85,yin,,0,0,0,,设为大于等于某个特定大小\\N{\\fs12}greater than or equal to some particular size,\r\nDialogue: 0,1:01:12.86,1:01:15.17,yin,,0,0,0,,我可以对它们使用内容压缩优先级\\N{\\fs12}and I could use the content hugging priority\r\nDialogue: 0,1:01:15.17,1:01:17.56,yin,,0,0,0,,和内容抗压缩优先级\\N{\\fs12}and compression priority between these two\r\nDialogue: 0,1:01:17.84,1:01:21.38,yin,,0,0,0,,确定哪个对象要得到更大的空间\\N{\\fs12}to make sure that whichever I wanted to get the extra space,\r\nDialogue: 0,1:01:21.39,1:01:24.73,yin,,0,0,0,,当屏幕变长的时候 就像这样\\N{\\fs12}when it got taller, like this, okay?\r\nDialogue: 0,1:01:26.39,1:01:27.72,yin,,0,0,0,,我可以定义这个规则\\N{\\fs12}I could make that be defined,\r\nDialogue: 0,1:01:27.73,1:01:29.23,yin,,0,0,0,,但是将按钮高度设为固定值\\N{\\fs12}but by fixing this one,\r\nDialogue: 0,1:01:29.63,1:01:31.72,yin,,0,0,0,,保证了文本视图得到全部剩余空间\\N{\\fs12}I'm guaranteeing this one gets all the extra space.\r\nDialogue: 0,1:01:32.03,1:01:33.09,yin,,0,0,0,,当你用的是图像时\\N{\\fs12}So when you have an image,\r\nDialogue: 0,1:01:33.10,1:01:35.32,yin,,0,0,0,,我说了有时使用魔术数字是可以的\\N{\\fs12}I said that sometimes a magic number's okay,\r\nDialogue: 0,1:01:35.72,1:01:36.97,yin,,0,0,0,,通常是针对图像\\N{\\fs12}usually it's when you have an image,\r\nDialogue: 0,1:01:36.98,1:01:39.54,yin,,0,0,0,,有人绘制了一个插图\\N{\\fs12}some artwork that somebody has drawn\r\nDialogue: 0,1:01:39.82,1:01:42.62,yin,,0,0,0,,有一个大小约束 就是图像的大小\\N{\\fs12}has a size to it that that's its size.\r\nDialogue: 0,1:01:42.80,1:01:45.33,yin,,0,0,0,,我想让这些方块保持这个大小\\N{\\fs12}And here, these squares, I want them to be this size,\r\nDialogue: 0,1:01:45.35,1:01:46.04,yin,,0,0,0,,所以设置了高度约束\\N{\\fs12}so I pick those,\r\nDialogue: 0,1:01:46.05,1:01:47.90,yin,,0,0,0,,很高兴你问了这个问题 很好的问题\\N{\\fs12}I'm glad you brought that up, that's a good question.\r\nDialogue: 0,1:01:48.52,1:01:50.29,yin,,0,0,0,,这里我还要处理的是\\N{\\fs12}Okay, the other thing I'm going to do here\r\nDialogue: 0,1:01:50.79,1:01:51.73,yin,,0,0,0,,右边这一部分\\N{\\fs12}is play around with this,\r\nDialogue: 0,1:01:51.74,1:01:53.97,yin,,0,0,0,,左边这部分运行正常 不用改了\\N{\\fs12}this is working fine, nothing to change here.\r\nDialogue: 0,1:01:54.17,1:01:55.10,yin,,0,0,0,,那这边这部分呢\\N{\\fs12}What about this guy over here?\r\nDialogue: 0,1:01:55.10,1:01:57.01,yin,,0,0,0,,这个挺不好办的\\N{\\fs12}Well, this one's pretty bad.\r\nDialogue: 0,1:01:57.12,1:01:58.67,yin,,0,0,0,,我将它们拖放在这里时\\N{\\fs12}I kind of dragged these in here\r\nDialogue: 0,1:01:58.68,1:02:02.14,yin,,0,0,0,,没有使用辅助线一类的东西\\N{\\fs12}without using the, the lines or something,\r\nDialogue: 0,1:02:02.15,1:02:03.83,yin,,0,0,0,,所以它们是在随机位置上\\N{\\fs12}so they're kind of in random spots.\r\nDialogue: 0,1:02:04.01,1:02:05.25,yin,,0,0,0,,正好可以演示一下\\N{\\fs12}So here's a good chance to show you\r\nDialogue: 0,1:02:05.27,1:02:07.83,yin,,0,0,0,,在不使用建议约束的条件下\\N{\\fs12}how to put these things in their place,\r\nDialogue: 0,1:02:08.58,1:02:10.61,yin,,0,0,0,,如何正确放置控件\\N{\\fs12}not using suggested constraints.\r\nDialogue: 0,1:02:10.86,1:02:13.73,yin,,0,0,0,,也就是指定控件的位置\\N{\\fs12}Okay? In other words, actually specifying.\r\nDialogue: 0,1:02:14.45,1:02:17.22,yin,,0,0,0,,我会演示两种方法\\N{\\fs12}So I'll show you both ways to do it.\r\nDialogue: 0,1:02:17.33,1:02:19.40,yin,,0,0,0,,两种方法都不是建议约束\\N{\\fs12}The both non-suggested constraints.\r\nDialogue: 0,1:02:19.43,1:02:22.66,yin,,0,0,0,,将轮廓字符这条放在右下角\\N{\\fs12}So let's put outline text in this corner down here,\r\nDialogue: 0,1:02:22.95,1:02:26.09,yin,,0,0,0,,或者将彩色字符这条放在这里 都可以\\N{\\fs12}and, or we'll put color down there, whichever,\r\nDialogue: 0,1:02:26.29,1:02:29.13,yin,,0,0,0,,然后让另一条显示在它的上方\\N{\\fs12}and then we'll have the other one stacked on top of it.\r\nDialogue: 0,1:02:29.13,1:02:31.89,yin,,0,0,0,,所以我希望它们是这个样子的\\N{\\fs12}So I eventually want it to look like this and this,\r\nDialogue: 0,1:02:31.91,1:02:34.88,yin,,0,0,0,,但我不会用辅助线\\N{\\fs12}but I'm not gonna use the guidelines, okay?\r\nDialogue: 0,1:02:34.95,1:02:36.24,yin,,0,0,0,,因为我想演示一下其他方法\\N{\\fs12}Because I want to show you a different way to do it.\r\nDialogue: 0,1:02:36.25,1:02:38.06,yin,,0,0,0,,我选中了彩色字符\\N{\\fs12}So, here I have colorful characters.\r\nDialogue: 0,1:02:38.39,1:02:40.16,yin,,0,0,0,,目前它没有约束\\N{\\fs12}So it has no constraints, currently,\r\nDialogue: 0,1:02:40.17,1:02:42.52,yin,,0,0,0,,因为我用重设为建议约束时\\N{\\fs12}because when I said reset suggest constraints,\r\nDialogue: 0,1:02:42.61,1:02:44.87,yin,,0,0,0,,只针对左边这部分\\N{\\fs12}I was doing that for this guy only, right?\r\nDialogue: 0,1:02:44.88,1:02:46.48,yin,,0,0,0,,点击这里的钛战机按钮时\\N{\\fs12}When you go here to the TIE fighter,\r\nDialogue: 0,1:02:46.62,1:02:48.69,yin,,0,0,0,,这里说了是在Attributor视图控制器中\\N{\\fs12}it says in Attributor view controller,\r\nDialogue: 0,1:02:48.70,1:02:50.55,yin,,0,0,0,,并没有说Stats视图控制器\\N{\\fs12}it doesn't say stats view controller,\r\nDialogue: 0,1:02:50.64,1:02:52.04,yin,,0,0,0,,所以只针对前者\\N{\\fs12}so it only did it in that one,\r\nDialogue: 0,1:02:52.97,1:02:54.03,yin,,0,0,0,,这里我没有重置约束\\N{\\fs12}and I didn't reset it here,\r\nDialogue: 0,1:02:54.04,1:02:55.74,yin,,0,0,0,,所以它们没有约束\\N{\\fs12}so these things have no constraints.\r\nDialogue: 0,1:02:56.21,1:02:59.71,yin,,0,0,0,,我们将它设置到左下角\\N{\\fs12}So let's set this one to be in this lower left-hand corner\r\nDialogue: 0,1:02:59.77,1:03:01.21,yin,,0,0,0,,不使用辅助线\\N{\\fs12}without using the guidelines.\r\nDialogue: 0,1:03:01.58,1:03:05.15,yin,,0,0,0,,方法是使用底部这个按钮\\N{\\fs12}So I'm gonna do that with this guy.\r\nDialogue: 0,1:03:05.86,1:03:08.03,yin,,0,0,0,,这里这个小按钮\\N{\\fs12}Okay? So this little button right here,\r\nDialogue: 0,1:03:08.15,1:03:09.35,yin,,0,0,0,,在这里能够指定...\\N{\\fs12}it lets you specify--\r\nDialogue: 0,1:03:09.35,1:03:11.07,yin,,0,0,0,,宽度相等就是在这里设置的\\N{\\fs12}this is where we did equal widths,\r\nDialogue: 0,1:03:11.20,1:03:12.79,yin,,0,0,0,,但现在我只选中了一个对象\\N{\\fs12}but here I only have one thing selected,\r\nDialogue: 0,1:03:12.79,1:03:14.25,yin,,0,0,0,,无法勾选宽度相等这一项\\N{\\fs12}so I can't even pick equal widths,\r\nDialogue: 0,1:03:14.25,1:03:15.86,yin,,0,0,0,,必须要选中两个以上对象才可以\\N{\\fs12}I'd have to pick two things for that,\r\nDialogue: 0,1:03:16.10,1:03:17.93,yin,,0,0,0,,但是在上面这里 可以看到\\N{\\fs12}but up here at the top, you'll notice,\r\nDialogue: 0,1:03:17.94,1:03:23.12,yin,,0,0,0,,可以指定它与周围视图的绑定方式\\N{\\fs12}you can specify that this thing is tied to views around it.\r\nDialogue: 0,1:03:23.13,1:03:25.00,yin,,0,0,0,,可以是它的父视图或其他视图\\N{\\fs12}Either its superview or its other views.\r\nDialogue: 0,1:03:25.66,1:03:29.73,yin,,0,0,0,,我还可以选择标准值\\N{\\fs12}Okay? And also, I can pick the standard value here.\r\nDialogue: 0,1:03:29.92,1:03:32.72,yin,,0,0,0,,就是使用默认值\\N{\\fs12}So I'm using the default value, okay?\r\nDialogue: 0,1:03:33.66,1:03:35.06,yin,,0,0,0,,通常都要这样做\\N{\\fs12}Which you generally want to do,\r\nDialogue: 0,1:03:35.07,1:03:36.04,yin,,0,0,0,,你不会想在这里使用魔术数字的\\N{\\fs12}you don't want to have a magic number,\r\nDialogue: 0,1:03:36.05,1:03:38.05,yin,,0,0,0,,比如这里的100和71\\N{\\fs12}like 100 and 71, in here,\r\nDialogue: 0,1:03:38.23,1:03:39.83,yin,,0,0,0,,这两个间距就不设置了\\N{\\fs12}but I'm not picking these I beams,\r\nDialogue: 0,1:03:39.83,1:03:41.30,yin,,0,0,0,,所以它们不会受影响\\N{\\fs12}so those are not going to be affected.\r\nDialogue: 0,1:03:41.47,1:03:43.42,yin,,0,0,0,,可以看到 系统要添加两条约束\\N{\\fs12}And do you see, it wants to add those two constraints,\r\nDialogue: 0,1:03:43.43,1:03:44.55,yin,,0,0,0,,就是这两条\\N{\\fs12}that's this one and this one.\r\nDialogue: 0,1:03:45.00,1:03:47.83,yin,,0,0,0,,我还要说一下这个更新框架\\N{\\fs12}I'm also gonna show you this, update frames.\r\nDialogue: 0,1:03:48.07,1:03:49.54,yin,,0,0,0,,你可以更新框架\\N{\\fs12}You can update the frames,\r\nDialogue: 0,1:03:49.55,1:03:51.54,yin,,0,0,0,,换句话说\\N{\\fs12}in other words, move the view\r\nDialogue: 0,1:03:51.55,1:03:53.39,yin,,0,0,0,,移动当前屏幕上显示的视图\\N{\\fs12}as it currently is showing the scene,\r\nDialogue: 0,1:03:53.47,1:03:55.49,yin,,0,0,0,,可以是整个容器中的全部框架\\N{\\fs12}either all the frames in the entire container,\r\nDialogue: 0,1:03:55.51,1:03:57.84,yin,,0,0,0,,或者只是新约束涉及的那些框架\\N{\\fs12}or just the frames that got new constraints.\r\nDialogue: 0,1:03:58.29,1:03:59.51,yin,,0,0,0,,通常会选择这个\\N{\\fs12}Usually you're going to pick this one,\r\nDialogue: 0,1:03:59.51,1:04:01.32,yin,,0,0,0,,Items of New Constraints\\N{\\fs12}items of new constraints.\r\nDialogue: 0,1:04:01.53,1:04:03.97,yin,,0,0,0,,我要点击这个按钮 看看会发生什么\\N{\\fs12}So I'm gonna hit this, and watch what's gonna happen,\r\nDialogue: 0,1:04:04.13,1:04:05.01,yin,,0,0,0,,彩色字符那个标签\\N{\\fs12}that colorful thing,\r\nDialogue: 0,1:04:05.02,1:04:07.32,yin,,0,0,0,,会自动跳到左下角\\N{\\fs12}it's going to jump to lower left-hand corner,\r\nDialogue: 0,1:04:07.32,1:04:11.37,yin,,0,0,0,,和父视图边缘保持标准间距\\N{\\fs12}standard distance away, automatically.\r\nDialogue: 0,1:04:13.22,1:04:15.22,yin,,0,0,0,,这是设置约束的另一种方法\\N{\\fs12}So that's another way to set the constraints,\r\nDialogue: 0,1:04:15.22,1:04:17.07,yin,,0,0,0,,看到这里的标准间距了吗\\N{\\fs12}see it put standard distances here,\r\nDialogue: 0,1:04:17.22,1:04:18.61,yin,,0,0,0,,添加了这些标准间距约束\\N{\\fs12}it's got these standard constraints,\r\nDialogue: 0,1:04:18.85,1:04:19.95,yin,,0,0,0,,那么它呢\\N{\\fs12}and how about this guy?\r\nDialogue: 0,1:04:20.37,1:04:24.35,yin,,0,0,0,,我们想让它对齐显示在彩色字符的上方\\N{\\fs12}We want this guy to be lined up on top of this one.\r\nDialogue: 0,1:04:24.91,1:04:27.74,yin,,0,0,0,,也可以通过这个按钮来实现\\N{\\fs12}We could do that, also, with this, okay?\r\nDialogue: 0,1:04:27.76,1:04:30.13,yin,,0,0,0,,可以设置间距等等\\N{\\fs12}We could set the I beam here and all that stuff,\r\nDialogue: 0,1:04:30.26,1:04:32.58,yin,,0,0,0,,但这里我要用control拖拽来实现\\N{\\fs12}but I'm gonna use the control dragging to do that,\r\nDialogue: 0,1:04:32.60,1:04:34.01,yin,,0,0,0,,我要按住control键\\N{\\fs12}so I'm going to hold down control,\r\nDialogue: 0,1:04:34.30,1:04:36.67,yin,,0,0,0,,从上面这个标签拖到下面\\N{\\fs12}and I drag from this guy to this guy,\r\nDialogue: 0,1:04:37.00,1:04:39.90,yin,,0,0,0,,选择垂直间距\\N{\\fs12}and I'm going to have the vertical spacing,\r\nDialogue: 0,1:04:39.92,1:04:41.39,yin,,0,0,0,,使用shift选择多项\\N{\\fs12}I'm using shift, by the way,\r\nDialogue: 0,1:04:41.56,1:04:44.98,yin,,0,0,0,,选择垂直间距和左边缘\\N{\\fs12}vertical spacing, and left, in this case, the left edge,\r\nDialogue: 0,1:04:44.99,1:04:46.25,yin,,0,0,0,,我想让它们对齐\\N{\\fs12}I want those lined up,\r\nDialogue: 0,1:04:46.36,1:04:47.53,yin,,0,0,0,,然后只要点击返回\\N{\\fs12}and then I just hit return,\r\nDialogue: 0,1:04:48.00,1:04:50.09,yin,,0,0,0,,系统为我创建了相应的两条约束\\N{\\fs12}and it created me two constraints for that.\r\nDialogue: 0,1:04:50.40,1:04:52.14,yin,,0,0,0,,下间距和与彩色字符标签对齐\\N{\\fs12}Bottom space and colorful character.\r\nDialogue: 0,1:04:52.35,1:04:53.88,yin,,0,0,0,,我们看看怎么样\\N{\\fs12}So let's go see what that looks like.\r\nDialogue: 0,1:04:55.80,1:04:57.35,yin,,0,0,0,,出来了 点击Stats\\N{\\fs12}Alright, so we have this, we do stats,\r\nDialogue: 0,1:04:57.36,1:04:58.80,yin,,0,0,0,,标签显示在左下角\\N{\\fs12}it stays in the lower left.\r\nDialogue: 0,1:04:59.32,1:05:01.41,yin,,0,0,0,,横屏和竖屏模式都可以\\N{\\fs12}Whether we're portrait or landscape.\r\nDialogue: 0,1:05:01.99,1:05:04.60,yin,,0,0,0,,运行得不错 二者始终显示在一起\\N{\\fs12}So that worked perfectly, and they stay stacked on each other.\r\nDialogue: 0,1:05:05.40,1:05:07.60,yin,,0,0,0,,我还要演示一下 看这个\\N{\\fs12}One thing I want to show you is this, watch this.\r\nDialogue: 0,1:05:07.82,1:05:09.62,yin,,0,0,0,,选择一大段文字\\N{\\fs12}Let's pick a whole bunch of text here\r\nDialogue: 0,1:05:10.43,1:05:12.13,yin,,0,0,0,,添加轮廓和颜色\\N{\\fs12}and make it outlined and colored.\r\nDialogue: 0,1:05:12.38,1:05:13.30,yin,,0,0,0,,转到统计数据\\N{\\fs12}And go to stats.\r\nDialogue: 0,1:05:13.53,1:05:18.33,yin,,0,0,0,,可以看到 标签内容完整地显示出来了\\N{\\fs12}And you see how these, these nicely show the whole word,\r\nDialogue: 0,1:05:18.34,1:05:19.90,yin,,0,0,0,,226个彩色字符\\N{\\fs12}226 colorful characters.\r\nDialogue: 0,1:05:20.00,1:05:21.34,yin,,0,0,0,,也就是说文字没有被切掉\\N{\\fs12}In other words, they don't get cut off.\r\nDialogue: 0,1:05:21.53,1:05:24.72,yin,,0,0,0,,因为它们用的是内置大小\\N{\\fs12}That's because these two things are their intrinsic size.\r\nDialogue: 0,1:05:25.00,1:05:29.46,yin,,0,0,0,,如果将其中一个的大小设为固定值会怎样\\N{\\fs12}What happens if, instead, I fix the size of one,\r\nDialogue: 0,1:05:29.62,1:05:30.77,yin,,0,0,0,,这里大家会看到\\N{\\fs12}and this is why you're gonna see\r\nDialogue: 0,1:05:30.78,1:05:32.55,yin,,0,0,0,,为什么将内置大小设为固定值不好\\N{\\fs12}these intrinsic size being fixed is bad.\r\nDialogue: 0,1:05:32.56,1:05:34.37,yin,,0,0,0,,我要将彩色字符这个标签\\N{\\fs12}So I'm gonna take this colorful character one,\r\nDialogue: 0,1:05:34.54,1:05:35.83,yin,,0,0,0,,设为固定宽度\\N{\\fs12}I'm gonna fix its width\r\nDialogue: 0,1:05:35.84,1:05:39.45,yin,,0,0,0,,方法是control拖拽到它自己\\N{\\fs12}and I'm gonna do that by control dragging to itself, okay?\r\nDialogue: 0,1:05:39.84,1:05:40.66,yin,,0,0,0,,选择宽度\\N{\\fs12}And saying width,\r\nDialogue: 0,1:05:41.24,1:05:43.21,yin,,0,0,0,,还可以通过下面这些按钮实现\\N{\\fs12}I could also do it with these buttons down here.\r\nDialogue: 0,1:05:43.47,1:05:46.67,yin,,0,0,0,,约束在这里 宽度为157 就是它的当前宽度\\N{\\fs12}And there it is, width equals 157, which is its current width,\r\nDialogue: 0,1:05:46.68,1:05:47.90,yin,,0,0,0,,我就用这个值了\\N{\\fs12}I'm just gonna leave it that way.\r\nDialogue: 0,1:05:48.07,1:05:50.20,yin,,0,0,0,,现在运行一下 看看会怎样\\N{\\fs12}Okay, not let's run and see what happens.\r\nDialogue: 0,1:05:52.00,1:05:54.65,yin,,0,0,0,,看起来没问题 都很好\\N{\\fs12}Okay, so it seems like no problem, everything's good.\r\nDialogue: 0,1:05:54.77,1:05:56.89,yin,,0,0,0,,但我们再选择大量文字试一下\\N{\\fs12}But let's select a lot of text again.\r\nDialogue: 0,1:05:58.53,1:05:59.80,yin,,0,0,0,,这就不太好了\\N{\\fs12}Oh, not so good.\r\nDialogue: 0,1:06:00.63,1:06:04.20,yin,,0,0,0,,它的大小现在不是其内置大小了\\N{\\fs12}You see? Since this thing is not its intrinsic size,\r\nDialogue: 0,1:06:04.43,1:06:08.13,yin,,0,0,0,,能容下0个字符 但是127个字符就不行了\\N{\\fs12}it couldn't fit when I went to 127 characters instead of 0.\r\nDialogue: 0,1:06:08.46,1:06:10.58,yin,,0,0,0,,所以就变成了点点点 显示不出来了\\N{\\fs12}Right? So it just went dot, dot, dot, I can't fit.\r\nDialogue: 0,1:06:10.71,1:06:13.14,yin,,0,0,0,,这是可以控制的\\N{\\fs12}Okay? It always does, you can control this,\r\nDialogue: 0,1:06:13.14,1:06:16.06,yin,,0,0,0,,但是如果容不下 默认就是三个点\\N{\\fs12}but by default it does this dot, dot, dot, if it can't fit.\r\nDialogue: 0,1:06:16.56,1:06:17.98,yin,,0,0,0,,大家明白\\N{\\fs12}Okay, so do you see the hazards\r\nDialogue: 0,1:06:18.25,1:06:22.20,yin,,0,0,0,,固定宽度的危险之处了吗\\N{\\fs12}of having these hardwired widths in here?\r\nDialogue: 0,1:06:22.34,1:06:26.00,yin,,0,0,0,,删掉它 再运行一次\\N{\\fs12}So if I take this and delete it, and run again,\r\nDialogue: 0,1:06:27.51,1:06:29.09,yin,,0,0,0,,转到统计数据\\N{\\fs12}now when we go to the stats,\r\nDialogue: 0,1:06:29.11,1:06:36.23,yin,,0,0,0,,即使内容很多 也能都显示出来\\N{\\fs12}even if we have a lot of stuff, it'll fit. Okay?\r\nDialogue: 0,1:06:38.07,1:06:41.15,yin,,0,0,0,,还有一个知识点 我快速演示一下\\N{\\fs12}Alright, one other thing I guess I'll show you real quick\r\nDialogue: 0,1:06:41.38,1:06:43.61,yin,,0,0,0,,如果...\\N{\\fs12}is what happens--\r\nDialogue: 0,1:06:43.68,1:06:45.95,yin,,0,0,0,,看一下现在的文档大纲\\N{\\fs12}let me show you the document outline piece of this.\r\nDialogue: 0,1:06:46.10,1:06:47.67,yin,,0,0,0,,没有错误\\N{\\fs12}Okay, so nothing's wrong in here,\r\nDialogue: 0,1:06:47.73,1:06:48.98,yin,,0,0,0,,但我要制造些错误\\N{\\fs12}but I'm going to make something wrong,\r\nDialogue: 0,1:06:48.98,1:06:49.98,yin,,0,0,0,,选中轮廓字符标签\\N{\\fs12}let me go to this guy\r\nDialogue: 0,1:06:49.98,1:06:53.15,yin,,0,0,0,,删掉它的前置对齐约束\\N{\\fs12}and let's delete its aligned leading, okay,\r\nDialogue: 0,1:06:53.15,1:06:55.70,yin,,0,0,0,,这样它就不再和彩色字符标签对齐了\\N{\\fs12}so it's no longer lined up with this.\r\nDialogue: 0,1:06:55.98,1:06:58.73,yin,,0,0,0,,这样做之后 注意这条线变黄了\\N{\\fs12}Okay? When I do that, notice this one turns yellow,\r\nDialogue: 0,1:06:58.95,1:07:01.97,yin,,0,0,0,,因为它代表对象的一条约束\\N{\\fs12}because it is a constraint for an object\r\nDialogue: 0,1:07:02.17,1:07:05.14,yin,,0,0,0,,出现了问题\\N{\\fs12}that has problems, okay?\r\nDialogue: 0,1:07:05.42,1:07:07.44,yin,,0,0,0,,所以只要你的对象有问题\\N{\\fs12}So anytime you have an object that has problems,\r\nDialogue: 0,1:07:07.46,1:07:09.59,yin,,0,0,0,,它的约束都会变为黄色 甚至红色\\N{\\fs12}all its constraints will be yellow, or even red,\r\nDialogue: 0,1:07:09.60,1:07:10.60,yin,,0,0,0,,如果出现冲突的话\\N{\\fs12}if they're conflicting.\r\nDialogue: 0,1:07:10.96,1:07:13.28,yin,,0,0,0,,可以看到 这里出现了红色圆形图标\\N{\\fs12}So you can see we've got this little red guy here\r\nDialogue: 0,1:07:13.50,1:07:14.98,yin,,0,0,0,,说这个对象有问题\\N{\\fs12}saying that there's a problem with this guy,\r\nDialogue: 0,1:07:14.99,1:07:16.48,yin,,0,0,0,,我们知道问题是什么 对吧\\N{\\fs12}and we know what the problem is, right?\r\nDialogue: 0,1:07:16.75,1:07:19.36,yin,,0,0,0,,我们不知道它的水平位置\\N{\\fs12}We don't know where it is horizontally,\r\nDialogue: 0,1:07:19.52,1:07:22.19,yin,,0,0,0,,只知道它的垂直位置\\N{\\fs12}we only know where it is vertically, okay?\r\nDialogue: 0,1:07:22.45,1:07:23.47,yin,,0,0,0,,我们来做一下\\N{\\fs12}So let's go do that.\r\nDialogue: 0,1:07:24.52,1:07:26.60,yin,,0,0,0,,这里提示 需要X轴位置的约束\\N{\\fs12}And it says needs constraint for X position,\r\nDialogue: 0,1:07:26.62,1:07:28.90,yin,,0,0,0,,同样的 我可以点击这个红色图标\\N{\\fs12}again, I can click on this little red thing.\r\nDialogue: 0,1:07:29.12,1:07:31.10,yin,,0,0,0,,点击添加缺失约束\\N{\\fs12}It'll say add missing constraints,\r\nDialogue: 0,1:07:31.20,1:07:31.93,yin,,0,0,0,,它很聪明\\N{\\fs12}it's smart,\r\nDialogue: 0,1:07:31.95,1:07:34.40,yin,,0,0,0,,它知道这两项之前是左对齐的\\N{\\fs12}it knows these two were lined up on the left\r\nDialogue: 0,1:07:34.41,1:07:35.94,yin,,0,0,0,,这两个标签相邻\\N{\\fs12}it said, it's nearby,\r\nDialogue: 0,1:07:35.95,1:07:37.82,yin,,0,0,0,,它说 没准它们想要左对齐\\N{\\fs12}it said, oh, it probably wants to be left-aligned,\r\nDialogue: 0,1:07:37.95,1:07:39.46,yin,,0,0,0,,所以系统就添加了一条左对齐约束\\N{\\fs12}so it put a left align in there.\r\nDialogue: 0,1:07:42.70,1:07:44.34,yin,,0,0,0,,还有一点 我快速演示一下\\N{\\fs12}One other thing I'll show you real quick,\r\nDialogue: 0,1:07:44.35,1:07:45.66,yin,,0,0,0,,如果移动了这个标签\\N{\\fs12}you see if moved this guy.\r\nDialogue: 0,1:07:45.89,1:07:47.85,yin,,0,0,0,,现在这些线都变成黄色了\\N{\\fs12}Okay? You see how now these are yellow,\r\nDialogue: 0,1:07:47.87,1:07:49.98,yin,,0,0,0,,因为位置不匹配\\N{\\fs12}because this doesn't match up,\r\nDialogue: 0,1:07:49.99,1:07:51.59,yin,,0,0,0,,这是虚线框的位置\\N{\\fs12}this is where the dashed box is,\r\nDialogue: 0,1:07:51.77,1:07:53.83,yin,,0,0,0,,同样的 可以在文档大纲中点击它\\N{\\fs12}again, in the outline, if I click this,\r\nDialogue: 0,1:07:54.05,1:07:55.57,yin,,0,0,0,,系统会提供一些选项\\N{\\fs12}I have these choices up here,\r\nDialogue: 0,1:07:55.67,1:07:57.46,yin,,0,0,0,,更新框架 让它归位\\N{\\fs12}I'll update the frame to put it back.\r\nDialogue: 0,1:07:58.16,1:08:01.05,yin,,0,0,0,,还有一点 这样移动之后\\N{\\fs12}One other thing, notice that in all this moving around\r\nDialogue: 0,1:08:01.06,1:08:04.93,yin,,0,0,0,,这里变为了8 而不是标准间距了\\N{\\fs12}this got set to 8, instead of the standard space,\r\nDialogue: 0,1:08:04.94,1:08:05.92,yin,,0,0,0,,有时会出现这样的情况\\N{\\fs12}that sometimes happens,\r\nDialogue: 0,1:08:05.93,1:08:08.37,yin,,0,0,0,,我不知道为什么会丢掉它的默认间距\\N{\\fs12}I'm not really sure why it lost its default space\r\nDialogue: 0,1:08:08.38,1:08:10.84,yin,,0,0,0,,我们也没有做什么指定它的操作\\N{\\fs12}we didn't really do anything to specify that,\r\nDialogue: 0,1:08:10.97,1:08:13.10,yin,,0,0,0,,你可以对它进行编辑 选择Select and Edit\\N{\\fs12}but you can edit, select and edit,\r\nDialogue: 0,1:08:13.11,1:08:14.87,yin,,0,0,0,,甚至还可以...\\N{\\fs12}or you can even, okay,\r\nDialogue: 0,1:08:14.88,1:08:17.25,yin,,0,0,0,,可以在这里将其修改为Standard\\N{\\fs12}so we could edit here and change this to standard,\r\nDialogue: 0,1:08:17.47,1:08:18.70,yin,,0,0,0,,或者使用这个小技巧\\N{\\fs12}or watch this little trick.\r\nDialogue: 0,1:08:18.87,1:08:21.25,yin,,0,0,0,,看见这个图标了吗 双击它\\N{\\fs12}You see that little guy? I'm gonna double click on that.\r\nDialogue: 0,1:08:21.98,1:08:23.88,yin,,0,0,0,,如果在一个约束上双击\\N{\\fs12}Okay, if you double click on a constraint,\r\nDialogue: 0,1:08:24.11,1:08:27.14,yin,,0,0,0,,这些选项就会显示在点击位置\\N{\\fs12}all this stuff will appear right you are.\r\nDialogue: 0,1:08:27.50,1:08:29.80,yin,,0,0,0,,在这里 我要将8修改为\\N{\\fs12}So, in this case, I'm going to switch from 8\r\nDialogue: 0,1:08:29.82,1:08:31.12,yin,,0,0,0,,Standard Value标准值\\N{\\fs12}to the standard value.\r\nDialogue: 0,1:08:32.17,1:08:33.39,yin,,0,0,0,,点击返回\\N{\\fs12}Okay? When I hit return,\r\nDialogue: 0,1:08:33.41,1:08:35.98,yin,,0,0,0,,看来8就是标准值 没有变化\\N{\\fs12}8 is the standard value it turns out, so nothing changed,\r\nDialogue: 0,1:08:35.99,1:08:38.02,yin,,0,0,0,,只是想为大家演示一下\\N{\\fs12}but just wanted to show you there\r\nDialogue: 0,1:08:38.03,1:08:40.96,yin,,0,0,0,,可以通过双击约束\\N{\\fs12}how you can double click on a constraint\r\nDialogue: 0,1:08:41.45,1:08:43.52,yin,,0,0,0,,来设置它的优先级等选项\\N{\\fs12}to set things like its priority and stuff like that.\r\nDialogue: 0,1:08:44.27,1:08:46.61,yin,,0,0,0,,好了 就是这样\\N{\\fs12}Okay? So that's it!\r\nDialogue: 0,1:08:46.95,1:08:47.67,yin,,0,0,0,,在作业中\\N{\\fs12}For your homework,\r\nDialogue: 0,1:08:47.78,1:08:49.46,yin,,0,0,0,,大家只要实现一点自动布局内容\\N{\\fs12}you only have a little bit of autolayout to do\r\nDialogue: 0,1:08:49.47,1:08:50.31,yin,,0,0,0,,因为你只有...\\N{\\fs12}because you only have a--\r\nDialogue: 0,1:08:50.33,1:08:52.14,yin,,0,0,0,,除了包含卡牌的视图\\N{\\fs12}besides the card-containing view,\r\nDialogue: 0,1:08:52.24,1:08:55.72,yin,,0,0,0,,可能还有重新发牌 增加更多卡牌 分数等等 我也不知道\\N{\\fs12}you may have redeal, add more cards, score, I don't know,\r\nDialogue: 0,1:08:56.01,1:08:58.13,yin,,0,0,0,,因为上次作业中\\N{\\fs12}because I let you delete some of the other stuff\r\nDialogue: 0,1:08:58.88,1:09:00.31,yin,,0,0,0,,我让大家删掉了一些内容\\N{\\fs12}from previous assignment.\r\nDialogue: 0,1:09:00.31,1:09:02.41,yin,,0,0,0,,作业中的自动布局应该很简单\\N{\\fs12}So, autolayout should be pretty simple for this,\r\nDialogue: 0,1:09:02.55,1:09:05.15,yin,,0,0,0,,但学期后面的课程中\\N{\\fs12}but for the rest of this class, all quarter-long,\r\nDialogue: 0,1:09:05.23,1:09:06.83,yin,,0,0,0,,大家全部都要使用自动布局\\N{\\fs12}you should always be using autolayout.\r\nDialogue: 0,1:09:07.02,1:09:09.55,yin,,0,0,0,,你的应用应该适用于横屏和竖屏模式\\N{\\fs12}Your app should always work in landscape and portrait\r\nDialogue: 0,1:09:09.55,1:09:10.67,yin,,0,0,0,,这门课之后的全部内容\\N{\\fs12}for the rest of this class,\r\nDialogue: 0,1:09:10.84,1:09:11.81,yin,,0,0,0,,所有作业都要这样\\N{\\fs12}okay, all assignments.\r\nDialogue: 0,1:09:11.81,1:09:14.04,yin,,0,0,0,,布置作业时会说到 但这里先告诉大家\\N{\\fs12}It'll be in the assignments, but, just so you know.\r\nDialogue: 0,1:09:15.36,1:09:16.27,yin,,0,0,0,,非常感谢\\N{\\fs12}Thank you very much!\r\nDialogue: 0,1:09:18.10,1:09:21.50,yin,,0,0,0,,更多内容 请访问斯坦福网站\\N{\\fs12}For more, please visit us at standford.edu.\r\n"
  }
]