├── .github ├── PULL_REQUEST_TEMPLATE.md └── issue_template.md ├── .gitignore ├── .wakatime-project ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── SUPPORT.md ├── _config.yml ├── en └── subtitles │ ├── 1. Introduction to iOS 11, Xcode 9 and Swift 4.srt │ ├── 10. Multithreading and Autolayout.srt │ ├── 11. Drag and Drop, Table View, and Collection View.srt │ ├── 12. Drag and Drop, Table View, Collection View, and Text Field.srt │ ├── 13. Persistence and Documents.srt │ ├── 14. Persistence and Documents Demo.srt │ ├── 15. Alerts, Notifications, Application Lifecycle.srt │ ├── 16. More Segues.srt │ ├── 17. Core Motion and Camera.srt │ ├── 2. MVC.srt │ ├── 3. Swift Programming Language.srt │ ├── 4. More Swift.srt │ ├── 5. Drawing.srt │ ├── 6. Multitouch.srt │ ├── 7. Multiple MVCs, Timer, and Animation.srt │ ├── 8. Animation.srt │ ├── 9. View Controller Lifecycle and Scroll View.srt │ ├── Friday Session 1. Debugging and Xcode Tips and Tricks.srt │ ├── Friday Session 2. Github and Source Control Workflow.srt │ └── Friday Session 3. Instruments.srt ├── subtitles ├── 1. Introduction to iOS 11, Xcode 9 and Swift 4.srt ├── 10. Multithreading and Autolayout.srt ├── 11. Drag and Drop, Table View, and Collection View.srt ├── 12. Drag and Drop, Table View, Collection View, and Text Field.srt ├── 13. Persistence and Documents.srt ├── 14. Persistence and Documents Demo.srt ├── 15. Alerts, Notifications, Application Lifecycle.srt ├── 16. More Segues.srt ├── 17. Core Motion and Camera.srt ├── 2. MVC.srt ├── 3. Swift Programming Language.srt ├── 4. More Swift.srt ├── 5. Drawing.srt ├── 6. Multitouch.srt ├── 7. Multiple MVCs, Timer, and Animation.srt ├── 8. Animation.srt ├── 9. View Controller Lifecycle and Scroll View.srt ├── Friday Session 1. Debugging and Xcode Tips and Tricks.srt ├── Friday Session 2. Github and Source Control Workflow.srt └── Friday Session 3. Instruments.srt ├── tools ├── update │ ├── download.md │ ├── main.swift │ └── update.xcodeproj │ │ ├── project.pbxproj │ │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── validation │ ├── main.swift │ └── validation.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ └── contents.xcworkspacedata └── translation-style-guide.md /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - [ ] 我已阅读 [翻译标准/校对规则](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/blob/master/translation-style-guide.md) 2 | - [ ] 我已使用 [工具](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/blob/master/tools/validation/main.swift) 简单校对过修改的 srt 文件 3 | 4 | ## 类型 5 | - [x] 翻译 6 | - [ ] 校对 7 | - [ ] 其他 8 | 9 | 集数: 10 | 开始段: 11 | 结束段: 12 | 13 | 备注(如果有,请列出): 14 | - 没有则不填 15 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | - [ ] 请先查看 [常见问题与解答](../SUPPORT.md) 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bilicookies 2 | .vscode 3 | /videos 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | .DS_Store? 9 | ._* 10 | .Spotlight-V100 11 | .Trashes 12 | ehthumbs.db 13 | Thumbs.db 14 | Desktop.ini 15 | 16 | # Xcode 17 | # 18 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 19 | 20 | ## Build generated 21 | build/ 22 | DerivedData/ 23 | Debug/ 24 | Release/ 25 | 26 | ## Various settings 27 | *.pbxuser 28 | !default.pbxuser 29 | *.mode1v3 30 | !default.mode1v3 31 | *.mode2v3 32 | !default.mode2v3 33 | *.perspectivev3 34 | !default.perspectivev3 35 | xcuserdata/ 36 | 37 | ## Other 38 | *.moved-aside 39 | *.xcuserstate 40 | 41 | ## Obj-C/Swift specific 42 | *.hmap 43 | *.ipa 44 | *.dSYM.zip 45 | *.dSYM 46 | 47 | ## Playgrounds 48 | timeline.xctimeline 49 | playground.xcworkspace 50 | 51 | # Swift Package Manager 52 | # 53 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 54 | # Packages/ 55 | .build/ 56 | 57 | # CocoaPods 58 | # 59 | # We recommend against adding the Pods directory to your .gitignore. However 60 | # you should judge for yourself, the pros and cons are mentioned at: 61 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 62 | # 63 | # Pods/ 64 | 65 | # Carthage 66 | # 67 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 68 | # Carthage/Checkouts 69 | 70 | Carthage/Build 71 | 72 | # fastlane 73 | # 74 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 75 | # screenshots whenever they are needed. 76 | # For more information about the recommended setup visit: 77 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 78 | 79 | fastlane/report.xml 80 | fastlane/Preview.html 81 | fastlane/screenshots 82 | fastlane/test_output 83 | *.bcc 84 | -------------------------------------------------------------------------------- /.wakatime-project: -------------------------------------------------------------------------------- 1 | Developing-iOS-11-Apps-with-Swift -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Each line is a file pattern followed by one or more owners. 2 | 3 | # These owners will be the default owners for everything in the repo. 4 | * @ApolloZhu @LiulietLee 5 | 6 | # Order is important; the last matching pattern takes the most precedence. 7 | *.srt @ApolloZhu 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 任务相关说明 2 | 3 | > Swifters of China, unite! 4 | 5 | 欢迎加入翻译的队伍!去年和前年的现在还没有翻译完,为了避免这样的情况再次发生,希望能有更多的小伙伴们加入。 6 | 7 | 总之大家先 Watch + Star 这个 repository,有兴趣也可以加 QQ 群 277542197。 8 | 9 | ## 领取任务 10 | 11 | 1. 每节新内容发布以后,[issue 区](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/issues) 会开一个当节的「任务分配」issue。 12 | 2. ***请确认不和他人重复之后*** ,到每节的 issue 中评论「翻译」或「校对」。评论的内容包括: 13 | 1. 段数。建议选择 issue 下第一条里公布的,一般会是 300 或 500 段,也可以自定义。 14 | 2. 预计完成时间。我个人的翻译速度是每小时 50 段,请结合个人情况进行估计,建议控制在一个星期以内。海外党请用本地时,并注明时区。 15 | 16 | **翻译、校对任务的段数不是指字幕文件中行数,而是指** 17 | 18 | 67 <----此处的数字 19 | 00:03:04,860 --> 00:03:06,960 20 | we talked about the NSNumber format and all that. 21 | 22 | ## 进行翻译 23 | 24 | 1. 请认真阅读并遵守 [翻译标准/校对规则](./translation-style-guide.md)。 25 | 2. 为了避免其他人也翻译同样的内容,请只翻译分配的段数。如果您不小心翻译了其他部分,请立刻告诉我,避免重复劳动。 26 | 3. 如果忙碌或者有困难一定要及时提出来,我也可以把任务转给其他人。这并不会对您有任何影响,觉得难为情可以邮件/私信我。 27 | 4. Fork 本项目到您的账户下,然后 Clone 保存到本地。 28 | 5. 如果已经 fork 过了,请通过 sync/update from master/fetch origin 等方式完成同步。 29 | 6. 翻译过程中请不要 update from master。 30 | 7. 翻译 **subtitles** 文件夹下对应 srt 文件的对应段,在英文行下面添加中文翻译。 31 | - srt 就是普通的文本文件,所以使用的程序只要能够保证保存为同样格式就行,个人偏好是 Visual Studio Code,也可以直接在 GitHub 上编辑。 32 | - 千万 **不要** 翻译 en/subtitles 文件夹里的,那些是保留原版字幕以备后用。区别方法如下: 33 | - 要翻译的文件所有的英文都只有一行; 34 | - 要翻译的文件至少第一句和最后一句都已经翻译过了。 35 | 8. 建议每完成一部分就 **commit** 一次,这样我们能对进度有个大概的把握。 36 | 9. 翻译或校对的过程中有拿不准的地方,请先尝试按照标准里提到的方法解决,也可以进入该节的 issue 中讨论(如这个词该不该翻译,该翻译成什么等)。 37 | 38 | ## 提交翻译 39 | 40 | 1. **全部** 翻译完之后提交 pull request,你会看到它出现在 [这里](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/pulls),具体步骤可以参考 [教程](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)。 41 | 2. 如果有,请在提交信息中注明我们需要特别注意的地方,和其他任务行之外的改动。 42 | 3. 为了加快进度,我们会采用每一集整体校对的形式,所以我们基本会马上 merge 你的 pull request。 43 | 4. 如果翻译格式不正确,或是有严重问题等,我们会在 pull request 的 comment 里提出,请修改并 commit。(不需要关闭 pull request,所有的 commit 会自动加入 pull request 里) 44 | 5. 在看到主项目出现一个标题为 `集数_开始段-结束段 翻译 @你` 的 commit 之后就算完成了。如果有需要,这个时候就可以安全地删除 fork 和本地文件了。 45 | 46 | ---- 47 | 48 | 本规则基于 [github.com/SwiftGGTeam/Developing-iOS-9-Apps-with-Swift/issues/3](https://github.com/SwiftGGTeam/Developing-iOS-9-Apps-with-Swift/issues/3) 修订而成。 49 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 本项目(包括字幕,代码等),以及原斯坦福课程均采用 知识共享 署名-非商业性使用-相同方式共享 3.0 美国 许可协议 进行许可。协议详见 https://creativecommons.org/licenses/by-nc-sa/3.0/us/deed.zh。 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Developing iOS 11 Apps with Swift 字幕简体中文翻译项目 2 | 3 | 如果您想支持我们,请点击项目右上角的 Star 按钮来 Star 本项目。 4 | 5 | 如果您感兴趣,有能力,我们欢迎您参与翻译/校对本项目。详情见 [任务相关说明](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/blob/master/CONTRIBUTING.md)。 6 | 7 | - 翻译进度: ![5集](http://progressed.io/bar/5?scale=20&suffix=%E9%9B%86) 8 | - 校对进度: ![2集](http://progressed.io/bar/3?scale=20&suffix=%E9%9B%86) 9 | - 课程录像: [bilibili](https://www.bilibili.com/video/av16339375/)。字幕会在每集 **校对后** 以 Close Caption 上传 10 | - 从 iTunes U 提取: [下载列表](./tools/update/download.md)(因 iTunes 机制变更,暂时不能访问) 11 | 12 | 其它问题请参见本文档剩下的部分或 [常见问题与解答](./SUPPORT.md)。 13 | 14 | #### 字幕下载 15 | 16 | [`subtitles`](./subtitles) 文件夹中是中英字幕(不一定都翻译了),[`en/subtitles`](./en/subtitles) 文件夹中是纯英文字幕。您可以通过 [下载整个项目](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/archive/master.zip) 来获取这些字幕。 17 | 18 | 字幕的格式是 `.srt`,所以您可能需要用带外挂字幕功能的视频播放器,比如 [VLC](http://www.videolan.org/vlc/index.zh.html) 或 [IINA](https://lhc70000.github.io/iina/zh-cn/) 等才可使用。其他字幕使用问题的解答请查看 [常见问题与解答](./SUPPORT.md) 的字幕使用章节。 19 | 20 | #### 课程相关资源 21 | 22 | |[Paul Hegarty](https://piazza.com/professors/show/paul_hegarty)|iTunes U(仅 iOS)|Podcasts(多平台)| 23 | |--:|:--:|:--:| 24 | |[CS 193P](http://web.stanford.edu/class/cs193p/cgi-bin/drupal/) [iPhone Application Development](https://explorecourses.stanford.edu/search?q=CS+193P%3A+iOS+Application+Development)|[Developing iOS 11 Apps with Swift - Free Course by Stanford](https://itunes.apple.com/course/id1309275316) |[Developing iOS 11 Apps with Swift By Paul Hegarty](https://itunes.apple.com/podcast/id1315130780)| 25 | |RSS 源|[每周三更新,更新完毕](https://p1-u.itunes.apple.com/WebObjects/LZStudent.woa/ra/feed/CODOAOSRJY0GOAQH)|[结束后统一更新,更新完毕](http://podcasts.apple.com/stanford/developing_ios11_apps.xml)| 26 | |课程封面|[![iTunes U](https://is3-ssl.mzstatic.com/image/thumb/course/CobaltPublic128/v4/81/d0/9c/81d09ca1-ec7b-19b2-a215-4ae39df215c5/source/466x570.png)](https://is3-ssl.mzstatic.com/image/thumb/course/CobaltPublic128/v4/81/d0/9c/81d09ca1-ec7b-19b2-a215-4ae39df215c5/source/466x570.png)|[![Podcasts](http://is1.mzstatic.com/image/thumb/Music128/v4/fa/b1/5c/fab15cf7-b968-7e65-0f32-9955ae02fc3e/source/1024x1024bb.jpg)](http://is1.mzstatic.com/image/thumb/Music128/v4/fa/b1/5c/fab15cf7-b968-7e65-0f32-9955ae02fc3e/source/1024x1024bb.jpg)| 27 | |[![首页推广](http://is5.mzstatic.com/image/thumb/comp/Features118/v4/b5/ad/37/b5ad3702-1d82-94b6-3056-787cbf98c41b/temp..lejovgyc.png/1360x520fa.jpg)](http://is5.mzstatic.com/image/thumb/comp/Features118/v4/b5/ad/37/b5ad3702-1d82-94b6-3056-787cbf98c41b/temp..lejovgyc.png/1360x520fa.jpg)|[![带英文](http://is5.mzstatic.com/image/thumb/comp/Features118/v4/b5/ad/37/b5ad3702-1d82-94b6-3056-787cbf98c41b/temp..lejovgyc.png/1360x520fa.jpg?fbl=en-GB&cdt=cdt-1-326037343&cte=cte-1504292368040-10000&dk=dk-20209947-1474866501&l=en-GB)](http://is5.mzstatic.com/image/thumb/comp/Features118/v4/b5/ad/37/b5ad3702-1d82-94b6-3056-787cbf98c41b/temp..lejovgyc.png/1360x520fa.jpg?fbl=en-GB&cdt=cdt-1-326037343&cte=cte-1504292368040-10000&dk=dk-20209947-1474866501&l=en-GB)|[![Twitter](https://pbs.twimg.com/media/DPz9KZ4VQAAyUwJ.jpg)](https://pbs.twimg.com/media/DPz9KZ4VQAAyUwJ.jpg)| 28 | 29 | #### 项目相关资源 30 | 31 | - [Developing iOS 10 Apps with Swift 字幕翻译](https://github.com/Apollonyan/Developing-iOS-10-Apps-with-Swift) 32 | - [Developing iOS 9 Apps with Swift 字幕翻译](https://github.com/SwiftGGTeam/Developing-iOS-9-Apps-with-Swift) 33 | - [Developing iOS 8 Apps with Swift 字幕翻译](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift) 34 | - 提取字幕:[CCExtractor](https://www.ccextractor.org/) 35 | - 字幕重排:[X140Yu/Developing_iOS_8_Apps_With_Swift/tools/trim.rb](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift/blob/master/tools/trim.rb) 36 | - 字幕上传:[Srt2BilibiliKit](https://github.com/ApolloZhu/Srt2BilibiliKit) 37 | 38 | ### 版权说明 39 | 40 | 知识共享许可协议 41 | 42 | 本项目(包括字幕,代码等),以及原 Stanford(斯坦福)课程均采用 知识共享 署名-非商业性使用-相同方式共享 3.0 美国 许可协议 进行许可。 43 | 44 | ---- 45 | 46 |
47 | 48 | 49 | 50 | 57 | 58 |
59 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # 常见问题与解答 2 | 3 | 如果您阅读完后还是有问题,请通过 “联系我们” 中提供的方式咨询。 4 | 5 | ## 联系我们 6 | 7 | 推荐 [GitHub Issues](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/issues/new),或者发电子邮件到 [public-apollonian@outlook.com](mailto:public-apollonian@outlook.com)。 8 | 9 | ## 字幕使用 10 | 11 | ### 字幕乱码 12 | 13 | 如果字幕有乱码,请点击 [中文乱码报错用 Issue](https://github.com/x140yu/Developing_iOS_8_Apps_With_Swift/issues/131) 进行乱码的报错和寻求解决方案。 14 | 15 | ### 字幕看不清 16 | 17 | 播放器应该都可以设置字幕样式,所以不接受在字幕中加上声明样式的代码。 18 | 19 | 设置方法每个系统每个播放器的每个版本都可能不一样,请自行搜索/研究。 20 | 21 | 推荐样式是白字+黑边,一般情况下都是能看清的。 22 | 23 | ## 字幕更新 24 | 25 | ### 如何关注更新? 26 | 27 | 如果您想收到每集翻译完成的更新,请订阅 [RSS源](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/releases.atom)。如果您想要更密切地获得最新动态,您也可以 [关注(Watch)项目的更新](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/subscription)。 28 | 29 | ## 支持我们 30 | 31 | 在此先感谢所有关注、分享和参与本项目的所有人! 32 | 33 | ### 您的分享非常重要! 34 | 35 | 除了 ***Star*** 之外,同时也希望您能够通过各种国内外社交平台,如 微信公众号,微博,博客,开发者头条,简书,CSDN 等为我们宣传推广,以**吸引更多的人加入翻译,加快翻译速度**,同时帮助更多有需要的人。 36 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /en/subtitles/Friday Session 2. Github and Source Control Workflow.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,401 --> 00:00:04,803 3 | [MUSIC] 4 | 5 | 2 6 | 00:00:04,872 --> 00:00:10,008 7 | Stanford University. 8 | >> Welcome everyone to 9 | 10 | 3 11 | 00:00:10,077 --> 00:00:14,613 12 | our Friday section of CS193P. 13 | I'm Junjie, one of your TAs. 14 | 15 | 4 16 | 00:00:14,682 --> 00:00:18,249 17 | And today, I'm gonna 18 | talk about the GitHub and 19 | 20 | 5 21 | 00:00:18,318 --> 00:00:23,221 22 | the source control 23 | workflow in Xcode 9. So, 24 | 25 | 6 26 | 00:00:23,290 --> 00:00:28,126 27 | what is source control? 28 | Like have you used like 29 | 30 | 7 31 | 00:00:28,195 --> 00:00:31,029 32 | some source control 33 | systems like GitHub? 34 | 35 | 8 36 | 00:00:31,098 --> 00:00:36,067 37 | Yeah, so as a software 38 | developer, you will like, 39 | 40 | 9 41 | 00:00:36,136 --> 00:00:40,672 42 | almost like it's 43 | a necessary skill set for 44 | 45 | 10 46 | 00:00:40,741 --> 00:00:43,442 47 | you to learn how to use 48 | source control systems. 49 | 50 | 11 51 | 00:00:43,510 --> 00:00:46,611 52 | Like big companies like 53 | Facebook and Google, 54 | 55 | 12 56 | 00:00:46,680 --> 00:00:50,381 57 | they all have their own 58 | source control systems. And 59 | 60 | 13 61 | 00:00:50,450 --> 00:00:54,385 62 | it's very important for you to 63 | master those skills before you 64 | 65 | 14 66 | 00:00:54,454 --> 00:00:58,223 67 | really go into the industry. 68 | So what is source control? 69 | 70 | 15 71 | 00:00:58,291 --> 00:01:03,328 72 | Why should we matter? 73 | Why should we care about it? 74 | 75 | 16 76 | 00:01:03,397 --> 00:01:07,933 77 | It allows you to track your 78 | code changes over time. 79 | 80 | 17 81 | 00:01:08,002 --> 00:01:11,370 82 | You can revert your files 83 | back to a previous state. 84 | 85 | 18 86 | 00:01:11,438 --> 00:01:16,107 87 | You can compare different 88 | versions of code side by side. 89 | 90 | 19 91 | 00:01:16,176 --> 00:01:18,476 92 | And it also makes 93 | it a lot easier for 94 | 95 | 20 96 | 00:01:18,545 --> 00:01:22,481 97 | you to work with 98 | other teammates. And 99 | 100 | 21 101 | 00:01:22,549 --> 00:01:26,884 102 | like when bugs happen, it's 103 | much easier to take it down. 104 | 105 | 22 106 | 00:01:26,953 --> 00:01:31,556 107 | Today, our topic is one of the 108 | biggest source control system 109 | 110 | 23 111 | 00:01:31,625 --> 00:01:36,361 112 | in the world, and 113 | it's built right into Xcode 9. 114 | 115 | 24 116 | 00:01:36,430 --> 00:01:39,697 117 | Xcode 9 has done a lot of 118 | great things to integrate 119 | 120 | 25 121 | 00:01:39,766 --> 00:01:44,670 122 | GitHub to make it 123 | very easy to use. So 124 | 125 | 26 126 | 00:01:44,738 --> 00:01:49,808 127 | I'm gonna try to demo you some 128 | of the basics in Xcode 9, 129 | 130 | 27 131 | 00:01:49,877 --> 00:01:54,446 132 | how to use GitHub. Before 133 | that, you should register 134 | 135 | 28 136 | 00:01:54,515 --> 00:01:59,284 137 | an account in github.com. 138 | The repository, 139 | 140 | 29 141 | 00:01:59,353 --> 00:02:04,690 142 | the public repository or 143 | a repo, is free. And, a repo 144 | 145 | 30 146 | 00:02:04,758 --> 00:02:08,693 147 | is just like a code directory 148 | for you to store the code. 149 | 150 | 31 151 | 00:02:08,762 --> 00:02:12,930 152 | And if you register using 153 | your Stanford email account, 154 | 155 | 32 156 | 00:02:12,999 --> 00:02:17,068 157 | you can get the private 158 | repository for free. I highly, 159 | 160 | 33 161 | 00:02:17,137 --> 00:02:21,072 162 | highly encourage you to use 163 | a private repo to manage 164 | 165 | 34 166 | 00:02:21,141 --> 00:02:24,342 167 | all your assignments, 168 | all your cost projects. 169 | 170 | 35 171 | 00:02:24,411 --> 00:02:28,547 172 | And it's much easier for 173 | you to collaborate with your 174 | 175 | 36 176 | 00:02:28,616 --> 00:02:31,716 177 | teammates, and in- 178 | >> Remind people not to make 179 | 180 | 37 181 | 00:02:31,785 --> 00:02:33,284 182 | it public, though. 183 | >> Yeah, yeah. 184 | 185 | 38 186 | 00:02:33,353 --> 00:02:34,252 187 | >> [CROSSTALK] the public 188 | 189 | 39 190 | 00:02:34,320 --> 00:02:35,020 191 | to private. 192 | >> So 193 | 194 | 40 195 | 00:02:35,088 --> 00:02:39,658 196 | that's why you wanna register 197 | using your Stanford email. 198 | 199 | 41 200 | 00:02:39,727 --> 00:02:41,926 201 | You would never like up, 202 | upload 203 | 204 | 42 205 | 00:02:41,995 --> 00:02:46,164 206 | your assignments onto GitHub 207 | using a public repository cuz 208 | 209 | 43 210 | 00:02:46,233 --> 00:02:50,268 211 | like you don't know who will 212 | just download all the code and 213 | 214 | 44 215 | 00:02:50,337 --> 00:02:55,040 216 | copy, copy out of no place. 217 | So last Friday's session, 218 | 219 | 45 220 | 00:02:55,108 --> 00:02:59,344 221 | Jason also mentioned that 222 | there's a Pro Git ebook. 223 | 224 | 46 225 | 00:02:59,413 --> 00:03:03,181 226 | That's really great for you to 227 | learn some of the basics of 228 | 229 | 47 230 | 00:03:03,250 --> 00:03:06,584 231 | GitHub and the source control, 232 | some of the concepts. 233 | 234 | 48 235 | 00:03:06,653 --> 00:03:09,754 236 | It's a really good 237 | starting point for 238 | 239 | 49 240 | 00:03:09,823 --> 00:03:14,259 241 | you to learn those skills. 242 | I post a link here and 243 | 244 | 50 245 | 00:03:14,327 --> 00:03:19,697 246 | you can like check it out if 247 | you want. So there are three 248 | 249 | 51 250 | 00:03:19,766 --> 00:03:24,069 251 | main components in like Xcode 252 | 9 Source Control Workflow, and 253 | 254 | 52 255 | 00:03:24,138 --> 00:03:27,839 256 | I will go through 257 | each of them briefly. 258 | 259 | 53 260 | 00:03:27,908 --> 00:03:32,410 261 | The first one is pulling and 262 | pushing. For pulling and 263 | 264 | 54 265 | 00:03:32,479 --> 00:03:35,647 266 | pushing is like dealing 267 | with your local changes and 268 | 269 | 55 270 | 00:03:35,716 --> 00:03:39,518 271 | the changes in the remote 272 | repository. So, for 273 | 274 | 56 275 | 00:03:39,586 --> 00:03:40,551 276 | clone and pull, 277 | 278 | 57 279 | 00:03:40,620 --> 00:03:44,522 280 | you can download all the code 281 | from the remote repository to 282 | 283 | 58 284 | 00:03:44,591 --> 00:03:48,860 285 | your own laptop. Xcode 9 286 | actually make it really, 287 | 288 | 59 289 | 00:03:48,929 --> 00:03:53,298 290 | really easy to download 291 | a repository. You just click 292 | 293 | 60 294 | 00:03:53,366 --> 00:03:57,502 295 | the Clone and Download button 296 | and then open it in Xcode. 297 | 298 | 61 299 | 00:03:57,570 --> 00:04:00,571 300 | And Xcode will download 301 | all the changes for 302 | 303 | 62 304 | 00:04:00,640 --> 00:04:02,573 305 | you. It's really nice. And 306 | 307 | 63 308 | 00:04:02,642 --> 00:04:07,112 309 | I will show you how to do that 310 | in a demo. And another way to 311 | 312 | 64 313 | 00:04:07,181 --> 00:04:12,650 314 | do it is to copy out this 315 | GitHub repository address. 316 | 317 | 65 318 | 00:04:12,719 --> 00:04:17,221 319 | And I will also show you how 320 | to do that in a demo. For 321 | 322 | 66 323 | 00:04:17,290 --> 00:04:20,925 324 | the push, it's like you 325 | make some local changes, 326 | 327 | 67 328 | 00:04:20,994 --> 00:04:24,563 329 | you, and you want to push to 330 | the remote so that you can 331 | 332 | 68 333 | 00:04:24,631 --> 00:04:30,469 334 | edit it in another machine or 335 | share it to your friends. 336 | 337 | 69 338 | 00:04:32,606 --> 00:04:37,509 339 | So, every batch of code 340 | changes is called a commit. 341 | 342 | 70 343 | 00:04:37,578 --> 00:04:41,679 344 | The commit it's like 345 | a snapshot of all the code 346 | 347 | 71 348 | 00:04:41,748 --> 00:04:46,784 349 | changes and 350 | also the description message. 351 | 352 | 72 353 | 00:04:46,853 --> 00:04:51,423 354 | It has the author, description 355 | message, and also the time. 356 | 357 | 73 358 | 00:04:51,491 --> 00:04:55,927 359 | I highly encourage you to 360 | make small commits instead of 361 | 362 | 74 363 | 00:04:55,996 --> 00:05:00,732 364 | making a really big commit, 365 | like only one commit for 366 | 367 | 75 368 | 00:05:00,801 --> 00:05:05,303 369 | the repository. That's 370 | like the final finish one. 371 | 372 | 76 373 | 00:05:05,372 --> 00:05:10,875 374 | Because making small commits 375 | makes it much easier to debug. 376 | 377 | 77 378 | 00:05:10,944 --> 00:05:14,279 379 | The rule of thumb is one 380 | feature at a time, and 381 | 382 | 78 383 | 00:05:14,348 --> 00:05:17,449 384 | each commit should 385 | be self-contained. 386 | 387 | 79 388 | 00:05:17,517 --> 00:05:21,653 389 | When bugs happen, you can 390 | easily revert to the previous 391 | 392 | 80 393 | 00:05:21,721 --> 00:05:27,225 394 | state without affecting 395 | the other files. So 396 | 397 | 81 398 | 00:05:27,293 --> 00:05:33,364 399 | here's what the commit panel 400 | looks like in Xcode 9. 401 | 402 | 82 403 | 00:05:33,433 --> 00:05:37,569 404 | You get the commit message 405 | here and also the author, 406 | 407 | 83 408 | 00:05:37,638 --> 00:05:40,304 409 | the branches, 410 | the tags and remotes. 411 | 412 | 84 413 | 00:05:40,373 --> 00:05:44,409 414 | We will go through these 415 | concepts in a demo. And 416 | 417 | 85 418 | 00:05:44,477 --> 00:05:48,113 419 | here's the identifier, 420 | it is the SHA identifier for 421 | 422 | 86 423 | 00:05:48,181 --> 00:05:53,051 424 | this commit. The last 425 | 426 | 87 427 | 00:05:53,119 --> 00:05:57,221 428 | concept I'm introducing 429 | today is the branching. So 430 | 431 | 88 432 | 00:05:57,290 --> 00:06:04,061 433 | each little commits, one after 434 | one, is called a code branch. 435 | 436 | 89 437 | 00:06:04,130 --> 00:06:06,297 438 | In the GitHub repo, 439 | repository, 440 | 441 | 90 442 | 00:06:06,366 --> 00:06:10,435 443 | the most important one is the 444 | master branch. You would wanna 445 | 446 | 91 447 | 00:06:10,503 --> 00:06:13,772 448 | always keep your master 449 | branch clean, bug-free and 450 | 451 | 92 452 | 00:06:13,840 --> 00:06:18,710 453 | stable. And when you want 454 | to work on new features, 455 | 456 | 93 457 | 00:06:18,778 --> 00:06:23,347 458 | you would like to branch 459 | from the master. So 460 | 461 | 94 462 | 00:06:23,416 --> 00:06:28,119 463 | Xcode 9 is really easy for 464 | you to just right-click and 465 | 466 | 95 467 | 00:06:28,188 --> 00:06:32,523 468 | create a new branch. The new 469 | branch will have the same 470 | 471 | 96 472 | 00:06:32,592 --> 00:06:37,595 473 | code as the master. But when 474 | you keep developing your code, 475 | 476 | 97 477 | 00:06:37,664 --> 00:06:43,000 478 | it won't affect the master 479 | branch. And after you finish 480 | 481 | 98 482 | 00:06:43,069 --> 00:06:46,438 483 | developing all your features, 484 | you've unit tested your code, 485 | 486 | 99 487 | 00:06:46,507 --> 00:06:49,841 488 | you can merge it back 489 | to master branch. 490 | 491 | 100 492 | 00:06:49,910 --> 00:06:55,946 493 | I will show you how to do the 494 | branching in this demo. So, 495 | 496 | 101 497 | 00:06:56,015 --> 00:07:01,119 498 | any questions so far? No, 499 | 500 | 102 501 | 00:07:01,187 --> 00:07:06,925 502 | so let's go into the demo. 503 | So let's pull out Xcode. 504 | 505 | 103 506 | 00:07:08,628 --> 00:07:11,896 507 | So before we do the fancy 508 | things in Xcode, 509 | 510 | 104 511 | 00:07:11,964 --> 00:07:15,833 512 | we would like to set up the 513 | GitHub account in Xcode. So 514 | 515 | 105 516 | 00:07:15,902 --> 00:07:21,372 517 | the way to do it as click 518 | on Xcode > Preferences 519 | 520 | 106 521 | 00:07:21,441 --> 00:07:26,077 522 | > Accounts. When you 523 | select the Add button, 524 | 525 | 107 526 | 00:07:26,145 --> 00:07:30,548 527 | you can add GitHub Enterprise. 528 | Enterprise is like, 529 | 530 | 108 531 | 00:07:30,617 --> 00:07:34,419 532 | when you work for a company, 533 | they will have the company 534 | 535 | 109 536 | 00:07:34,488 --> 00:07:38,590 537 | GitHub account. So 538 | I'm gonna select the GitHub. 539 | 540 | 110 541 | 00:07:38,658 --> 00:07:47,165 542 | And I'm using my Stanford 543 | email address. So 544 | 545 | 111 546 | 00:07:47,234 --> 00:07:51,369 547 | we've already signed in. And 548 | before we jump into the code, 549 | 550 | 112 551 | 00:07:51,437 --> 00:07:55,106 552 | we would wanna make sure the 553 | Source Control is setting up 554 | 555 | 113 556 | 00:07:55,175 --> 00:08:00,211 557 | correctly. So, these options 558 | is like, whether you 559 | 560 | 114 561 | 00:08:00,279 --> 00:08:05,850 562 | want Xcode to download 563 | the remote changes for you. 564 | 565 | 115 566 | 00:08:05,919 --> 00:08:11,322 567 | So that you won't need to pull 568 | the changes in command line. 569 | 570 | 116 571 | 00:08:11,391 --> 00:08:14,992 572 | And when you click on the Git 573 | button here, you can set up 574 | 575 | 117 576 | 00:08:15,061 --> 00:08:20,665 577 | some global ignored files. If 578 | you have used GitHub before, 579 | 580 | 118 581 | 00:08:20,734 --> 00:08:24,869 582 | you know that there's 583 | a gitignore file so 584 | 585 | 119 586 | 00:08:24,938 --> 00:08:31,041 587 | that your files won't be 588 | checked by the GitHub system. 589 | 590 | 120 591 | 00:08:31,110 --> 00:08:35,113 592 | So you can set up some global 593 | ignored files here. That means 594 | 595 | 121 596 | 00:08:35,181 --> 00:08:40,652 597 | like .D_Store files won't 598 | be checked by the GitHub. So 599 | 600 | 122 601 | 00:08:40,720 --> 00:08:45,790 602 | let's start by creating 603 | a new Xcode product. 604 | 605 | 123 606 | 00:08:49,529 --> 00:08:54,799 607 | Let's do Single View, 608 | and then GitTutorial. 609 | 610 | 124 611 | 00:08:59,305 --> 00:09:03,174 612 | And it's basically the same 613 | thing as we are doing when 614 | 615 | 125 616 | 00:09:03,243 --> 00:09:06,377 617 | creating the new project for 618 | our homework, 619 | 620 | 126 621 | 00:09:06,446 --> 00:09:10,815 622 | but the difference is that we 623 | wanna select this button. So 624 | 625 | 127 626 | 00:09:10,884 --> 00:09:13,951 627 | this is the mysterious 628 | Source Control button we never 629 | 630 | 128 631 | 00:09:14,020 --> 00:09:15,920 632 | talk about in class. 633 | 634 | 129 635 | 00:09:15,989 --> 00:09:20,591 636 | And this means that Xcode will 637 | initialize a Git repository 638 | 639 | 130 640 | 00:09:20,660 --> 00:09:25,297 641 | for you. So we would select 642 | this button for this section. 643 | 644 | 131 645 | 00:09:26,399 --> 00:09:31,436 646 | Hit Create, and 647 | then we would have 648 | 649 | 132 650 | 00:09:31,504 --> 00:09:36,408 651 | a Git repository, and 652 | 653 | 133 654 | 00:09:36,476 --> 00:09:43,582 655 | we can inspect the Source 656 | Control panel over here. 657 | 658 | 134 659 | 00:09:43,650 --> 00:09:47,485 660 | It's on the top left, 661 | and the second button. 662 | 663 | 135 664 | 00:09:50,056 --> 00:09:53,658 665 | It shows that we are currently 666 | at the master branch. And 667 | 668 | 136 669 | 00:09:53,726 --> 00:09:57,896 670 | the initial commit is just 671 | some free code given by Xcode 672 | 673 | 137 674 | 00:09:57,964 --> 00:10:02,166 675 | that create, initialize, 676 | and then push the code for 677 | 678 | 138 679 | 00:10:02,235 --> 00:10:07,539 680 | you. So, 681 | let's make some change. 682 | 683 | 139 684 | 00:10:09,076 --> 00:10:14,012 685 | Maybe I will delete 686 | this free code. And 687 | 688 | 140 689 | 00:10:14,080 --> 00:10:22,420 690 | then add a print line. 691 | 692 | 141 693 | 00:10:22,489 --> 00:10:27,525 694 | And once I've saved the file, 695 | there's an M appeared here. 696 | 697 | 142 698 | 00:10:27,594 --> 00:10:31,429 699 | That M stands for modified. 700 | Basically, it means that your 701 | 702 | 143 703 | 00:10:31,497 --> 00:10:37,268 704 | local repository have some 705 | uncommitted changes. And 706 | 707 | 144 708 | 00:10:37,337 --> 00:10:41,305 709 | that's also modified in 710 | storyboard. I want to drag our 711 | 712 | 145 713 | 00:10:41,374 --> 00:10:47,645 714 | button. And 715 | 716 | 146 717 | 00:10:47,714 --> 00:10:51,816 718 | put it in the middle. Okay, 719 | 720 | 147 721 | 00:10:51,885 --> 00:10:57,087 722 | let's save the change. So 723 | now I have made some change. 724 | 725 | 148 726 | 00:10:57,156 --> 00:11:00,658 727 | So we wanna commit 728 | those changes. 729 | 730 | 149 731 | 00:11:00,727 --> 00:11:03,828 732 | It's like clicking 733 | the Source Control here, and 734 | 735 | 150 736 | 00:11:03,897 --> 00:11:09,901 737 | then hit Commit. Then 738 | a Version Editor will appear. 739 | 740 | 151 741 | 00:11:09,970 --> 00:11:14,505 742 | And it's really nice because 743 | you can see your change 744 | 745 | 152 746 | 00:11:14,573 --> 00:11:19,110 747 | side by side by clicking the 748 | filename. And it shows that 749 | 750 | 153 751 | 00:11:19,179 --> 00:11:22,780 752 | you've added one line and 753 | you've deleted some code. 754 | 755 | 154 756 | 00:11:22,849 --> 00:11:26,851 757 | And if you click on 758 | the button in the middle, 759 | 760 | 155 761 | 00:11:26,919 --> 00:11:30,554 762 | you can actually don't 763 | commit this specific line or 764 | 765 | 156 766 | 00:11:30,623 --> 00:11:37,962 767 | discards the change. So, let's 768 | also look at the storyboard. 769 | 770 | 157 771 | 00:11:38,030 --> 00:11:41,299 772 | Maybe it's your first time 773 | looking the storyboard. 774 | 775 | 158 776 | 00:11:41,368 --> 00:11:45,603 777 | At this level, we generally 778 | don't like added the file in, 779 | 780 | 159 781 | 00:11:45,671 --> 00:11:49,173 782 | in this level. 783 | It's a XML file, so 784 | 785 | 160 786 | 00:11:49,242 --> 00:11:54,511 787 | it's super complicated. After 788 | you've confirmed that this is 789 | 790 | 161 791 | 00:11:54,580 --> 00:11:58,817 792 | the change you want, you would 793 | enter the commit message here. 794 | 795 | 162 796 | 00:12:00,420 --> 00:12:07,558 797 | Added a button and 798 | a print. Notice that 799 | 800 | 163 801 | 00:12:07,626 --> 00:12:12,096 802 | there's also a Push to remote 803 | button here. But we don't 804 | 805 | 164 806 | 00:12:12,165 --> 00:12:16,767 807 | have a remote now because the 808 | repository only lives locally. 809 | 810 | 165 811 | 00:12:16,836 --> 00:12:19,937 812 | We don't have a remote 813 | repository in the GitHub. 814 | 815 | 166 816 | 00:12:20,006 --> 00:12:25,542 817 | If we have the remote origin, 818 | we can push also to remote. 819 | 820 | 167 821 | 00:12:25,611 --> 00:12:28,879 822 | And I will show you how to add 823 | the remote origin in a second. 824 | 825 | 168 826 | 00:12:28,948 --> 00:12:34,418 827 | So now let's just 828 | commit the files. So 829 | 830 | 169 831 | 00:12:34,487 --> 00:12:37,354 832 | once I do that, 833 | the M disappeared. And 834 | 835 | 170 836 | 00:12:37,423 --> 00:12:41,659 837 | let's go back to 838 | the Source Control Panel. 839 | 840 | 171 841 | 00:12:41,727 --> 00:12:46,764 842 | Look, here's the commit I just 843 | made. And you can inspect 844 | 845 | 172 846 | 00:12:46,833 --> 00:12:51,503 847 | it by clicking it and then 848 | select the button here. And 849 | 850 | 173 851 | 00:12:51,571 --> 00:12:57,007 852 | it shows the author, 853 | the date, the branches, 854 | 855 | 174 856 | 00:12:57,076 --> 00:13:02,079 857 | and also the files. If you 858 | want to inspect the changes, 859 | 860 | 175 861 | 00:13:02,148 --> 00:13:07,051 862 | you can actually click 863 | on the Assistant Editor. 864 | 865 | 176 866 | 00:13:07,119 --> 00:13:10,922 867 | I want my Assistant Editor 868 | on the bottom. And 869 | 870 | 177 871 | 00:13:10,991 --> 00:13:16,427 872 | then when I click the file, 873 | it actually 874 | 875 | 178 876 | 00:13:16,496 --> 00:13:21,232 877 | displays the changes side by 878 | side. You can easily see what 879 | 880 | 179 881 | 00:13:21,301 --> 00:13:26,237 882 | files you've changed in 883 | this specific commit. 884 | 885 | 180 886 | 00:13:32,112 --> 00:13:37,816 887 | And let's make more 888 | changes here, like print, 889 | 890 | 181 891 | 00:13:40,086 --> 00:13:43,621 892 | hello CS193p. 893 | 894 | 182 895 | 00:13:47,393 --> 00:13:51,829 896 | And over to Source Control 897 | button here, I can actually 898 | 899 | 183 900 | 00:13:51,897 --> 00:13:56,734 901 | discard all the changes 902 | in my current repository. 903 | 904 | 184 905 | 00:13:56,802 --> 00:14:01,705 906 | That basically roll back 907 | to the latest commit. But 908 | 909 | 185 910 | 00:14:01,774 --> 00:14:07,544 911 | I will show you how to revert 912 | to several commits ago. 913 | 914 | 186 915 | 00:14:07,613 --> 00:14:11,315 916 | So let's add this 917 | commit first. 918 | 919 | 187 920 | 00:14:11,383 --> 00:14:17,087 921 | Add an, another print. 922 | 923 | 188 924 | 00:14:17,156 --> 00:14:20,625 925 | But we should have 926 | successfully committed because 927 | 928 | 189 929 | 00:14:20,693 --> 00:14:25,095 930 | there's no M over the 931 | ViewController. And say, for 932 | 933 | 190 934 | 00:14:25,164 --> 00:14:30,534 935 | this specific file, I want to 936 | roll back to two commits ago. 937 | 938 | 191 939 | 00:14:30,603 --> 00:14:36,073 940 | I can open this 941 | Source Control button. 942 | 943 | 192 944 | 00:14:36,142 --> 00:14:40,812 945 | And then it's a side by side 946 | comparison between your 947 | 948 | 193 949 | 00:14:40,880 --> 00:14:45,250 950 | local revision and 951 | your commits. So 952 | 953 | 194 954 | 00:14:47,153 --> 00:14:52,990 955 | if I select the commit, 956 | two commits ago, 957 | 958 | 195 959 | 00:14:53,058 --> 00:14:58,495 960 | I can see all my changes. 961 | And I can click on the button 962 | 963 | 196 964 | 00:14:58,564 --> 00:15:03,368 965 | here, if I want to 966 | discard all the changes. 967 | 968 | 197 969 | 00:15:05,204 --> 00:15:10,641 970 | Revert, so 971 | now my local repository 972 | 973 | 198 974 | 00:15:10,710 --> 00:15:15,647 975 | have reverted those changes. 976 | 977 | 199 978 | 00:15:18,584 --> 00:15:25,023 979 | That's commit. Revert. 980 | 981 | 200 982 | 00:15:29,528 --> 00:15:31,495 983 | Like I just mentioned, 984 | 985 | 201 986 | 00:15:31,564 --> 00:15:35,833 987 | all the code now lives 988 | in my local repository, 989 | 990 | 202 991 | 00:15:35,901 --> 00:15:40,971 992 | so there's no way I can share 993 | it to my teammate or work 994 | 995 | 203 996 | 00:15:41,040 --> 00:15:46,076 997 | on the other workstation. And 998 | also if I just lost my laptop, 999 | 1000 | 204 1001 | 00:15:46,145 --> 00:15:49,213 1002 | everything will be gone. 1003 | You certainly don't want that. 1004 | 1005 | 205 1006 | 00:15:49,282 --> 00:15:54,218 1007 | So let's see like how to 1008 | add a remote. Origin for 1009 | 1010 | 206 1011 | 00:15:54,286 --> 00:15:58,322 1012 | this GitTutorial repo. 1013 | And it's super simple here, 1014 | 1015 | 207 1016 | 00:15:58,391 --> 00:16:02,727 1017 | you just click on the Remote, 1018 | and right-click. 1019 | 1020 | 208 1021 | 00:16:02,796 --> 00:16:06,464 1022 | There's a Create GitTutorial 1023 | Remote on GitHub. 1024 | 1025 | 209 1026 | 00:16:08,668 --> 00:16:11,435 1027 | And it allows you 1028 | to select public or 1029 | 1030 | 210 1031 | 00:16:11,504 --> 00:16:15,939 1032 | private repository. So since 1033 | I'm using my Stanford account, 1034 | 1035 | 211 1036 | 00:16:16,008 --> 00:16:18,543 1037 | I can get the free 1038 | private repo. 1039 | 1040 | 212 1041 | 00:16:27,086 --> 00:16:30,788 1042 | Okay, now we have 1043 | a remote origin, and 1044 | 1045 | 213 1046 | 00:16:30,856 --> 00:16:33,724 1047 | let's take a look. So 1048 | 1049 | 214 1050 | 00:16:33,792 --> 00:16:41,198 1051 | here's my 1052 | Stanford GitHub account. 1053 | 1054 | 215 1055 | 00:16:41,267 --> 00:16:45,603 1056 | And there's a GitTutorial 1057 | repository we just created. 1058 | 1059 | 216 1060 | 00:16:47,507 --> 00:16:51,042 1061 | And it has all the files 1062 | we've modified. 1063 | 1064 | 217 1065 | 00:16:54,613 --> 00:16:59,750 1066 | And if you want to work 1067 | in the other workstation, 1068 | 1069 | 218 1070 | 00:16:59,819 --> 00:17:04,989 1071 | you can just clone or download 1072 | and open in Xcode and/or copy 1073 | 1074 | 219 1075 | 00:17:05,058 --> 00:17:10,427 1076 | the address. So before I 1077 | show you how to clone, 1078 | 1079 | 220 1080 | 00:17:10,496 --> 00:17:14,531 1081 | let me show you how to add 1082 | the collaborator. It's super 1083 | 1084 | 221 1085 | 00:17:14,600 --> 00:17:17,668 1086 | useful if you want to work 1087 | with the other teammate. So 1088 | 1089 | 222 1090 | 00:17:17,737 --> 00:17:22,473 1091 | for this specific repository, 1092 | you go to Setting, 1093 | 1094 | 223 1095 | 00:17:23,509 --> 00:17:26,177 1096 | and hit Collaborators. 1097 | 1098 | 224 1099 | 00:17:26,245 --> 00:17:31,282 1100 | And basically, you need to 1101 | know your friend's GitHub ID, 1102 | 1103 | 225 1104 | 00:17:31,350 --> 00:17:34,452 1105 | and you just type it here. 1106 | For demonstration, 1107 | 1108 | 226 1109 | 00:17:34,521 --> 00:17:39,857 1110 | I will add my personal 1111 | account here. And 1112 | 1113 | 227 1114 | 00:17:39,926 --> 00:17:43,761 1115 | GitHub will you send an email 1116 | to your friend and, or 1117 | 1118 | 228 1119 | 00:17:43,830 --> 00:17:46,596 1120 | you can just share 1121 | this invite link. 1122 | 1123 | 229 1124 | 00:17:46,665 --> 00:17:51,502 1125 | Let me copy it here, and then 1126 | sign into my personal account. 1127 | 1128 | 230 1129 | 00:18:05,084 --> 00:18:10,788 1130 | So I click on this link And 1131 | 1132 | 231 1133 | 00:18:10,857 --> 00:18:15,392 1134 | it says that you are invited 1135 | to collaborate. So 1136 | 1137 | 232 1138 | 00:18:15,461 --> 00:18:22,366 1139 | I can accept the invitation. 1140 | Now, 1141 | 1142 | 233 1143 | 00:18:22,434 --> 00:18:28,339 1144 | I have the push access to 1145 | this private repository. 1146 | 1147 | 234 1148 | 00:18:32,278 --> 00:18:36,313 1149 | So another way to create 1150 | the repo is by cloning 1151 | 1152 | 235 1153 | 00:18:36,382 --> 00:18:40,718 1154 | the existing repo 1155 | from the GitHub. Say, 1156 | 1157 | 236 1158 | 00:18:40,787 --> 00:18:45,089 1159 | I have a Concentration 1160 | private repo here. 1161 | 1162 | 237 1163 | 00:18:46,593 --> 00:18:50,327 1164 | And I want to download 1165 | it to my local machine. 1166 | 1167 | 238 1168 | 00:18:50,396 --> 00:18:55,066 1169 | I can just hit Open in Xcode, 1170 | and Yes. 1171 | 1172 | 239 1173 | 00:18:58,070 --> 00:19:02,540 1174 | So all the code were 1175 | downloaded by Xcode. And 1176 | 1177 | 240 1178 | 00:19:02,608 --> 00:19:07,411 1179 | the other way to do it 1180 | is save this address. 1181 | 1182 | 241 1183 | 00:19:07,479 --> 00:19:11,782 1184 | And then, 1185 | 1186 | 242 1187 | 00:19:11,851 --> 00:19:15,619 1188 | in our Xcode welcome page, 1189 | 1190 | 243 1191 | 00:19:15,688 --> 00:19:18,589 1192 | you can select this Clone 1193 | an existing project. 1194 | 1195 | 244 1196 | 00:19:22,261 --> 00:19:29,834 1197 | You can paste in the address, 1198 | and then just clone. 1199 | 1200 | 245 1201 | 00:19:37,409 --> 00:19:39,610 1202 | So Xcode will do 1203 | the exact same thing. 1204 | 1205 | 246 1206 | 00:19:39,678 --> 00:19:42,880 1207 | It's just copying all 1208 | the files from remote. 1209 | 1210 | 247 1211 | 00:19:42,948 --> 00:19:47,585 1212 | The good thing is that in 1213 | the source control panel here, 1214 | 1215 | 248 1216 | 00:19:47,653 --> 00:19:50,254 1217 | you can actually get all 1218 | the code changes for 1219 | 1220 | 249 1221 | 00:19:50,322 --> 00:19:54,258 1222 | the repository. And 1223 | you can also like inspect all 1224 | 1225 | 250 1226 | 00:19:54,327 --> 00:19:59,229 1227 | the changes you've made. 1228 | So for 1229 | 1230 | 251 1231 | 00:19:59,298 --> 00:20:03,968 1232 | this specific repo, actually, 1233 | the master is a fully 1234 | 1235 | 252 1236 | 00:20:04,036 --> 00:20:08,372 1237 | functional version. The, I 1238 | want to like work on the other 1239 | 1240 | 253 1241 | 00:20:08,440 --> 00:20:12,276 1242 | new features that may be, 1243 | I think, is a little risky. So 1244 | 1245 | 254 1246 | 00:20:12,345 --> 00:20:18,749 1247 | I, I can branch from master 1248 | by right-click here. 1249 | 1250 | 255 1251 | 00:20:18,817 --> 00:20:23,688 1252 | And I will call my new branch 1253 | test because I don't have 1254 | 1255 | 256 1256 | 00:20:23,756 --> 00:20:29,092 1257 | better names. 1258 | So my current epository is set 1259 | 1260 | 257 1261 | 00:20:29,161 --> 00:20:33,598 1262 | to test. Now, it has the same 1263 | copy of code as the master. 1264 | 1265 | 258 1266 | 00:20:35,234 --> 00:20:39,870 1267 | Let's work on some 1268 | risky new features. 1269 | 1270 | 259 1271 | 00:20:39,939 --> 00:20:45,542 1272 | So that's to change the color 1273 | of the button. Maybe I 1274 | 1275 | 260 1276 | 00:20:45,611 --> 00:20:49,914 1277 | think blue is too ugly. 1278 | I want to change it to red. 1279 | 1280 | 261 1281 | 00:20:55,287 --> 00:20:57,221 1282 | And I commit this change. 1283 | 1284 | 262 1285 | 00:21:03,395 --> 00:21:06,430 1286 | Notice that because we 1287 | have a remote origin, 1288 | 1289 | 263 1290 | 00:21:06,499 --> 00:21:09,967 1291 | we can actually select 1292 | Push to remote. And 1293 | 1294 | 264 1295 | 00:21:10,035 --> 00:21:14,404 1296 | because the test branch only 1297 | lives locally in my machine, 1298 | 1299 | 265 1300 | 00:21:14,473 --> 00:21:18,475 1301 | actually Xcode can create 1302 | that remote origin test for 1303 | 1304 | 266 1305 | 00:21:18,544 --> 00:21:23,481 1306 | you. So 1307 | we can commit and push. 1308 | 1309 | 267 1310 | 00:21:30,990 --> 00:21:36,493 1311 | So in my current test branch, 1312 | I have this changed. But 1313 | 1314 | 268 1315 | 00:21:36,562 --> 00:21:42,966 1316 | my master branch 1317 | is not affected. 1318 | 1319 | 269 1320 | 00:21:43,035 --> 00:21:46,570 1321 | So, if you want to switch 1322 | back to the master, 1323 | 1324 | 270 1325 | 00:21:46,638 --> 00:21:51,008 1326 | you can right-click on 1327 | master and select Checkout. 1328 | 1329 | 271 1330 | 00:21:55,381 --> 00:21:58,815 1331 | Now my current branch 1332 | is master. And when 1333 | 1334 | 272 1335 | 00:21:58,884 --> 00:22:02,953 1336 | I go back to the storyboard, 1337 | the button is still blue. 1338 | 1339 | 273 1340 | 00:22:06,325 --> 00:22:10,794 1341 | Now say, you've fully tested 1342 | your code, and you're saying 1343 | 1344 | 274 1345 | 00:22:10,863 --> 00:22:15,332 1346 | that the button should be red 1347 | instead of blue in the master. 1348 | 1349 | 275 1350 | 00:22:15,401 --> 00:22:17,634 1351 | You can right-click here, and 1352 | 1353 | 276 1354 | 00:22:17,703 --> 00:22:20,404 1355 | then select Merge 1356 | test into master. 1357 | 1358 | 277 1359 | 00:22:26,111 --> 00:22:30,214 1360 | The version editor is like for 1361 | you to see whether this merge 1362 | 1363 | 278 1364 | 00:22:30,283 --> 00:22:36,553 1365 | is what you want. 1366 | Another thing is that, 1367 | 1368 | 279 1369 | 00:22:36,622 --> 00:22:41,691 1370 | because the storyboard is the 1371 | XML file, you would never want 1372 | 1373 | 280 1374 | 00:22:41,760 --> 00:22:46,330 1375 | to merge the same storyboard 1376 | with the other teammates. 1377 | 1378 | 281 1379 | 00:22:46,399 --> 00:22:49,466 1380 | You can work on different 1381 | storyboards, but 1382 | 1383 | 282 1384 | 00:22:49,535 --> 00:22:54,104 1385 | you would never like want 1386 | to merge the change in 1387 | 1388 | 283 1389 | 00:22:54,173 --> 00:22:59,242 1390 | the same storyboard, because 1391 | that's really, really painful. 1392 | 1393 | 284 1394 | 00:22:59,311 --> 00:23:04,582 1395 | Now we are at the master, 1396 | and we also have the Changed 1397 | 1398 | 285 1399 | 00:23:04,650 --> 00:23:10,054 1400 | button color here. And when 1401 | I go back to the storyboard, 1402 | 1403 | 286 1404 | 00:23:13,425 --> 00:23:17,895 1405 | The button is now red. 1406 | So we've successfully merged 1407 | 1408 | 287 1409 | 00:23:17,963 --> 00:23:23,200 1410 | the change. And 1411 | 1412 | 288 1413 | 00:23:23,269 --> 00:23:27,204 1414 | notice that our current 1415 | master is ahead 1416 | 1417 | 289 1418 | 00:23:27,272 --> 00:23:31,909 1419 | of the original master. 1420 | So another way to push to 1421 | 1422 | 290 1423 | 00:23:31,977 --> 00:23:36,580 1424 | the origin is to click 1425 | Source Control > Push. 1426 | 1427 | 291 1428 | 00:23:44,824 --> 00:23:48,993 1429 | Now all my notes are at 1430 | the same snapshot. 1431 | 1432 | 292 1433 | 00:23:51,364 --> 00:23:54,264 1434 | Another cool thing I 1435 | want to show you is that, 1436 | 1437 | 293 1438 | 00:23:54,333 --> 00:23:57,968 1439 | they make it really easy 1440 | if you want to inspect your 1441 | 1442 | 294 1443 | 00:23:58,036 --> 00:24:02,706 1444 | commits. Like I have 1445 | some commit for button. 1446 | 1447 | 295 1448 | 00:24:02,775 --> 00:24:06,577 1449 | It will show all the commit 1450 | message that should, 1451 | 1452 | 296 1453 | 00:24:06,646 --> 00:24:12,148 1454 | has button in it. And 1455 | you can also filter by author, 1456 | 1457 | 297 1458 | 00:24:12,217 --> 00:24:15,719 1459 | like author is junjie. And 1460 | 1461 | 298 1462 | 00:24:15,788 --> 00:24:20,690 1463 | you can also search last 1464 | 24 hours, last 30 days. 1465 | 1466 | 299 1467 | 00:24:20,759 --> 00:24:24,795 1468 | It's really helpful if you 1469 | want to search your change. 1470 | 1471 | 300 1472 | 00:24:27,166 --> 00:24:32,969 1473 | So that's basically all for 1474 | our demo. 1475 | 1476 | 301 1477 | 00:24:33,038 --> 00:24:38,809 1478 | Do you have any questions? No, 1479 | 1480 | 302 1481 | 00:24:38,877 --> 00:24:44,014 1482 | okay, so that's it for today. 1483 | Thank you for coming, and 1484 | 1485 | 303 1486 | 00:24:44,083 --> 00:24:47,784 1487 | good luck on your assignments. 1488 | >> For more, 1489 | 1490 | 304 1491 | 00:24:47,853 --> 00:24:56,359 1492 | please visit us 1493 | at stanford.edu. 1494 | 1495 | -------------------------------------------------------------------------------- /subtitles/Friday Session 2. Github and Source Control Workflow.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,401 --> 00:00:04,803 3 | 本字幕由志愿者义务贡献,采用许可协议 4 | 知识共享 署名-非商业性使用-相同方式共享 3.0 美国 5 | 6 | 2 7 | 00:00:04,872 --> 00:00:10,008 8 | Stanford University. >> Welcome everyone to 9 | >> 斯坦福大学 >> 欢迎大家来到 10 | 11 | 3 12 | 00:00:10,077 --> 00:00:14,613 13 | our Friday section of CS193P. I'm Junjie, one of your TAs. 14 | CS193P 的周五课程,我是教师助理 Junjie 15 | 16 | 4 17 | 00:00:14,682 --> 00:00:18,249 18 | And today, I'm gonna talk about the GitHub and 19 | 20 | 5 21 | 00:00:18,318 --> 00:00:23,221 22 | the source control workflow in Xcode 9. So, 23 | 24 | 6 25 | 00:00:23,290 --> 00:00:28,126 26 | what is source control? Like have you used like 27 | 28 | 7 29 | 00:00:28,195 --> 00:00:31,029 30 | some source control systems like GitHub? 31 | 32 | 8 33 | 00:00:31,098 --> 00:00:36,067 34 | Yeah, so as a software developer, you will like, 35 | 36 | 9 37 | 00:00:36,136 --> 00:00:40,672 38 | almost like it's a necessary skill set for 39 | 40 | 10 41 | 00:00:40,741 --> 00:00:43,442 42 | you to learn how to use source control systems. 43 | 44 | 11 45 | 00:00:43,510 --> 00:00:46,611 46 | Like big companies like Facebook and Google, 47 | 48 | 12 49 | 00:00:46,680 --> 00:00:50,381 50 | they all have their own source control systems. And 51 | 52 | 13 53 | 00:00:50,450 --> 00:00:54,385 54 | it's very important for you to master those skills before you 55 | 56 | 14 57 | 00:00:54,454 --> 00:00:58,223 58 | really go into the industry. So what is source control? 59 | 60 | 15 61 | 00:00:58,291 --> 00:01:03,328 62 | Why should we matter? Why should we care about it? 63 | 64 | 16 65 | 00:01:03,397 --> 00:01:07,933 66 | It allows you to track your code changes over time. 67 | 68 | 17 69 | 00:01:08,002 --> 00:01:11,370 70 | You can revert your files back to a previous state. 71 | 72 | 18 73 | 00:01:11,438 --> 00:01:16,107 74 | You can compare different versions of code side by side. 75 | 76 | 19 77 | 00:01:16,176 --> 00:01:18,476 78 | And it also makes it a lot easier for 79 | 80 | 20 81 | 00:01:18,545 --> 00:01:22,481 82 | you to work with other teammates. And 83 | 84 | 21 85 | 00:01:22,549 --> 00:01:26,884 86 | like when bugs happen, it's much easier to take it down. 87 | 88 | 22 89 | 00:01:26,953 --> 00:01:31,556 90 | Today, our topic is one of the biggest source control system 91 | 92 | 23 93 | 00:01:31,625 --> 00:01:36,361 94 | in the world, and it's built right into Xcode 9. 95 | 96 | 24 97 | 00:01:36,430 --> 00:01:39,697 98 | Xcode 9 has done a lot of great things to integrate 99 | 100 | 25 101 | 00:01:39,766 --> 00:01:44,670 102 | GitHub to make it very easy to use. So 103 | 104 | 26 105 | 00:01:44,738 --> 00:01:49,808 106 | I'm gonna try to demo you some of the basics in Xcode 9, 107 | 108 | 27 109 | 00:01:49,877 --> 00:01:54,446 110 | how to use GitHub. Before that, you should register 111 | 112 | 28 113 | 00:01:54,515 --> 00:01:59,284 114 | an account in github.com. The repository, 115 | 116 | 29 117 | 00:01:59,353 --> 00:02:04,690 118 | the public repository or a repo, is free. And, a repo 119 | 120 | 30 121 | 00:02:04,758 --> 00:02:08,693 122 | is just like a code directory for you to store the code. 123 | 124 | 31 125 | 00:02:08,762 --> 00:02:12,930 126 | And if you register using your Stanford email account, 127 | 128 | 32 129 | 00:02:12,999 --> 00:02:17,068 130 | you can get the private repository for free. I highly, 131 | 132 | 33 133 | 00:02:17,137 --> 00:02:21,072 134 | highly encourage you to use a private repo to manage 135 | 136 | 34 137 | 00:02:21,141 --> 00:02:24,342 138 | all your assignments, all your cost projects. 139 | 140 | 35 141 | 00:02:24,411 --> 00:02:28,547 142 | And it's much easier for you to collaborate with your 143 | 144 | 36 145 | 00:02:28,616 --> 00:02:31,716 146 | teammates, and in- >> Remind people not to make 147 | 148 | 37 149 | 00:02:31,785 --> 00:02:33,284 150 | it public, though. >> Yeah, yeah. 151 | 152 | 38 153 | 00:02:33,353 --> 00:02:34,252 154 | >> [CROSSTALK] the public 155 | 156 | 39 157 | 00:02:34,320 --> 00:02:35,020 158 | to private. >> So 159 | 160 | 40 161 | 00:02:35,088 --> 00:02:39,658 162 | that's why you wanna register using your Stanford email. 163 | 164 | 41 165 | 00:02:39,727 --> 00:02:41,926 166 | You would never like up, upload 167 | 168 | 42 169 | 00:02:41,995 --> 00:02:46,164 170 | your assignments onto GitHub using a public repository cuz 171 | 172 | 43 173 | 00:02:46,233 --> 00:02:50,268 174 | like you don't know who will just download all the code and 175 | 176 | 44 177 | 00:02:50,337 --> 00:02:55,040 178 | copy, copy out of no place. So last Friday's session, 179 | 180 | 45 181 | 00:02:55,108 --> 00:02:59,344 182 | Jason also mentioned that there's a Pro Git ebook. 183 | 184 | 46 185 | 00:02:59,413 --> 00:03:03,181 186 | That's really great for you to learn some of the basics of 187 | 188 | 47 189 | 00:03:03,250 --> 00:03:06,584 190 | GitHub and the source control, some of the concepts. 191 | 192 | 48 193 | 00:03:06,653 --> 00:03:09,754 194 | It's a really good starting point for 195 | 196 | 49 197 | 00:03:09,823 --> 00:03:14,259 198 | you to learn those skills. I post a link here and 199 | 200 | 50 201 | 00:03:14,327 --> 00:03:19,697 202 | you can like check it out if you want. So there are three 203 | 204 | 51 205 | 00:03:19,766 --> 00:03:24,069 206 | main components in like Xcode 9 Source Control Workflow, and 207 | 208 | 52 209 | 00:03:24,138 --> 00:03:27,839 210 | I will go through each of them briefly. 211 | 212 | 53 213 | 00:03:27,908 --> 00:03:32,410 214 | The first one is pulling and pushing. For pulling and 215 | 216 | 54 217 | 00:03:32,479 --> 00:03:35,647 218 | pushing is like dealing with your local changes and 219 | 220 | 55 221 | 00:03:35,716 --> 00:03:39,518 222 | the changes in the remote repository. So, for 223 | 224 | 56 225 | 00:03:39,586 --> 00:03:40,551 226 | clone and pull, 227 | 228 | 57 229 | 00:03:40,620 --> 00:03:44,522 230 | you can download all the code from the remote repository to 231 | 232 | 58 233 | 00:03:44,591 --> 00:03:48,860 234 | your own laptop. Xcode 9 actually make it really, 235 | 236 | 59 237 | 00:03:48,929 --> 00:03:53,298 238 | really easy to download a repository. You just click 239 | 240 | 60 241 | 00:03:53,366 --> 00:03:57,502 242 | the Clone and Download button and then open it in Xcode. 243 | 244 | 61 245 | 00:03:57,570 --> 00:04:00,571 246 | And Xcode will download all the changes for 247 | 248 | 62 249 | 00:04:00,640 --> 00:04:02,573 250 | you. It's really nice. And 251 | 252 | 63 253 | 00:04:02,642 --> 00:04:07,112 254 | I will show you how to do that in a demo. And another way to 255 | 256 | 64 257 | 00:04:07,181 --> 00:04:12,650 258 | do it is to copy out this GitHub repository address. 259 | 260 | 65 261 | 00:04:12,719 --> 00:04:17,221 262 | And I will also show you how to do that in a demo. For 263 | 264 | 66 265 | 00:04:17,290 --> 00:04:20,925 266 | the push, it's like you make some local changes, 267 | 268 | 67 269 | 00:04:20,994 --> 00:04:24,563 270 | you, and you want to push to the remote so that you can 271 | 272 | 68 273 | 00:04:24,631 --> 00:04:30,469 274 | edit it in another machine or share it to your friends. 275 | 276 | 69 277 | 00:04:32,606 --> 00:04:37,509 278 | So, every batch of code changes is called a commit. 279 | 280 | 70 281 | 00:04:37,578 --> 00:04:41,679 282 | The commit it's like a snapshot of all the code 283 | 284 | 71 285 | 00:04:41,748 --> 00:04:46,784 286 | changes and also the description message. 287 | 288 | 72 289 | 00:04:46,853 --> 00:04:51,423 290 | It has the author, description message, and also the time. 291 | 292 | 73 293 | 00:04:51,491 --> 00:04:55,927 294 | I highly encourage you to make small commits instead of 295 | 296 | 74 297 | 00:04:55,996 --> 00:05:00,732 298 | making a really big commit, like only one commit for 299 | 300 | 75 301 | 00:05:00,801 --> 00:05:05,303 302 | the repository. That's like the final finish one. 303 | 304 | 76 305 | 00:05:05,372 --> 00:05:10,875 306 | Because making small commits makes it much easier to debug. 307 | 308 | 77 309 | 00:05:10,944 --> 00:05:14,279 310 | The rule of thumb is one feature at a time, and 311 | 312 | 78 313 | 00:05:14,348 --> 00:05:17,449 314 | each commit should be self-contained. 315 | 316 | 79 317 | 00:05:17,517 --> 00:05:21,653 318 | When bugs happen, you can easily revert to the previous 319 | 320 | 80 321 | 00:05:21,721 --> 00:05:27,225 322 | state without affecting the other files. So 323 | 324 | 81 325 | 00:05:27,293 --> 00:05:33,364 326 | here's what the commit panel looks like in Xcode 9. 327 | 328 | 82 329 | 00:05:33,433 --> 00:05:37,569 330 | You get the commit message here and also the author, 331 | 332 | 83 333 | 00:05:37,638 --> 00:05:40,304 334 | the branches, the tags and remotes. 335 | 336 | 84 337 | 00:05:40,373 --> 00:05:44,409 338 | We will go through these concepts in a demo. And 339 | 340 | 85 341 | 00:05:44,477 --> 00:05:48,113 342 | here's the identifier, it is the SHA identifier for 343 | 344 | 86 345 | 00:05:48,181 --> 00:05:53,051 346 | this commit. The last 347 | 348 | 87 349 | 00:05:53,119 --> 00:05:57,221 350 | concept I'm introducing today is the branching. So 351 | 352 | 88 353 | 00:05:57,290 --> 00:06:04,061 354 | each little commits, one after one, is called a code branch. 355 | 356 | 89 357 | 00:06:04,130 --> 00:06:06,297 358 | In the GitHub repo, repository, 359 | 360 | 90 361 | 00:06:06,366 --> 00:06:10,435 362 | the most important one is the master branch. You would wanna 363 | 364 | 91 365 | 00:06:10,503 --> 00:06:13,772 366 | always keep your master branch clean, bug-free and 367 | 368 | 92 369 | 00:06:13,840 --> 00:06:18,710 370 | stable. And when you want to work on new features, 371 | 372 | 93 373 | 00:06:18,778 --> 00:06:23,347 374 | you would like to branch from the master. So 375 | 376 | 94 377 | 00:06:23,416 --> 00:06:28,119 378 | Xcode 9 is really easy for you to just right-click and 379 | 380 | 95 381 | 00:06:28,188 --> 00:06:32,523 382 | create a new branch. The new branch will have the same 383 | 384 | 96 385 | 00:06:32,592 --> 00:06:37,595 386 | code as the master. But when you keep developing your code, 387 | 388 | 97 389 | 00:06:37,664 --> 00:06:43,000 390 | it won't affect the master branch. And after you finish 391 | 392 | 98 393 | 00:06:43,069 --> 00:06:46,438 394 | developing all your features, you've unit tested your code, 395 | 396 | 99 397 | 00:06:46,507 --> 00:06:49,841 398 | you can merge it back to master branch. 399 | 400 | 100 401 | 00:06:49,910 --> 00:06:55,946 402 | I will show you how to do the branching in this demo. So, 403 | 404 | 101 405 | 00:06:56,015 --> 00:07:01,119 406 | any questions so far? No, 407 | 408 | 102 409 | 00:07:01,187 --> 00:07:06,925 410 | so let's go into the demo. So let's pull out Xcode. 411 | 412 | 103 413 | 00:07:08,628 --> 00:07:11,896 414 | So before we do the fancy things in Xcode, 415 | 416 | 104 417 | 00:07:11,964 --> 00:07:15,833 418 | we would like to set up the GitHub account in Xcode. So 419 | 420 | 105 421 | 00:07:15,902 --> 00:07:21,372 422 | the way to do it as click on Xcode > Preferences 423 | 424 | 106 425 | 00:07:21,441 --> 00:07:26,077 426 | > Accounts. When you select the Add button, 427 | 428 | 107 429 | 00:07:26,145 --> 00:07:30,548 430 | you can add GitHub Enterprise. Enterprise is like, 431 | 432 | 108 433 | 00:07:30,617 --> 00:07:34,419 434 | when you work for a company, they will have the company 435 | 436 | 109 437 | 00:07:34,488 --> 00:07:38,590 438 | GitHub account. So I'm gonna select the GitHub. 439 | 440 | 110 441 | 00:07:38,658 --> 00:07:47,165 442 | And I'm using my Stanford email address. So 443 | 444 | 111 445 | 00:07:47,234 --> 00:07:51,369 446 | we've already signed in. And before we jump into the code, 447 | 448 | 112 449 | 00:07:51,437 --> 00:07:55,106 450 | we would wanna make sure the Source Control is setting up 451 | 452 | 113 453 | 00:07:55,175 --> 00:08:00,211 454 | correctly. So, these options is like, whether you 455 | 456 | 114 457 | 00:08:00,279 --> 00:08:05,850 458 | want Xcode to download the remote changes for you. 459 | 460 | 115 461 | 00:08:05,919 --> 00:08:11,322 462 | So that you won't need to pull the changes in command line. 463 | 464 | 116 465 | 00:08:11,391 --> 00:08:14,992 466 | And when you click on the Git button here, you can set up 467 | 468 | 117 469 | 00:08:15,061 --> 00:08:20,665 470 | some global ignored files. If you have used GitHub before, 471 | 472 | 118 473 | 00:08:20,734 --> 00:08:24,869 474 | you know that there's a gitignore file so 475 | 476 | 119 477 | 00:08:24,938 --> 00:08:31,041 478 | that your files won't be checked by the GitHub system. 479 | 480 | 120 481 | 00:08:31,110 --> 00:08:35,113 482 | So you can set up some global ignored files here. That means 483 | 484 | 121 485 | 00:08:35,181 --> 00:08:40,652 486 | like .D_Store files won't be checked by the GitHub. So 487 | 488 | 122 489 | 00:08:40,720 --> 00:08:45,790 490 | let's start by creating a new Xcode product. 491 | 492 | 123 493 | 00:08:49,529 --> 00:08:54,799 494 | Let's do Single View, and then GitTutorial. 495 | 496 | 124 497 | 00:08:59,305 --> 00:09:03,174 498 | And it's basically the same thing as we are doing when 499 | 500 | 125 501 | 00:09:03,243 --> 00:09:06,377 502 | creating the new project for our homework, 503 | 504 | 126 505 | 00:09:06,446 --> 00:09:10,815 506 | but the difference is that we wanna select this button. So 507 | 508 | 127 509 | 00:09:10,884 --> 00:09:13,951 510 | this is the mysterious Source Control button we never 511 | 512 | 128 513 | 00:09:14,020 --> 00:09:15,920 514 | talk about in class. 515 | 516 | 129 517 | 00:09:15,989 --> 00:09:20,591 518 | And this means that Xcode will initialize a Git repository 519 | 520 | 130 521 | 00:09:20,660 --> 00:09:25,297 522 | for you. So we would select this button for this section. 523 | 524 | 131 525 | 00:09:26,399 --> 00:09:31,436 526 | Hit Create, and then we would have 527 | 528 | 132 529 | 00:09:31,504 --> 00:09:36,408 530 | a Git repository, and 531 | 532 | 133 533 | 00:09:36,476 --> 00:09:43,582 534 | we can inspect the Source Control panel over here. 535 | 536 | 134 537 | 00:09:43,650 --> 00:09:47,485 538 | It's on the top left, and the second button. 539 | 540 | 135 541 | 00:09:50,056 --> 00:09:53,658 542 | It shows that we are currently at the master branch. And 543 | 544 | 136 545 | 00:09:53,726 --> 00:09:57,896 546 | the initial commit is just some free code given by Xcode 547 | 548 | 137 549 | 00:09:57,964 --> 00:10:02,166 550 | that create, initialize, and then push the code for 551 | 552 | 138 553 | 00:10:02,235 --> 00:10:07,539 554 | you. So, let's make some change. 555 | 556 | 139 557 | 00:10:09,076 --> 00:10:14,012 558 | Maybe I will delete this free code. And 559 | 560 | 140 561 | 00:10:14,080 --> 00:10:22,420 562 | then add a print line. 563 | 564 | 141 565 | 00:10:22,489 --> 00:10:27,525 566 | And once I've saved the file, there's an M appeared here. 567 | 568 | 142 569 | 00:10:27,594 --> 00:10:31,429 570 | That M stands for modified. Basically, it means that your 571 | 572 | 143 573 | 00:10:31,497 --> 00:10:37,268 574 | local repository have some uncommitted changes. And 575 | 576 | 144 577 | 00:10:37,337 --> 00:10:41,305 578 | that's also modified in storyboard. I want to drag our 579 | 580 | 145 581 | 00:10:41,374 --> 00:10:47,645 582 | button. And 583 | 584 | 146 585 | 00:10:47,714 --> 00:10:51,816 586 | put it in the middle. Okay, 587 | 588 | 147 589 | 00:10:51,885 --> 00:10:57,087 590 | let's save the change. So now I have made some change. 591 | 592 | 148 593 | 00:10:57,156 --> 00:11:00,658 594 | So we wanna commit those changes. 595 | 596 | 149 597 | 00:11:00,727 --> 00:11:03,828 598 | It's like clicking the Source Control here, and 599 | 600 | 150 601 | 00:11:03,897 --> 00:11:09,901 602 | then hit Commit. Then a Version Editor will appear. 603 | 604 | 151 605 | 00:11:09,970 --> 00:11:14,505 606 | And it's really nice because you can see your change 607 | 608 | 152 609 | 00:11:14,573 --> 00:11:19,110 610 | side by side by clicking the filename. And it shows that 611 | 612 | 153 613 | 00:11:19,179 --> 00:11:22,780 614 | you've added one line and you've deleted some code. 615 | 616 | 154 617 | 00:11:22,849 --> 00:11:26,851 618 | And if you click on the button in the middle, 619 | 620 | 155 621 | 00:11:26,919 --> 00:11:30,554 622 | you can actually don't commit this specific line or 623 | 624 | 156 625 | 00:11:30,623 --> 00:11:37,962 626 | discards the change. So, let's also look at the storyboard. 627 | 628 | 157 629 | 00:11:38,030 --> 00:11:41,299 630 | Maybe it's your first time looking the storyboard. 631 | 632 | 158 633 | 00:11:41,368 --> 00:11:45,603 634 | At this level, we generally don't like added the file in, 635 | 636 | 159 637 | 00:11:45,671 --> 00:11:49,173 638 | in this level. It's a XML file, so 639 | 640 | 160 641 | 00:11:49,242 --> 00:11:54,511 642 | it's super complicated. After you've confirmed that this is 643 | 644 | 161 645 | 00:11:54,580 --> 00:11:58,817 646 | the change you want, you would enter the commit message here. 647 | 648 | 162 649 | 00:12:00,420 --> 00:12:07,558 650 | Added a button and a print. Notice that 651 | 652 | 163 653 | 00:12:07,626 --> 00:12:12,096 654 | there's also a Push to remote button here. But we don't 655 | 656 | 164 657 | 00:12:12,165 --> 00:12:16,767 658 | have a remote now because the repository only lives locally. 659 | 660 | 165 661 | 00:12:16,836 --> 00:12:19,937 662 | We don't have a remote repository in the GitHub. 663 | 664 | 166 665 | 00:12:20,006 --> 00:12:25,542 666 | If we have the remote origin, we can push also to remote. 667 | 668 | 167 669 | 00:12:25,611 --> 00:12:28,879 670 | And I will show you how to add the remote origin in a second. 671 | 672 | 168 673 | 00:12:28,948 --> 00:12:34,418 674 | So now let's just commit the files. So 675 | 676 | 169 677 | 00:12:34,487 --> 00:12:37,354 678 | once I do that, the M disappeared. And 679 | 680 | 170 681 | 00:12:37,423 --> 00:12:41,659 682 | let's go back to the Source Control Panel. 683 | 684 | 171 685 | 00:12:41,727 --> 00:12:46,764 686 | Look, here's the commit I just made. And you can inspect 687 | 688 | 172 689 | 00:12:46,833 --> 00:12:51,503 690 | it by clicking it and then select the button here. And 691 | 692 | 173 693 | 00:12:51,571 --> 00:12:57,007 694 | it shows the author, the date, the branches, 695 | 696 | 174 697 | 00:12:57,076 --> 00:13:02,079 698 | and also the files. If you want to inspect the changes, 699 | 700 | 175 701 | 00:13:02,148 --> 00:13:07,051 702 | you can actually click on the Assistant Editor. 703 | 704 | 176 705 | 00:13:07,119 --> 00:13:10,922 706 | I want my Assistant Editor on the bottom. And 707 | 708 | 177 709 | 00:13:10,991 --> 00:13:16,427 710 | then when I click the file, it actually 711 | 712 | 178 713 | 00:13:16,496 --> 00:13:21,232 714 | displays the changes side by side. You can easily see what 715 | 716 | 179 717 | 00:13:21,301 --> 00:13:26,237 718 | files you've changed in this specific commit. 719 | 720 | 180 721 | 00:13:32,112 --> 00:13:37,816 722 | And let's make more changes here, like print, 723 | 724 | 181 725 | 00:13:40,086 --> 00:13:43,621 726 | hello CS193p. 727 | 728 | 182 729 | 00:13:47,393 --> 00:13:51,829 730 | And over to Source Control button here, I can actually 731 | 732 | 183 733 | 00:13:51,897 --> 00:13:56,734 734 | discard all the changes in my current repository. 735 | 736 | 184 737 | 00:13:56,802 --> 00:14:01,705 738 | That basically roll back to the latest commit. But 739 | 740 | 185 741 | 00:14:01,774 --> 00:14:07,544 742 | I will show you how to revert to several commits ago. 743 | 744 | 186 745 | 00:14:07,613 --> 00:14:11,315 746 | So let's add this commit first. 747 | 748 | 187 749 | 00:14:11,383 --> 00:14:17,087 750 | Add an, another print. 751 | 752 | 188 753 | 00:14:17,156 --> 00:14:20,625 754 | But we should have successfully committed because 755 | 756 | 189 757 | 00:14:20,693 --> 00:14:25,095 758 | there's no M over the ViewController. And say, for 759 | 760 | 190 761 | 00:14:25,164 --> 00:14:30,534 762 | this specific file, I want to roll back to two commits ago. 763 | 764 | 191 765 | 00:14:30,603 --> 00:14:36,073 766 | I can open this Source Control button. 767 | 768 | 192 769 | 00:14:36,142 --> 00:14:40,812 770 | And then it's a side by side comparison between your 771 | 772 | 193 773 | 00:14:40,880 --> 00:14:45,250 774 | local revision and your commits. So 775 | 776 | 194 777 | 00:14:47,153 --> 00:14:52,990 778 | if I select the commit, two commits ago, 779 | 780 | 195 781 | 00:14:53,058 --> 00:14:58,495 782 | I can see all my changes. And I can click on the button 783 | 784 | 196 785 | 00:14:58,564 --> 00:15:03,368 786 | here, if I want to discard all the changes. 787 | 788 | 197 789 | 00:15:05,204 --> 00:15:10,641 790 | Revert, so now my local repository 791 | 792 | 198 793 | 00:15:10,710 --> 00:15:15,647 794 | have reverted those changes. 795 | 796 | 199 797 | 00:15:18,584 --> 00:15:25,023 798 | That's commit. Revert. 799 | 800 | 200 801 | 00:15:29,528 --> 00:15:31,495 802 | Like I just mentioned, 803 | 804 | 201 805 | 00:15:31,564 --> 00:15:35,833 806 | all the code now lives in my local repository, 807 | 808 | 202 809 | 00:15:35,901 --> 00:15:40,971 810 | so there's no way I can share it to my teammate or work 811 | 812 | 203 813 | 00:15:41,040 --> 00:15:46,076 814 | on the other workstation. And also if I just lost my laptop, 815 | 816 | 204 817 | 00:15:46,145 --> 00:15:49,213 818 | everything will be gone. You certainly don't want that. 819 | 820 | 205 821 | 00:15:49,282 --> 00:15:54,218 822 | So let's see like how to add a remote. Origin for 823 | 824 | 206 825 | 00:15:54,286 --> 00:15:58,322 826 | this GitTutorial repo. And it's super simple here, 827 | 828 | 207 829 | 00:15:58,391 --> 00:16:02,727 830 | you just click on the Remote, and right-click. 831 | 832 | 208 833 | 00:16:02,796 --> 00:16:06,464 834 | There's a Create GitTutorial Remote on GitHub. 835 | 836 | 209 837 | 00:16:08,668 --> 00:16:11,435 838 | And it allows you to select public or 839 | 840 | 210 841 | 00:16:11,504 --> 00:16:15,939 842 | private repository. So since I'm using my Stanford account, 843 | 844 | 211 845 | 00:16:16,008 --> 00:16:18,543 846 | I can get the free private repo. 847 | 848 | 212 849 | 00:16:27,086 --> 00:16:30,788 850 | Okay, now we have a remote origin, and 851 | 852 | 213 853 | 00:16:30,856 --> 00:16:33,724 854 | let's take a look. So 855 | 856 | 214 857 | 00:16:33,792 --> 00:16:41,198 858 | here's my Stanford GitHub account. 859 | 860 | 215 861 | 00:16:41,267 --> 00:16:45,603 862 | And there's a GitTutorial repository we just created. 863 | 864 | 216 865 | 00:16:47,507 --> 00:16:51,042 866 | And it has all the files we've modified. 867 | 868 | 217 869 | 00:16:54,613 --> 00:16:59,750 870 | And if you want to work in the other workstation, 871 | 872 | 218 873 | 00:16:59,819 --> 00:17:04,989 874 | you can just clone or download and open in Xcode and/or copy 875 | 876 | 219 877 | 00:17:05,058 --> 00:17:10,427 878 | the address. So before I show you how to clone, 879 | 880 | 220 881 | 00:17:10,496 --> 00:17:14,531 882 | let me show you how to add the collaborator. It's super 883 | 884 | 221 885 | 00:17:14,600 --> 00:17:17,668 886 | useful if you want to work with the other teammate. So 887 | 888 | 222 889 | 00:17:17,737 --> 00:17:22,473 890 | for this specific repository, you go to Setting, 891 | 892 | 223 893 | 00:17:23,509 --> 00:17:26,177 894 | and hit Collaborators. 895 | 896 | 224 897 | 00:17:26,245 --> 00:17:31,282 898 | And basically, you need to know your friend's GitHub ID, 899 | 900 | 225 901 | 00:17:31,350 --> 00:17:34,452 902 | and you just type it here. For demonstration, 903 | 904 | 226 905 | 00:17:34,521 --> 00:17:39,857 906 | I will add my personal account here. And 907 | 908 | 227 909 | 00:17:39,926 --> 00:17:43,761 910 | GitHub will you send an email to your friend and, or 911 | 912 | 228 913 | 00:17:43,830 --> 00:17:46,596 914 | you can just share this invite link. 915 | 916 | 229 917 | 00:17:46,665 --> 00:17:51,502 918 | Let me copy it here, and then sign into my personal account. 919 | 920 | 230 921 | 00:18:05,084 --> 00:18:10,788 922 | So I click on this link And 923 | 924 | 231 925 | 00:18:10,857 --> 00:18:15,392 926 | it says that you are invited to collaborate. So 927 | 928 | 232 929 | 00:18:15,461 --> 00:18:22,366 930 | I can accept the invitation. Now, 931 | 932 | 233 933 | 00:18:22,434 --> 00:18:28,339 934 | I have the push access to this private repository. 935 | 936 | 234 937 | 00:18:32,278 --> 00:18:36,313 938 | So another way to create the repo is by cloning 939 | 940 | 235 941 | 00:18:36,382 --> 00:18:40,718 942 | the existing repo from the GitHub. Say, 943 | 944 | 236 945 | 00:18:40,787 --> 00:18:45,089 946 | I have a Concentration private repo here. 947 | 948 | 237 949 | 00:18:46,593 --> 00:18:50,327 950 | And I want to download it to my local machine. 951 | 952 | 238 953 | 00:18:50,396 --> 00:18:55,066 954 | I can just hit Open in Xcode, and Yes. 955 | 956 | 239 957 | 00:18:58,070 --> 00:19:02,540 958 | So all the code were downloaded by Xcode. And 959 | 960 | 240 961 | 00:19:02,608 --> 00:19:07,411 962 | the other way to do it is save this address. 963 | 964 | 241 965 | 00:19:07,479 --> 00:19:11,782 966 | And then, 967 | 968 | 242 969 | 00:19:11,851 --> 00:19:15,619 970 | in our Xcode welcome page, 971 | 972 | 243 973 | 00:19:15,688 --> 00:19:18,589 974 | you can select this Clone an existing project. 975 | 976 | 244 977 | 00:19:22,261 --> 00:19:29,834 978 | You can paste in the address, and then just clone. 979 | 980 | 245 981 | 00:19:37,409 --> 00:19:39,610 982 | So Xcode will do the exact same thing. 983 | 984 | 246 985 | 00:19:39,678 --> 00:19:42,880 986 | It's just copying all the files from remote. 987 | 988 | 247 989 | 00:19:42,948 --> 00:19:47,585 990 | The good thing is that in the source control panel here, 991 | 992 | 248 993 | 00:19:47,653 --> 00:19:50,254 994 | you can actually get all the code changes for 995 | 996 | 249 997 | 00:19:50,322 --> 00:19:54,258 998 | the repository. And you can also like inspect all 999 | 1000 | 250 1001 | 00:19:54,327 --> 00:19:59,229 1002 | the changes you've made. So for 1003 | 1004 | 251 1005 | 00:19:59,298 --> 00:20:03,968 1006 | this specific repo, actually, the master is a fully 1007 | 1008 | 252 1009 | 00:20:04,036 --> 00:20:08,372 1010 | functional version. The, I want to like work on the other 1011 | 1012 | 253 1013 | 00:20:08,440 --> 00:20:12,276 1014 | new features that may be, I think, is a little risky. So 1015 | 1016 | 254 1017 | 00:20:12,345 --> 00:20:18,749 1018 | I, I can branch from master by right-click here. 1019 | 1020 | 255 1021 | 00:20:18,817 --> 00:20:23,688 1022 | And I will call my new branch test because I don't have 1023 | 1024 | 256 1025 | 00:20:23,756 --> 00:20:29,092 1026 | better names. So my current epository is set 1027 | 1028 | 257 1029 | 00:20:29,161 --> 00:20:33,598 1030 | to test. Now, it has the same copy of code as the master. 1031 | 1032 | 258 1033 | 00:20:35,234 --> 00:20:39,870 1034 | Let's work on some risky new features. 1035 | 1036 | 259 1037 | 00:20:39,939 --> 00:20:45,542 1038 | So that's to change the color of the button. Maybe I 1039 | 1040 | 260 1041 | 00:20:45,611 --> 00:20:49,914 1042 | think blue is too ugly. I want to change it to red. 1043 | 1044 | 261 1045 | 00:20:55,287 --> 00:20:57,221 1046 | And I commit this change. 1047 | 1048 | 262 1049 | 00:21:03,395 --> 00:21:06,430 1050 | Notice that because we have a remote origin, 1051 | 1052 | 263 1053 | 00:21:06,499 --> 00:21:09,967 1054 | we can actually select Push to remote. And 1055 | 1056 | 264 1057 | 00:21:10,035 --> 00:21:14,404 1058 | because the test branch only lives locally in my machine, 1059 | 1060 | 265 1061 | 00:21:14,473 --> 00:21:18,475 1062 | actually Xcode can create that remote origin test for 1063 | 1064 | 266 1065 | 00:21:18,544 --> 00:21:23,481 1066 | you. So we can commit and push. 1067 | 1068 | 267 1069 | 00:21:30,990 --> 00:21:36,493 1070 | So in my current test branch, I have this changed. But 1071 | 1072 | 268 1073 | 00:21:36,562 --> 00:21:42,966 1074 | my master branch is not affected. 1075 | 1076 | 269 1077 | 00:21:43,035 --> 00:21:46,570 1078 | So, if you want to switch back to the master, 1079 | 1080 | 270 1081 | 00:21:46,638 --> 00:21:51,008 1082 | you can right-click on master and select Checkout. 1083 | 1084 | 271 1085 | 00:21:55,381 --> 00:21:58,815 1086 | Now my current branch is master. And when 1087 | 1088 | 272 1089 | 00:21:58,884 --> 00:22:02,953 1090 | I go back to the storyboard, the button is still blue. 1091 | 1092 | 273 1093 | 00:22:06,325 --> 00:22:10,794 1094 | Now say, you've fully tested your code, and you're saying 1095 | 1096 | 274 1097 | 00:22:10,863 --> 00:22:15,332 1098 | that the button should be red instead of blue in the master. 1099 | 1100 | 275 1101 | 00:22:15,401 --> 00:22:17,634 1102 | You can right-click here, and 1103 | 1104 | 276 1105 | 00:22:17,703 --> 00:22:20,404 1106 | then select Merge test into master. 1107 | 1108 | 277 1109 | 00:22:26,111 --> 00:22:30,214 1110 | The version editor is like for you to see whether this merge 1111 | 1112 | 278 1113 | 00:22:30,283 --> 00:22:36,553 1114 | is what you want. Another thing is that, 1115 | 1116 | 279 1117 | 00:22:36,622 --> 00:22:41,691 1118 | because the storyboard is the XML file, you would never want 1119 | 1120 | 280 1121 | 00:22:41,760 --> 00:22:46,330 1122 | to merge the same storyboard with the other teammates. 1123 | 1124 | 281 1125 | 00:22:46,399 --> 00:22:49,466 1126 | You can work on different storyboards, but 1127 | 1128 | 282 1129 | 00:22:49,535 --> 00:22:54,104 1130 | you would never like want to merge the change in 1131 | 1132 | 283 1133 | 00:22:54,173 --> 00:22:59,242 1134 | the same storyboard, because that's really, really painful. 1135 | 1136 | 284 1137 | 00:22:59,311 --> 00:23:04,582 1138 | Now we are at the master, and we also have the Changed 1139 | 1140 | 285 1141 | 00:23:04,650 --> 00:23:10,054 1142 | button color here. And when I go back to the storyboard, 1143 | 1144 | 286 1145 | 00:23:13,425 --> 00:23:17,895 1146 | The button is now red. So we've successfully merged 1147 | 1148 | 287 1149 | 00:23:17,963 --> 00:23:23,200 1150 | the change. And 1151 | 1152 | 288 1153 | 00:23:23,269 --> 00:23:27,204 1154 | notice that our current master is ahead 1155 | 1156 | 289 1157 | 00:23:27,272 --> 00:23:31,909 1158 | of the original master. So another way to push to 1159 | 1160 | 290 1161 | 00:23:31,977 --> 00:23:36,580 1162 | the origin is to click Source Control > Push. 1163 | 1164 | 291 1165 | 00:23:44,824 --> 00:23:48,993 1166 | Now all my notes are at the same snapshot. 1167 | 1168 | 292 1169 | 00:23:51,364 --> 00:23:54,264 1170 | Another cool thing I want to show you is that, 1171 | 1172 | 293 1173 | 00:23:54,333 --> 00:23:57,968 1174 | they make it really easy if you want to inspect your 1175 | 1176 | 294 1177 | 00:23:58,036 --> 00:24:02,706 1178 | commits. Like I have some commit for button. 1179 | 1180 | 295 1181 | 00:24:02,775 --> 00:24:06,577 1182 | It will show all the commit message that should, 1183 | 1184 | 296 1185 | 00:24:06,646 --> 00:24:12,148 1186 | has button in it. And you can also filter by author, 1187 | 1188 | 297 1189 | 00:24:12,217 --> 00:24:15,719 1190 | like author is junjie. And 1191 | 1192 | 298 1193 | 00:24:15,788 --> 00:24:20,690 1194 | you can also search last 24 hours, last 30 days. 1195 | 1196 | 299 1197 | 00:24:20,759 --> 00:24:24,795 1198 | It's really helpful if you want to search your change. 1199 | 1200 | 300 1201 | 00:24:27,166 --> 00:24:32,969 1202 | So that's basically all for our demo. 1203 | 1204 | 301 1205 | 00:24:33,038 --> 00:24:38,809 1206 | Do you have any questions? No, 1207 | 1208 | 302 1209 | 00:24:38,877 --> 00:24:44,014 1210 | okay, so that's it for today. Thank you for coming, and 1211 | 1212 | 303 1213 | 00:24:44,083 --> 00:24:47,784 1214 | good luck on your assignments. >> For more, 1215 | 祝你们顺利完成作业。 >> 更多课程 1216 | 1217 | 304 1218 | 00:24:47,853 --> 00:24:56,359 1219 | please visit us at stanford.edu. 1220 | 详见 stanford.edu 1221 | -------------------------------------------------------------------------------- /subtitles/Friday Session 3. Instruments.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,401 --> 00:00:04,769 3 | 本字幕由志愿者义务贡献,采用许可协议 4 | 知识共享 署名-非商业性使用-相同方式共享 3.0 美国 5 | 6 | 2 7 | 00:00:04,838 --> 00:00:09,307 8 | Stanford University. >> All right welcome class, 9 | >> 斯坦福大学 >> 好,欢迎同学们 10 | 11 | 3 12 | 00:00:09,376 --> 00:00:12,244 13 | everybody, to iPhone section about instruments. 14 | 15 | 4 16 | 00:00:12,313 --> 00:00:14,212 17 | We're gonna learn today about instruments which is a tool 18 | 19 | 5 20 | 00:00:14,281 --> 00:00:17,382 21 | that helps you with figuring how to profile your code, and 22 | 23 | 6 24 | 00:00:17,451 --> 00:00:20,185 25 | profiling means a few different things. So we'll get 26 | 27 | 7 28 | 00:00:20,254 --> 00:00:22,387 29 | started with a little bit of background on what it means to 30 | 31 | 8 32 | 00:00:22,455 --> 00:00:24,422 33 | even profile code in the first place cuz that may not be 34 | 35 | 9 36 | 00:00:24,491 --> 00:00:27,726 37 | something you've done before. Even outside of Xcode in 38 | 39 | 10 40 | 00:00:27,794 --> 00:00:31,964 41 | general with your programming career. So, I want you to 42 | 43 | 11 44 | 00:00:32,032 --> 00:00:34,833 45 | rewind back to kinda when people were building OS' back 46 | 47 | 12 48 | 00:00:34,902 --> 00:00:37,702 49 | in the day and people had all kinds of questions that they 50 | 51 | 13 52 | 00:00:37,771 --> 00:00:40,806 53 | wanted to ask about their code as it was running in their OS. 54 | 55 | 14 56 | 00:00:40,874 --> 00:00:43,575 57 | And those questions would range across things from like 58 | 59 | 15 60 | 00:00:43,644 --> 00:00:46,210 61 | the hard disk to main memory to the CPU and just to try to 62 | 63 | 16 64 | 00:00:46,279 --> 00:00:49,280 65 | figure out like how the OS was allocating various resources. 66 | 67 | 17 68 | 00:00:49,349 --> 00:00:51,649 69 | For the disk you might ask something like, what, 70 | 71 | 18 72 | 00:00:51,718 --> 00:00:54,486 73 | what processes are asking for a given resource right now and 74 | 75 | 19 76 | 00:00:54,555 --> 00:00:56,989 77 | which command requested that resource from the OS so 78 | 79 | 20 80 | 00:00:57,057 --> 00:00:59,291 81 | you could figure out whether there are some bug or 82 | 83 | 21 84 | 00:00:59,360 --> 00:01:00,325 85 | what was going on. 86 | 87 | 22 88 | 00:01:00,394 --> 00:01:02,661 89 | You might have a problem in memory like there's a leak or 90 | 91 | 23 92 | 00:01:02,730 --> 00:01:03,661 93 | something like that and 94 | 95 | 24 96 | 00:01:03,730 --> 00:01:05,931 97 | you wanna figure out how you can trace down that leak. 98 | 99 | 25 100 | 00:01:05,999 --> 00:01:08,634 101 | And then very importantly you might wanna figure out how 102 | 103 | 26 104 | 00:01:08,702 --> 00:01:11,202 105 | long certain processes are taking on the CPU compared to 106 | 107 | 27 108 | 00:01:11,271 --> 00:01:13,972 109 | other processes or how long a process is taking in general. 110 | 111 | 28 112 | 00:01:14,040 --> 00:01:16,542 113 | Or, when it spikes to 100% usage or something like 114 | 115 | 29 116 | 00:01:16,610 --> 00:01:19,143 117 | that so, these are all really important questions. 118 | 119 | 30 120 | 00:01:19,212 --> 00:01:21,179 121 | But, in order to figure it out, you'd have to go in and 122 | 123 | 31 124 | 00:01:21,247 --> 00:01:23,915 125 | manually write a bunch of code, and that's not very fun. 126 | 127 | 32 128 | 00:01:23,984 --> 00:01:26,385 129 | So if somebody came along around the early 2000s, and 130 | 131 | 33 132 | 00:01:26,454 --> 00:01:29,054 133 | said hey, there must be a better way. And 134 | 135 | 34 136 | 00:01:29,122 --> 00:01:30,956 137 | so I believe at Sun Microsystems, 138 | 139 | 35 140 | 00:01:31,024 --> 00:01:33,958 141 | they created this thing called DTrace, which is a little 142 | 143 | 36 144 | 00:01:34,027 --> 00:01:36,962 145 | lightweight scripting language that looks kind of like C, so 146 | 147 | 37 148 | 00:01:37,030 --> 00:01:39,398 149 | it fit right in with your operating systems code. 150 | 151 | 38 152 | 00:01:39,466 --> 00:01:42,233 153 | And DTrace would do is like you would place this little 154 | 155 | 39 156 | 00:01:42,302 --> 00:01:45,369 157 | things called probes which are little of code inside your, 158 | 159 | 40 160 | 00:01:45,438 --> 00:01:46,872 161 | inside your bigger system. 162 | 163 | 41 164 | 00:01:46,940 --> 00:01:49,507 165 | And then they would trigger output about how long it was 166 | 167 | 42 168 | 00:01:49,576 --> 00:01:52,110 169 | taking to run various things and you could figure how 170 | 171 | 43 172 | 00:01:52,179 --> 00:01:54,913 173 | much memory was being used by given resource and what not. 174 | 175 | 44 176 | 00:01:54,982 --> 00:01:57,249 177 | And what is great is really, really expressive which meant 178 | 179 | 45 180 | 00:01:57,318 --> 00:01:59,350 181 | that you could do a lot of different things with it, 182 | 183 | 46 184 | 00:01:59,419 --> 00:02:01,386 185 | by writing very little code and you could deploy it to 186 | 187 | 47 188 | 00:02:01,455 --> 00:02:03,422 189 | production no problem because when it was running in 190 | 191 | 48 192 | 00:02:03,490 --> 00:02:05,423 193 | production mode. It wouldn't take any hit on the CPU, so 194 | 195 | 49 196 | 00:02:05,492 --> 00:02:07,191 197 | you can just leave your code in there, 198 | 199 | 50 200 | 00:02:07,260 --> 00:02:10,595 201 | in the live production system. So, that's a super great step 202 | 203 | 51 204 | 00:02:10,664 --> 00:02:13,265 205 | in the right direction, but I had a little bit of a problem, 206 | 207 | 52 208 | 00:02:14,601 --> 00:02:16,435 209 | which is that, for example here, 210 | 211 | 53 212 | 00:02:16,503 --> 00:02:18,703 213 | when you see this one that compares process times, 214 | 215 | 54 216 | 00:02:18,772 --> 00:02:20,939 217 | you see this one in the center here is, 218 | 219 | 55 220 | 00:02:21,008 --> 00:02:25,043 221 | is outputting a distributing of processes as Atsy text. So 222 | 223 | 56 224 | 00:02:25,111 --> 00:02:27,178 225 | it's showing you these little at signs to say that that, 226 | 227 | 57 228 | 00:02:27,247 --> 00:02:29,447 229 | that process in the center is taking up half of the overall 230 | 231 | 58 232 | 00:02:29,516 --> 00:02:31,215 233 | time and the other ones are taking up the rest, 234 | 235 | 59 236 | 00:02:31,284 --> 00:02:32,884 237 | it's not the best GUI. So 238 | 239 | 60 240 | 00:02:32,953 --> 00:02:37,823 241 | you end up with this non-ideal situation where you kinda got 242 | 243 | 61 244 | 00:02:37,891 --> 00:02:41,826 245 | all this console of output and we really didn't want that 246 | 247 | 62 248 | 00:02:41,895 --> 00:02:44,595 249 | with Apple when we were creating, you know Xcode and 250 | 251 | 63 252 | 00:02:44,664 --> 00:02:46,765 253 | IOS because in most cases, 254 | 255 | 64 256 | 00:02:46,833 --> 00:02:48,467 257 | people who are using it are maybe programming for 258 | 259 | 65 260 | 00:02:48,535 --> 00:02:50,735 261 | the first time. They've never made apps before and 262 | 263 | 66 264 | 00:02:50,804 --> 00:02:53,204 265 | this is just something that you don't wanna have to go and 266 | 267 | 67 268 | 00:02:53,273 --> 00:02:57,108 269 | deal with. So, This is kind of the vision in my head 270 | 271 | 68 272 | 00:02:57,177 --> 00:02:59,644 273 | of DTrace, it's like this very powerful machine that has way 274 | 275 | 69 276 | 00:02:59,713 --> 00:03:00,645 277 | too many knobs and, and 278 | 279 | 70 280 | 00:03:00,714 --> 00:03:01,946 281 | buttons to get used to easily and 282 | 283 | 71 284 | 00:03:02,015 --> 00:03:04,649 285 | you have to kinda learn it up front to be able to use it. 286 | 287 | 72 288 | 00:03:04,718 --> 00:03:07,652 289 | And the solution instead, is to have something happier and 290 | 291 | 73 292 | 00:03:07,721 --> 00:03:09,888 293 | friendlier like our friend Eve here, 294 | 295 | 74 296 | 00:03:09,957 --> 00:03:12,257 297 | or Eva, I forget how you say it. And 298 | 299 | 75 300 | 00:03:12,326 --> 00:03:17,228 301 | the solution is called Instruments, Instruments, 302 | 303 | 76 304 | 00:03:17,297 --> 00:03:21,800 305 | Instruments. And so what Instruments is, is it's a GUI, 306 | 307 | 77 308 | 00:03:21,869 --> 00:03:24,469 309 | and it sits on top of DTrace, that same little programming 310 | 311 | 78 312 | 00:03:24,538 --> 00:03:27,238 313 | language, scripting language that we just talked about. 314 | 315 | 79 316 | 00:03:27,307 --> 00:03:30,041 317 | And it's built right into Xcode and so it, it kinda 318 | 319 | 80 320 | 00:03:30,109 --> 00:03:33,078 321 | democratized this idea that you could do CPU analysis or 322 | 323 | 81 324 | 00:03:33,147 --> 00:03:35,079 325 | memory analysis or disc analysis and 326 | 327 | 82 328 | 00:03:35,148 --> 00:03:39,317 329 | things like these. And one of the interesting differences 330 | 331 | 83 332 | 00:03:39,386 --> 00:03:43,154 333 | between instruments and using something like DTrace is that. 334 | 335 | 84 336 | 00:03:43,223 --> 00:03:45,557 337 | Since it's a GUI we now can't do all of these, 338 | 339 | 85 340 | 00:03:45,626 --> 00:03:48,427 341 | all of the D Trace tasks that we would wanna do within one 342 | 343 | 86 344 | 00:03:48,495 --> 00:03:51,863 345 | single window because there're just too many of them. So 346 | 347 | 87 348 | 00:03:51,932 --> 00:03:54,900 349 | what instruments does instead, is it splits off 350 | 351 | 88 352 | 00:03:54,968 --> 00:03:58,003 353 | all of all of the thing that you'd possibly wanna do with 354 | 355 | 89 356 | 00:03:58,071 --> 00:04:00,838 357 | an iOS app with profiling into lots of different flavors. 358 | 359 | 90 360 | 00:04:00,907 --> 00:04:04,509 361 | So, you see that we have these things like the activity 362 | 363 | 91 364 | 00:04:04,578 --> 00:04:07,145 365 | monitor, which is, you may be used to from your actual OS, 366 | 367 | 92 368 | 00:04:07,214 --> 00:04:10,381 369 | which shows you how much stuff different, 370 | 371 | 93 372 | 00:04:10,450 --> 00:04:12,784 373 | processes are taking up, how many different resources. 374 | 375 | 94 376 | 00:04:12,852 --> 00:04:14,353 377 | And you might have this thing called the time profiler, 378 | 379 | 95 380 | 00:04:14,421 --> 00:04:17,489 381 | which tells you how long it takes for a given 382 | 383 | 96 384 | 00:04:17,557 --> 00:04:21,025 385 | CPU process to do a certain task or something like that. 386 | 387 | 97 388 | 00:04:21,094 --> 00:04:22,894 389 | But, you can't have all of them within one window, or 390 | 391 | 98 392 | 00:04:22,963 --> 00:04:24,729 393 | it would just be too much clutter and too much stuff. 394 | 395 | 99 396 | 00:04:24,798 --> 00:04:27,565 397 | So, the way an instruments works from a high level is, 398 | 399 | 100 400 | 00:04:27,634 --> 00:04:30,902 401 | you're gonna launch a specific subpar, sub module like this. 402 | 403 | 101 404 | 00:04:30,971 --> 00:04:32,870 405 | And then you're going to focus on only that for 406 | 407 | 102 408 | 00:04:32,939 --> 00:04:34,139 409 | the duration of your app, and 410 | 411 | 103 412 | 00:04:34,207 --> 00:04:37,242 413 | that way you get this nice GUI, that's not cluttered up. 414 | 415 | 104 416 | 00:04:37,310 --> 00:04:40,445 417 | And in particular with these instruments what we'll focus 418 | 419 | 105 420 | 00:04:40,514 --> 00:04:43,681 421 | on today are the ones that are most useful for probably 95% 422 | 423 | 106 424 | 00:04:43,750 --> 00:04:46,484 425 | of the use cases that you'd ever use instruments for 426 | 427 | 107 428 | 00:04:46,553 --> 00:04:48,820 429 | you'll be using these four instruments. 430 | 431 | 108 432 | 00:04:48,888 --> 00:04:50,922 433 | So you'll notice that four of them are blue because they 434 | 435 | 109 436 | 00:04:50,991 --> 00:04:53,658 437 | have more to do with CPU stuff. And then two of them 438 | 439 | 110 440 | 00:04:53,727 --> 00:04:55,694 441 | are orange because they have more to do with RAM stuff 442 | 443 | 111 444 | 00:04:55,762 --> 00:04:58,162 445 | with memory. So, we'll go through these four today 446 | 447 | 112 448 | 00:04:58,231 --> 00:05:00,999 449 | starting with the two CPU ones and then we'll end up talking 450 | 451 | 113 452 | 00:05:01,067 --> 00:05:04,770 453 | about memory stuff with allocations and leaks. And 454 | 455 | 114 456 | 00:05:04,838 --> 00:05:06,737 457 | the one big takeaway from today, that I want 458 | 459 | 115 460 | 00:05:06,806 --> 00:05:08,407 461 | you to have is that instruments is not 462 | 463 | 116 464 | 00:05:08,475 --> 00:05:10,675 465 | some kind of like, nice to have optional thing that 466 | 467 | 117 468 | 00:05:10,743 --> 00:05:13,511 469 | sometimes people go off and use if they have a problem. 470 | 471 | 118 472 | 00:05:13,580 --> 00:05:15,780 473 | It's actually very critical, even if you think you've 474 | 475 | 119 476 | 00:05:15,849 --> 00:05:18,116 477 | created your app properly and you don't have any problems or 478 | 479 | 120 480 | 00:05:18,185 --> 00:05:20,252 481 | memory leaks or anything like that. Going through and 482 | 483 | 121 484 | 00:05:20,320 --> 00:05:22,487 485 | profiling it before you deploy a real production app and 486 | 487 | 122 488 | 00:05:22,556 --> 00:05:24,856 489 | making sure that it's using memory properly and that it's 490 | 491 | 123 492 | 00:05:24,925 --> 00:05:26,958 493 | not taking too much CPU time when it shouldn't be and 494 | 495 | 124 496 | 00:05:27,027 --> 00:05:28,560 497 | things like that that really matters. 498 | 499 | 125 500 | 00:05:28,628 --> 00:05:30,161 501 | So, Instruments is something that's 502 | 503 | 126 504 | 00:05:30,230 --> 00:05:33,098 505 | a necessary thing to learn if you're trying to become a real 506 | 507 | 127 508 | 00:05:33,166 --> 00:05:35,400 509 | iOS programmer. So don't consider this as like this 510 | 511 | 128 512 | 00:05:35,468 --> 00:05:38,269 513 | optional thing that you may not need some day. So 514 | 515 | 129 516 | 00:05:38,338 --> 00:05:40,371 517 | we're gonna go into right into a demo here and 518 | 519 | 130 520 | 00:05:40,440 --> 00:05:43,207 521 | we're gonna show a little app, a little mobile app and it's 522 | 523 | 131 524 | 00:05:43,276 --> 00:05:46,210 525 | gonna have a few, few issues with it that we're gonna track 526 | 527 | 132 528 | 00:05:46,279 --> 00:05:48,379 529 | down like little detectives inside of Instruments and 530 | 531 | 133 532 | 00:05:48,448 --> 00:05:50,181 533 | it'll illustrate how those four 534 | 535 | 134 536 | 00:05:50,250 --> 00:05:54,786 537 | flavors of Instruments work that I was speaking about. So, 538 | 539 | 135 540 | 00:05:57,724 --> 00:06:00,791 541 | The first thing I'll do is I'll run this app in 542 | 543 | 136 544 | 00:06:00,860 --> 00:06:03,428 545 | the most basic version of Instruments and we'll kinda 546 | 547 | 137 548 | 00:06:03,497 --> 00:06:07,232 549 | just give you a little tour of what this app is doing. And 550 | 551 | 138 552 | 00:06:07,301 --> 00:06:10,568 553 | the idea with Instruments is that you go up to this 554 | 555 | 139 556 | 00:06:10,637 --> 00:06:13,238 557 | Product menu and you click on Profile, 558 | 559 | 140 560 | 00:06:13,306 --> 00:06:16,708 561 | which you can access with Cmd + I. And then when you run 562 | 563 | 141 564 | 00:06:16,777 --> 00:06:19,511 565 | Profile it builds a version of your app with certain 566 | 567 | 142 568 | 00:06:19,579 --> 00:06:22,147 569 | debugging stuff built in and pops up in the same so 570 | 571 | 143 572 | 00:06:22,215 --> 00:06:24,950 573 | many flavors thing that I showed you from earlier. 574 | 575 | 144 576 | 00:06:25,018 --> 00:06:27,252 577 | And then we'll select the Activity Monitor, 578 | 579 | 145 580 | 00:06:27,320 --> 00:06:29,587 581 | which just as it says monitor CPU memory disk and 582 | 583 | 146 584 | 00:06:29,656 --> 00:06:32,657 585 | network usage statistics for processes and the file system. 586 | 587 | 147 588 | 00:06:32,725 --> 00:06:36,895 589 | So just general statistics about stuff going 590 | 591 | 148 592 | 00:06:36,964 --> 00:06:40,732 593 | on on your system, and in this case we click Choose. 594 | 595 | 149 596 | 00:06:40,801 --> 00:06:43,734 597 | This is the instruments GUI that pops up that's gonna show 598 | 599 | 150 600 | 00:06:43,803 --> 00:06:45,236 601 | us all of our statistics. 602 | 603 | 151 604 | 00:06:45,304 --> 00:06:48,172 605 | And in order to run your app while recording all of these 606 | 607 | 152 608 | 00:06:48,241 --> 00:06:51,342 609 | statistics, you click the Record button. It's kind of 610 | 611 | 153 612 | 00:06:51,411 --> 00:06:55,413 613 | like using iTunes or something but for debugging information, 614 | 615 | 154 616 | 00:06:55,482 --> 00:06:58,783 617 | and then we'll pop open our simulator here. And 618 | 619 | 155 620 | 00:06:58,852 --> 00:07:01,686 621 | first thing I'll do is explain what this app is just briefly, 622 | 623 | 156 624 | 00:07:01,754 --> 00:07:04,355 625 | the idea is that we're number theorists here. 626 | 627 | 157 628 | 00:07:04,424 --> 00:07:07,992 629 | And we've got some big prime number that you see right here 630 | 631 | 158 632 | 00:07:08,061 --> 00:07:10,895 633 | at the top, and we want to figure out what its prime 634 | 635 | 159 636 | 00:07:10,964 --> 00:07:12,763 637 | factors are. So since the number's so 638 | 639 | 160 640 | 00:07:12,832 --> 00:07:15,566 641 | big that's gonna take a lot of CPU time to compute so 642 | 643 | 161 644 | 00:07:15,635 --> 00:07:18,903 645 | let's see what happens when we try to compute it. And I also 646 | 647 | 162 648 | 00:07:18,972 --> 00:07:21,272 649 | have two options here for how we're gonna factor this, 650 | 651 | 163 652 | 00:07:21,341 --> 00:07:22,740 653 | one is to do it the main thread, and 654 | 655 | 164 656 | 00:07:22,809 --> 00:07:24,876 657 | the other one is to do it on the background thread. 658 | 659 | 165 660 | 00:07:24,944 --> 00:07:27,479 661 | Now the first thing we'll experience is what Paul talked 662 | 663 | 166 664 | 00:07:27,547 --> 00:07:28,446 665 | about in lecture this 666 | 667 | 167 668 | 00:07:28,515 --> 00:07:31,049 669 | week which is that when you do things on the main thread, and 670 | 671 | 168 672 | 00:07:31,118 --> 00:07:33,685 673 | they're really CPU intensive, you actually block the main 674 | 675 | 169 676 | 00:07:33,753 --> 00:07:37,989 677 | thread. So when we click on this button here, We notice 678 | 679 | 170 680 | 00:07:38,057 --> 00:07:40,358 681 | that the UI is completely blocked I can't click anywhere 682 | 683 | 171 684 | 00:07:40,426 --> 00:07:42,460 685 | else, because it's off factoring this number, 686 | 687 | 172 688 | 00:07:42,528 --> 00:07:45,129 689 | figuring out the prime factors on the main thread. 690 | 691 | 173 692 | 00:07:45,198 --> 00:07:47,164 693 | You'll also notice over here, we have a list of all 694 | 695 | 174 696 | 00:07:47,233 --> 00:07:49,200 697 | of the processes running on my machine right now. 698 | 699 | 175 700 | 00:07:49,269 --> 00:07:52,370 701 | Since we're in the simulator this is my actual Mac Book all 702 | 703 | 176 704 | 00:07:52,439 --> 00:07:54,339 705 | of the processes and the name of this app 706 | 707 | 177 708 | 00:07:54,408 --> 00:07:56,974 709 | as you can see up here is instruments demo. So 710 | 711 | 178 712 | 00:07:57,043 --> 00:08:00,011 713 | one of the first things we can do is instruments demo here is 714 | 715 | 179 716 | 00:08:00,080 --> 00:08:02,847 717 | taking up a lot of the CPU time in fact, 718 | 719 | 180 720 | 00:08:02,916 --> 00:08:05,717 721 | Twice as much as the total percentage, because it's off 722 | 723 | 181 724 | 00:08:05,786 --> 00:08:08,352 725 | finding the prime factors of this large number. And 726 | 727 | 182 728 | 00:08:08,421 --> 00:08:11,656 729 | if we want we can even filter to get rid of all the noise, 730 | 731 | 183 732 | 00:08:11,724 --> 00:08:14,859 733 | by typing in the name of the process we want to inspect. 734 | 735 | 184 736 | 00:08:14,928 --> 00:08:18,763 737 | You'll also notice that there's other 738 | 739 | 185 740 | 00:08:18,831 --> 00:08:20,598 741 | information displayed here in the activity monitor 742 | 743 | 186 744 | 00:08:20,667 --> 00:08:22,299 745 | like the number of threads that are currently running. 746 | 747 | 187 748 | 00:08:22,368 --> 00:08:25,970 749 | So since I have this. Forking on a background thread options 750 | 751 | 188 752 | 00:08:26,039 --> 00:08:28,039 753 | down here at the bottom. To solve this problem, 754 | 755 | 189 756 | 00:08:28,107 --> 00:08:29,707 757 | I'll go ahead and click on this a few times, 758 | 759 | 190 760 | 00:08:29,776 --> 00:08:33,911 761 | fork up a bunch of threads. And 762 | 763 | 191 764 | 00:08:33,980 --> 00:08:36,481 765 | you can see I hover over here inside instruments for 766 | 767 | 192 768 | 00:08:36,550 --> 00:08:39,784 769 | seeing the number of threads pop up. Now we have a bunch of 770 | 771 | 193 772 | 00:08:39,852 --> 00:08:42,120 773 | different threads all going off in the background to try 774 | 775 | 194 776 | 00:08:42,189 --> 00:08:44,288 777 | to figure out these prime factors all on their own. 778 | 779 | 195 780 | 00:08:44,357 --> 00:08:46,691 781 | And then they're gonna report back when done. And we'll see 782 | 783 | 196 784 | 00:08:46,759 --> 00:08:48,359 785 | these number of threads go down when they finish. 786 | 787 | 197 788 | 00:08:48,428 --> 00:08:50,494 789 | So this just kind of gives you a general sense of what 790 | 791 | 198 792 | 00:08:50,563 --> 00:08:52,897 793 | instruments is like. The activity monitor you can see, 794 | 795 | 199 796 | 00:08:52,966 --> 00:08:55,132 797 | doesn't give you superfine grained information. 798 | 799 | 200 800 | 00:08:55,201 --> 00:08:57,402 801 | It kinda just gives you the high level, like. You know 802 | 803 | 201 804 | 00:08:57,470 --> 00:08:59,537 805 | what the name of the process is and how much CPU time and 806 | 807 | 202 808 | 00:08:59,606 --> 00:09:02,373 809 | the number of threads and the memory, just basic stats, but 810 | 811 | 203 812 | 00:09:02,442 --> 00:09:03,941 813 | it doesn't allow you to dig deeper. To do that, 814 | 815 | 204 816 | 00:09:04,010 --> 00:09:05,944 817 | you have to as I said earlier you have to go back and 818 | 819 | 205 820 | 00:09:06,013 --> 00:09:07,612 821 | run instruments with a different flavor, 822 | 823 | 206 824 | 00:09:07,681 --> 00:09:10,215 825 | so that you can inspect that particular thing. 826 | 827 | 207 828 | 00:09:10,283 --> 00:09:15,119 829 | So, let's do that. We'll stop this 830 | 831 | 208 832 | 00:09:15,188 --> 00:09:18,056 833 | here. And you can actually save 834 | 835 | 209 836 | 00:09:18,124 --> 00:09:21,092 837 | off what's called the trace. So the actual record of what 838 | 839 | 210 840 | 00:09:21,161 --> 00:09:22,226 841 | happened with that run of instrument. 842 | 843 | 211 844 | 00:09:22,295 --> 00:09:24,695 845 | So you can maybe compare across multiple runs. Or 846 | 847 | 212 848 | 00:09:24,764 --> 00:09:31,002 849 | do additional analysis later. And we will 850 | 851 | 213 852 | 00:09:31,070 --> 00:09:35,206 853 | go back to profile. And the next time we want to profile 854 | 855 | 214 856 | 00:09:35,275 --> 00:09:37,842 857 | on what's actually taking so long to factor this prime 858 | 859 | 215 860 | 00:09:37,911 --> 00:09:40,344 861 | number? Maybe there's some way we can optimize this algorithm 862 | 863 | 216 864 | 00:09:40,413 --> 00:09:43,047 865 | to make it faster for example and we've looked at our code 866 | 867 | 217 868 | 00:09:43,116 --> 00:09:46,117 869 | a bunch. They aren't quite sure what's going on. 870 | 871 | 218 872 | 00:09:46,186 --> 00:09:48,453 873 | Why is it taking so long to factor this prime number? 874 | 875 | 219 876 | 00:09:48,522 --> 00:09:51,022 877 | And so we don't have a theory we're not sure why but 878 | 879 | 220 880 | 00:09:51,091 --> 00:09:52,823 881 | we know figure on the time profiler. 882 | 883 | 221 884 | 00:09:52,892 --> 00:09:55,159 885 | Maybe it will help us dig in to exactly what's taken so 886 | 887 | 222 888 | 00:09:55,228 --> 00:09:58,363 889 | much time on the CPU. And like of us more algorithmic insight 890 | 891 | 223 892 | 00:09:58,432 --> 00:10:01,165 893 | into what we're doing wrong, with our, with our 894 | 895 | 224 896 | 00:10:01,234 --> 00:10:04,268 897 | factorization methods. So we'll run the time profiler. 898 | 899 | 225 900 | 00:10:04,337 --> 00:10:06,404 901 | Okay, so here we are in the time profiler, and 902 | 903 | 226 904 | 00:10:06,472 --> 00:10:08,873 905 | we can see we have this nice graph at the top that says, 906 | 907 | 227 908 | 00:10:08,942 --> 00:10:10,441 909 | CPU usage, and it's also showing 910 | 911 | 228 912 | 00:10:10,510 --> 00:10:13,010 913 | us how much usage in the main thread, versus this 914 | 915 | 229 916 | 00:10:13,079 --> 00:10:15,880 917 | dispatch worker thread that's running in the background and 918 | 919 | 230 920 | 00:10:15,948 --> 00:10:20,051 921 | these other threads. And like earlier, we'll notice that 922 | 923 | 231 924 | 00:10:20,120 --> 00:10:22,620 925 | when we click do it on the main thread, and we block 926 | 927 | 232 928 | 00:10:22,689 --> 00:10:26,557 929 | the UI here, we see that the CP usage skyrockets. So you'll 930 | 931 | 233 932 | 00:10:26,626 --> 00:10:29,127 933 | got this long running process. And if we wait long enough, 934 | 935 | 234 936 | 00:10:29,196 --> 00:10:31,395 937 | eventually we should see the factorization complete. 938 | 939 | 235 940 | 00:10:31,464 --> 00:10:33,931 941 | And that CP usage should drop back down to zero. 942 | 943 | 236 944 | 00:10:34,000 --> 00:10:36,667 945 | So this is the general idea behind the time profiler. 946 | 947 | 237 948 | 00:10:36,736 --> 00:10:38,102 949 | Also at the bottom while this is going on, 950 | 951 | 238 952 | 00:10:38,171 --> 00:10:40,872 953 | you'll see that we have this sort of call trace here. 954 | 955 | 239 956 | 00:10:40,940 --> 00:10:45,142 957 | This call stack, which is actually it's a tree of calls. 958 | 959 | 240 960 | 00:10:45,211 --> 00:10:47,846 961 | And it shows you what's going on nested inside all of 962 | 963 | 241 964 | 00:10:49,049 --> 00:10:51,215 965 | this apps different threads. 966 | 967 | 242 968 | 00:10:51,284 --> 00:10:54,151 969 | So if you'll notice we're done factoring here. 970 | 971 | 243 972 | 00:10:54,220 --> 00:10:56,888 973 | We've found all the prime factors of this number. And 974 | 975 | 244 976 | 00:10:58,925 --> 00:11:03,127 977 | it took a 99% of the CPU time within the main thread and 978 | 979 | 245 980 | 00:11:03,196 --> 00:11:06,464 981 | 99.3 within the start method. And then so on and so forth. 982 | 983 | 246 984 | 00:11:06,532 --> 00:11:09,067 985 | And so it's showing us the percentage of total CPU time, 986 | 987 | 247 988 | 00:11:09,135 --> 00:11:12,970 989 | that's happening within all this different stuff. 990 | 991 | 248 992 | 00:11:13,039 --> 00:11:14,305 993 | this is not a very fun process to dig through all these 994 | 995 | 249 996 | 00:11:14,306 --> 00:11:15,572 997 | But obviously, 998 | 999 | 250 1000 | 00:11:15,641 --> 00:11:16,507 1001 | system methods right, 1002 | 1003 | 251 1004 | 00:11:16,576 --> 00:11:17,809 1005 | because we didn't even write these methods. 1006 | 1007 | 252 1008 | 00:11:17,878 --> 00:11:19,677 1009 | We're just, we're just curious about our code. 1010 | 1011 | 253 1012 | 00:11:19,746 --> 00:11:21,846 1013 | All we care about is the app what I wrote. 1014 | 1015 | 254 1016 | 00:11:21,915 --> 00:11:23,781 1017 | Where is all the information for that stuff? So 1018 | 1019 | 255 1020 | 00:11:23,849 --> 00:11:26,317 1021 | there's a nice set of options down here inside this call 1022 | 1023 | 256 1024 | 00:11:26,385 --> 00:11:28,519 1025 | tree menu, so if I click on this, 1026 | 1027 | 257 1028 | 00:11:28,588 --> 00:11:31,656 1029 | you'll notice there's already this option checked by default 1030 | 1031 | 258 1032 | 00:11:31,724 --> 00:11:34,259 1033 | to separate things by thread as we've seen up at the top. 1034 | 1035 | 259 1036 | 00:11:34,327 --> 00:11:37,128 1037 | But another thing we can do is hide system libraries. So 1038 | 1039 | 260 1040 | 00:11:37,196 --> 00:11:40,131 1041 | the moment that we click, hide system libraries, you'll 1042 | 1043 | 261 1044 | 00:11:40,200 --> 00:11:42,766 1045 | notice that it collapsed all of that junk that we were just 1046 | 1047 | 262 1048 | 00:11:42,835 --> 00:11:45,470 1049 | look at into just the stuff inside of our application. 1050 | 1051 | 263 1052 | 00:11:45,538 --> 00:11:47,371 1053 | So we see stuff inside of our view controller for 1054 | 1055 | 264 1056 | 00:11:47,440 --> 00:11:50,140 1057 | example, like factor on mean thread which is the method 1058 | 1059 | 265 1060 | 00:11:50,209 --> 00:11:52,776 1061 | that went off to do factoring of this prime number on 1062 | 1063 | 266 1064 | 00:11:52,845 --> 00:11:55,280 1065 | the mean thread as opposed to on the background thread. And 1066 | 1067 | 267 1068 | 00:11:55,348 --> 00:11:56,547 1069 | then inside of there, 1070 | 1071 | 268 1072 | 00:11:56,616 --> 00:11:59,183 1073 | there was part of it that was taking a lot of time. So 1074 | 1075 | 269 1076 | 00:11:59,252 --> 00:12:02,453 1077 | we'll go dig into our methods and we see this prime factors 1078 | 1079 | 270 1080 | 00:12:02,521 --> 00:12:04,355 1081 | method that we've written apparently is taking up a lot 1082 | 1083 | 271 1084 | 00:12:04,424 --> 00:12:07,292 1085 | of time. And then there is what some method in there 1086 | 1087 | 272 1088 | 00:12:07,360 --> 00:12:10,494 1089 | taking up a quarter of the time that's testing a divisor. 1090 | 1091 | 273 1092 | 00:12:10,563 --> 00:12:13,231 1093 | So at some point we we we're down to a part of the code 1094 | 1095 | 274 1096 | 00:12:13,300 --> 00:12:14,932 1097 | that seems more granular and 1098 | 1099 | 275 1100 | 00:12:15,001 --> 00:12:17,068 1101 | this is where the actual problem is happening. 1102 | 1103 | 276 1104 | 00:12:17,136 --> 00:12:20,371 1105 | And we can actually go into code level detail from 1106 | 1107 | 277 1108 | 00:12:20,439 --> 00:12:23,674 1109 | instruments by double clicking on that method. So 1110 | 1111 | 278 1112 | 00:12:23,743 --> 00:12:26,544 1113 | the moment I click on that, or thrown into our code base, and 1114 | 1115 | 279 1116 | 00:12:26,613 --> 00:12:29,013 1117 | we look at this, we have on the right side here, 1118 | 1119 | 280 1120 | 00:12:29,082 --> 00:12:32,016 1121 | we have different percentages of what lines were taking so 1122 | 1123 | 281 1124 | 00:12:32,085 --> 00:12:34,886 1125 | long to run. So if we're looking at our algorithm here 1126 | 1127 | 282 1128 | 00:12:34,954 --> 00:12:39,357 1129 | for factoring prime numbers, this is the overall function 1130 | 1131 | 283 1132 | 00:12:39,426 --> 00:12:41,392 1133 | that computes it. We pass in some big integer, 1134 | 1135 | 284 1136 | 00:12:41,461 --> 00:12:44,462 1137 | and or a long long in this case just because it's so 1138 | 1139 | 285 1140 | 00:12:44,530 --> 00:12:46,964 1141 | large and then we have an enter function here 1142 | 1143 | 286 1144 | 00:12:47,033 --> 00:12:49,433 1145 | called test which is gonna test a given divisor. 1146 | 1147 | 287 1148 | 00:12:49,502 --> 00:12:52,770 1149 | To see is that large number divisible by this divisor? And 1150 | 1151 | 288 1152 | 00:12:52,838 --> 00:12:56,774 1153 | since that divisor can be a divisor multiple times of of 1154 | 1155 | 289 1156 | 00:12:56,843 --> 00:12:59,243 1157 | a given number maybe, you know, 1158 | 1159 | 290 1160 | 00:12:59,312 --> 00:13:02,313 1161 | the number 31 that actually is 2 times 31 times 31, right? 1162 | 1163 | 291 1164 | 00:13:02,382 --> 00:13:04,448 1165 | So we have this while loop here which checks that same 1166 | 1167 | 292 1168 | 00:13:04,517 --> 00:13:08,052 1169 | number multiple times, and then appends it to a result 1170 | 1171 | 293 1172 | 00:13:08,121 --> 00:13:10,354 1173 | array which is that thing that we were outputting in the app 1174 | 1175 | 294 1176 | 00:13:10,423 --> 00:13:14,525 1177 | earlier. And then what we do to figure out the overall 1178 | 1179 | 295 1180 | 00:13:14,594 --> 00:13:17,362 1181 | total set of prime factors here in this algorithm is we 1182 | 1183 | 296 1184 | 00:13:17,430 --> 00:13:22,766 1185 | go from i b 2 up by ones all the way up to N, 1186 | 1187 | 297 1188 | 00:13:22,835 --> 00:13:25,103 1189 | which is the number. So we're checking every number from 2, 1190 | 1191 | 298 1192 | 00:13:25,171 --> 00:13:27,371 1193 | 3, 4, 5, 6 all the way up to this large number N. 1194 | 1195 | 299 1196 | 00:13:27,440 --> 00:13:30,207 1197 | And we're testing each of them to see whether it's a divisor 1198 | 1199 | 300 1200 | 00:13:30,276 --> 00:13:34,244 1201 | of that number. And what our instruments demo here is 1202 | 1203 | 301 1204 | 00:13:34,313 --> 00:13:39,183 1205 | saying is that 43.5% of it is taken up, 1206 | 1207 | 302 1208 | 00:13:39,251 --> 00:13:40,952 1209 | I think this line should actually 1210 | 1211 | 303 1212 | 00:13:41,021 --> 00:13:43,253 1213 | be referring to the line immediately following it, so 1214 | 1215 | 304 1216 | 00:13:43,322 --> 00:13:45,356 1217 | the line that's actually doing the stride. So just doing this 1218 | 1219 | 305 1220 | 00:13:45,425 --> 00:13:47,992 1221 | many iterations of a loop is taking a lot of time. And 1222 | 1223 | 306 1224 | 00:13:48,060 --> 00:13:50,661 1225 | then inside of here, we're doing, we're spending a lot of 1226 | 1227 | 307 1228 | 00:13:50,730 --> 00:13:53,598 1229 | time iterating on these loops. So it's just as 1230 | 1231 | 308 1232 | 00:13:53,666 --> 00:13:58,102 1233 | if the total number of loops that we're doing 1234 | 1235 | 309 1236 | 00:13:58,171 --> 00:13:59,938 1237 | is just too many. So that might give us the insight. 1238 | 1239 | 310 1240 | 00:14:00,006 --> 00:14:01,972 1241 | Maybe we're just trying to divide too many numbers, 1242 | 1243 | 311 1244 | 00:14:02,041 --> 00:14:04,509 1245 | right. Which of course we are, because we're going all 1246 | 1247 | 312 1248 | 00:14:04,577 --> 00:14:07,879 1249 | the way from two to the actual number and itself, 1250 | 1251 | 313 1252 | 00:14:07,947 --> 00:14:09,413 1253 | which is kind of crazy if you think about it. 1254 | 1255 | 314 1256 | 00:14:09,482 --> 00:14:12,783 1257 | Because first off, if we were to go over 1258 | 1259 | 315 1260 | 00:14:12,852 --> 00:14:15,787 1261 | n divided by 2, that's already kind of crazy because we 1262 | 1263 | 316 1264 | 00:14:15,855 --> 00:14:17,488 1265 | already tried all the numbers that were less than that. 1266 | 1267 | 317 1268 | 00:14:17,557 --> 00:14:20,391 1269 | So we would have found them already by that point. And 1270 | 1271 | 318 1272 | 00:14:20,459 --> 00:14:23,061 1273 | if you think it a little bit harder actually, 1274 | 1275 | 319 1276 | 00:14:23,129 --> 00:14:26,096 1277 | the more standard mathematical way to solve this problem 1278 | 1279 | 320 1280 | 00:14:26,165 --> 00:14:29,100 1281 | would actually be to only go up the square root of N. 1282 | 1283 | 321 1284 | 00:14:29,169 --> 00:14:31,302 1285 | You can think about that from a math perspective with like 1286 | 1287 | 322 1288 | 00:14:31,371 --> 00:14:33,371 1289 | a proof by contradiction where you you assume that if there 1290 | 1291 | 323 1292 | 00:14:33,440 --> 00:14:35,706 1293 | were some. Prime factor of a number that were larger 1294 | 1295 | 324 1296 | 00:14:35,774 --> 00:14:39,110 1297 | than the square root of n that that number in order for 1298 | 1299 | 325 1300 | 00:14:39,179 --> 00:14:40,945 1301 | it to be multiplied by another number to reach that number 1302 | 1303 | 326 1304 | 00:14:41,013 --> 00:14:43,213 1305 | would need to be larger than the square root of n which, 1306 | 1307 | 327 1308 | 00:14:43,282 --> 00:14:45,316 1309 | is a contradiction so it doesn't make sense. So 1310 | 1311 | 328 1312 | 00:14:45,385 --> 00:14:49,053 1313 | anyway we have that already typed down here for 1314 | 1315 | 329 1316 | 00:14:49,121 --> 00:14:53,991 1317 | you so. I will prove that instruments has done it's task 1318 | 1319 | 330 1320 | 00:14:54,060 --> 00:14:58,295 1321 | correctly by, instead of iterating over every number, 1322 | 1323 | 331 1324 | 00:14:58,364 --> 00:15:01,665 1325 | doing it by starting with the divisor two, 1326 | 1327 | 332 1328 | 00:15:01,734 --> 00:15:05,002 1329 | because that's our first prime number, and 1330 | 1331 | 333 1332 | 00:15:05,071 --> 00:15:08,906 1333 | testing two. And then starting at the number three, 1334 | 1335 | 334 1336 | 00:15:08,974 --> 00:15:11,809 1337 | because only odd numbers can be prime numbers after two. 1338 | 1339 | 335 1340 | 00:15:11,877 --> 00:15:13,877 1341 | And then going up to the square root of n by 2, so 1342 | 1343 | 336 1344 | 00:15:13,946 --> 00:15:16,713 1345 | we're gonna try 3 5 7 all the way up to the square root of n 1346 | 1347 | 337 1348 | 00:15:16,782 --> 00:15:17,949 1349 | which should be a much smaller number. 1350 | 1351 | 338 1352 | 00:15:18,018 --> 00:15:19,250 1353 | And then when we go off and 1354 | 1355 | 339 1356 | 00:15:19,318 --> 00:15:27,591 1357 | we profile this. We'll notice that, 1358 | 1359 | 340 1360 | 00:15:27,660 --> 00:15:29,961 1361 | when we click on factor on the main thread 1362 | 1363 | 341 1364 | 00:15:30,029 --> 00:15:32,930 1365 | we're done immediately, yay. So instruments did its job, 1366 | 1367 | 342 1368 | 00:15:32,999 --> 00:15:34,932 1369 | the time profiler's very useful, and it can help you 1370 | 1371 | 343 1372 | 00:15:35,001 --> 00:15:37,101 1373 | find what's taking up a lot of your CPU time, 1374 | 1375 | 344 1376 | 00:15:37,170 --> 00:15:40,170 1377 | it's about that simple. You can bumble around in all these 1378 | 1379 | 345 1380 | 00:15:40,239 --> 00:15:42,073 1381 | other options inside here to see what they afford you. 1382 | 1383 | 346 1384 | 00:15:42,141 --> 00:15:45,476 1385 | But the main ones are the ones that I just showed you. So 1386 | 1387 | 347 1388 | 00:15:45,545 --> 00:15:47,978 1389 | let's switch gears for a moment. I've shown you kind of 1390 | 1391 | 348 1392 | 00:15:48,047 --> 00:15:54,351 1393 | the two first instruments that have to do with CPU time and 1394 | 1395 | 349 1396 | 00:15:54,420 --> 00:15:56,420 1397 | what we'll do instead is start looking more into memory. So 1398 | 1399 | 350 1400 | 00:15:56,421 --> 00:15:58,421 1401 | processes. And 1402 | 1403 | 351 1404 | 00:15:58,491 --> 00:16:00,224 1405 | like I mentioned earlier, the two that are most useful for 1406 | 1407 | 352 1408 | 00:16:00,293 --> 00:16:03,828 1409 | this are going to be allocations and leaks. So 1410 | 1411 | 353 1412 | 00:16:03,896 --> 00:16:05,629 1413 | the simpler of the two would be allocations. 1414 | 1415 | 354 1416 | 00:16:05,698 --> 00:16:07,832 1417 | We're just gonna see how much memory is getting allocated at 1418 | 1419 | 355 1420 | 00:16:07,900 --> 00:16:11,936 1421 | various times in the program. And we will hit Choose and 1422 | 1423 | 356 1424 | 00:16:12,004 --> 00:16:17,041 1425 | Run. We will go over to this classroom section here. And 1426 | 1427 | 357 1428 | 00:16:17,110 --> 00:16:19,010 1429 | the first thing that we'll notice about allocations, 1430 | 1431 | 358 1432 | 00:16:19,078 --> 00:16:20,844 1433 | which is showing us the memory that's being used, 1434 | 1435 | 359 1436 | 00:16:20,913 --> 00:16:22,313 1437 | is that when we go off to a new 1438 | 1439 | 360 1440 | 00:16:22,382 --> 00:16:24,048 1441 | view controller, the number, 1442 | 1443 | 361 1444 | 00:16:24,116 --> 00:16:26,384 1445 | the amount of memory being used currently sky rockets up 1446 | 1447 | 362 1448 | 00:16:26,452 --> 00:16:28,152 1449 | because we have a stack of navigation controllers. 1450 | 1451 | 363 1452 | 00:16:28,221 --> 00:16:29,820 1453 | We have the one that's still allocated that's still on 1454 | 1455 | 364 1456 | 00:16:29,889 --> 00:16:31,088 1457 | the stack and then we have this new one. 1458 | 1459 | 365 1460 | 00:16:31,157 --> 00:16:33,991 1461 | So we should see this go up. And likewise, when we go back 1462 | 1463 | 366 1464 | 00:16:34,059 --> 00:16:36,527 1465 | we should see it go down a little bit. And it does. 1466 | 1467 | 367 1468 | 00:16:36,595 --> 00:16:39,864 1469 | So that's great. As we go to the classroom controller and 1470 | 1471 | 368 1472 | 00:16:39,932 --> 00:16:41,999 1473 | from it we see allocations going up and down. 1474 | 1475 | 369 1476 | 00:16:42,067 --> 00:16:43,701 1477 | Sometimes if you have some kind of bug in your app 1478 | 1479 | 370 1480 | 00:16:43,770 --> 00:16:46,403 1481 | you might have it that when you go back from a view 1482 | 1483 | 371 1484 | 00:16:46,472 --> 00:16:49,506 1485 | controller. All of a sudden you don't see the allocations 1486 | 1487 | 372 1488 | 00:16:49,575 --> 00:16:50,475 1489 | go down, which would be a bug. 1490 | 1491 | 373 1492 | 00:16:50,543 --> 00:16:53,711 1493 | So that's something that you might wanna check for. 1494 | 1495 | 374 1496 | 00:16:53,780 --> 00:16:55,779 1497 | And what we'll do here in this case is, 1498 | 1499 | 375 1500 | 00:16:55,848 --> 00:16:58,583 1501 | is explain what's going on in this tab of the app. And then 1502 | 1503 | 376 1504 | 00:16:58,651 --> 00:17:02,052 1505 | we'll kind of look for, for any possible errors. So when 1506 | 1507 | 377 1508 | 00:17:02,121 --> 00:17:06,457 1509 | we click this little button here, we will show a hint. And 1510 | 1511 | 378 1512 | 00:17:06,525 --> 00:17:09,393 1513 | the hint is that Jack, this friendly student here who is 1514 | 1515 | 379 1516 | 00:17:09,462 --> 00:17:11,028 1517 | an image we fetched from online, 1518 | 1519 | 380 1520 | 00:17:11,097 --> 00:17:13,831 1521 | is asking what tips can we use to speed up prime fact-finding 1522 | 1523 | 381 1524 | 00:17:13,900 --> 00:17:16,266 1525 | prime factors? Paul says, have you considered the domain or 1526 | 1527 | 382 1528 | 00:17:16,335 --> 00:17:17,835 1529 | possible factors? Maybe you're trying too many, 1530 | 1531 | 383 1532 | 00:17:17,904 --> 00:17:20,337 1533 | which is the exact bug that we went and fixed earlier with 1534 | 1535 | 384 1536 | 00:17:20,406 --> 00:17:23,373 1537 | the time profiling so. We noticed that when we clicked 1538 | 1539 | 385 1540 | 00:17:23,442 --> 00:17:26,811 1541 | on Show Hint, this really skyrocketed up a lot because 1542 | 1543 | 386 1544 | 00:17:26,880 --> 00:17:28,379 1545 | here we are loading an image into the app and 1546 | 1547 | 387 1548 | 00:17:28,448 --> 00:17:29,980 1549 | that contains a lot of data. So 1550 | 1551 | 388 1552 | 00:17:30,049 --> 00:17:32,849 1553 | what we might do is just play around with all the operations 1554 | 1555 | 389 1556 | 00:17:32,918 --> 00:17:38,389 1557 | we can do inside the app. And just see what's going on here. 1558 | 1559 | 390 1560 | 00:17:38,458 --> 00:17:39,823 1561 | And we immediately find something kind of 1562 | 1563 | 391 1564 | 00:17:39,892 --> 00:17:42,893 1565 | suspicious which is that every time I click Show Hint, we see 1566 | 1567 | 392 1568 | 00:17:42,961 --> 00:17:45,662 1569 | our memory usage is going up, but when we unclick it and 1570 | 1571 | 393 1572 | 00:17:45,731 --> 00:17:48,399 1573 | click it again, it doesn't go back down. So that seems like 1574 | 1575 | 394 1576 | 00:17:48,467 --> 00:17:51,202 1577 | we've got some kind of problem here, seems kinda strange. 1578 | 1579 | 395 1580 | 00:17:51,270 --> 00:17:53,237 1581 | Why would it be going up each time you click Show Hint? 1582 | 1583 | 396 1584 | 00:17:53,305 --> 00:17:55,172 1585 | All that happens each time is we display an image on the 1586 | 1587 | 397 1588 | 00:17:55,240 --> 00:17:58,042 1589 | screen, and then we put these two labels on the screen. 1590 | 1591 | 398 1592 | 00:17:58,111 --> 00:18:01,645 1593 | So why would there not be memory being, being freed? 1594 | 1595 | 399 1596 | 00:18:01,714 --> 00:18:02,346 1597 | In this case it's not like, 1598 | 1599 | 400 1600 | 00:18:02,414 --> 00:18:04,482 1601 | not like necessary that we have a leak, but 1602 | 1603 | 401 1604 | 00:18:04,550 --> 00:18:06,917 1605 | we're just using too much memory for some reason. And so 1606 | 1607 | 402 1608 | 00:18:06,986 --> 00:18:10,454 1609 | let's go off into the code here. And 1610 | 1611 | 403 1612 | 00:18:10,523 --> 00:18:12,690 1613 | we're inside this ClassroomViewController, 1614 | 1615 | 404 1616 | 00:18:12,758 --> 00:18:17,361 1617 | which I will kinda show how it works at the high level. 1618 | 1619 | 405 1620 | 00:18:17,430 --> 00:18:21,632 1621 | It's pretty simple. We have this UI switch, which is that 1622 | 1623 | 406 1624 | 00:18:21,701 --> 00:18:24,869 1625 | button at the top that appears next to the show hint text. 1626 | 1627 | 407 1628 | 00:18:24,937 --> 00:18:27,838 1629 | And when we tap on it and it's on, we fetch this hint. So 1630 | 1631 | 408 1632 | 00:18:27,907 --> 00:18:30,474 1633 | the idea is we're simulating doing a number of requests and 1634 | 1635 | 409 1636 | 00:18:30,543 --> 00:18:31,409 1637 | getting this data back for 1638 | 1639 | 410 1640 | 00:18:31,477 --> 00:18:32,710 1641 | this particular hint from online. 1642 | 1643 | 411 1644 | 00:18:32,779 --> 00:18:35,045 1645 | And then we're displaying it on the screen and 1646 | 1647 | 412 1648 | 00:18:35,114 --> 00:18:39,050 1649 | otherwise we're going to null out this stuff that existed. 1650 | 1651 | 413 1652 | 00:18:41,620 --> 00:18:43,888 1653 | So when we call fetch hint, what we do is we 1654 | 1655 | 414 1656 | 00:18:45,624 --> 00:18:47,824 1657 | allocate this thing called the factorization question, 1658 | 1659 | 415 1660 | 00:18:47,893 --> 00:18:51,395 1661 | which is this class down here at the bottom. And we allocate 1662 | 1663 | 416 1664 | 00:18:51,464 --> 00:18:54,165 1665 | a factorization answer which is this other class down here 1666 | 1667 | 417 1668 | 00:18:54,234 --> 00:18:55,899 1669 | at the bottom, which has text for the answers. 1670 | 1671 | 418 1672 | 00:18:55,968 --> 00:18:58,535 1673 | So these two labels being displayed at the bottom. And 1674 | 1675 | 419 1676 | 00:18:58,604 --> 00:19:01,038 1677 | then on the answer itself, 1678 | 1679 | 420 1680 | 00:19:01,107 --> 00:19:03,707 1681 | we give a handle back to the question. 1682 | 1683 | 421 1684 | 00:19:03,776 --> 00:19:08,345 1685 | And then inside of the question itself, 1686 | 1687 | 422 1688 | 00:19:08,414 --> 00:19:11,515 1689 | we also have an array, which is trying to store references 1690 | 1691 | 423 1692 | 00:19:11,584 --> 00:19:13,484 1693 | off to all the answers for that particular question. 1694 | 1695 | 424 1696 | 00:19:13,552 --> 00:19:15,953 1697 | In this case, there's just one. But we can imagine a data 1698 | 1699 | 425 1700 | 00:19:16,022 --> 00:19:17,321 1701 | structure needing many answers, 1702 | 1703 | 426 1704 | 00:19:17,390 --> 00:19:19,623 1705 | because we might have many answers to a given question. 1706 | 1707 | 427 1708 | 00:19:19,692 --> 00:19:21,325 1709 | So that's what's going on there. 1710 | 1711 | 428 1712 | 00:19:21,394 --> 00:19:23,694 1713 | And then we have this thing called the askerImgUrl, 1714 | 1715 | 429 1716 | 00:19:23,763 --> 00:19:26,196 1717 | which is the, the image that's gonna get displayed for 1718 | 1719 | 430 1720 | 00:19:26,265 --> 00:19:30,667 1721 | the person asking the current question. And that is the URL 1722 | 1723 | 431 1724 | 00:19:30,736 --> 00:19:34,805 1725 | of some image from the web. And so once we fetch the hint, 1726 | 1727 | 432 1728 | 00:19:34,874 --> 00:19:37,007 1729 | and we update the UI, we go off and 1730 | 1731 | 433 1732 | 00:19:37,076 --> 00:19:40,844 1733 | we set off all the text on those labels. We set that 1734 | 1735 | 434 1736 | 00:19:40,913 --> 00:19:44,081 1737 | the whole bottom section on the screen should be mapped to 1738 | 1739 | 435 1740 | 00:19:44,149 --> 00:19:47,651 1741 | whether that's reach up the top is enabled or disabled. 1742 | 1743 | 436 1744 | 00:19:47,720 --> 00:19:51,488 1745 | And then, if it has just been turn on we go often and 1746 | 1747 | 437 1748 | 00:19:51,557 --> 00:19:54,925 1749 | fetch this image online. So, that's what this code is 1750 | 1751 | 438 1752 | 00:19:54,993 --> 00:19:57,761 1753 | doing here and when we're done way inside here and 1754 | 1755 | 439 1756 | 00:19:57,830 --> 00:20:00,298 1757 | may have the data from this image, we're making image for 1758 | 1759 | 440 1760 | 00:20:00,366 --> 00:20:03,300 1761 | you. And we set it off as an image with data, 1762 | 1763 | 441 1764 | 00:20:03,369 --> 00:20:06,236 1765 | like Paul did in lecture. And then we set its contentMode, 1766 | 1767 | 442 1768 | 00:20:06,305 --> 00:20:10,408 1769 | and we add a subview. So every time that the hintSwitch gets 1770 | 1771 | 443 1772 | 00:20:10,476 --> 00:20:12,843 1773 | turns on, we go off and fetch the image from online, and 1774 | 1775 | 444 1776 | 00:20:12,912 --> 00:20:14,711 1777 | we add a subview to the screen. So, of course, 1778 | 1779 | 445 1780 | 00:20:14,780 --> 00:20:15,645 1781 | we have a problem here, 1782 | 1783 | 446 1784 | 00:20:15,714 --> 00:20:17,948 1785 | which is that if you keep adding successive subviews, 1786 | 1787 | 447 1788 | 00:20:18,017 --> 00:20:20,017 1789 | you are adding memory to your app, repeatedly. 1790 | 1791 | 448 1792 | 00:20:22,154 --> 00:20:24,455 1793 | That's why we saw the blue line going up and up and 1794 | 1795 | 449 1796 | 00:20:24,524 --> 00:20:27,225 1797 | up and up and up, right? So that kinda tipped us off, 1798 | 1799 | 450 1800 | 00:20:27,293 --> 00:20:28,659 1801 | since it's going up and up we should go look 1802 | 1803 | 451 1804 | 00:20:28,728 --> 00:20:30,461 1805 | inside the code and see if there is any reason why we 1806 | 1807 | 452 1808 | 00:20:30,529 --> 00:20:32,563 1809 | would just be repeatedly allocating memory without 1810 | 1811 | 453 1812 | 00:20:32,631 --> 00:20:34,598 1813 | ever freeing it. And here is our answer right here, 1814 | 1815 | 454 1816 | 00:20:34,667 --> 00:20:36,534 1817 | its this highlighted line of code. So it's 1818 | 1819 | 455 1820 | 00:20:36,602 --> 00:20:38,502 1821 | kind of how the allocation still works, it's for kind of 1822 | 1823 | 456 1824 | 00:20:38,571 --> 00:20:40,604 1825 | generally figuring out where memory is being allocated. 1826 | 1827 | 457 1828 | 00:20:40,673 --> 00:20:42,673 1829 | But it doesn't actually go that much deeper into 1830 | 1831 | 458 1832 | 00:20:42,741 --> 00:20:45,342 1833 | figuring out did you leak memory or anything like that. 1834 | 1835 | 459 1836 | 00:20:45,410 --> 00:20:47,578 1837 | So that's what the next and final instrument that we're 1838 | 1839 | 460 1840 | 00:20:47,647 --> 00:20:50,347 1841 | going to show today is for, which is the lease instrument. 1842 | 1843 | 461 1844 | 00:20:50,416 --> 00:20:54,285 1845 | So let's pop open instruments again, 1846 | 1847 | 462 1848 | 00:20:54,353 --> 00:20:56,787 1849 | stop our previous run. 1850 | 1851 | 463 1852 | 00:21:01,994 --> 00:21:04,428 1853 | And we will click on the next and final leaks tool. 1854 | 1855 | 464 1856 | 00:21:10,836 --> 00:21:14,004 1857 | And then we will head on over to the classroom again and 1858 | 1859 | 465 1860 | 00:21:14,073 --> 00:21:16,706 1861 | we'll notice that at the bottom here we have this 1862 | 1863 | 466 1864 | 00:21:16,775 --> 00:21:19,877 1865 | kind of like, periodic little green check mark saying, 1866 | 1867 | 467 1868 | 00:21:19,946 --> 00:21:22,979 1869 | you have no memory leaks, good job. So far for this, 1870 | 1871 | 468 1872 | 00:21:23,048 --> 00:21:25,816 1873 | one of the instrument's trees we haven't detected any leaked 1874 | 1875 | 469 1876 | 00:21:25,885 --> 00:21:27,351 1877 | memory and you can see it's still green and 1878 | 1879 | 470 1880 | 00:21:27,419 --> 00:21:28,218 1881 | that's great. So 1882 | 1883 | 471 1884 | 00:21:28,287 --> 00:21:30,754 1885 | what you might do in this case is just go off through normal 1886 | 1887 | 472 1888 | 00:21:30,823 --> 00:21:32,022 1889 | use cases of your app and 1890 | 1891 | 473 1892 | 00:21:32,091 --> 00:21:34,458 1893 | just try things out and see if you have any problems. 1894 | 1895 | 474 1896 | 00:21:34,526 --> 00:21:38,362 1897 | So we might, like, show this hint, unshow this hint, and 1898 | 1899 | 475 1900 | 00:21:38,431 --> 00:21:40,498 1901 | the moment that we do that we actually see that we already 1902 | 1903 | 476 1904 | 00:21:40,566 --> 00:21:43,033 1905 | have a red x here which means that the leak checker has 1906 | 1907 | 477 1908 | 00:21:43,102 --> 00:21:46,871 1909 | detected we have a memory leak somehow. That's no good. So 1910 | 1911 | 478 1912 | 00:21:46,939 --> 00:21:48,939 1913 | if we want to figure out more details about what's going 1914 | 1915 | 479 1916 | 00:21:49,008 --> 00:21:51,108 1917 | on let's say that we go onto one of these x's where it says 1918 | 1919 | 480 1920 | 00:21:51,176 --> 00:21:53,944 1921 | look there are twenty new leaks. And we click on it and 1922 | 1923 | 481 1924 | 00:21:54,013 --> 00:21:56,280 1925 | wow look at all these leaks that are happening, 1926 | 1927 | 482 1928 | 00:21:56,348 --> 00:21:58,281 1929 | and how could so many leaks be happening within a single 1930 | 1931 | 483 1932 | 00:21:58,350 --> 00:22:00,851 1933 | simple application? But it turns out that these leaks 1934 | 1935 | 484 1936 | 00:22:00,920 --> 00:22:04,821 1937 | are all happening very under the hood like malic this malic 1938 | 1939 | 485 1940 | 00:22:04,890 --> 00:22:08,259 1941 | leak to this leak. So those might be caused by one general 1942 | 1943 | 486 1944 | 00:22:08,327 --> 00:22:11,394 1945 | greater leak inside of our app which is things like 1946 | 1947 | 487 1948 | 00:22:11,463 --> 00:22:14,465 1949 | question and answer which were those classes that we created. 1950 | 1951 | 488 1952 | 00:22:14,534 --> 00:22:17,233 1953 | You can see them here inside that view controller. So 1954 | 1955 | 489 1956 | 00:22:17,302 --> 00:22:19,803 1957 | these are the things that are the root cause of these leaks. 1958 | 1959 | 490 1960 | 00:22:19,872 --> 00:22:21,739 1961 | But still looking at this trace right here it's not 1962 | 1963 | 491 1964 | 00:22:21,807 --> 00:22:22,839 1965 | exactly obvious 1966 | 1967 | 492 1968 | 00:22:22,908 --> 00:22:24,475 1969 | why that leak happened. And so 1970 | 1971 | 493 1972 | 00:22:24,543 --> 00:22:26,209 1973 | we might want to go into a little bit more detail, 1974 | 1975 | 494 1976 | 00:22:26,278 --> 00:22:28,745 1977 | and figure out, what the heck, why, where is this thing 1978 | 1979 | 495 1980 | 00:22:28,814 --> 00:22:31,715 1981 | coming from and what's going on here. And if you'll notice 1982 | 1983 | 496 1984 | 00:22:31,783 --> 00:22:35,085 1985 | up here on this tab, which exists in all the instruments, 1986 | 1987 | 497 1988 | 00:22:35,153 --> 00:22:37,922 1989 | we can actually select the way that we want it to display 1990 | 1991 | 498 1992 | 00:22:37,990 --> 00:22:40,758 1993 | this data. So right here we just have this kind of big, 1994 | 1995 | 499 1996 | 00:22:40,827 --> 00:22:41,859 1997 | set of all the information, 1998 | 1999 | 500 2000 | 00:22:41,927 --> 00:22:44,862 2001 | but we can also do this thing called cycles and routes, 2002 | 2003 | 501 2004 | 00:22:44,930 --> 00:22:47,698 2005 | inside the leak checker. So when we go inside here, 2006 | 2007 | 502 2008 | 00:22:47,766 --> 00:22:51,001 2009 | we see that we have some kind of MallocBlock 2010 | 2011 | 503 2012 | 00:22:51,070 --> 00:22:53,203 2013 | right here that is referencing something else that was 2014 | 2015 | 504 2016 | 00:22:53,272 --> 00:22:56,740 2017 | referenced up here earlier. And that there is overall some 2018 | 2019 | 505 2020 | 00:22:56,809 --> 00:22:59,343 2021 | circular reference of memory, some circular dependency. And 2022 | 2023 | 506 2024 | 00:22:59,411 --> 00:23:01,545 2025 | so maybe when we're freeing memory from one thing, 2026 | 2027 | 507 2028 | 00:23:01,614 --> 00:23:04,415 2029 | it's not actually freeing everything because things 2030 | 2031 | 508 2032 | 00:23:04,483 --> 00:23:07,017 2033 | still have references to things that don't exist in 2034 | 2035 | 509 2036 | 00:23:07,086 --> 00:23:09,353 2037 | memory. So we're actually getting rid of all of our 2038 | 2039 | 510 2040 | 00:23:09,422 --> 00:23:12,289 2041 | references. And sometimes when you run instruments it won't 2042 | 2043 | 511 2044 | 00:23:12,358 --> 00:23:16,393 2045 | actually symbolicate your, the names of your code classes, 2046 | 2047 | 512 2048 | 00:23:16,462 --> 00:23:19,663 2049 | or objects in memory, into the cycle checker, 2050 | 2051 | 513 2052 | 00:23:19,731 --> 00:23:21,498 2053 | and sometimes it will properly do that. So, 2054 | 2055 | 514 2056 | 00:23:21,567 --> 00:23:26,736 2057 | if I run it again here We'll start, we'll restart the app, 2058 | 2059 | 515 2060 | 00:23:26,805 --> 00:23:31,308 2061 | maybe we'll get luckier this time. And 2062 | 2063 | 516 2064 | 00:23:31,377 --> 00:23:37,848 2065 | when we show a hint, And then we unshow a hint. 2066 | 2067 | 517 2068 | 00:23:41,687 --> 00:23:45,055 2069 | We'll see that there's a leak here. Oops, I guess we 2070 | 2071 | 518 2072 | 00:23:45,123 --> 00:23:48,659 2073 | have the same problem. So, first lesson of instruments is 2074 | 2075 | 519 2076 | 00:23:48,728 --> 00:23:50,527 2077 | that sometimes in the leaks checker you'll notice that it 2078 | 2079 | 520 2080 | 00:23:50,596 --> 00:23:53,630 2081 | doesn't actually symbolicate this. In some use cases of 2082 | 2083 | 521 2084 | 00:23:53,699 --> 00:23:57,334 2085 | this you might see it show that the questions arrayed 2086 | 2087 | 522 2088 | 00:23:57,403 --> 00:23:59,136 2089 | down here in the answers array are up at the top and 2090 | 2091 | 523 2092 | 00:23:59,204 --> 00:24:01,104 2093 | that they have a circular reference to each other. 2094 | 2095 | 524 2096 | 00:24:01,173 --> 00:24:03,741 2097 | It might actually show that if it symbolicates the debugging 2098 | 2099 | 525 2100 | 00:24:03,809 --> 00:24:06,977 2101 | information. But you're not guaranteed to have that. But 2102 | 2103 | 526 2104 | 00:24:07,046 --> 00:24:08,912 2105 | in any case, we know that we have a cycle here. 2106 | 2107 | 527 2108 | 00:24:08,981 --> 00:24:11,515 2109 | So what we can do now is go off knowing that we have 2110 | 2111 | 528 2112 | 00:24:11,583 --> 00:24:15,919 2113 | a memory cycle somehow, and look at our code and go hm, 2114 | 2115 | 529 2116 | 00:24:15,988 --> 00:24:18,789 2117 | something about questions and answers has a memory cycle. 2118 | 2119 | 530 2120 | 00:24:18,857 --> 00:24:21,391 2121 | And so I, you can see I have these helpful comments here 2122 | 2123 | 531 2124 | 00:24:21,460 --> 00:24:24,027 2125 | after each line like the factorization reference count 2126 | 2127 | 532 2128 | 00:24:24,096 --> 00:24:26,397 2129 | is 1. So when we allocate when we 2130 | 2131 | 533 2132 | 00:24:26,465 --> 00:24:29,399 2133 | allocate a question to set off to this instance variable, 2134 | 2135 | 534 2136 | 00:24:29,468 --> 00:24:33,370 2137 | which is the optional question here, factorization question, 2138 | 2139 | 535 2140 | 00:24:33,439 --> 00:24:38,075 2141 | then there's also an answer. We're making one here and 2142 | 2143 | 536 2144 | 00:24:38,144 --> 00:24:40,477 2145 | one here, which means the reference count is one for 2146 | 2147 | 537 2148 | 00:24:40,546 --> 00:24:42,345 2149 | each of them because these are classes, 2150 | 2151 | 538 2152 | 00:24:42,414 --> 00:24:45,282 2153 | which means they're reference types, so they're allocated 2154 | 2155 | 539 2156 | 00:24:45,351 --> 00:24:48,418 2157 | with reference counting. And then you see down here when we 2158 | 2159 | 540 2160 | 00:24:48,487 --> 00:24:52,122 2161 | set off the factorization answers question property, 2162 | 2163 | 541 2164 | 00:24:52,191 --> 00:24:55,525 2165 | now factorization question has a reference count of 2 because 2166 | 2167 | 542 2168 | 00:24:55,594 --> 00:24:58,595 2169 | we actually stored it off on the answer. And then the same 2170 | 2171 | 543 2172 | 00:24:58,664 --> 00:25:01,598 2173 | thing is true for setting off on the answers. 2174 | 2175 | 544 2176 | 00:25:01,667 --> 00:25:04,467 2177 | So in theory, it makes sense we could have a cycle here 2178 | 2179 | 545 2180 | 00:25:04,536 --> 00:25:06,570 2181 | because we have the answer referencing the question and 2182 | 2183 | 546 2184 | 00:25:06,639 --> 00:25:08,705 2185 | the question referencing the answers. So 2186 | 2187 | 547 2188 | 00:25:08,774 --> 00:25:11,541 2189 | there is circularity going on. 2190 | 2191 | 548 2192 | 00:25:11,610 --> 00:25:15,645 2193 | And of course, we do because we are never actually, when we 2194 | 2195 | 549 2196 | 00:25:15,714 --> 00:25:20,383 2197 | uncheck the hint switch up at the top, that's this else case 2198 | 2199 | 550 2200 | 00:25:20,452 --> 00:25:23,753 2201 | right here, we're nilling out the factorization answer 2202 | 2203 | 551 2204 | 00:25:23,822 --> 00:25:28,057 2205 | optional and the question optional. But 2206 | 2207 | 552 2208 | 00:25:28,126 --> 00:25:31,028 2209 | the reference counts were two, not one, because we internally 2210 | 2211 | 553 2212 | 00:25:31,097 --> 00:25:34,264 2213 | set references to each of them off on each other. So 2214 | 2215 | 554 2216 | 00:25:34,332 --> 00:25:36,233 2217 | we never actually get the reference counts down to zero, 2218 | 2219 | 555 2220 | 00:25:36,302 --> 00:25:38,701 2221 | which would cause them to be fully deallocated, 2222 | 2223 | 556 2224 | 00:25:38,770 --> 00:25:40,971 2225 | which is why we have a memory leak popping up due to what's 2226 | 2227 | 557 2228 | 00:25:41,040 --> 00:25:43,073 2229 | called a complex cycle. That's what instruments was telling 2230 | 2231 | 558 2232 | 00:25:43,142 --> 00:25:46,409 2233 | us. So now our question becomes, how on earth do we 2234 | 2235 | 559 2236 | 00:25:46,478 --> 00:25:48,612 2237 | solve this problem? And there are lots of ways that we could 2238 | 2239 | 560 2240 | 00:25:48,681 --> 00:25:51,248 2241 | solve this problem. One of the ways is we could say, 2242 | 2243 | 561 2244 | 00:25:51,317 --> 00:25:53,149 2245 | the problem has to do with reference counts. What we 2246 | 2247 | 562 2248 | 00:25:53,218 --> 00:25:55,552 2249 | really need to do is get these reference counts down to zero. 2250 | 2251 | 563 2252 | 00:25:55,621 --> 00:25:59,957 2253 | So manually we can go in like it's 1995 and say 2254 | 2255 | 564 2256 | 00:26:00,025 --> 00:26:03,727 2257 | factorizationAnswer.question = nil, 2258 | 2259 | 565 2260 | 00:26:03,795 --> 00:26:08,899 2261 | which will cause the reference count to actually be zero. 2262 | 2263 | 566 2264 | 00:26:08,967 --> 00:26:11,301 2265 | And then that will cause the reference count to hit zero. 2266 | 2267 | 567 2268 | 00:26:11,370 --> 00:26:13,436 2269 | And then it will get deallocated properly. But 2270 | 2271 | 568 2272 | 00:26:13,505 --> 00:26:15,639 2273 | imagine if every time you ever wrote a code that used classes 2274 | 2275 | 569 2276 | 00:26:15,707 --> 00:26:17,707 2277 | and allocated things on the heap, you had to manually go 2278 | 2279 | 570 2280 | 00:26:17,776 --> 00:26:19,342 2281 | make sure your reference counts were zero, 2282 | 2283 | 571 2284 | 00:26:19,411 --> 00:26:21,678 2285 | that would be really gross. And it would be nice if 2286 | 2287 | 572 2288 | 00:26:21,747 --> 00:26:23,947 2289 | the programming language itself gave you constructs to 2290 | 2291 | 573 2292 | 00:26:24,016 --> 00:26:26,683 2293 | avoid this problem in the first place. And of course, 2294 | 2295 | 574 2296 | 00:26:26,752 --> 00:26:30,520 2297 | Swift does. It affords you many. So the first and 2298 | 2299 | 575 2300 | 00:26:30,589 --> 00:26:33,190 2301 | simplest way that Paul has gone over in lecture with 2302 | 2303 | 576 2304 | 00:26:33,258 --> 00:26:37,126 2305 | regard to closures is to use this keyword called weak. So 2306 | 2307 | 577 2308 | 00:26:37,195 --> 00:26:41,064 2309 | if we store off the reference to the question inside answer 2310 | 2311 | 578 2312 | 00:26:41,133 --> 00:26:44,901 2313 | as a weak variable, then it doesn't actually increment 2314 | 2315 | 579 2316 | 00:26:44,970 --> 00:26:47,704 2317 | that reference count. And there's actually no reason 2318 | 2319 | 580 2320 | 00:26:47,773 --> 00:26:49,806 2321 | that why when the answer itself is set to nil, 2322 | 2323 | 581 2324 | 00:26:49,875 --> 00:26:50,874 2325 | it won't go down to zero and 2326 | 2327 | 582 2328 | 00:26:50,943 --> 00:26:53,410 2329 | get deallocated properly. So all we really need to do 2330 | 2331 | 583 2332 | 00:26:53,479 --> 00:26:56,212 2333 | is add weak in order to get the same behavior as manually 2334 | 2335 | 584 2336 | 00:26:56,281 --> 00:26:59,316 2337 | going off and 2338 | 2339 | 585 2340 | 00:26:59,384 --> 00:27:01,851 2341 | So that's a nice thing that Swift provides you to solve 2342 | 2343 | 586 2344 | 00:27:01,920 --> 00:27:03,654 2345 | a reference counting problem like that. But 2346 | 2347 | 587 2348 | 00:27:03,722 --> 00:27:06,656 2349 | there's one more way that Swift gives you to solve this 2350 | 2351 | 588 2352 | 00:27:06,725 --> 00:27:09,859 2353 | problem up front in the very first place. Which is to say, 2354 | 2355 | 589 2356 | 00:27:09,928 --> 00:27:12,562 2357 | you know, we have this distinction between 2358 | 2359 | 590 2360 | 00:27:12,631 --> 00:27:16,466 2361 | classes and structs, reference types and value types. And why 2362 | 2363 | 591 2364 | 00:27:16,535 --> 00:27:20,270 2365 | on earth are we using classes here to increment reference 2366 | 2367 | 592 2368 | 00:27:20,339 --> 00:27:24,207 2369 | types when a struct would have done just the same. This is, 2370 | 2371 | 593 2372 | 00:27:24,276 --> 00:27:26,042 2373 | there's no reason that this needs to be a class. We don't 2374 | 2375 | 594 2376 | 00:27:26,111 --> 00:27:27,944 2377 | need a handle on it anywhere else in the application. 2378 | 2379 | 595 2380 | 00:27:28,013 --> 00:27:30,614 2381 | We don't need a pointer to it. We don't need to worry about 2382 | 2383 | 596 2384 | 00:27:30,683 --> 00:27:33,483 2385 | the fact that making many of them is going to cause 2386 | 2387 | 597 2388 | 00:27:33,552 --> 00:27:35,686 2389 | way too much memory to happen cuz they're just questions and 2390 | 2391 | 598 2392 | 00:27:35,754 --> 00:27:38,188 2393 | answers which are tiny amounts of data. So what the heck? 2394 | 2395 | 599 2396 | 00:27:38,256 --> 00:27:40,456 2397 | Why are these classes in the first place? All righty, so 2398 | 2399 | 600 2400 | 00:27:40,525 --> 00:27:43,426 2401 | since we've changed these two structs now, we should have no 2402 | 2403 | 601 2404 | 00:27:43,495 --> 00:27:45,829 2405 | more reference kind of going on anywhere with questions and 2406 | 2407 | 602 2408 | 00:27:45,898 --> 00:27:48,799 2409 | answers. Which means that value typing has solved our 2410 | 2411 | 603 2412 | 00:27:48,868 --> 00:27:51,568 2413 | whole allocation leak problem outright, 2414 | 2415 | 604 2416 | 00:27:51,637 --> 00:27:54,705 2417 | which is a great feature of the Swift language 2418 | 2419 | 605 2420 | 00:27:54,773 --> 00:27:57,006 2421 | in the first place. So that's actually kind of the, 2422 | 2423 | 606 2424 | 00:27:57,075 --> 00:27:58,675 2425 | the nuclear bomb and great solution to, 2426 | 2427 | 607 2428 | 00:27:58,743 --> 00:28:01,145 2429 | to this problem which is that you should just use, 2430 | 2431 | 608 2432 | 00:28:01,213 --> 00:28:03,880 2433 | you should use value types when, when possible, and 2434 | 2435 | 609 2436 | 00:28:03,949 --> 00:28:05,983 2437 | when it makes sense to. If you don't need a reference type, 2438 | 2439 | 610 2440 | 00:28:06,052 --> 00:28:09,086 2441 | then you should use the value type. And 2442 | 2443 | 611 2444 | 00:28:09,154 --> 00:28:11,754 2445 | that's kind of the end of the leaks demonstration here. 2446 | 2447 | 612 2448 | 00:28:11,823 --> 00:28:16,459 2449 | So as you can, as you can see, we've been through these four 2450 | 2451 | 613 2452 | 00:28:16,528 --> 00:28:19,929 2453 | main types of instruments here, the activity monitor, 2454 | 2455 | 614 2456 | 00:28:19,998 --> 00:28:22,266 2457 | the time profiler, allocations, and leaks. 2458 | 2459 | 615 2460 | 00:28:22,334 --> 00:28:23,333 2461 | And you've gotten a kind of taste 2462 | 2463 | 616 2464 | 00:28:23,402 --> 00:28:24,601 2465 | of how they work. If you wanna go off and 2466 | 2467 | 617 2468 | 00:28:24,670 --> 00:28:27,037 2469 | learn how more of them work, maybe you're going off, 2470 | 2471 | 618 2472 | 00:28:27,106 --> 00:28:28,772 2473 | you wanna figure out what's going over the network. 2474 | 2475 | 619 2476 | 00:28:28,841 --> 00:28:30,974 2477 | You can learn more about the Network tab on your own time, 2478 | 2479 | 620 2480 | 00:28:31,042 --> 00:28:33,777 2481 | or you're making some kind of graphics application, 2482 | 2483 | 621 2484 | 00:28:33,845 --> 00:28:37,080 2485 | you might use these purple colored ones, like scene kit, 2486 | 2487 | 622 2488 | 00:28:37,149 --> 00:28:38,948 2489 | or metal system trace, or core animation. 2490 | 2491 | 623 2492 | 00:28:39,017 --> 00:28:40,917 2493 | So there's lots more that you can do with instruments. 2494 | 2495 | 624 2496 | 00:28:40,986 --> 00:28:42,653 2497 | And it's very fun to go off and use it. 2498 | 2499 | 625 2500 | 00:28:42,721 --> 00:28:45,222 2501 | So I encourage you to go off and try all of them out and 2502 | 2503 | 626 2504 | 00:28:45,290 --> 00:28:47,290 2505 | figure out how you can Introduce it 2506 | 2507 | 627 2508 | 00:28:47,359 --> 00:28:49,626 2509 | into your debugging process so that you're not sitting there 2510 | 2511 | 628 2512 | 00:28:49,695 --> 00:28:52,296 2513 | really confused by your most complex bugs. And instead, 2514 | 2515 | 629 2516 | 00:28:52,364 --> 00:28:54,631 2517 | you're going off and just getting more data and figuring 2518 | 2519 | 630 2520 | 00:28:54,700 --> 00:28:56,866 2521 | out what's true and not true about your application. 2522 | 2523 | 631 2524 | 00:28:56,935 --> 00:28:58,902 2525 | So that's it for the instruments demo for today. 2526 | 2527 | 632 2528 | 00:28:58,971 --> 00:29:01,805 2529 | I hope this has been useful, and we'll see you in class on 2530 | 2531 | 633 2532 | 00:29:01,874 --> 00:29:03,806 2533 | Monday. >> For 2534 | 2535 | 634 2536 | 00:29:03,875 --> 00:29:13,282 2537 | more, please visit us at stanford.edu. 2538 | >> 更多课程详见 stanford.edu 2539 | -------------------------------------------------------------------------------- /tools/update/download.md: -------------------------------------------------------------------------------- 1 | [返回主页](../../README.md) / [Back to Main Page](../../en/README.md) 2 | 3 | # 课程视频 / Lecture Videos 4 | 5 | 1.
Introduction to iOS 11, Xcode 9 and Swift 4Paul Hegarty provides an overview of the lecture series and introduces the different components in iOS. He concludes with a demo of Concentration Game.
6 | 2.
MVCPaul Hegarty explains the Model-View-Controller (MVC) concept. He then continues the Concentration demo: demonstrating the application of MVC to the Concentration Game.
7 | 3.
Swift Programming LanguagePaul Hegarty begins with a demonstration of making Concentration's button layout dynamic. He then reviews the first two lectures and continues diving into Swift.
8 | 4.
More SwiftPaul Hegarty continues his coverage of Swift.
9 | 5.
DrawingPaul Hegarty covers error handling, special types any and anyobject, and casting. He then introduces views.
10 | 6.
MultitouchPaul Hegarty continues his PlayingCard demonstration on views. He then introduces gestures and concludes with a demo on swiping, tapping and pinching.
11 | 7.
Multiple MVCs, Timer, and AnimationPaul Hegarty begins with an explanation of multiple MVCs and demonstrates Theme Chooser in Concentration. He then introduces timer and animation.
12 | 8.
AnimationPaul Hegarty continues his coverage of Animation.
13 | 9.
View Controller Lifecycle and Scroll ViewPaul Hegarty delves into the view controller lifecycle – keeping track of what's happening in your Controller as it goes through its lifetime – and then demonstrates putting print()s into the multiple-MVC version of Concentration. He then covers scroll view.
14 | 10.
Multithreading and AutolayoutPaul Hegarty covers multithreading and then demonstrates with a multithreaded Cassini. He then introduces autolayout.
15 | 11.
Drag and Drop, Table View, and Collection ViewPaul Hegarty lectures about drag and drop – transferring information around within and between apps – and demonstrates applying it in a demonstration of EmojiArt. He then introduces UITableView and UICollectionView.
16 | 12.
Drag and Drop, Table View, Collection View, and Text FieldPaul Hegarty continues his demo of EmojiArt. He then covers editable text input control with UITextField.
17 | 13.
Persistence and DocumentsPaul Hegarty continues his demo of Emoji Art where he implements UITextField to add more Emoji. He then introduces persistence.
18 | 14.
Persistence and Documents DemoPaul Hegarty extends his coverage of Documents. He then does a demonstration of using Codable to create a JSON representation, storing it in the filesystem then letting UIDocument store it instead, and then using UIDocumentBrowserViewController to choose/create/rename/move documents.
19 | 15.
Alerts, Notifications, Application LifecyclePaul Hegarty covers alerts and action sheets, notifications and KVO, and the application lifecycle.
20 | 16.
More SeguesPaul Hegarty talks about modal, popover, unwind, and embed segues.
21 | 17.
Core Motion and CameraPaul Hegarty introduces Core Motion – detecting the position and movement of the device – and then does a demo with Gravity-Driven Playing Card. He then covers taking pictures within your app.
22 | 23 | # 周五课程 / Friday Sessions 24 | 25 | 1.
Debugging and Xcode Tips and TricksJason Riggs talks about debugging and shares Xcode tips and tricks.
26 | 2.
Github and Source Control WorkflowJunjie Ke covers Github and the source control workflow.
27 | 3.
InstrumentsJason Riggs explains instruments.
28 | 29 | # 课程讲义 / Slides 30 | 31 | 1. [Lecture 1 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/b8/e3/2e/b8e32eaf-b0c4-4c3c-15e3-047f446b3e39/306-8064245884110005836-CS193P_F17_Lecture_1.pdf) 32 | 2. [Lecture 2 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/c2/d5/8f/c2d58f95-6448-17c1-fd56-46536fe6e2ae/335-8348407309262319289-CS193P_F17_Lecture_2.pdf) 33 | 3. [Lecture 3 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/2a/94/52/2a945263-f1f8-16b6-43e1-6ee87eab15c2/331-7606507835520006753-CS193P_F17_Lecture_3.pdf) 34 | 4. [Lecture 4 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/0e/70/72/0e707292-d70e-c91d-dbb4-e75eacf606cd/332-7722181712227503268-CS193P_F17_Lecture_4.pdf) 35 | 5. [Lecture 5 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/1f/17/6e/1f176e43-2235-47c3-01d3-8b79dffd5a47/330-1915007205404420726-CS193P_F17_Lecture_5.pdf) 36 | 6. [Lecture 6 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/e5/a7/ae/e5a7aeba-db5f-b50f-a6d3-861dd0bb8a57/312-5688919973254424356-CS193P_F17_Lecture_6.pdf) 37 | 7. [Lecture 7 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/a9/6f/3b/a96f3b8a-35c1-50bd-ce9f-e26a54d48544/320-5503734535583450465-CS193P_F17_Lecture_7.pdf) 38 | 8. [Lecture 8 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/bf/dd/b5/bfddb5ba-503e-0057-a1b7-dfaeeb999387/335-3416648937156657194-CS193P_F17_Lecture_8.pdf) 39 | 9. [Lecture 9 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/84/92/46/849246d8-03f1-4eb8-9ab6-bedde8580d24/332-3154341613995510587-CS193P_F17_Lecture_9.pdf) 40 | 10. [Lecture 10 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/d2/d2/6b/d2d26bfc-0528-265c-6c60-90ec126e6ee5/322-6515997048783028736-CS193P_F17_Lecture_10.pdf) 41 | 11. [Lecture 11 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/90/9f/cf/909fcfbf-7e6a-6722-fe59-27429115ff6b/317-8823617114003497609-CS193P_F17_Lecture_11.pdf) 42 | 12. [Lecture 12 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/40/1e/67/401e6721-4436-fb80-2ca1-9d5378b2101e/306-4082649130340532415-CS193P_F17_Lecture_12.pdf) 43 | 13. [Lecture 13 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/b6/6b/ae/b66bae2e-4eaa-0b2f-ec1e-f056af95bde1/323-4247208383177102782-CS193P_F17_Lecture_13.pdf) 44 | 14. [Lecture 14 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/fa/71/a4/fa71a463-d836-f2d2-005d-e00ca2d84b48/322-5794459892624250293-CS193P_F17_Lecture_14.pdf) 45 | 15. [Lecture 15 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/1d/4d/19/1d4d19f2-e6de-0cb4-d7c7-f33d68f66b23/522-830176750758320683-CS193P_F17_Lecture_15.pdf) 46 | 16. [Lecture 16 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/71/df/17/71df17c8-daa9-747c-cc0e-610303b1129d/512-802352814004650525-CS193P_F17_Lecture_16.pdf) 47 | 17. [Lecture 17 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/2c/43/84/2c438427-46b9-efb4-d774-0edc98073f3b/520-5280642336803569160-CS193P_F17_Lecture_17_Slides.pdf) 48 | 49 | # 阅读作业 / Readings 50 | 51 | 1. [Intro to Swift](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/4b/1b/f6/4b1bf6e4-f408-21fe-924d-c5fdb8ec9ea3/309-1725317477475915568-CS193P_F17_Reading_1.pdf) 52 | 2. [Intro to Swift](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/a1/8b/72/a18b72d5-6c48-9898-ff1e-7d95d2c5d914/301-1950499169436194703-CS193P_F17_Reading_2.pdf) 53 | 3. [Finishing Off Swift](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/d3/2d/e5/d32de58b-bbb0-2264-be85-25b2c84a4733/336-3367719085568248138-CS193P_F17_Reading_3.pdf) 54 | 55 | # 编程作业 / Programming Projects 56 | 57 | 1. [Concentration](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/04/b5/81/04b58115-f130-54e7-e23d-020840f92932/311-6986826354385551794-CS193P_F17_Assignment_1_iTunesU.pdf) 58 | 2. [Set](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/a9/7f/a3/a97fa31e-7bb6-6fa3-3e37-dd3654699ba4/314-6143069573660719394-CS193P_F17_Assignment_2.pdf) 59 | 3. [Graphical Set](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/5e/34/b1/5e34b154-8ffd-ee18-2df3-16d50177b8cc/309-1475895300459033080-CS193P_F17_Assignment_3.pdf) 60 | 4. [Animated Set](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/5e/89/9f/5e899f5d-19e7-aa34-6ca7-93a1e645eefc/309-2441628197055099936-CS193P_F17_Assignment_4.pdf) 61 | 5. [Image Gallery](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic118/v4/22/c3/00/22c30013-28dd-41eb-e104-a4594ec95dad/308-8518403617003934463-CS193P_F17_Assignment_5.pdf) 62 | 6. [Persistent Image Gallery](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic128/v4/5a/46/19/5a4619d5-bee0-1379-e204-731912cea353/307-9138746427331321981-CS193P_F17_Assignment_6.pdf) 63 | 64 |
已收录 46/46 Entries
65 | -------------------------------------------------------------------------------- /tools/update/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Apollo Zhu on 3/12/17. 3 | // This work is licensed under a 4 | // Creative Commons Attribution-NonCommercial-ShareAlike 3.0 United States License. 5 | // 6 | 7 | import Foundation 8 | import AppKit 9 | 10 | /// itunes.apple.com/course/id<#iTunesUCourseID#> 11 | let iTunesUCourseID = 1309275316 12 | 13 | enum ResourceType: String, CustomStringConvertible { 14 | // Raw Type: video/x-m4v, video/mp4 15 | case lecture = "." 16 | case friday = "Friday Session" 17 | // Raw Type: application/pdf 18 | case slides = "Slides" 19 | case demo = "Demo Code" 20 | case reading = "Reading" 21 | case project = "Programming Project" 22 | 23 | static let all: [ResourceType] = [.lecture, .friday, .slides, .demo, .reading, .project] 24 | 25 | var description: String { 26 | switch self { 27 | case .lecture: return "课程视频 / Lecture Videos" 28 | case .friday: return "周五课程 / Friday Sessions" 29 | case .slides: return "课程讲义 / Slides" 30 | case .demo: return "示例代码 / Demo Code" 31 | case .reading: return "阅读作业 / Readings" 32 | case .project: return "编程作业 / Programming Projects" 33 | } 34 | } 35 | } 36 | 37 | struct Resource: CustomStringConvertible { 38 | let index: Int 39 | let title: String 40 | let type: ResourceType 41 | let url: String 42 | let summary: String? 43 | 44 | init?(title: String, url: String, summary: String?) { 45 | self.url = url 46 | 47 | let optional = ResourceType.all.first { title.contains($0.rawValue) } 48 | if let type = optional { self.type = type } else { return nil } 49 | 50 | var parts: [String] 51 | switch type { 52 | case .lecture: 53 | // 4. Views -> index: 4, title: Views 54 | parts = title.components(separatedBy: ". ") 55 | case .reading: 56 | // Reading 1: Intro to Swift -> index: 1, title: Intro to Swift 57 | parts = title.components(separatedBy: ": ") 58 | parts[0] = parts[0].components(separatedBy: " ")[1] 59 | case .project, .friday: 60 | // Programming Project 2: Calculator Brain -> index: 2, title: Calculator Brain 61 | // Friday Session 3: Instruments 62 | parts = title.components(separatedBy: ": ") 63 | parts[0] = parts[0].components(separatedBy: " ")[2] 64 | default: 65 | // Lecture 6 Slides -> index: 6, title: Lecture 6 Slides 66 | // Lecture 9 Demo Code: Smashtag -> index: 9, title: Lecture 9 Demo Code: Smashtag 67 | parts = [title.components(separatedBy: " ")[1], title] 68 | } 69 | guard parts.count > 1, let index = Int(parts[0]) else { return nil } 70 | self.index = index 71 | self.title = parts[1] 72 | 73 | self.summary = summary == title ? nil : summary?.trimmingCharacters(in: .whitespacesAndNewlines) 74 | } 75 | 76 | var description: String { 77 | guard let summary = summary else { return "\(index). [\(title)](\(url))" } 78 | return "\(index).
\(title)\(summary)
" 79 | } 80 | } 81 | 82 | /* Example XML 83 | 84 | 85 | Paul Hegarty 86 | 87 | 88 | <![CDATA[ <#Title#> ]]> 89 | 90 | 1/COETAIHAJLZIQXJI/MAEC2FBSEERRMTUH 91 | 2017-03-10T18:19:21PST 92 | 2017-03-10T17:36:29PST 93 | 94 | 95 | 96 | 97 | 98 | */ 99 | class ParsingDelegate: NSObject, XMLParserDelegate { 100 | var resources = [Resource]() 101 | 102 | var title: String? 103 | var isParsingTitle = false 104 | var url: String? 105 | var summary: String? 106 | var isParsingSummary = false 107 | var totalSkipped = 0 108 | var total = 0 109 | 110 | func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { 111 | switch elementName { 112 | case "title": 113 | isParsingTitle = true 114 | case "summary": 115 | isParsingSummary = true 116 | case "link": 117 | url = attributeDict["href"] 118 | default: 119 | break 120 | } 121 | } 122 | 123 | func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) { 124 | if let cData = String(data: CDATABlock, encoding: .utf8) { 125 | if isParsingTitle { 126 | title = cData 127 | } else if isParsingSummary { 128 | summary = cData 129 | } else { 130 | debugPrint("Ignored CDATA[ \(CDATABlock) ]") 131 | } 132 | } else { 133 | fatalError("Unable to parse CDATA[ \(CDATABlock) ]") 134 | } 135 | } 136 | 137 | func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { 138 | switch elementName { 139 | case "title": 140 | isParsingTitle = false 141 | case "summary": 142 | isParsingSummary = false 143 | case "entry": 144 | total += 1 145 | if let res = Resource(title: title!, url: url!, summary: summary) { 146 | resources.append(res) 147 | } else { 148 | totalSkipped += 1 149 | debugPrint("Skipped \(title ?? "Titleless")") 150 | } 151 | title = nil 152 | isParsingTitle = false 153 | url = nil 154 | summary = nil 155 | isParsingSummary = false 156 | default: 157 | break 158 | } 159 | } 160 | 161 | func parserDidEndDocument(_ parser: XMLParser) { 162 | let sorted = ResourceType.all.map { [resources] type in 163 | resources.filter { $0.type == type } .sorted { $0.index < $1.index } 164 | } 165 | 166 | var out = "[返回主页](../../README.md) / [Back to Main Page](../../en/README.md)\n\n" 167 | for (index, type) in ResourceType.all.enumerated() { 168 | guard !sorted[index].isEmpty else { 169 | continue 170 | // fatalError("Missing Resources of Type \(type)") 171 | } 172 | out += "# \(type)\n\n" 173 | + "\(sorted[index].reduce("") { "\($0)\($1)\n" })\n" 174 | } 175 | 176 | out += "
已收录 \(total-totalSkipped)/\(total) Entries
\n" 177 | 178 | let cwd = CommandLine.arguments.first { $0.contains(#file) } ?? FileManager.default.currentDirectoryPath 179 | let url = URL(fileURLWithPath: cwd).deletingLastPathComponent().appendingPathComponent("download.md") 180 | do { 181 | try out.write(to: url, atomically: true, encoding: .utf8) 182 | #if swift(>=4) 183 | let workspace = NSWorkspace.shared 184 | #else 185 | let workspace = NSWorkspace.shared() 186 | #endif 187 | workspace.activateFileViewerSelecting([url]) 188 | print("Written to \(url.path)") 189 | } catch { 190 | print(out) 191 | } 192 | } 193 | } 194 | 195 | let url = URL(string: "https://itunesu.itunes.apple.com/WebObjects/LZDirectory.woa/ra/directory/courses/\(iTunesUCourseID)/feed")! 196 | let parser = XMLParser(contentsOf: url)! 197 | let delegate = ParsingDelegate() 198 | parser.delegate = delegate 199 | parser.parse() 200 | -------------------------------------------------------------------------------- /tools/update/update.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 52D71C3B1E7612ED0036EE1C /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D71C3A1E7612ED0036EE1C /* main.swift */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 522CA2021E75E64B00EE2E2F /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = /usr/share/man/man1/; 18 | dstSubfolderSpec = 0; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 1; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 522CA2041E75E64B00EE2E2F /* update */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = update; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 52D71C3A1E7612ED0036EE1C /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = SOURCE_ROOT; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | 522CA2011E75E64B00EE2E2F /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 522CA1FB1E75E64B00EE2E2F = { 42 | isa = PBXGroup; 43 | children = ( 44 | 52D71C3A1E7612ED0036EE1C /* main.swift */, 45 | 522CA2051E75E64B00EE2E2F /* Products */, 46 | ); 47 | sourceTree = ""; 48 | }; 49 | 522CA2051E75E64B00EE2E2F /* Products */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | 522CA2041E75E64B00EE2E2F /* update */, 53 | ); 54 | name = Products; 55 | sourceTree = ""; 56 | }; 57 | /* End PBXGroup section */ 58 | 59 | /* Begin PBXNativeTarget section */ 60 | 522CA2031E75E64B00EE2E2F /* update */ = { 61 | isa = PBXNativeTarget; 62 | buildConfigurationList = 522CA20B1E75E64B00EE2E2F /* Build configuration list for PBXNativeTarget "update" */; 63 | buildPhases = ( 64 | 522CA2001E75E64B00EE2E2F /* Sources */, 65 | 522CA2011E75E64B00EE2E2F /* Frameworks */, 66 | 522CA2021E75E64B00EE2E2F /* CopyFiles */, 67 | ); 68 | buildRules = ( 69 | ); 70 | dependencies = ( 71 | ); 72 | name = update; 73 | productName = update; 74 | productReference = 522CA2041E75E64B00EE2E2F /* update */; 75 | productType = "com.apple.product-type.tool"; 76 | }; 77 | /* End PBXNativeTarget section */ 78 | 79 | /* Begin PBXProject section */ 80 | 522CA1FC1E75E64B00EE2E2F /* Project object */ = { 81 | isa = PBXProject; 82 | attributes = { 83 | LastSwiftUpdateCheck = 0820; 84 | LastUpgradeCheck = 0930; 85 | ORGANIZATIONNAME = WWITDC; 86 | TargetAttributes = { 87 | 522CA2031E75E64B00EE2E2F = { 88 | CreatedOnToolsVersion = 8.2.1; 89 | LastSwiftMigration = 0900; 90 | ProvisioningStyle = Automatic; 91 | }; 92 | }; 93 | }; 94 | buildConfigurationList = 522CA1FF1E75E64B00EE2E2F /* Build configuration list for PBXProject "update" */; 95 | compatibilityVersion = "Xcode 3.2"; 96 | developmentRegion = English; 97 | hasScannedForEncodings = 0; 98 | knownRegions = ( 99 | en, 100 | ); 101 | mainGroup = 522CA1FB1E75E64B00EE2E2F; 102 | productRefGroup = 522CA2051E75E64B00EE2E2F /* Products */; 103 | projectDirPath = ""; 104 | projectRoot = ""; 105 | targets = ( 106 | 522CA2031E75E64B00EE2E2F /* update */, 107 | ); 108 | }; 109 | /* End PBXProject section */ 110 | 111 | /* Begin PBXSourcesBuildPhase section */ 112 | 522CA2001E75E64B00EE2E2F /* Sources */ = { 113 | isa = PBXSourcesBuildPhase; 114 | buildActionMask = 2147483647; 115 | files = ( 116 | 52D71C3B1E7612ED0036EE1C /* main.swift in Sources */, 117 | ); 118 | runOnlyForDeploymentPostprocessing = 0; 119 | }; 120 | /* End PBXSourcesBuildPhase section */ 121 | 122 | /* Begin XCBuildConfiguration section */ 123 | 522CA2091E75E64B00EE2E2F /* Debug */ = { 124 | isa = XCBuildConfiguration; 125 | buildSettings = { 126 | ALWAYS_SEARCH_USER_PATHS = NO; 127 | CLANG_ANALYZER_NONNULL = YES; 128 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 129 | CLANG_CXX_LIBRARY = "libc++"; 130 | CLANG_ENABLE_MODULES = YES; 131 | CLANG_ENABLE_OBJC_ARC = YES; 132 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 133 | CLANG_WARN_BOOL_CONVERSION = YES; 134 | CLANG_WARN_COMMA = YES; 135 | CLANG_WARN_CONSTANT_CONVERSION = YES; 136 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 137 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 138 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 139 | CLANG_WARN_EMPTY_BODY = YES; 140 | CLANG_WARN_ENUM_CONVERSION = YES; 141 | CLANG_WARN_INFINITE_RECURSION = YES; 142 | CLANG_WARN_INT_CONVERSION = YES; 143 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 144 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 145 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 146 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 147 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 148 | CLANG_WARN_STRICT_PROTOTYPES = YES; 149 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 150 | CLANG_WARN_UNREACHABLE_CODE = YES; 151 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 152 | CODE_SIGN_IDENTITY = "-"; 153 | COPY_PHASE_STRIP = NO; 154 | DEBUG_INFORMATION_FORMAT = dwarf; 155 | ENABLE_STRICT_OBJC_MSGSEND = YES; 156 | ENABLE_TESTABILITY = YES; 157 | GCC_C_LANGUAGE_STANDARD = gnu99; 158 | GCC_DYNAMIC_NO_PIC = NO; 159 | GCC_NO_COMMON_BLOCKS = YES; 160 | GCC_OPTIMIZATION_LEVEL = 0; 161 | GCC_PREPROCESSOR_DEFINITIONS = ( 162 | "DEBUG=1", 163 | "$(inherited)", 164 | ); 165 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 166 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 167 | GCC_WARN_UNDECLARED_SELECTOR = YES; 168 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 169 | GCC_WARN_UNUSED_FUNCTION = YES; 170 | GCC_WARN_UNUSED_VARIABLE = YES; 171 | MACOSX_DEPLOYMENT_TARGET = 10.9; 172 | MTL_ENABLE_DEBUG_INFO = YES; 173 | ONLY_ACTIVE_ARCH = YES; 174 | SDKROOT = macosx; 175 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 176 | }; 177 | name = Debug; 178 | }; 179 | 522CA20A1E75E64B00EE2E2F /* Release */ = { 180 | isa = XCBuildConfiguration; 181 | buildSettings = { 182 | ALWAYS_SEARCH_USER_PATHS = NO; 183 | CLANG_ANALYZER_NONNULL = YES; 184 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 185 | CLANG_CXX_LIBRARY = "libc++"; 186 | CLANG_ENABLE_MODULES = YES; 187 | CLANG_ENABLE_OBJC_ARC = YES; 188 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 189 | CLANG_WARN_BOOL_CONVERSION = YES; 190 | CLANG_WARN_COMMA = YES; 191 | CLANG_WARN_CONSTANT_CONVERSION = YES; 192 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 193 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 194 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 195 | CLANG_WARN_EMPTY_BODY = YES; 196 | CLANG_WARN_ENUM_CONVERSION = YES; 197 | CLANG_WARN_INFINITE_RECURSION = YES; 198 | CLANG_WARN_INT_CONVERSION = YES; 199 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 200 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 201 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 202 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 203 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 204 | CLANG_WARN_STRICT_PROTOTYPES = YES; 205 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 206 | CLANG_WARN_UNREACHABLE_CODE = YES; 207 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 208 | CODE_SIGN_IDENTITY = "-"; 209 | COPY_PHASE_STRIP = NO; 210 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 211 | ENABLE_NS_ASSERTIONS = NO; 212 | ENABLE_STRICT_OBJC_MSGSEND = YES; 213 | GCC_C_LANGUAGE_STANDARD = gnu99; 214 | GCC_NO_COMMON_BLOCKS = YES; 215 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 216 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 217 | GCC_WARN_UNDECLARED_SELECTOR = YES; 218 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 219 | GCC_WARN_UNUSED_FUNCTION = YES; 220 | GCC_WARN_UNUSED_VARIABLE = YES; 221 | MACOSX_DEPLOYMENT_TARGET = 10.9; 222 | MTL_ENABLE_DEBUG_INFO = NO; 223 | SDKROOT = macosx; 224 | SWIFT_COMPILATION_MODE = wholemodule; 225 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 226 | }; 227 | name = Release; 228 | }; 229 | 522CA20C1E75E64B00EE2E2F /* Debug */ = { 230 | isa = XCBuildConfiguration; 231 | buildSettings = { 232 | CLANG_ENABLE_OBJC_WEAK = YES; 233 | CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/$(CONFIGURATION)"; 234 | DEVELOPMENT_TEAM = ""; 235 | PRODUCT_NAME = "$(TARGET_NAME)"; 236 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 237 | SWIFT_VERSION = 4.0; 238 | }; 239 | name = Debug; 240 | }; 241 | 522CA20D1E75E64B00EE2E2F /* Release */ = { 242 | isa = XCBuildConfiguration; 243 | buildSettings = { 244 | CLANG_ENABLE_OBJC_WEAK = YES; 245 | CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/$(CONFIGURATION)"; 246 | DEVELOPMENT_TEAM = ""; 247 | PRODUCT_NAME = "$(TARGET_NAME)"; 248 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 249 | SWIFT_VERSION = 4.0; 250 | }; 251 | name = Release; 252 | }; 253 | /* End XCBuildConfiguration section */ 254 | 255 | /* Begin XCConfigurationList section */ 256 | 522CA1FF1E75E64B00EE2E2F /* Build configuration list for PBXProject "update" */ = { 257 | isa = XCConfigurationList; 258 | buildConfigurations = ( 259 | 522CA2091E75E64B00EE2E2F /* Debug */, 260 | 522CA20A1E75E64B00EE2E2F /* Release */, 261 | ); 262 | defaultConfigurationIsVisible = 0; 263 | defaultConfigurationName = Release; 264 | }; 265 | 522CA20B1E75E64B00EE2E2F /* Build configuration list for PBXNativeTarget "update" */ = { 266 | isa = XCConfigurationList; 267 | buildConfigurations = ( 268 | 522CA20C1E75E64B00EE2E2F /* Debug */, 269 | 522CA20D1E75E64B00EE2E2F /* Release */, 270 | ); 271 | defaultConfigurationIsVisible = 0; 272 | defaultConfigurationName = Release; 273 | }; 274 | /* End XCConfigurationList section */ 275 | }; 276 | rootObject = 522CA1FC1E75E64B00EE2E2F /* Project object */; 277 | } 278 | -------------------------------------------------------------------------------- /tools/update/update.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tools/update/update.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tools/validation/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Apollo Zhu on 11/29/17. 3 | // This work is licensed under a 4 | // Creative Commons Attribution-NonCommercial-ShareAlike 3.0 United States License. 5 | // 6 | 7 | import Foundation 8 | 9 | guard let file = CommandLine.arguments.first(where: { $0.hasSuffix(".srt") }) else { fatalError("参数未指定 srt 字幕文件") } 10 | guard let contents = try? String(contentsOfFile: file) else { fatalError("无法读取 \(file)") } 11 | var lines = contents.components(separatedBy: "\n") 12 | let toTrim = CharacterSet(charactersIn: ",。").union(.whitespacesAndNewlines) 13 | for i in lines.indices { 14 | lines[i] = lines[i].trimmingCharacters(in: toTrim) 15 | if lines[i].utf8.count > 100 { fputs("第 \(i + 1) 行过长: \(lines[i])\n", __stderrp) } 16 | } 17 | try! lines.joined(separator: "\n").write(toFile: file, atomically: true, encoding: .utf8) 18 | print("已保存至 \(file)") 19 | -------------------------------------------------------------------------------- /tools/validation/validation.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 52E4A1B71FCFBA85008B9010 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E4A1B61FCFBA85008B9010 /* main.swift */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 52E4A1B11FCFBA85008B9010 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = /usr/share/man/man1/; 18 | dstSubfolderSpec = 0; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 1; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 52E4A1B31FCFBA85008B9010 /* validation */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = validation; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 52E4A1B61FCFBA85008B9010 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | 52E4A1B01FCFBA85008B9010 /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 52E4A1AA1FCFBA85008B9010 = { 42 | isa = PBXGroup; 43 | children = ( 44 | 52E4A1B61FCFBA85008B9010 /* main.swift */, 45 | 52E4A1B41FCFBA85008B9010 /* Products */, 46 | ); 47 | sourceTree = ""; 48 | }; 49 | 52E4A1B41FCFBA85008B9010 /* Products */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | 52E4A1B31FCFBA85008B9010 /* validation */, 53 | ); 54 | name = Products; 55 | sourceTree = ""; 56 | }; 57 | /* End PBXGroup section */ 58 | 59 | /* Begin PBXNativeTarget section */ 60 | 52E4A1B21FCFBA85008B9010 /* validation */ = { 61 | isa = PBXNativeTarget; 62 | buildConfigurationList = 52E4A1BA1FCFBA85008B9010 /* Build configuration list for PBXNativeTarget "validation" */; 63 | buildPhases = ( 64 | 52E4A1AF1FCFBA85008B9010 /* Sources */, 65 | 52E4A1B01FCFBA85008B9010 /* Frameworks */, 66 | 52E4A1B11FCFBA85008B9010 /* CopyFiles */, 67 | ); 68 | buildRules = ( 69 | ); 70 | dependencies = ( 71 | ); 72 | name = validation; 73 | productName = validation; 74 | productReference = 52E4A1B31FCFBA85008B9010 /* validation */; 75 | productType = "com.apple.product-type.tool"; 76 | }; 77 | /* End PBXNativeTarget section */ 78 | 79 | /* Begin PBXProject section */ 80 | 52E4A1AB1FCFBA85008B9010 /* Project object */ = { 81 | isa = PBXProject; 82 | attributes = { 83 | LastSwiftUpdateCheck = 0920; 84 | LastUpgradeCheck = 0930; 85 | TargetAttributes = { 86 | 52E4A1B21FCFBA85008B9010 = { 87 | CreatedOnToolsVersion = 9.2; 88 | ProvisioningStyle = Automatic; 89 | }; 90 | }; 91 | }; 92 | buildConfigurationList = 52E4A1AE1FCFBA85008B9010 /* Build configuration list for PBXProject "validation" */; 93 | compatibilityVersion = "Xcode 8.0"; 94 | developmentRegion = en; 95 | hasScannedForEncodings = 0; 96 | knownRegions = ( 97 | en, 98 | ); 99 | mainGroup = 52E4A1AA1FCFBA85008B9010; 100 | productRefGroup = 52E4A1B41FCFBA85008B9010 /* Products */; 101 | projectDirPath = ""; 102 | projectRoot = ""; 103 | targets = ( 104 | 52E4A1B21FCFBA85008B9010 /* validation */, 105 | ); 106 | }; 107 | /* End PBXProject section */ 108 | 109 | /* Begin PBXSourcesBuildPhase section */ 110 | 52E4A1AF1FCFBA85008B9010 /* Sources */ = { 111 | isa = PBXSourcesBuildPhase; 112 | buildActionMask = 2147483647; 113 | files = ( 114 | 52E4A1B71FCFBA85008B9010 /* main.swift in Sources */, 115 | ); 116 | runOnlyForDeploymentPostprocessing = 0; 117 | }; 118 | /* End PBXSourcesBuildPhase section */ 119 | 120 | /* Begin XCBuildConfiguration section */ 121 | 52E4A1B81FCFBA85008B9010 /* Debug */ = { 122 | isa = XCBuildConfiguration; 123 | buildSettings = { 124 | ALWAYS_SEARCH_USER_PATHS = NO; 125 | CLANG_ANALYZER_NONNULL = YES; 126 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 127 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 128 | CLANG_CXX_LIBRARY = "libc++"; 129 | CLANG_ENABLE_MODULES = YES; 130 | CLANG_ENABLE_OBJC_ARC = YES; 131 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 132 | CLANG_WARN_BOOL_CONVERSION = YES; 133 | CLANG_WARN_COMMA = YES; 134 | CLANG_WARN_CONSTANT_CONVERSION = YES; 135 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 136 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 137 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 138 | CLANG_WARN_EMPTY_BODY = YES; 139 | CLANG_WARN_ENUM_CONVERSION = YES; 140 | CLANG_WARN_INFINITE_RECURSION = YES; 141 | CLANG_WARN_INT_CONVERSION = YES; 142 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 143 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 144 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 145 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 146 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 147 | CLANG_WARN_STRICT_PROTOTYPES = YES; 148 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 149 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 150 | CLANG_WARN_UNREACHABLE_CODE = YES; 151 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 152 | CODE_SIGN_IDENTITY = "-"; 153 | COPY_PHASE_STRIP = NO; 154 | DEBUG_INFORMATION_FORMAT = dwarf; 155 | ENABLE_STRICT_OBJC_MSGSEND = YES; 156 | ENABLE_TESTABILITY = YES; 157 | GCC_C_LANGUAGE_STANDARD = gnu11; 158 | GCC_DYNAMIC_NO_PIC = NO; 159 | GCC_NO_COMMON_BLOCKS = YES; 160 | GCC_OPTIMIZATION_LEVEL = 0; 161 | GCC_PREPROCESSOR_DEFINITIONS = ( 162 | "DEBUG=1", 163 | "$(inherited)", 164 | ); 165 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 166 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 167 | GCC_WARN_UNDECLARED_SELECTOR = YES; 168 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 169 | GCC_WARN_UNUSED_FUNCTION = YES; 170 | GCC_WARN_UNUSED_VARIABLE = YES; 171 | MACOSX_DEPLOYMENT_TARGET = 10.13; 172 | MTL_ENABLE_DEBUG_INFO = YES; 173 | ONLY_ACTIVE_ARCH = YES; 174 | SDKROOT = macosx; 175 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 176 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 177 | }; 178 | name = Debug; 179 | }; 180 | 52E4A1B91FCFBA85008B9010 /* Release */ = { 181 | isa = XCBuildConfiguration; 182 | buildSettings = { 183 | ALWAYS_SEARCH_USER_PATHS = NO; 184 | CLANG_ANALYZER_NONNULL = YES; 185 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 186 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 187 | CLANG_CXX_LIBRARY = "libc++"; 188 | CLANG_ENABLE_MODULES = YES; 189 | CLANG_ENABLE_OBJC_ARC = YES; 190 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 191 | CLANG_WARN_BOOL_CONVERSION = YES; 192 | CLANG_WARN_COMMA = YES; 193 | CLANG_WARN_CONSTANT_CONVERSION = YES; 194 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 195 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 196 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 197 | CLANG_WARN_EMPTY_BODY = YES; 198 | CLANG_WARN_ENUM_CONVERSION = YES; 199 | CLANG_WARN_INFINITE_RECURSION = YES; 200 | CLANG_WARN_INT_CONVERSION = YES; 201 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 202 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 203 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 204 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 205 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 206 | CLANG_WARN_STRICT_PROTOTYPES = YES; 207 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 208 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 209 | CLANG_WARN_UNREACHABLE_CODE = YES; 210 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 211 | CODE_SIGN_IDENTITY = "-"; 212 | COPY_PHASE_STRIP = NO; 213 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 214 | ENABLE_NS_ASSERTIONS = NO; 215 | ENABLE_STRICT_OBJC_MSGSEND = YES; 216 | GCC_C_LANGUAGE_STANDARD = gnu11; 217 | GCC_NO_COMMON_BLOCKS = YES; 218 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 219 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 220 | GCC_WARN_UNDECLARED_SELECTOR = YES; 221 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 222 | GCC_WARN_UNUSED_FUNCTION = YES; 223 | GCC_WARN_UNUSED_VARIABLE = YES; 224 | MACOSX_DEPLOYMENT_TARGET = 10.13; 225 | MTL_ENABLE_DEBUG_INFO = NO; 226 | SDKROOT = macosx; 227 | SWIFT_COMPILATION_MODE = wholemodule; 228 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 229 | }; 230 | name = Release; 231 | }; 232 | 52E4A1BB1FCFBA85008B9010 /* Debug */ = { 233 | isa = XCBuildConfiguration; 234 | buildSettings = { 235 | CLANG_ENABLE_OBJC_WEAK = YES; 236 | CODE_SIGN_STYLE = Automatic; 237 | PRODUCT_NAME = "$(TARGET_NAME)"; 238 | SWIFT_VERSION = 4.0; 239 | }; 240 | name = Debug; 241 | }; 242 | 52E4A1BC1FCFBA85008B9010 /* Release */ = { 243 | isa = XCBuildConfiguration; 244 | buildSettings = { 245 | CLANG_ENABLE_OBJC_WEAK = YES; 246 | CODE_SIGN_STYLE = Automatic; 247 | PRODUCT_NAME = "$(TARGET_NAME)"; 248 | SWIFT_VERSION = 4.0; 249 | }; 250 | name = Release; 251 | }; 252 | /* End XCBuildConfiguration section */ 253 | 254 | /* Begin XCConfigurationList section */ 255 | 52E4A1AE1FCFBA85008B9010 /* Build configuration list for PBXProject "validation" */ = { 256 | isa = XCConfigurationList; 257 | buildConfigurations = ( 258 | 52E4A1B81FCFBA85008B9010 /* Debug */, 259 | 52E4A1B91FCFBA85008B9010 /* Release */, 260 | ); 261 | defaultConfigurationIsVisible = 0; 262 | defaultConfigurationName = Release; 263 | }; 264 | 52E4A1BA1FCFBA85008B9010 /* Build configuration list for PBXNativeTarget "validation" */ = { 265 | isa = XCConfigurationList; 266 | buildConfigurations = ( 267 | 52E4A1BB1FCFBA85008B9010 /* Debug */, 268 | 52E4A1BC1FCFBA85008B9010 /* Release */, 269 | ); 270 | defaultConfigurationIsVisible = 0; 271 | defaultConfigurationName = Release; 272 | }; 273 | /* End XCConfigurationList section */ 274 | }; 275 | rootObject = 52E4A1AB1FCFBA85008B9010 /* Project object */; 276 | } 277 | -------------------------------------------------------------------------------- /tools/validation/validation.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /translation-style-guide.md: -------------------------------------------------------------------------------- 1 | # 翻译标准/校对规则(Transilation Standard/Checking Rules) 2 | 3 | ## 基本要求(Basic Requirements) 4 | 5 | 1. 请参与者尽量对照原视频(字幕,若听力好可不看字幕)并结合视频中具体场景进行翻译和校对工作,请勿望文生义,切记不要生硬翻译 6 | 2. 如保持英文顺序会影响对应中文理解,为保观看者理解的流畅,应采用中文理解优先原则,优先按中文的表达方式断句 7 | 3. 注意代词的指代对象,区分“它”,“他”,“她”的使用,“其他”除外 8 | 4. 当说话者变更时,请加 `>>` 来区分。如:Question? >> Is it? >> Yes. 9 | 5. 出现 Okay,All Right,Now 等语气词,请结合上下文选择合适的翻译,或直接省略不翻 10 | 6. 学生提问的部分如果听不清楚,字幕也不全([INAUDIBLE]),但是老师回答时候把问题复述了一遍,字幕可译为 `>> [学生提问]` 11 | 7. 出现 [COUGH],[LAUGH],[NOISE],[BLANK_AUDIO],[INAUDIBLE] 等,请自行把握,可结合上下文选择省略不翻译 12 | 8. 卖萌请不要使用字符表情,比如(*3)看起来就像是备注;如果是标注说了三遍,请使用 x3 标记 13 | 14 | ## 格式要求(Format Requirement) 15 | 16 | 1. 不要合并多条 **字幕**,两条字幕之间保持一个空行 17 | 2. 中英文字幕 **开头结尾** 均不留空格,以 Unix 样式的 LF (Line Feed 的缩写,即 \n) 换行 18 | 3. 省略字幕 **开头结尾** 不影响表意的标点。如保留问号,但省略如逗号、句号等 19 | 4. 除了 `[`,`]`,和 `>>` 以外使用全角中文标点,如果可能,使用中文数字 20 | 5. 保证每一条字幕中最多两行,一行英文一行翻译,翻译不会过长(不超过视频平台放映框最大长度) 21 | 6. 英文和阿拉伯数字同中文之间应当有一个空格 22 | 7. 如遇到英文词汇或阿拉伯数字和标点符号相邻的情况,则不需要再留空格 23 | 24 | 例:就算是最新的 iPad,也不能用 Swift Playgrounds 打包应用。 25 | 26 | ## 错误修正(Bug Fixing) 27 | 28 | 1. 修改错别字,明显的笔误,大小写错误(包括原英文字幕中的错误) 29 | 2. 如能找到对应的 Swift Evolution 编号,以类似(在 SE-0065 之前)……注明 30 | 3. 如能确定特定的 Swift 语言版本,以类似(在 Swift 4 之前)……或(对于 Swift 3)……注明 31 | 4. 如果完全错误,尝试以类似……(误:原因)或(注:补充)说明。如空间不够,可适当调整上下文。参考 iOS 10 第三课 [420](https://github.com/Apollonyan/Developing-iOS-10-Apps-with-Swift/blob/master/subtitles/3.%20More%20Swift%20and%20the%20Foundation%20Framework.srt#L2100) 和 [1304](https://github.com/Apollonyan/Developing-iOS-10-Apps-with-Swift/blob/master/subtitles/3.%20More%20Swift%20and%20the%20Foundation%20Framework.srt#L6521) 32 | 33 | ## 翻译术语(Terminology)的要求 34 | 35 | #### 术语的基本处理 36 | 37 | 1. 尽量和已翻译的内容保持一致,查阅 [统一翻译](https://github.com/Apollonyan/Developing-iOS-11-Apps-with-Swift/issues/7) 38 | 2. 参考 [术语的特殊处理](#术语的特殊处理) 39 | 3. 参考 [Apple Developer 网页中文版](https://developer.apple.com/cn/) 40 | 4. 参考历年来 [iOS 8](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift),[iOS 9](https://github.com/SwiftGGTeam/Developing-iOS-9-Apps-with-Swift) 和 [iOS 10](https://github.com/Apollonyan/Developing-iOS-10-Apps-with-Swift) 的翻译 41 | 5. 参考 [CocoaChina 代码库](http://code.cocoachina.com/) 对 UI 控件的翻译 42 | 6. 查阅 [《The Swift Programming Language》中文版](https://swiftgg.gitbook.io/swift/) 及其 [术语表](https://github.com/SwiftGGTeam/the-swift-programming-language-in-chinese#%E6%9C%AF%E8%AF%AD%E8%A1%A8) 对 Swift 语言相关名词的翻译 43 | 7. 参考该术语在其它编程语言中的翻译,可以使用 [微软官方术语搜索](https://www.microsoft.com/Language/zh-cn/Search.aspx) 等搜索引擎 44 | 8. 如果以上都没有找到合适的结果,你可以 45 | 1. 在得到任务分配的 issue 下讨论(Comment) 46 | 2. 直接使用英文原文 47 | 3. 自己思考一个合适的翻译 48 | 49 | #### 术语的特殊处理 50 | 51 | 1. 如果想在同时翻译并保留原文,请用括号(中文)补充。 52 | - 例:MVC,即 Model(模型)-View(视图)-Controller(控制器) 53 | 2. 不翻译通用的名称,如 MVC,iPhone,Xcode,storyboard 等 54 | 3. 不翻译直接引用的代码,包括但不限于 55 | - Swift 语言关键字:如 true,false 等 56 | - 类/结构体/元组类型的名称:如 UIView,String 等 57 | - 项目中的代码:如 var description 等 58 | 59 | **后期校对请参考以上标准对术语的使用进行统一** 60 | 61 | ## 补充说明(Addition) 62 | 63 | > 为何没有完全采用之前的[校对规范](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift/blob/master/proofread-rules.md)? 64 | 65 | 其一是因为确实有些由于 Swift 的更新需要修改的地方。其二是因为即使就像之前规则中说的,*“校对是一个很重要的部分,甚至比翻译还要重要”*,但是如果我们从翻译阶段就能做到统一规范,相信校对也能事半功倍。当然,既然这是新的规范,目前还(2018.6.16)没经过实践验证,欢迎大家根据实际情况讨论后提出修订意见。 66 | --------------------------------------------------------------------------------