├── .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 | - 翻译进度: 
8 | - 校对进度: 
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 | |课程封面|[](https://is3-ssl.mzstatic.com/image/thumb/course/CobaltPublic128/v4/81/d0/9c/81d09ca1-ec7b-19b2-a215-4ae39df215c5/source/466x570.png)|[](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?fbl=en-GB&cdt=cdt-1-326037343&cte=cte-1504292368040-10000&dk=dk-20209947-1474866501&l=en-GB)|[](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 | ]]>
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 |
--------------------------------------------------------------------------------