-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
337 lines (285 loc) · 89.7 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>我是步轩同学的分身</title>
<subtitle>没有小标题</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://zhengbuxuan.github.io/"/>
<updated>2017-09-03T08:36:38.000Z</updated>
<id>https://zhengbuxuan.github.io/</id>
<author>
<name>步轩同学</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>TableView 优化笔记</title>
<link href="https://zhengbuxuan.github.io/2017/09/02/TableView%20%E4%BC%98%E5%8C%96%E7%AC%94%E8%AE%B0/"/>
<id>https://zhengbuxuan.github.io/2017/09/02/TableView 优化笔记/</id>
<published>2017-09-02T13:44:13.000Z</published>
<updated>2017-09-03T08:36:38.000Z</updated>
<content type="html"><![CDATA[<h2 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h2><p>TableView 的优化是一个老生常谈的问题,无论是自己平常使用,还是面试笔试的时候,它都会无时不刻地出现。TableView 需要优化的问题主要有这几个:</p>
<ul>
<li><strong>列表巨长</strong><br>一般我们的 TableView 都会展示比较多的数据,尤其是请求网络的时候,都是哗啦啦的一个大列表。</li>
<li><strong>图片巨多</strong><br>如果是哗啦啦的大列表,每一个 cell 都带图片的话,帧率咔咔地往下掉…</li>
<li><strong>圆角巨多</strong><br>哗啦啦的大列表,加上图片,然后图片还得要是个圆形… 完了以后就是一堆圆角矩形的 label …</li>
<li><strong>高度巨乱</strong><br>万一你的 TableView 每一个 cell 的高度还都不一样…<br>这个笔记就当作是一个小总结,把上面这几个问题给小小地解决一下。今天先把思路写出来,挖好坑再填 Demo 和代码… 就是这么懒…</li>
</ul>
<h2 id="1-列表巨长"><a href="#1-列表巨长" class="headerlink" title="1. 列表巨长"></a>1. 列表巨长</h2><p>不管是剁手宝的搜索列表,还是知乎的主页流,都是需要展示非常长的列表。如果一下子全部加载进来,就算只有文字,界面也会卡住。万一网络环境再差一点,整个体验就烂到爆。所以一般在处理 TableView 的时候,都会先考虑 <strong>上拉加载</strong>。<br>上拉加载有两种实现的思路,一种是上拉到 <strong>列表底部</strong> 然后通过动画告知用户正在加载,一种是上拉到 <strong>靠近列表底部的某一个位置</strong> 然后预加载。第一种思路本身没有什么问题,但是如果列表真的很长,那用户就会看到很多次加载动画,会造成一点体验的割裂感,我自己不是很喜欢。第二种思路能够给用户一种比较顺畅的感觉,但是当用户滑动太快或者网络不是很好的时候,有可能预加载还没完成就滑到底了… 所以这个时候最好是也加上一个加载动画,以免造成用户的体验困惑。<br>下面是采用第二种思路的小 Demo 以及对应的部分代码</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 获取更多数据</span></div><div class="line"><span class="function"><span class="keyword">func</span> <span class="title">getMoreData</span><span class="params">()</span></span> {</div><div class="line"></div><div class="line"> <span class="keyword">self</span>.flag = <span class="literal">true</span></div><div class="line"></div><div class="line"> <span class="type">DispatchQueue</span>.global().async {</div><div class="line"> <span class="comment">// 假装这是网络加载的时间</span></div><div class="line"> sleep(<span class="number">2</span>)</div><div class="line"> <span class="comment">// 假装这是加载来的 20 个新数据</span></div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">20</span> {</div><div class="line"> <span class="keyword">self</span>.titleTestData.append(<span class="string">"新加入的第<span class="subst">\(i)</span>个标题"</span>)</div><div class="line"> <span class="keyword">self</span>.textTestData.append(<span class="string">"我是新的只有文字的单元格"</span>)</div><div class="line"> }</div><div class="line"> <span class="comment">// 主线程刷一刷</span></div><div class="line"> <span class="type">DispatchQueue</span>.main.async {</div><div class="line"> <span class="keyword">self</span>.flag = <span class="literal">false</span></div><div class="line"> <span class="keyword">self</span>.tableView.reloadData()</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// 用TableView 的 willDisplayCell 方法判断什么时候加载新数据</span></div><div class="line"><span class="function"><span class="keyword">func</span> <span class="title">tableView</span><span class="params">(<span class="number">_</span> tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)</span></span> {</div><div class="line"> <span class="keyword">if</span> <span class="keyword">self</span>.flag == <span class="literal">true</span> {</div><div class="line"> <span class="keyword">return</span></div><div class="line"> }</div><div class="line"> <span class="comment">// 当下拉到只剩 10 个数据没展示的时候就加载进来新数据</span></div><div class="line"> <span class="keyword">if</span> indexPath.row > (<span class="keyword">self</span>.titleTestData.<span class="built_in">count</span> - <span class="number">10</span>) {</div><div class="line"> <span class="keyword">self</span>.getMoreData()</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// 设置提示"加载中"的页脚</span></div><div class="line"><span class="function"><span class="keyword">func</span> <span class="title">setTableFooterView</span><span class="params">()</span></span> {</div><div class="line"></div><div class="line"> <span class="keyword">let</span> footerView = <span class="type">UIView</span>(frame: <span class="type">CGRect</span>(x: <span class="number">0</span>, y: <span class="number">0</span>, width: tableView.frame.width, height: <span class="number">72</span>))</div><div class="line"> footerView.backgroundColor = .white</div><div class="line"></div><div class="line"> <span class="keyword">let</span> loadingLabel = <span class="type">UILabel</span>(frame: <span class="type">CGRect</span>(x: <span class="number">0</span>, y: <span class="number">0</span>, width: <span class="number">12</span>, height: <span class="number">12</span>))</div><div class="line"> loadingLabel.text = <span class="string">"加载中..."</span></div><div class="line"> loadingLabel.font = <span class="type">UIFont</span>.systemFont(ofSize: <span class="number">12</span>)</div><div class="line"> loadingLabel.textColor = .darkGray</div><div class="line"> loadingLabel.sizeToFit()</div><div class="line"> loadingLabel.center = footerView.center</div><div class="line"></div><div class="line"> footerView.addSubview(loadingLabel)</div><div class="line"> tableView.tableFooterView = footerView</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>如果只是想让用户知道上拉可以加载但是自己又懒得写的话,可以用 <strong>ESPullToRefresh</strong> 来实现,这是一个很棒的框架。<a href="https://github.com/eggswift/pull-to-refresh" target="_blank" rel="external">ESPullToRefresh 的 GitHub 传送门</a></p>
<h2 id="2-图片巨多"><a href="#2-图片巨多" class="headerlink" title="2. 图片巨多"></a>2. 图片巨多</h2><p>TableView 的图片是一个逃不掉的话题。如果每一个 cell 都包含了一张图片,而且是实时加载的话,TableView 的滑动很大可能会掉帧。所以聪明的人类想出了一个解决办法——忽略加载。就是说滑动的时候那些新来的图片我就不加载,等到你停住了不滑动了,我再加载出来给你看。这个解决的思路尤其在快速滑动的时候非常好,因为如果用户是快速滑动的话,那意味着他很大程度上对这些滑过去的内容是不感兴趣的,他需要的是更下面的内容。<br>下面是一个巨长的列表加上图片,用预加载和图片忽略加载的小 Demo 以及对应的部分代码:</p>
<p><strong>demo 和代码</strong></p>
<h2 id="3-圆角巨多"><a href="#3-圆角巨多" class="headerlink" title="3. 圆角巨多"></a>3. 圆角巨多</h2><p>圆角得分两种情况来说,一种是 UIView 的圆角,一种是 UIImageView/UILabel 的圆角。两种圆角的区别在于,如果用最原生的方式 cornerRadius 设置圆角半径的话,UIImageView 和 UILabel 是需要用 maskToBounds() 方法来给它们上遮罩的,但是 UIView 不需要。也就是说,如果你是需要给 UIView 画圆角那就直接设置 cornerRadius 好了,这个不会造成什么卡顿。而针对 UIImageView 和 UILabel,聪明的人类又想出了一个特别作弊的办法——圆角图片。就是直接画一张带圆角的中间镂空的图片给你叠上去… 简直就是作弊… 可能有人会说,固定大小的是可以,那如果是长度不同的 UILabel 怎么办咧。方法就是,你就左右各一张嘛… (逃…)<br>下面是一个巨长的列表加上圆角图片和圆角 Label,用预加载、图片忽略加载和圆角作弊法的小 Demo 以及对应的部分代码:</p>
<p><strong>demo 和代码</strong></p>
<h2 id="4-高度巨乱"><a href="#4-高度巨乱" class="headerlink" title="4. 高度巨乱"></a>4. 高度巨乱</h2><p>像朋友圈这样,cell 的行高是跟每个用户发布的内容有关系,所以每个 cell 的行高就不得不计算。不定行高也是 TableView 优化不能不解决的问题。解决的办法就是——缓存。</p>
<h2 id="5-小结"><a href="#5-小结" class="headerlink" title="5. 小结"></a>5. 小结</h2><p>TableView 是一个特别可恨的东西… 因为毕竟全世界都在为它的这些使用场景做优化,非常期待水果在某一天能够给出一个官方的解决方案或者直接写好方法(没错就是这么懒)…<br>还有一个非常重要的点,一定要根据情况来定制具体方案。<br>如果 TableView 不长那么分页加载来干什么…<br>如果圆角不多,只是掉个一两帧那有什么好优化的…<br>作为一个程序员,一定要… 懒… [手动狗头] [手动狗头] [手动狗头]</p>
]]></content>
<summary type="html">
<h2 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h2><p>TableView 的优化是一个老生常谈的问题,无论是自己平常使用,还是面试笔试的时候,它都会无时不刻地出现。Table
</summary>
<category term="iOS 优化" scheme="https://zhengbuxuan.github.io/tags/iOS-%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>iOS 多线程 GCD Swift 3</title>
<link href="https://zhengbuxuan.github.io/2017/08/31/iOS%20%E5%A4%9A%E7%BA%BF%E7%A8%8B%E4%B9%8B%20GCD/"/>
<id>https://zhengbuxuan.github.io/2017/08/31/iOS 多线程之 GCD/</id>
<published>2017-08-31T15:00:00.000Z</published>
<updated>2017-09-01T15:20:35.000Z</updated>
<content type="html"><![CDATA[<h1 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h1><p>GCD(Grand Central Dispatch)是 Apple 开发的一种多核编程的方法,主要的作用是优化应用程序对多核处理器的运用,是在线程池模式的基础上执行的并行任务。GCD中有两个重要的基本概念—-<strong>任务</strong> 和 <strong>队列</strong>。</p>
<hr>
<h1 id="1-任务和队列"><a href="#1-任务和队列" class="headerlink" title="1. 任务和队列"></a>1. 任务和队列</h1><p><strong>任务</strong> 就是执行的操作,也就是在线程中执行的代码,封装在 Swift 的闭包(Closure)或者 OC 的块(block)里。根据能否具备开启新线程可以分成 <strong>同步执行</strong> 和 <strong>异步执行</strong>。</p>
<ul>
<li><strong>同步执行(sync)</strong> 只能在当前线程中执行任务,不能开新线程,当前的代码段没有执行完就不能够执行下一部分,会阻塞当前线程。</li>
<li><strong>异步执行(async)</strong> 可以在新线程中执行任务,能够开启新线程,不用等待当前的代码段执行完就可以往下执行后续代码,不会阻塞当前线程。</li>
</ul>
<p><strong>队列</strong> 就是任务队列,是一种特殊的线性表,满足 FIFO 的原则。在 GCD 里分为 <strong>串行队列</strong> 和 <strong>并发队列</strong>。</p>
<ul>
<li>串行队列(Serial Dispatch Queue) 一个任务完成后接着执行下一个任务。</li>
<li>并发队列(Concurrent Dispatch Queue) 自动开启多个线程进行多个任务并发执行,而且并发只有在异步执行(dispatch_async)情况下才有效。</li>
</ul>
<hr>
<h1 id="2-创建队列"><a href="#2-创建队列" class="headerlink" title="2. 创建队列"></a>2. 创建队列</h1><p><strong>系统默认队列—-主队列(串行)</strong></p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//主队列</span></div><div class="line"><span class="keyword">let</span> mainQueue = <span class="type">DispatchQueue</span>.main</div></pre></td></tr></table></figure>
<p><strong>系统默认队列—-全局队列(并发)</strong></p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//全局队列</span></div><div class="line"><span class="keyword">let</span> globalQueue = <span class="type">DispatchQueue</span>.global()</div></pre></td></tr></table></figure>
<p>全局队列有 4 个执行的优先级,从高到低分别是: <strong>.userInitiated</strong>,<strong>.default</strong>,<strong>.utility</strong>,<strong>.background</strong> 所以当需要创建指定某个优先级的全局队列时:</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">let</span> defaultGlobalQueue = <span class="type">DispatchQueue</span>.global(qos: .<span class="keyword">default</span>)</div></pre></td></tr></table></figure>
<p><strong>自定义创建队列</strong></p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//创建串行队列</span></div><div class="line"><span class="keyword">let</span> serialQueue = <span class="type">DispatchQueue</span>(label: <span class="string">"serialQueue_1"</span>)</div><div class="line"><span class="comment">//创建优先级为default的串行队列</span></div><div class="line"><span class="keyword">let</span> serialQueue = <span class="type">DispatchQueue</span>(label: <span class="string">"serialQueue_2"</span>, qos: .<span class="keyword">default</span>)</div><div class="line"></div><div class="line"><span class="comment">//创建优先级为background的并发队列</span></div><div class="line"><span class="keyword">let</span> concurrentQueue = <span class="type">DispatchQueue</span>(label: <span class="string">"concurrentQueue"</span>, qos: .background, attributes: .concurrent)</div></pre></td></tr></table></figure>
<hr>
<h1 id="队列执行"><a href="#队列执行" class="headerlink" title="队列执行"></a>队列执行</h1><p>队列的执行部分可以用 3 个任务来反映出任务执行的顺序。 <strong>同步并行</strong> 代码示例:</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">func</span> <span class="title">syncConcurrent</span><span class="params">()</span></span> {</div><div class="line"></div><div class="line"> <span class="keyword">let</span> queue = <span class="type">DispatchQueue</span>(label: <span class="string">"queue"</span>, attributes: .concurrent)</div><div class="line"></div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- begin ---"</span>)</div><div class="line"></div><div class="line"> queue.sync {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅰️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> queue.sync {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅱️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> queue.sync {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅾️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- end ---"</span>)</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>打印结果</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">--- begin ---</div><div class="line">--- 🅰️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400006f380</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅰️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400006f380</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅰️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400006f380</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅱️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400006f380</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅱️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400006f380</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅱️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400006f380</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅾️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400006f380</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅾️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400006f380</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅾️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400006f380</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- end ---</div></pre></td></tr></table></figure>
<blockquote>
<p>任务是按照顺序逐个执行的,并且只有一个主线程在战斗</p>
</blockquote>
<p><strong>异步并行</strong> 代码示例</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">func</span> <span class="title">asyncConcurrent</span><span class="params">()</span></span> {</div><div class="line"></div><div class="line"> <span class="keyword">let</span> queue = <span class="type">DispatchQueue</span>(label: <span class="string">"queue"</span>, attributes: .concurrent)</div><div class="line"></div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- begin ---"</span>)</div><div class="line"></div><div class="line"> queue.async {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅰️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> queue.async {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅱️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> queue.async {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅾️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- end ---"</span>)</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>打印结果 1</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">--- begin ---</div><div class="line">--- 🅰️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x604000078bc0</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅱️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x6080000747c0</span>>{number = <span class="number">4</span>, name = (null)}</div><div class="line">--- 🅰️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x604000078bc0</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅾️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x6040000793c0</span>>{number = <span class="number">5</span>, name = (null)}</div><div class="line">--- 🅱️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x6080000747c0</span>>{number = <span class="number">4</span>, name = (null)}</div><div class="line">--- 🅰️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x604000078bc0</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- end ---</div><div class="line">--- 🅾️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x6040000793c0</span>>{number = <span class="number">5</span>, name = (null)}</div><div class="line">--- 🅱️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x6080000747c0</span>>{number = <span class="number">4</span>, name = (null)}</div><div class="line">--- 🅾️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x6040000793c0</span>>{number = <span class="number">5</span>, name = (null)}</div></pre></td></tr></table></figure>
<p>打印结果 2</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">--- begin ---</div><div class="line">--- 🅰️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x604000069140</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅱️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x60800006aa40</span>>{number = <span class="number">4</span>, name = (null)}</div><div class="line">--- 🅰️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x604000069140</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅱️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x60800006aa40</span>>{number = <span class="number">4</span>, name = (null)}</div><div class="line">--- 🅾️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x60800006a900</span>>{number = <span class="number">5</span>, name = (null)}</div><div class="line">--- 🅰️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x604000069140</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- end ---</div><div class="line">--- 🅾️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x60800006a900</span>>{number = <span class="number">5</span>, name = (null)}</div><div class="line">--- 🅱️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x60800006aa40</span>>{number = <span class="number">4</span>, name = (null)}</div><div class="line">--- 🅾️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x60800006a900</span>>{number = <span class="number">5</span>, name = (null)}</div></pre></td></tr></table></figure>
<blockquote>
<p>每一次运行的执行顺序不一定相同,任务的执行是交替的,一共新开了 3 个线程在战斗。并且从 begin 和 end 的位置可以看出,3 个任务被添加到队列之后就立刻开始了战斗。</p>
</blockquote>
<p><strong>同步串行</strong></p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">func</span> <span class="title">syncSerial</span><span class="params">()</span></span> {</div><div class="line"></div><div class="line"> <span class="keyword">let</span> queue = <span class="type">DispatchQueue</span>(label: <span class="string">"queue"</span>)</div><div class="line"></div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- begin ---"</span>)</div><div class="line"></div><div class="line"> queue.sync {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅰️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> queue.sync {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅱️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> queue.sync {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅾️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- end ---"</span>)</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>打印结果</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">--- begin ---</div><div class="line">--- 🅰️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x6000000777c0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅰️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x6000000777c0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅰️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x6000000777c0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅱️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x6000000777c0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅱️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x6000000777c0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅱️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x6000000777c0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅾️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x6000000777c0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅾️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x6000000777c0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- 🅾️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x6000000777c0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line">--- end ---</div></pre></td></tr></table></figure>
<blockquote>
<p>打印结果和同步并行一个样,都是只有主线程在战斗,并且按照顺序逐一执行。</p>
</blockquote>
<p><strong>串行异步</strong> 代码示例</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">func</span> <span class="title">asyncSerial</span><span class="params">()</span></span> {</div><div class="line"></div><div class="line"> <span class="keyword">let</span> queue = <span class="type">DispatchQueue</span>(label: <span class="string">"queue"</span>)</div><div class="line"></div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- begin ---"</span>)</div><div class="line"></div><div class="line"> queue.async {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅰️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> queue.async {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅱️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> queue.async {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">3</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- 🅾️ <span class="subst">\(i)</span> ---<span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="built_in">print</span>(<span class="string">"--- end ---"</span>)</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>打印结果</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">--- begin ---</div><div class="line">--- 🅰️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400007a700</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅰️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400007a700</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅰️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400007a700</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- end ---</div><div class="line">--- 🅱️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400007a700</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅱️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400007a700</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅱️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400007a700</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅾️ <span class="number">1</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400007a700</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅾️ <span class="number">2</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400007a700</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line">--- 🅾️ <span class="number">3</span> ---<<span class="type">NSThread</span>: <span class="number">0x60400007a700</span>>{number = <span class="number">3</span>, name = (null)}</div></pre></td></tr></table></figure>
<blockquote>
<p>任务是按顺序逐一进行的,开启了一条新的线程。</p>
</blockquote>
<p><strong>主队列和全局队列的同步/异步</strong> 同步</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="type">DispatchQueue</span>.global(qos: .<span class="keyword">default</span>).async {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"I'm in global."</span>)</div><div class="line"> <span class="type">DispatchQueue</span>.main.async {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"I'm back in main."</span>)</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>异步</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//Global Dispatch Queue</span></div><div class="line"><span class="comment">//不会死锁,但代码顺序执行,后续代码需要等待前面代码执行完毕</span></div><div class="line"><span class="type">DispatchQueue</span>.global(qos: .<span class="keyword">default</span>).sync {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"I'm in global."</span>)</div><div class="line"> <span class="built_in">print</span>(<span class="string">"I'm still in global."</span>)</div><div class="line">}</div><div class="line"><span class="built_in">print</span>(<span class="string">"I'm out."</span>)</div><div class="line"></div><div class="line"><span class="comment">//Main Queue</span></div><div class="line"><span class="comment">//死锁。按照同步的执行顺序,一个任务需要等待前一个任务执行完毕,但是"I'm in main."是添加在"I'm out."之后,但是"I'm out"又需要等待"I'm in main."执行完毕之后再执行。所以彼此等待造成了死锁。</span></div><div class="line"><span class="type">DispatchQueue</span>.main.sync {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"I'm in main."</span>)</div><div class="line">}</div><div class="line"><span class="built_in">print</span>(<span class="string">"I'm out."</span>)</div></pre></td></tr></table></figure>
<p><strong>队列暂停和继续</strong></p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//暂停</span></div><div class="line">queue.suspend()</div><div class="line"><span class="comment">//继续</span></div><div class="line">queue.resume()</div></pre></td></tr></table></figure>
<p>suspend() 和 resume() 是异步函数,在两个闭包之间生效。 suspend() 会使得已经添加到 Dispatch Queue 但是还没有执行的任务在改行代码之后暂停执行,等到 resume() 之后才能继续执行。</p>
<p><strong>单次执行</strong> 单次执行在多线程编程的使用过程中很常见,当然除了多线程之外也有一些其他的用途。 在 Swift 3 之前,单次执行可以通过 dispatch_once 来实现,但是 Swift 3 把它废弃了… 查了一些资料发现要实现原来的 dispatch_once 可以通过下面几个方式:</p>
<ul>
<li><p>全局常量</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">let</span> constant = <span class="type">SomeClass</span>()</div></pre></td></tr></table></figure>
</li>
<li><p>全局变量(带有立即执行的闭包构造器)</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> variable: <span class="type">SomeClass</span> = {</div><div class="line"> <span class="keyword">let</span> constant = <span class="type">SomeClass</span>()</div><div class="line"> constant.oneProperty = <span class="string">"HeySiri"</span></div><div class="line"> constant.oneMethod()</div><div class="line"> <span class="keyword">return</span> constant</div><div class="line">}()</div></pre></td></tr></table></figure>
</li>
</ul>
<hr>
<h1 id="3-未完待续…"><a href="#3-未完待续…" class="headerlink" title="3. 未完待续…"></a>3. 未完待续…</h1>]]></content>
<summary type="html">
<h1 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h1><p>GCD(Grand Central Dispatch)是 Apple 开发的一种多核编程的方法,主要的作用是优化应用程序
</summary>
<category term="iOS 多线程" scheme="https://zhengbuxuan.github.io/tags/iOS-%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
</entry>
<entry>
<title>iOS 多线程之 基础</title>
<link href="https://zhengbuxuan.github.io/2017/08/29/iOS%20%E5%A4%9A%E7%BA%BF%E7%A8%8B%E4%B9%8B%20%E5%9F%BA%E7%A1%80/"/>
<id>https://zhengbuxuan.github.io/2017/08/29/iOS 多线程之 基础/</id>
<published>2017-08-29T12:00:00.000Z</published>
<updated>2017-08-29T15:00:39.000Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><hr>
<p>关于多线程需要理解的一些基本的概念,为了防止打代码打到阿尔兹海默症,写下几个抖机灵的 🌰 …</p>
<p><br></p>
<h2 id="进程和线程"><a href="#进程和线程" class="headerlink" title="进程和线程"></a>进程和线程</h2><hr>
<p><strong><code>1</code> 进程是什么</strong></p>
<p>进程可以理解为一个正在运行的的程序,各个进程之间是相互独立的。</p>
<p><strong><code>2</code> 线程是什么</strong></p>
<p>线程是进程运行过程中的执行路径。每一个进程想要运行,都需要至少一个线程来确定代码的执行路径。</p>
<p><strong><code>3</code> 然后呢…</strong></p>
<p>举个栗子,手机里的微信和QQ在运行的时候,都是 iOS 系统中的进程。当你打开微信,给你的好基友发了一条 60 秒的语音信息,在你松开手之后,你想给他发一个表情 🙄️,所以你点击对话框输入 🙄️。<br>如果发语音和对话框输入必须按照顺序进行,也就是说这两个动作必须按顺序走,那么万一你所处环境网络状态很差,你就需要等这 60 秒语音完全用渣网络发完之后,你才能够点得动对话框来输入。我相信这个时候你已经把手机砸了…</p>
<p><strong><code>4</code> 所以呢…</strong></p>
<p>所以,这就是多线程的必要性啊…</p>
<p><br></p>
<h2 id="串行、并行和并发"><a href="#串行、并行和并发" class="headerlink" title="串行、并行和并发"></a>串行、并行和并发</h2><hr>
<p><strong><code>1</code>串行是什么</strong></p>
<p>串行是指在同一时间点,只执行一个任务。比如只有一个 CPU,只能跑一条线程。</p>
<p><strong><code>2</code> 并行是什么</strong></p>
<p>并行是指在同一时间点,同时执行多个任务。比如有两个 CPU,可以同时跑两条线程。</p>
<p><strong><code>3</code> 并发是什么</strong></p>
<p>并发是指在同一时间点,有执行多个任务的能力。比如只有一个 CPU,但是可以非常快速地在两条线程上切来切去,看起来像是同时跑两条线程。</p>
<p><strong><code>4</code> 用人话来说</strong></p>
<p>冰雪消融,万物复苏,春天来了,又到了撸串的时候,我们能看到老板把 1 块羊肉穿进串,再把 1 块软骨穿进串,接着是 1 块彩椒… 循环 1…8 次,返回 2 串骨肉相连。这是串行。</p>
<p>又双到了撸串的时候,比较牛逼的老板手里可以拿 2 根签子,同时串 2 块羊肉,再是 2 块软骨,接着 2 块彩椒… 循环 1…4 次,返回 2 串骨头相连。这是并行。</p>
<p>又双叒是撸串的时候,发现老板一手握起两个签子… 大概是这样 —👊—</p>
<p>然后,穿 1 块羊肉,唰,手非常快速地转到另一头,穿 1 块羊肉,唰,手又非常快速地(🙄️)转到另一头… 循环 1…4 次,返回 2 串骨肉相连。这是并发。</p>
<p><br></p>
<h2 id="同步和异步"><a href="#同步和异步" class="headerlink" title="同步和异步"></a>同步和异步</h2><hr>
<p><strong><code>1</code> 同步是什么</strong></p>
<p>同步方法是完成任务之后返回,控制权交回给方法调用者,同时给结果。</p>
<p><strong><code>2</code> 异步是什么</strong></p>
<p>异步方法是任务开始就立即返回,控制权马上回归方法调用者,结果在需要时由掌权者去拿。</p>
<p><strong><code>3</code> 人话</strong></p>
<p>同步就是我给你一张纸条,上面写着<code>买 7 杯冰美式给我</code>,你把纸条拿去,买了 7 杯冰美式回来,同时把纸条还给我。</p>
<p>异步就是我给你一张纸条,上面写着<code>买 7 杯冰美式放到前台</code>,你看完把纸条还给我,买了 7 杯冰美式放到了前台,我需要的时候再去前台拿。</p>
<p><br></p>
<h2 id="队列"><a href="#队列" class="headerlink" title="队列"></a>队列</h2><hr>
<p><strong><code>1</code> 顺序队列</strong></p>
<p>- - - <code>任务1</code> <code>我是任务2</code> <code>我任务3</code> - - -</p>
<p><strong><code>2</code> 并发队列</strong></p>
<p>- - -<code>任务1</code>- - - - - - - - - - - - - - - - - - - - -</p>
<p>- - - - - - - -<code>我是任务2</code> - - - - - - - - - - - -</p>
<p>- - - - - - - - - - - -<code>我任务3</code>- - - - - - - - - -</p>
<p><br></p>
<h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><hr>
<p><strong><code>1</code> 临界区</strong></p>
<p>不能并发执行的代码。比如说你口袋里有 1 个硬币,左手知道有 1 个硬币所以想拿 1 个,同时右手也知道有 1 个硬币也想拿 1 个。如果左手拿了 1 个,右手就没得拿,但它又是被告知口袋里有 1 个硬币,然后就一直找一直找,最后,右手卒。反之,左手卒。</p>
<p><strong><code>2</code> 线程安全</strong></p>
<p>能够并发执行或者多个线程同时调用的代码。比如说你口袋里有 1 个硬币,不能拿只能摸(…),左手想摸 1 个硬币,同时右手也想摸 1 个硬币,然后它们都摸到了…</p>
<p><strong><code>3</code> 互斥锁</strong></p>
<p>给临界区加锁,保证一次只能有一个线程调用。</p>
<p><strong><code>4</code> 死锁</strong></p>
<p>两个或两个以上的线程,因为要等待彼此任务的完成而陷入双方或多方均不能继续进行的困境。也就是经常在交叉路口四辆车互不退让的情况。</p>
]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><hr>
<p>关于多线程需要理解的一些基本的概念,为了防止打代码打到阿尔兹海默症,写下几个抖机灵的 🌰 …</p>
<p><br></p>
<
</summary>
<category term="iOS 多线程" scheme="https://zhengbuxuan.github.io/tags/iOS-%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="https://zhengbuxuan.github.io/2017/08/27/hello-world/"/>
<id>https://zhengbuxuan.github.io/2017/08/27/hello-world/</id>
<published>2017-08-27T15:00:23.000Z</published>
<updated>2017-08-27T15:00:23.000Z</updated>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo new <span class="string">"My New Post"</span></div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo server</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="external">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo generate</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="external">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo deploy</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="external">Deployment</a></p>
]]></content>
<summary type="html">
<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.
</summary>
</entry>
<entry>
<title>iOS 多线程 NSThread Swift 3</title>
<link href="https://zhengbuxuan.github.io/2017/08/27/iOS%20%E5%A4%9A%E7%BA%BF%E7%A8%8B%E4%B9%8B%20NSThread/"/>
<id>https://zhengbuxuan.github.io/2017/08/27/iOS 多线程之 NSThread/</id>
<published>2017-08-27T14:30:00.000Z</published>
<updated>2017-08-29T14:39:37.000Z</updated>
<content type="html"><![CDATA[<h2 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h2><p>NSThread 是 iOS 多线程当中最基础最轻量的多线程技术,但是需要自行管理线程的生命周期和同步问题,所以使用起来其实比较麻烦。<br>在 Swift 3 中,<strong>NSThread</strong> 已经被重命名为 <strong>Thread</strong>,很多的方法名也进行了修改。<br>下面就写一下自己学到的东西,当作学习笔记,以后可以翻看。如果有错误的地方望指正。</p>
<h2 id="1-创建线程和获取线程"><a href="#1-创建线程和获取线程" class="headerlink" title="1. 创建线程和获取线程"></a>1. 创建线程和获取线程</h2><ul>
<li>直接创建线程是最基本的创建方式,<strong>可以获取到线程线程对象</strong>,适合需要对线程对象进行操作的情况。需要<strong>手动启动</strong>。</li>
</ul>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//直接创建</span></div><div class="line"><span class="keyword">let</span> thread = <span class="type">Thread</span>.<span class="keyword">init</span>(target: <span class="keyword">self</span>, selector: <span class="type">Selector</span>(<span class="string">"run"</span>), object: <span class="literal">nil</span>)</div><div class="line">thread.name = <span class="string">"firstThread"</span></div><div class="line">thread.start()</div></pre></td></tr></table></figure>
<ul>
<li>分离子线程,<strong>不能获取到线程对象</strong>,创建之后<strong>自启动</strong>。</li>
</ul>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//分离子线程</span></div><div class="line"><span class="type">Thread</span>.detachNewThreadSelector(<span class="type">Selector</span>(<span class="string">"run"</span>), toTarget: <span class="keyword">self</span>, with: <span class="literal">nil</span>)</div></pre></td></tr></table></figure>
<ul>
<li>开启一条后台线程,同样<strong>不能获取到线程对象</strong>,创建后<strong>自启动</strong>。</li>
</ul>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//后台线程</span></div><div class="line"><span class="keyword">self</span>.performSelector(inBackground: <span class="type">Selector</span>(<span class="string">"run"</span>), with: <span class="literal">nil</span>)</div></pre></td></tr></table></figure>
<ul>
<li>自定义线程类继承自Thread,对内部的方法进行重写封装,满足自定义需求。</li>
</ul>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//自定义线程</span></div><div class="line"><span class="keyword">let</span> customThread = <span class="type">CustomThread</span>()</div><div class="line">customThread.start()</div></pre></td></tr></table></figure>
<ul>
<li>获取线程</li>
</ul>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//获取主线程</span></div><div class="line"><span class="keyword">let</span> mainThread = <span class="type">Thread</span>.main</div><div class="line"></div><div class="line"><span class="comment">//获取当前线程</span></div><div class="line"><span class="keyword">let</span> currentThread = <span class="type">Thread</span>.current</div><div class="line"></div><div class="line"><span class="comment">//判断当前线程是否为主线程 返回类型为Bool</span></div><div class="line"><span class="keyword">let</span> currentIsMain = <span class="type">Thread</span>.isMainThread</div></pre></td></tr></table></figure>
<h2 id="2-线程状态"><a href="#2-线程状态" class="headerlink" title="2. 线程状态"></a>2. 线程状态</h2><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//退出线程</span></div><div class="line"><span class="type">Thread</span>.exit()</div><div class="line"></div><div class="line"><span class="comment">//线程休眠给定时间</span></div><div class="line"><span class="type">Thread</span>.sleep(forTimeInterval: <span class="number">1.0</span>)</div><div class="line"></div><div class="line"><span class="comment">//线程休眠至特定时间</span></div><div class="line"><span class="type">Thread</span>.sleep(until: <span class="type">Date</span>(timeIntervalSinceNow: <span class="number">1.0</span>))</div></pre></td></tr></table></figure>
<h2 id="3-线程同步与加锁"><a href="#3-线程同步与加锁" class="headerlink" title="3. 线程同步与加锁"></a>3. 线程同步与加锁</h2><p>关于同步和加锁,是多线程逃不掉的话题。Thread 中的线程同步一般用 NSCondition 来加锁实现。NSCondition(这个没有改名字…)主要使用的是 lock()、wait() 和 unlock()。<br>苹果的 API 文档是这么描述 NSCondition 的:</p>
<blockquote>
<p>The NSCondition class implements a condition variable whose semantics follow those used for POSIX-style conditions.<br>A condition object acts as both a lock and a checkpoint in a given thread.</p>
</blockquote>
<p>意思就是 NSCondition 所描述的条件对象在线程当中同时扮演锁(lock)和检查点(checkpoint)的角色。</p>
<blockquote>
<p>The lock protects your code while it tests the condition and performs the task triggered by the condition.<br>The checkpoint behavior requires that the condition be true before the thread proceeds with its task.<br>While the condition is not true, the thread blocks. It remains blocked until another thread signals the condition object.</p>
</blockquote>
<p>Lock 保护着你…… 的代码,以保证它们能按照逻辑来运行和满足条件时的触发执行。<br>线程要干活的时候需要 checkpoint 的条件为真,不然就阻塞罢工,直到其它线程给它发信号唤醒它。</p>
<p>下面是一个 🌰<br><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ViewController</span> : <span class="title">UIViewController</span> </span>{</div><div class="line"></div><div class="line"> <span class="comment">//声明两个线程</span></div><div class="line"> <span class="keyword">var</span> thread_1: <span class="type">Thread</span>?</div><div class="line"> <span class="keyword">var</span> thread_2: <span class="type">Thread</span>?</div><div class="line"></div><div class="line"> <span class="comment">//创建两个 NSCondition</span></div><div class="line"> <span class="keyword">let</span> condition_1 = <span class="type">NSCondition</span>()</div><div class="line"> <span class="keyword">let</span> condition_2 = <span class="type">NSCondition</span>()</div><div class="line"></div><div class="line"> <span class="keyword">override</span> <span class="function"><span class="keyword">func</span> <span class="title">viewDidLoad</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">super</span>.viewDidLoad()</div><div class="line"> <span class="comment">//两个线程的创建和 thread_1 的启动</span></div><div class="line"> thread_1 = <span class="type">Thread</span>(target: <span class="keyword">self</span>, selector: #selector(<span class="keyword">self</span>.forThreadOne) , object: <span class="literal">nil</span>)</div><div class="line"> thread_2 = <span class="type">Thread</span>(target: <span class="keyword">self</span>, selector: #selector(<span class="keyword">self</span>.forThreadTwo), object: <span class="literal">nil</span>)</div><div class="line"> thread_1?.start()</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//thread_1 需要执行的方法</span></div><div class="line"> <span class="meta">@objc</span> <span class="function"><span class="keyword">func</span> <span class="title">forThreadOne</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">7</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"Thread_1 is running for the #<span class="subst">\(i)</span> time(s)."</span>)</div><div class="line"> <span class="keyword">if</span> i % <span class="number">2</span> == <span class="number">0</span> {</div><div class="line"> <span class="comment">//判断 thread_2 是否在运行中,没运行就启动,如果在运行就发信号唤醒 thread_2</span></div><div class="line"> <span class="keyword">if</span> thread_2!.isExecuting {</div><div class="line"> condition_2.signal()</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> thread_2?.start()</div><div class="line"> }</div><div class="line"> <span class="comment">//锁住 thread_1</span></div><div class="line"> condition_1.lock()</div><div class="line"> condition_1.wait()</div><div class="line"> condition_1.unlock()</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="built_in">print</span>(<span class="string">"Thread_1 says it is ended."</span>)</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//thread_2 需要执行的方法</span></div><div class="line"> <span class="meta">@objc</span> <span class="function"><span class="keyword">func</span> <span class="title">forThreadTwo</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>...<span class="number">7</span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"Thread_2 is running for the #<span class="subst">\(i)</span> time(s)."</span>)</div><div class="line"> <span class="keyword">if</span> i % <span class="number">2</span> == <span class="number">0</span> {</div><div class="line"> <span class="comment">//发信号唤醒 thread_1</span></div><div class="line"> condition_1.signal()</div><div class="line"> <span class="comment">//锁住 thread_2</span></div><div class="line"> condition_2.lock()</div><div class="line"> condition_2.wait()</div><div class="line"> condition_2.unlock()</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="built_in">print</span>(<span class="string">"Thread_2 says it is over."</span>)</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">override</span> <span class="function"><span class="keyword">func</span> <span class="title">didReceiveMemoryWarning</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">super</span>.didReceiveMemoryWarning()</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>Swift 还可以使用 objc_sync_enter(obj: Any!) 和 objc_sync_exit(obj: Any!) 来加互斥锁,二者必须成对使用,把需要加锁的代码放在它们两个中间。<br>比如举一个买 7 本书的 🌰<br><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> amountOfBooks = <span class="number">7</span></div><div class="line"></div><div class="line">...</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">func</span> <span class="title">run</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">while</span>(<span class="literal">true</span>) {</div><div class="line"> objc_sync_enter(<span class="keyword">self</span>)</div><div class="line"> <span class="keyword">let</span> current = amountOfBooks</div><div class="line"> <span class="keyword">if</span> current > <span class="number">0</span> {</div><div class="line"> amountOfBooks = current - <span class="number">1</span></div><div class="line"> <span class="built_in">print</span>(...)</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="built_in">print</span>(...)</div><div class="line"> <span class="keyword">break</span></div><div class="line"> }</div><div class="line"> objc_sync_exit(<span class="keyword">self</span>)</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p>
<blockquote>
<p><strong>题外话</strong><br>Swift 需要成对使用的方法很多,多到可以写一个总结…… 先挖个坑</p>
</blockquote>
<h2 id="4-线程通信"><a href="#4-线程通信" class="headerlink" title="4. 线程通信"></a>4. 线程通信</h2><p>主要涉及到的方法有三个,当前线程的、主线程的、指定线程的。<br><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//当前线程</span></div><div class="line"><span class="keyword">self</span>.perform(#selector(<span class="keyword">self</span>.run), with: <span class="literal">nil</span>)</div><div class="line"></div><div class="line"><span class="comment">//主线程</span></div><div class="line"><span class="keyword">self</span>.performSelector(onMainThread: #selector(<span class="keyword">self</span>.run), with: <span class="literal">nil</span>, waitUntilDone: <span class="literal">true</span>)</div><div class="line"></div><div class="line"><span class="comment">//指定线程</span></div><div class="line"><span class="keyword">self</span>.perform(#selector(<span class="keyword">self</span>.run), on: anotherThread, with: <span class="literal">nil</span>, waitUntilDone: <span class="literal">true</span>)</div></pre></td></tr></table></figure></p>
<p>举一个非常简单的小 🌰,在某个 ViewController的viewDidLoad 里,开启了一个子线程,运行 createNumber() 方法,声明 number 并赋值 7。<br>完了以后,使用 performSelector(onMainThread:…) 切换到主线程,并且跑起 printNumber() 方法,把 number 作为参数传入。<br>完成简单的线程间通信传值。<br><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ViewController</span> : <span class="title">UIViewController</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">override</span> <span class="function"><span class="keyword">func</span> <span class="title">viewDidLoad</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">super</span>.viewDidLoad()</div><div class="line"> <span class="type">Thread</span>.detachNewThreadSelector(#selector(<span class="keyword">self</span>.createNumber), toTarget: <span class="keyword">self</span>, with: <span class="literal">nil</span>)</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="meta">@objc</span> <span class="function"><span class="keyword">func</span> <span class="title">createNumber</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">let</span> number = <span class="number">7</span></div><div class="line"> <span class="built_in">print</span>(<span class="string">"Current Thread: <span class="subst">\(Thread.current)</span>"</span>)</div><div class="line"> <span class="keyword">self</span>.performSelector(onMainThread: #selector(<span class="keyword">self</span>.printNumber(number:)), with: number, waitUntilDone: <span class="literal">true</span>)</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="meta">@objc</span> <span class="function"><span class="keyword">func</span> <span class="title">printNumber</span><span class="params">(number: Int)</span></span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"The number is: <span class="subst">\(number)</span>."</span>)</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">override</span> <span class="function"><span class="keyword">func</span> <span class="title">didReceiveMemoryWarning</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">super</span>.didReceiveMemoryWarning()</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure></p>
<blockquote>
<p><strong>题外话 x 2</strong><br>#selector(@objc method) 是非常不 Swift 3 的写法,要求传入的是一个 @objc 的方法。<br>使用 Selector(“methodWithoutParameter”) 或者 Selector(“methodWithParameter:”) 的话就不用在方法前加 @objc 标签,但是会爆黄……</p>
</blockquote>
]]></content>
<summary type="html">
<h2 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h2><p>NSThread 是 iOS 多线程当中最基础最轻量的多线程技术,但是需要自行管理线程的生命周期和同步问题,所以使用起来
</summary>
<category term="iOS 多线程" scheme="https://zhengbuxuan.github.io/tags/iOS-%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
</entry>
<entry>
<title>iOS 多线程之 NSOperation (Swift)</title>
<link href="https://zhengbuxuan.github.io/2017/08/27/iOS%20%E5%A4%9A%E7%BA%BF%E7%A8%8B%E4%B9%8B%20NSOperation/"/>
<id>https://zhengbuxuan.github.io/2017/08/27/iOS 多线程之 NSOperation/</id>
<published>2017-08-27T12:52:15.000Z</published>
<updated>2017-09-02T13:35:45.000Z</updated>
<content type="html"><![CDATA[<h2 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h2><p>NSOperation 是苹果在 GCD 上的封装,NSOperation 相对于 GCD 而言,在处理数量较大的并发时比较牛逼一点,但是速度稍微比 GCD 慢一丢丢。<br><strong>NSOperation</strong> 现在在 Swift 里已经被改名成了 <strong>Operation</strong>。<br>Operation 将线程的管理和数据的同步问题完成了,所以我们只需要把我们想要干的事情搞好就可以了。</p>
<hr>
<h2 id="1-使用-Operation"><a href="#1-使用-Operation" class="headerlink" title="1. 使用 Operation"></a>1. 使用 Operation</h2><p>Operation 是一个 <strong>抽象类</strong> ,所以我们在使用的时候,要不就 <strong>写一个子类</strong> 来实现它,要不就用它已经 <strong>定义好的子类</strong> 。这个时候会接触到一个叫 <strong>OperationQueue</strong> 的队列,需要我们创建好 Operation 的对象之后,把这个对象丢到 OperationQueue 里面去执行。</p>
<h4 id="定义好的子类"><a href="#定义好的子类" class="headerlink" title="定义好的子类"></a>定义好的子类</h4><p>Operation 里面自带的一个子类叫 BlockOperation。看到 <strong>block</strong> 就知道这个东西又是从 Objective-C 搞过来的…<br><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ViewController</span> : <span class="title">UIViewController</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">override</span> <span class="function"><span class="keyword">func</span> <span class="title">viewDidLoad</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">super</span>.viewDidLoad()</div><div class="line"></div><div class="line"> <span class="keyword">let</span> blockOperation = <span class="type">BlockOperation</span>(block: { [<span class="keyword">weak</span> <span class="keyword">self</span>] <span class="keyword">in</span></div><div class="line"> <span class="keyword">self</span>?.printMessage()</div><div class="line"> <span class="keyword">return</span></div><div class="line"> })</div><div class="line"></div><div class="line"> <span class="keyword">let</span> operationQueue = <span class="type">OperationQueue</span>()</div><div class="line"> operationQueue.addOperation(blockOperation)</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">func</span> <span class="title">printMessage</span><span class="params">()</span></span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"I'm BlockOperation."</span>)</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure></p>
<h4 id="自己写的子类"><a href="#自己写的子类" class="headerlink" title="自己写的子类"></a>自己写的子类</h4><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ViewController</span> : <span class="title">UIViewController</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">override</span> <span class="function"><span class="keyword">func</span> <span class="title">viewDidLoad</span><span class="params">()</span></span> {</div><div class="line"> <span class="keyword">super</span>.viewDidLoad()</div><div class="line"></div><div class="line"> <span class="keyword">let</span> customizeOperation = customizeOperation()</div><div class="line"></div><div class="line"> <span class="keyword">let</span> operationQueue = <span class="type">OperationQueue</span>()</div><div class="line"> operationQueue.addOperation(customizeOperation)</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line">}</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">CustomizeOperation</span>: <span class="title">Operation</span> </span>{</div><div class="line"> <span class="keyword">override</span> <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</div><div class="line"> <span class="built_in">print</span>(<span class="string">"I'm CustomizeOperation!"</span>)</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<hr>
<h2 id="2-基础操作"><a href="#2-基础操作" class="headerlink" title="2. 基础操作"></a>2. 基础操作</h2><h4 id="Operation-添加"><a href="#Operation-添加" class="headerlink" title="Operation 添加"></a>Operation 添加</h4><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">operationQueue.addOperation(anOperationToAdd)</div></pre></td></tr></table></figure>
<h4 id="Operation-回调"><a href="#Operation-回调" class="headerlink" title="Operation 回调"></a>Operation 回调</h4><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 这个时候又会看到金光闪闪的一个 block ...</span></div><div class="line"><span class="comment">// 回调就是在 Operation 完成之后大喊一声 “我完事儿了” 表示任务结束...</span></div><div class="line">operation.completionBlock = { () -> <span class="type">Void</span> <span class="keyword">in</span></div><div class="line"> <span class="built_in">print</span>(<span class="string">"I'm done!"</span>)</div><div class="line"> }</div></pre></td></tr></table></figure>
<h4 id="Operation-依赖"><a href="#Operation-依赖" class="headerlink" title="Operation 依赖"></a>Operation 依赖</h4><p>假如说有好几个 Operation 的对象,当它们需要按照一定的顺序执行,或者说它们的工作内容需要其他 Operation 的结果的时候,就需要给 Operation 间添加依赖关系。<br><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">let</span> operation1 = <span class="type">BlockOperation</span> {</div><div class="line"> <span class="comment">// I will do my job when operation2 is completed.</span></div><div class="line">}</div><div class="line"><span class="keyword">let</span> operation2 = <span class="type">BlockOperation</span> {</div><div class="line"> <span class="comment">// I'm gonna do my job so that operation1 can do its job.</span></div><div class="line">}</div><div class="line"><span class="comment">// operation1 依赖于 operation2</span></div><div class="line">operation1.addDependency(operation2)</div><div class="line"><span class="comment">// 队列创建和操作添加,添加顺序无所谓</span></div><div class="line"><span class="keyword">let</span> dependencyQueue = <span class="type">OperationQueue</span>()</div><div class="line">dependencyQueue.addOperation(operation1)</div><div class="line">dependencyQueue.addOperation(operation2)</div></pre></td></tr></table></figure></p>
<h4 id="Operation-取消"><a href="#Operation-取消" class="headerlink" title="Operation 取消"></a>Operation 取消</h4><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 取消队列中的所有 Operation 操作</span></div><div class="line">operationQueue.cancelAllOperation()</div></pre></td></tr></table></figure>
<h4 id="OperationQueue-并发上限设置"><a href="#OperationQueue-并发上限设置" class="headerlink" title="OperationQueue 并发上限设置"></a>OperationQueue 并发上限设置</h4><figure class="highlight swift"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 设置最大并发操作数为 7 ,默认为 -1 表示无限制</span></div><div class="line">operationQueue.maxConcurrentOperationCount = <span class="number">7</span></div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<h2 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h2><p>NSOperation 是苹果在 GCD 上的封装,NSOperation 相对于 GCD 而言,在处理数量较大的并发时
</summary>
<category term="iOS 多线程" scheme="https://zhengbuxuan.github.io/tags/iOS-%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
</entry>
</feed>