-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
587 lines (381 loc) · 503 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
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>PerryWang🍎博客</title>
<subtitle>分享软件开发中学到的点滴知识</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2019-07-31T04:57:55.499Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>PerryWang</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>iOSvsFlutter</title>
<link href="http://yoursite.com/2019/07/31/iOSvsFlutter/"/>
<id>http://yoursite.com/2019/07/31/iOSvsFlutter/</id>
<published>2019-07-31T04:52:08.000Z</published>
<updated>2019-07-31T04:57:55.499Z</updated>
<content type="html"><![CDATA[<h2 id="iOS-vs-Flutter-语法篇"><a href="#iOS-vs-Flutter-语法篇" class="headerlink" title="iOS vs Flutter(语法篇)"></a>iOS vs Flutter(语法篇)</h2><p>首先说一下,为什么要关心iOS和Flutter的区别问题。因为移动端开发的业务逻辑设计模式等是一致的,区别可能只在于使用的语言不同,实现逻辑的风格不同而已。所以这里我们先分析一下iOS和Flutter的区别到底有哪些,有利于我们更快地去入门。</p><a id="more"></a><h3 id="生命周期:"><a href="#生命周期:" class="headerlink" title="生命周期:"></a>生命周期:</h3><h4 id="页面加载的生命周期:"><a href="#页面加载的生命周期:" class="headerlink" title="页面加载的生命周期:"></a>页面加载的生命周期:</h4><p>移动端开发首先要关注的一点肯定要了解一个页面加载的生命周期,就像了解iOS的viewcontroller的生命周期在UI绘制的场景中有多么重要:</p><h5 id="iOS:"><a href="#iOS:" class="headerlink" title="iOS:"></a>iOS:</h5><p>iOS的设计初衷就是MVC,所以iOS中的核心是Controller。每个Controller都有自己的生命周期:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">//类的初始化方法</span><br><span class="line">+ (void)initialize;</span><br><span class="line">//对象初始化方法</span><br><span class="line">- (instancetype)init;</span><br><span class="line">//从归档初始化</span><br><span class="line">- (instancetype)initWithCoder:(NSCoder *)coder;</span><br><span class="line">//加载视图</span><br><span class="line">-(void)loadView;</span><br><span class="line">//将要加载视图</span><br><span class="line">- (void)viewDidLoad;</span><br><span class="line">//将要布局子视图</span><br><span class="line">-(void)viewWillLayoutSubviews;</span><br><span class="line">//已经布局子视图</span><br><span class="line">-(void)viewDidLayoutSubviews;</span><br><span class="line">//内存警告</span><br><span class="line">- (void)didReceiveMemoryWarning;</span><br><span class="line">//已经展示</span><br><span class="line">-(void)viewDidAppear:(BOOL)animated;</span><br><span class="line">//将要展示</span><br><span class="line">-(void)viewWillAppear:(BOOL)animated;</span><br><span class="line">//将要消失</span><br><span class="line">-(void)viewWillDisappear:(BOOL)animated;</span><br><span class="line">//已经消失</span><br><span class="line">-(void)viewDidDisappear:(BOOL)animated;</span><br><span class="line">//被释放</span><br><span class="line">-(void)dealloc;</span><br></pre></td></tr></table></figure><h5 id="flutter:"><a href="#flutter:" class="headerlink" title="flutter:"></a>flutter:</h5><p>这一点flutter则有所不同,flutter页面加载的核心则是build一棵渲染树的过程。</p><p><img src="https://img-blog.csdnimg.cn/20190729161208558.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>如图所示大体上它的生命周期可以分为三个过程:初始化,状态改变,销毁。每一次build都是页面的一次加载。</p><p><strong>didUpdateWidget</strong>: Flutter中的Widget分为两种:stateful(状态可变)和stateless(状态不可变)。如果是stateful的widget需要实现setState方法。当调用了 setState 将 Widget 的状态被改变时 didUpdateWidget 会被调用,Flutter 会创建一个新的 Widget 来绑定这个 State,并在这个方法中传递旧的 Widget ,因此如果你想比对新旧 Widget 并且对 State 做一些调整,你可以用它,另外如果你的某些 Widget 上涉及到 controller 的变更,要么一定要在这个回调方法中移除旧的 controller 并创建新的 controller 监听。</p><p><strong>dispose</strong>:某些情况下你的 Widget 被释放了,一个很经典的例子是 Navigator.pop 被调用,如果被释放的 Widget 中有一些监听或持久化的变量,你需要在 dispose 中进行释放。很重要的一个应用是在 Bloc 或 Stream 时在这个回调方法中去关闭 Stream。</p><p>可参考博客:<a href="https://segmentfault.com/a/1190000015211309" target="_blank" rel="noopener">https://segmentfault.com/a/1190000015211309</a></p><h4 id="App-的生命周期"><a href="#App-的生命周期" class="headerlink" title="App 的生命周期"></a>App 的生命周期</h4><p>iOS中的APP的生命周期在appdelegate里设置,这里不多说。</p><p>而在flutter中如果我们想监听 App 级别的生命周期,可以通过向Binding 中添加一个 Observer,同时要实现didChangeAppLifecycleState来监听指定事件的到来,并且最后还需要在 dispose 回调方法中移除这个监听。但限制是它在iOS平台智能监听三种状态。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">class LifeCycleDemoState extends State<MyHomePage> with WidgetsBindingObserver {</span><br><span class="line"> @override</span><br><span class="line"> void initState() {</span><br><span class="line"> super.initState();</span><br><span class="line"> WidgetsBinding.instance.addObserver(this);</span><br><span class="line"> }</span><br><span class="line"> @override</span><br><span class="line"> void didChangeAppLifecycleState(AppLifecycleState state) {</span><br><span class="line"> super.didChangeAppLifecycleState(state);</span><br><span class="line"> switch (state) {</span><br><span class="line"> case AppLifecycleState.inactive:</span><br><span class="line"> print('Application Lifecycle inactive');</span><br><span class="line"> break;</span><br><span class="line"> case AppLifecycleState.paused:</span><br><span class="line"> print('Application Lifecycle paused');</span><br><span class="line"> break;</span><br><span class="line"> case AppLifecycleState.resumed:</span><br><span class="line"> print('Application Lifecycle resumed');</span><br><span class="line"> break;</span><br><span class="line"> default:</span><br><span class="line"> print('Application Lifecycle other');</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"> @override</span><br><span class="line"> void dispose(){</span><br><span class="line"> WidgetsBinding.instance.removeObserver(this);</span><br><span class="line"> super.dispose();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>详细使用源码看这里:<a href="https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/binding.dart" target="_blank" rel="noopener">https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/binding.dart</a></p><h3 id="布局:"><a href="#布局:" class="headerlink" title="布局:"></a>布局:</h3><p>Flutter的布局首先要建立一棵Widget树(分析一下UI图建立一棵控件树),根据树的结构层层嵌套Widget控件。margin和padding等的约束布局设置则有点类似css。</p><h4 id="UIView-gt-Widgets"><a href="#UIView-gt-Widgets" class="headerlink" title="UIView => Widgets"></a>UIView => Widgets</h4><p><strong>iOS</strong>:UIView可变,UIView发生改变本质上是间接调用(官方建议不要显式调用,因为这开销很大)了LayoutSubviews方法进行布局上的重构,drawRect进行显示上的重构,updateConstrains进行约束上的重构。三者的更新会在每次RunLoop之后进行update cycle操作(也可以调用layoutIfNeeded等方法进行立刻更新)。(推荐一篇讲述布局不错的文章:<a href="https://juejin.im/post/5a951c655188257a804abf94" target="_blank" rel="noopener">https://juejin.im/post/5a951c655188257a804abf94</a>)</p><p><strong>Flutter</strong>:Widget不可变,也正是由于不可变性,使得Widget比起UIView来说更轻量,因为它不是控件,只是UI的描述。</p><ul><li>widget的分为Stateful(状态可变)和Stateless(状态不可变)两种,Stateful本质上也是不可变的,它只是将状态拆分到State中去管理。State会存储Widget的状态数据,并在widget树重建时携带着它,因此状态不会丢失。</li><li>即使一个widget是有状态的,包含它的父亲的widget也可以是无状态的,只要父widget本身不响应这些变化即可。</li><li>在UI更新这一点上感觉flutter会比iOS要麻烦一点,例如点击按钮导致Text的文字发生变化,iOS只需要简单的target-action就可以,而flutter则需要将无状态的text套在一个StatefulWidget父类里面才可以。</li></ul><figure class="highlight dart"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SampleApp</span> <span class="keyword">extends</span> <span class="title">StatelessWidget</span> </span>{</span><br><span class="line"> <span class="meta">@override</span></span><br><span class="line"> Widget build(BuildContext context) {</span><br><span class="line"> <span class="keyword">return</span> MaterialApp(</span><br><span class="line"> title: <span class="string">'My App'</span>,</span><br><span class="line"> theme: ThemeData(</span><br><span class="line"> primarySwatch: Colors.blue,</span><br><span class="line"> ),</span><br><span class="line"> home: SampleAppPage(),</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SampleAppPage</span> <span class="keyword">extends</span> <span class="title">StatefulWidget</span> </span>{</span><br><span class="line"> SampleAppPage({Key key}) : <span class="keyword">super</span>(key: key);</span><br><span class="line"></span><br><span class="line"> <span class="meta">@override</span></span><br><span class="line"> _SampleAppPageState createState() => _SampleAppPageState();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">_SampleAppPageState</span> <span class="keyword">extends</span> <span class="title">State</span><<span class="title">SampleAppPage</span>> </span>{</span><br><span class="line"> <span class="comment">// Default placeholder text</span></span><br><span class="line"> <span class="built_in">String</span> textToShow = <span class="string">"Flutter"</span>;</span><br><span class="line"> <span class="keyword">void</span> _updateText() {</span><br><span class="line"> setState(() {</span><br><span class="line"> <span class="comment">// update the text</span></span><br><span class="line"> textToShow = <span class="string">"Text is changed!"</span>;</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@override</span></span><br><span class="line"> Widget build(BuildContext context) {</span><br><span class="line"> <span class="keyword">return</span> Scaffold(</span><br><span class="line"> appBar: AppBar(</span><br><span class="line"> title: Text(<span class="string">"My App"</span>),</span><br><span class="line"> ),</span><br><span class="line"> body: Center(child: Text(textToShow)),</span><br><span class="line"> floatingActionButton: FloatingActionButton(</span><br><span class="line"> onPressed: _updateText,</span><br><span class="line"> child: Icon(Icons.update),</span><br><span class="line"> ),</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [<span class="keyword">super</span> viewDidLoad];</span><br><span class="line"> <span class="comment">// Do any additional setup after loading the view.</span></span><br><span class="line"> <span class="built_in">UIButton</span> *button = [<span class="built_in">UIButton</span> buttonWithType:<span class="built_in">UIButtonTypeSystem</span>];</span><br><span class="line"> button.frame = <span class="built_in">CGRectMake</span>(<span class="number">300</span>, <span class="number">600</span>, <span class="number">80</span>, <span class="number">40</span>);</span><br><span class="line"> [button setTitle:<span class="string">@"点击"</span> forState:<span class="built_in">UIControlStateNormal</span>];</span><br><span class="line"> [button addTarget:<span class="keyword">self</span> action:<span class="keyword">@selector</span>(onClick) forControlEvents:<span class="built_in">UIControlEventTouchUpInside</span>];</span><br><span class="line"> [<span class="keyword">self</span>.view addSubview:button];</span><br><span class="line"> <span class="keyword">self</span>.textField = [[<span class="built_in">UITextField</span> alloc] initWithFrame:<span class="built_in">CGRectMake</span>(<span class="number">100</span>, <span class="number">300</span>, <span class="number">200</span>, <span class="number">60</span>)];</span><br><span class="line"> <span class="keyword">self</span>.textField.text = <span class="string">@"iOS"</span>;</span><br><span class="line"> [<span class="keyword">self</span>.view addSubview:<span class="keyword">self</span>.textField];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">-(<span class="keyword">void</span>) onClick</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">self</span>.textField.text = <span class="string">@"text has changed!"</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>在布局方面,iOS分为xib和storyboard还有代码布局的方式,flutter比较统一,通过建立一棵widget树进行布局,同时还有类似Center,Column等Widget进行布局。添加约束的话,iOS通过autolayout来添加约束,而flutter则是通过使用container容器添加padding,margin等属性来添加约束。这点非常类似html和css的布局原理。如下所示:</li></ul><p><img src="https://img-blog.csdnimg.cn/2019072916124644.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><ul><li><p>父子视图的移除方面,比如说举个常见的例子,一个bool值的改变导致两个视图的切换,iOS需要在父view中调用addSubview()或在子view中调用removeFromSuperView() 来动态添加或移除子view,如果涉及到一些传值问题可能还需要通过观察者模式来观察bool值的更新。而在flutter中则需要向父widget中传入一个返回widget的函数,并用bool来控制子widget的创建。</p><figure class="highlight dart"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SampleApp</span> <span class="keyword">extends</span> <span class="title">StatelessWidget</span> </span>{</span><br><span class="line"> <span class="meta">@override</span></span><br><span class="line"> Widget build(BuildContext context) {</span><br><span class="line"> <span class="keyword">return</span> MaterialApp(</span><br><span class="line"> title: <span class="string">'Sample App'</span>,</span><br><span class="line"> theme: ThemeData(</span><br><span class="line"> primarySwatch: Colors.blue,</span><br><span class="line"> ),</span><br><span class="line"> home: SampleAppPage(),</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SampleAppPage</span> <span class="keyword">extends</span> <span class="title">StatefulWidget</span> </span>{</span><br><span class="line"> SampleAppPage({Key key}) : <span class="keyword">super</span>(key: key);</span><br><span class="line"></span><br><span class="line"> <span class="meta">@override</span></span><br><span class="line"> _SampleAppPageState createState() => _SampleAppPageState();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">_SampleAppPageState</span> <span class="keyword">extends</span> <span class="title">State</span><<span class="title">SampleAppPage</span>> </span>{</span><br><span class="line"> <span class="built_in">bool</span> toggle = <span class="keyword">true</span>;</span><br><span class="line"> <span class="keyword">void</span> _toggle() {</span><br><span class="line"> setState(() {</span><br><span class="line"> toggle = !toggle;</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> _getToggleChild() {</span><br><span class="line"> <span class="keyword">if</span> (toggle) {</span><br><span class="line"> <span class="keyword">return</span> Text(<span class="string">'View One'</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> CupertinoButton(</span><br><span class="line"> onPressed: () {},</span><br><span class="line"> child: Text(<span class="string">'View Two'</span>),</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@override</span></span><br><span class="line"> Widget build(BuildContext context) {</span><br><span class="line"> <span class="keyword">return</span> Scaffold(</span><br><span class="line"> appBar: AppBar(</span><br><span class="line"> title: Text(<span class="string">"Sample App"</span>),</span><br><span class="line"> ),</span><br><span class="line"> body: Center(</span><br><span class="line"> child: _getToggleChild(),</span><br><span class="line"> ),</span><br><span class="line"> floatingActionButton: FloatingActionButton(</span><br><span class="line"> onPressed: _toggle,</span><br><span class="line"> tooltip: <span class="string">'Update Text'</span>,</span><br><span class="line"> child: Icon(Icons.update),</span><br><span class="line"> ),</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [<span class="keyword">super</span> viewDidLoad];</span><br><span class="line"> <span class="comment">// Do any additional setup after loading the view.</span></span><br><span class="line"> <span class="built_in">UIButton</span> *button = [<span class="built_in">UIButton</span> buttonWithType:<span class="built_in">UIButtonTypeSystem</span>];</span><br><span class="line"> button.frame = <span class="built_in">CGRectMake</span>(<span class="number">350</span>, <span class="number">750</span>, <span class="number">50</span>, <span class="number">30</span>);</span><br><span class="line"> [button setTitle:<span class="string">@"切换"</span> forState:<span class="built_in">UIControlStateNormal</span>];</span><br><span class="line"> [button addTarget:<span class="keyword">self</span> action:<span class="keyword">@selector</span>(onClick) forControlEvents:<span class="built_in">UIControlEventTouchUpInside</span>];</span><br><span class="line"> [<span class="keyword">self</span>.view addSubview:button];</span><br><span class="line"> <span class="keyword">self</span>.textField = [[<span class="built_in">UITextField</span> alloc] initWithFrame:<span class="built_in">CGRectMake</span>(<span class="number">100</span>, <span class="number">300</span>, <span class="number">200</span>, <span class="number">60</span>)];</span><br><span class="line"> <span class="keyword">self</span>.textField.text = <span class="string">@"View 1"</span>;</span><br><span class="line"> [<span class="keyword">self</span>.view addSubview: <span class="keyword">self</span>.textField];</span><br><span class="line"> <span class="keyword">self</span>.button2 = [<span class="built_in">UIButton</span> buttonWithType:<span class="built_in">UIButtonTypeSystem</span>];</span><br><span class="line"> <span class="keyword">self</span>.button2.frame = <span class="built_in">CGRectMake</span>(<span class="number">100</span>, <span class="number">300</span>, <span class="number">200</span>, <span class="number">60</span>);</span><br><span class="line"> [<span class="keyword">self</span>.button2 setTitle:<span class="string">@"View 2"</span> forState:<span class="built_in">UIControlStateNormal</span>];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">-(<span class="keyword">void</span>) onClick</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">self</span>.textField.superview) {</span><br><span class="line"> [<span class="keyword">self</span>.textField removeFromSuperview];</span><br><span class="line"> [<span class="keyword">self</span>.view addSubview:<span class="keyword">self</span>.button2];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> [<span class="keyword">self</span>.button2 removeFromSuperview];</span><br><span class="line"> [<span class="keyword">self</span>.view addSubview:<span class="keyword">self</span>.textField];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h3 id="导航"><a href="#导航" class="headerlink" title="导航"></a>导航</h3><h4 id="UIViewController-gt-Scaffold"><a href="#UIViewController-gt-Scaffold" class="headerlink" title="UIViewController => Scaffold"></a>UIViewController => Scaffold</h4><p>Flutter中没有专门用来管理视图而且类似那种和View一对一的Controller类。有类似的Scaffold,其包含控制器的appBar,也可以通过body设置一个widget来做其视图。</p><h4 id="页面跳转"><a href="#页面跳转" class="headerlink" title="页面跳转"></a>页面跳转</h4><p>iOS有UINavigationController栈进行push,pop操作,其并不负责显示,而是负责各个页面跳转。或者使用模态视图。</p><p>同时注意iOS通过navigationController导航时要记得添加NavigationController,可在stroyboard设置,如果代码的话添加如下:</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">ViewController *vc = [ViewController new];</span><br><span class="line"><span class="built_in">UINavigationController</span> *navigation = [[<span class="built_in">UINavigationController</span> alloc] initWithRootViewController:vc];</span><br><span class="line"><span class="keyword">self</span>.window.rootViewController = navigation;</span><br><span class="line">[<span class="keyword">self</span>.window makeKeyWindow];</span><br></pre></td></tr></table></figure><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// -------- ViewController --------</span></span><br><span class="line">-(NextViewController *)next</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (!_next)</span><br><span class="line"> {</span><br><span class="line"> _next = [NextViewController new];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> _next;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [<span class="keyword">super</span> viewDidLoad];</span><br><span class="line"> <span class="comment">// Do any additional setup after loading the view.</span></span><br><span class="line"> <span class="keyword">self</span>.view.backgroundColor = [<span class="built_in">UIColor</span> whiteColor];</span><br><span class="line"> <span class="built_in">UIButton</span> *button = [<span class="built_in">UIButton</span> buttonWithType:<span class="built_in">UIButtonTypeSystem</span>];</span><br><span class="line"> button.frame = <span class="built_in">CGRectMake</span>(<span class="number">350</span>, <span class="number">750</span>, <span class="number">50</span>, <span class="number">30</span>);</span><br><span class="line"> [button setTitle:<span class="string">@"切换"</span> forState:<span class="built_in">UIControlStateNormal</span>];</span><br><span class="line"> [button addTarget:<span class="keyword">self</span> action:<span class="keyword">@selector</span>(onClick) forControlEvents:<span class="built_in">UIControlEventTouchUpInside</span>];</span><br><span class="line"> [<span class="keyword">self</span>.view addSubview:button];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">-(<span class="keyword">void</span>) onClick</span><br><span class="line">{</span><br><span class="line"> [<span class="keyword">self</span>.navigationController pushViewController:<span class="keyword">self</span>.next animated:<span class="literal">YES</span>];</span><br><span class="line"> <span class="comment">// [self presentViewController:self.next animated:YES completion:nil];</span></span><br><span class="line">}</span><br><span class="line"><span class="comment">// -------- NextViewController --------</span></span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [<span class="keyword">super</span> viewDidLoad];</span><br><span class="line"> <span class="keyword">self</span>.view.backgroundColor = [<span class="built_in">UIColor</span> whiteColor];</span><br><span class="line"> <span class="comment">// Do any additional setup after loading the view.</span></span><br><span class="line"> <span class="built_in">UIButton</span> *button = [<span class="built_in">UIButton</span> buttonWithType:<span class="built_in">UIButtonTypeSystem</span>];</span><br><span class="line"> button.frame = <span class="built_in">CGRectMake</span>(<span class="number">350</span>, <span class="number">750</span>, <span class="number">50</span>, <span class="number">30</span>);</span><br><span class="line"> [button setTitle:<span class="string">@"返回"</span> forState:<span class="built_in">UIControlStateNormal</span>];</span><br><span class="line"> [button addTarget:<span class="keyword">self</span> action:<span class="keyword">@selector</span>(onClick) forControlEvents:<span class="built_in">UIControlEventTouchUpInside</span>];</span><br><span class="line"> [<span class="keyword">self</span>.view addSubview:button];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">-(<span class="keyword">void</span>) onClick</span><br><span class="line">{</span><br><span class="line"> [<span class="keyword">self</span>.navigationController popViewControllerAnimated:<span class="literal">YES</span>];</span><br><span class="line"> <span class="comment">// [self dismissViewControllerAnimated:YES completion:nil];</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Flutter中可以将MaterialApp理解为iOS的导航控制器,其包含一个navigationBar以及导航栈,这点和iOS是一样的。</p><p>Flutter中使用了 <code>Navigator</code> 和 <code>Routes</code>。一个路由是 App 中“屏幕”或“页面”的抽象,而一个 Navigator 是管理多个路由的 widget。可以粗略地把一个路由对应到一个 <code>UIViewController</code>。Navigator 的工作原理和 iOS 中 <code>UINavigationController</code> 非常相似,当你想跳转到新页面或者从新页面返回时,它可以 <code>push()</code> 和 <code>pop()</code> 路由。</p><p>在页面之间跳转,有如下选择:</p><ul><li>具体指定一个由路由名构成的 <code>Map</code>。(MaterialApp)</li><li>直接跳转到一个路由。(WidgetApp)</li></ul><p>下面是构建一个 Map 的例子:</p><figure class="highlight dart"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> main() {</span><br><span class="line"> runApp(MaterialApp(</span><br><span class="line"> home: MyAppHome(), <span class="comment">// becomes the route named '/'</span></span><br><span class="line"> routes: <<span class="built_in">String</span>, WidgetBuilder> {</span><br><span class="line"> <span class="string">'/a'</span>: (BuildContext context) => MyPage(title: <span class="string">'page A'</span>),</span><br><span class="line"> <span class="string">'/b'</span>: (BuildContext context) => MyPage(title: <span class="string">'page B'</span>),</span><br><span class="line"> <span class="string">'/c'</span>: (BuildContext context) => MyPage(title: <span class="string">'page C'</span>),</span><br><span class="line"> },</span><br><span class="line"> ));</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>通过把路由的名字 <code>push</code> 给一个 <code>Navigator</code> 来跳转:</p><figure class="highlight dart"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Navigator.of(context).pushNamed(<span class="string">'/b'</span>);</span><br></pre></td></tr></table></figure><h4 id="页面传值"><a href="#页面传值" class="headerlink" title="页面传值"></a>页面传值</h4><p>iOS中页面传值正向直接通过属性传输即可,反向的话可以通过Block,delegate,通知等方式进行传值。</p><p>而在Flutter中反向传值就简单了很多,举个例子,要跳转到“位置”路由来让用户选择一个地点,可能要这么做:</p><figure class="highlight dart"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Map</span> coordinates = <span class="keyword">await</span> Navigator.of(context).pushNamed(<span class="string">'/location'</span>);</span><br></pre></td></tr></table></figure><p>之后,在 location 路由中,一旦用户选择了地点,携带结果一起 <code>pop()</code> 出栈:</p><figure class="highlight dart"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Navigator.of(context).pop({<span class="string">"lat"</span>:<span class="number">43.821757</span>,<span class="string">"long"</span>:<span class="number">-79.226392</span>});</span><br></pre></td></tr></table></figure><h3 id="多线程"><a href="#多线程" class="headerlink" title="多线程"></a>多线程</h3><h4 id="RunLoop-VS-EventLoop"><a href="#RunLoop-VS-EventLoop" class="headerlink" title="RunLoop VS EventLoop"></a><code>RunLoop</code> <strong>VS</strong> <code>EventLoop</code></h4><p>说起Flutter的多线程前先谈一下Flutter中的Event Loop。我们都知道前端开发框架大都是事件驱动的。意味着程序中必然存在事件循环和事件队列。事件循环会不断地从事件队列中获取和处理各种事件。</p><p><strong>iOS</strong>:iOS中的类似机制是RunLoop,可以通过一个RunLoopObserver来实现对RunLoop的观察,当遇到Source0,Source1或者Timer等事件会进行处理。下面图可以很清晰的理解整个过程。(关于RunLoop的讲解推荐一篇很详细的文章:<a href="https://juejin.im/post/5add46606fb9a07abf721d1d" target="_blank" rel="noopener">https://juejin.im/post/5add46606fb9a07abf721d1d</a>)</p><p><img src="https://img-blog.csdnimg.cn/20190729161323870.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p><strong>Flutter</strong>:Flutter中的Event Loop和JavaScript的基本一样。循环中有两个队列。一个是微任务队列(MicroTask queue),一个是事件队列(Event queue)。这里类似iOS中存在set里面的Source0和Source1。</p><ul><li>event queue: 主要是外部事件,负责处理I/O事件、绘制事件、手势事件、Timer等</li><li>microtask queue:可以自己向<code>isolate</code>内部添加事件,事件的优先级比<code>event queue</code>高。</li></ul><p><img src="https://img-blog.csdnimg.cn/2019072916142898.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>两个队列是有优先级的,当<code>isolate</code>开始执行后,会先处理<code>microtask</code>的事件,当<code>microtask</code>队列中没有事件后,才会处理<code>event</code>队列中的事件,并按照这个顺序反复执行。当执行<code>microtask</code>的事件时会阻塞<code>event</code>队列,这会导致渲染响应手势等<code>event</code>事件响应延迟。为保证渲染和手势响应,所以应尽量将耗时操作放到<code>event</code>队列中。</p><h4 id="线程和协程:"><a href="#线程和协程:" class="headerlink" title="线程和协程:"></a>线程和协程:</h4><p>Flutter中的多线程和异步是比较难理解的一块。先看两个语法糖:</p><ol><li><p>Future:</p><p>学过js的童鞋应该很容易理解这块了,Future就是js里的Promise,曾经js里面延时只能层层回调,这样很容易造成回调地狱。所以应运而生了Promise(Future),它是一个链式操作,可以通过追加then方法进行多层处理。</p></li><li><p>async/await:用法完全沿用自js。</p></li></ol><p><strong>多协程:</strong></p><p>我们拆开来看,首先对于异步操作这块,flutter基本上是沿用ES6的async和await这些异步语法糖以及Future。这里涉及到一个和传统意义不一样的概念——协程(<a href="https://www.itcodemonkey.com/article/4620.html这篇漫画讲的比较生动,https://www.zhihu.com/question/308641794讲解为什么协程比线程要好),最早接触是在python里有遇到过,在Flutter中,执行到async则表示进入一个协程,会同步执行async的代码块。当执行到await时,则表示有任务需要等待,CPU则去调度执行其他IO。过一段时间CPU会轮询一次查看某个协程是否任务已经处理完成,有返回结果可以被继续执行,如果可以被继续执行的话,则会沿着上次离开时指针指向的位置继续执行。也就是await标志的位置。" target="_blank" rel="noopener">https://www.itcodemonkey.com/article/4620.html这篇漫画讲的比较生动,https://www.zhihu.com/question/308641794讲解为什么协程比线程要好),最早接触是在python里有遇到过,在Flutter中,执行到async则表示进入一个协程,会同步执行async的代码块。当执行到await时,则表示有任务需要等待,CPU则去调度执行其他IO。过一段时间CPU会轮询一次查看某个协程是否任务已经处理完成,有返回结果可以被继续执行,如果可以被继续执行的话,则会沿着上次离开时指针指向的位置继续执行。也就是await标志的位置。</a></p><p>iOS中有没有类似的实现呢,其实是有的,个人感觉是串行队列中的<code>dispatch_async</code>操作,遇到耗时操作也不会阻塞,而是放到事件队列中等待当前操作执行完再继续执行。Flutter在当执行到<code>await</code>时,保存当前的上下文,并将当前位置标记为待处理任务,用一个指针指向当前位置,并将待处理任务放入当前线程的队列中。在每个事件循环时都去询问这个任务,如果需要进行处理,就恢复上下文进行任务处理。</p><p><strong>多线程:</strong></p><p>而async和await是沿用自js的,但有一点要注意的是,js是脚本语言,所以必须是单线程的,到这里就足够了。而flutter是手机框架,很可能我们要进行很耗时的IO操作,这仅仅凭异步是解决不了的,必须要多线程。这里flutter引入了新的方案,叫做isolate。</p><p>但isolate和普通的Thread还不同,它具有独立的内存,isolate间的通信通过port来实现,这个port消息传递的过程是异步的。实例化一个isolate的过程也就是实例化isolate这个结构体、在堆中分配线程内存,配置port。</p><p>感觉从操作来看其实isolate更像是进程,而实际async则更像是线程操作。</p><figure class="highlight dart"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">loadData() <span class="keyword">async</span> {</span><br><span class="line"> <span class="comment">// 通过spawn新建一个isolate,并绑定静态方法</span></span><br><span class="line"> ReceivePort receivePort =ReceivePort();</span><br><span class="line"> <span class="keyword">await</span> Isolate.spawn(dataLoader, receivePort.sendPort);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 获取新isolate的监听port</span></span><br><span class="line"> SendPort sendPort = <span class="keyword">await</span> receivePort.first;</span><br><span class="line"> <span class="comment">// 调用sendReceive自定义方法</span></span><br><span class="line"> <span class="built_in">List</span> dataList = <span class="keyword">await</span> sendReceive(sendPort, <span class="string">'https://jsonplaceholder.typicode.com/posts'</span>);</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'dataList <span class="subst">$dataList</span>'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// isolate的绑定方法</span></span><br><span class="line"><span class="keyword">static</span> dataLoader(SendPort sendPort) <span class="keyword">async</span>{</span><br><span class="line"> <span class="comment">// 创建监听port,并将sendPort传给外界用来调用</span></span><br><span class="line"> ReceivePort receivePort =ReceivePort();</span><br><span class="line"> sendPort.send(receivePort.sendPort);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 监听外界调用</span></span><br><span class="line"> <span class="keyword">await</span> <span class="keyword">for</span> (<span class="keyword">var</span> msg <span class="keyword">in</span> receivePort) {</span><br><span class="line"> <span class="built_in">String</span> requestURL =msg[<span class="number">0</span>];</span><br><span class="line"> SendPort callbackPort =msg[<span class="number">1</span>];</span><br><span class="line"> </span><br><span class="line"> Client client = Client();</span><br><span class="line"> Response response = <span class="keyword">await</span> client.<span class="keyword">get</span>(requestURL);</span><br><span class="line"> <span class="built_in">List</span> dataList = json.decode(response.body);</span><br><span class="line"> <span class="comment">// 回调返回值给调用者</span></span><br><span class="line"> callbackPort.send(dataList);</span><br><span class="line"> } </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建自己的监听port,并且向新isolate发送消息</span></span><br><span class="line">Future sendReceive(SendPort sendPort, <span class="built_in">String</span> url) {</span><br><span class="line"> ReceivePort receivePort =ReceivePort();</span><br><span class="line"> sendPort.send([url, receivePort.sendPort]);</span><br><span class="line"> <span class="comment">// 接收到返回值,返回给调用者</span></span><br><span class="line"> <span class="keyword">return</span> receivePort.first;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>(代码引用自<a href="https://lequ7.com/2019/04/26/richang/shen-ru-li-jie-Flutter-duo-xian-cheng/" target="_blank" rel="noopener">https://lequ7.com/2019/04/26/richang/shen-ru-li-jie-Flutter-duo-xian-cheng/</a>)</p><h4 id="网络请求和数据解析"><a href="#网络请求和数据解析" class="headerlink" title="网络请求和数据解析"></a>网络请求和数据解析</h4><p>这点不做详述,理解了Dart的多线程以及网络请求的基本原理也很容易搞懂这块(<a href="https://flutterchina.club/networking/)。" target="_blank" rel="noopener">https://flutterchina.club/networking/)。</a></p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>文章不从性能进行分析,而是仅仅从语法方面进行入门比对。其实如果做过Web前端的童鞋学期Flutter来说应该会比较简单,因为Flutter中的Widget布局方式完全类似于html和css。而Dart语言本身有非常像js,尤其是ES6特性引入很多语法糖后的js,这些语法糖大大简化了代码的复杂度。</p>]]></content>
<summary type="html">
<h2 id="iOS-vs-Flutter-语法篇"><a href="#iOS-vs-Flutter-语法篇" class="headerlink" title="iOS vs Flutter(语法篇)"></a>iOS vs Flutter(语法篇)</h2><p>首先说一下,为什么要关心iOS和Flutter的区别问题。因为移动端开发的业务逻辑设计模式等是一致的,区别可能只在于使用的语言不同,实现逻辑的风格不同而已。所以这里我们先分析一下iOS和Flutter的区别到底有哪些,有利于我们更快地去入门。</p>
</summary>
<category term="Flutter" scheme="http://yoursite.com/categories/Flutter/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
<category term="Flutter" scheme="http://yoursite.com/tags/Flutter/"/>
<category term="Dart" scheme="http://yoursite.com/tags/Dart/"/>
<category term="Objective" scheme="http://yoursite.com/tags/Objective/"/>
</entry>
<entry>
<title>iOS || 缓存NSCache详解</title>
<link href="http://yoursite.com/2019/07/11/%E7%BC%93%E5%AD%98NSCache%E8%AF%A6%E8%A7%A3/"/>
<id>http://yoursite.com/2019/07/11/缓存NSCache详解/</id>
<published>2019-07-10T16:26:23.000Z</published>
<updated>2019-07-10T16:36:12.524Z</updated>
<content type="html"><![CDATA[<h3 id="NSCache"><a href="#NSCache" class="headerlink" title="NSCache"></a>NSCache</h3><p>NSCache使用很方便,提供了类似可变字典的实现方式,但它比可变字典更适用于实现缓存。</p><ul><li>最重要的原因是<code>NSCache</code>是线程安全的,使用<code>NSMutableDictionary</code>自定义实现缓存的时候需要考虑加锁和释放锁,<code>NSCache</code>已经帮我们做好了这一步。</li><li>其次,内存不足时<code>NSCache</code>会自动释放存储的对象,不需要手动干预,如果是自定义实现需要监听内存状态然后做进一步删除对象的操作。</li><li>还有一点<code>NSCache</code>的键<code>key</code>不会被复制,所以<code>key</code>不需要实现<code>NSCopying</code>协议。</li></ul><p>以上三点就是<code>NSCache</code>相比于<code>NSMutableDictionary</code>实现缓存功能的优点,在需要实现缓存的时候应优先考虑使用<code>NSCache</code>。</p><a id="more"></a><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//名称</span></span><br><span class="line">@property (copy) NSString *name;</span><br><span class="line"></span><br><span class="line"><span class="comment">//NSCacheDelegate代理</span></span><br><span class="line">@property (nullable, assign) id<NSCacheDelegate> delegate;</span><br><span class="line"></span><br><span class="line"><span class="comment">//通过key获取value,类似于字典中通过key取value的操作</span></span><br><span class="line">- (nullable ObjectType)objectForKey:(KeyType)key;</span><br><span class="line"></span><br><span class="line"><span class="comment">//设置key、value</span></span><br><span class="line">- (<span class="keyword">void</span>)setObject:(ObjectType)obj forKey:(KeyType)key; <span class="comment">// 0 cost</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">设置key、value</span></span><br><span class="line"><span class="comment">cost表示obj这个value对象的占用的消耗?可以自行设置每个需要添加进缓存的对象的cost值</span></span><br><span class="line"><span class="comment">这个值与后面的totalCostLimit对应,如果添加进缓存的cost总值大于totalCostLimit就会自动进行删除</span></span><br><span class="line"><span class="comment">感觉在实际开发中直接使用setObject:forKey:方法就可以解决问题了</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">- (<span class="keyword">void</span>)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;</span><br><span class="line"></span><br><span class="line"><span class="comment">//根据key删除value对象</span></span><br><span class="line">- (<span class="keyword">void</span>)removeObjectForKey:(KeyType)key;</span><br><span class="line"></span><br><span class="line"><span class="comment">//删除保存的所有的key-value</span></span><br><span class="line">- (<span class="keyword">void</span>)removeAllObjects;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">NSCache能够占用的消耗?的限制</span></span><br><span class="line"><span class="comment">当NSCache缓存的对象的总cost值大于这个值则会自动释放一部分对象直到占用小于该值</span></span><br><span class="line"><span class="comment">非严格限制意味着如果保存的对象超出这个大小也不一定会被删除</span></span><br><span class="line"><span class="comment">这个值就是与前面setObject:forKey:cost:方法对应</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">@property NSUInteger totalCostLimit; <span class="comment">// limits are imprecise/not strict</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">缓存能够保存的key-value个数的最大数量</span></span><br><span class="line"><span class="comment">当保存的数量大于该值就会被自动释放</span></span><br><span class="line"><span class="comment">非严格限制意味着如果超出了这个数量也不一定会被删除</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">@property NSUInteger countLimit; <span class="comment">// limits are imprecise/not strict</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">这个值与NSDiscardableContent协议有关,默认为YES</span></span><br><span class="line"><span class="comment">当一个类实现了该协议,并且这个类的对象不再被使用时意味着可以被释放</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">@property BOOL evictsObjectsWithDiscardedContent;</span><br><span class="line"></span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line"><span class="comment">//NSCacheDelegate协议</span></span><br><span class="line">@protocol NSCacheDelegate <NSObject></span><br><span class="line">@optional</span><br><span class="line"><span class="comment">//上述协议只有这一个方法,缓存中的一个对象即将被删除时被回调</span></span><br><span class="line">- (<span class="keyword">void</span>)cache:(NSCache *)cache willEvictObject:(id)obj;</span><br><span class="line">@end</span><br></pre></td></tr></table></figure><p>通过接口可以看出,<code>NSCache</code>提供的方法都很简单,属性的意义也很明确,接下来举一个简单的栗子:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ------ Test类实现Cache协议</span></span><br><span class="line">@interface CacheTest : NSObject <NSCacheDelegate></span><br><span class="line"></span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line"><span class="meta">#import <span class="meta-string">"CacheTest.h"</span></span></span><br><span class="line"></span><br><span class="line">@implementation CacheTest</span><br><span class="line"></span><br><span class="line"><span class="comment">// 当缓存中的一个对象即将被删除时会回调此方法</span></span><br><span class="line">- (<span class="keyword">void</span>)cache:(NSCache *)cache willEvictObject:(nonnull id)obj</span><br><span class="line">{</span><br><span class="line"> NSLog(@<span class="string">"Remove Object %@"</span>, obj);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line"><span class="comment">// ------ 使用</span></span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> NSCache *cache = [[NSCache alloc] init];</span><br><span class="line"> [cache setCountLimit:<span class="number">5</span>];</span><br><span class="line"> CacheTest *ct = [[CacheTest alloc] init];</span><br><span class="line"> cache.delegate = ct;</span><br><span class="line"> NSString *test = @<span class="string">"Hello World"</span>;</span><br><span class="line"> [cache setObject:test forKey:@<span class="string">"Test"</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> [cache setObject:[NSString stringWithFormat:@<span class="string">"World%d"</span>, i] forKey:[NSString stringWithFormat:@<span class="string">"Hello%d"</span>, i]];</span><br><span class="line"> NSLog(@<span class="string">"Add key:%@ value:%@ to Cache"</span>, [NSString stringWithFormat:@<span class="string">"Hello%d"</span>, i], [NSString stringWithFormat:@<span class="string">"World%d"</span>, i]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> NSLog(@<span class="string">"Get value:%@ for key :%@"</span>, [cache objectForKey:[NSString stringWithFormat:@<span class="string">"Hello%d"</span>, i]], [NSString stringWithFormat:@<span class="string">"Hello%d"</span>, i]);</span><br><span class="line"> }</span><br><span class="line"> [cache removeAllObjects];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> NSLog(@<span class="string">"Get value:%@ for key:%@"</span>, [cache objectForKey:[NSString stringWithFormat:@<span class="string">"World%d"</span>, i]], [NSString stringWithFormat:@<span class="string">"World%d"</span>, i]);</span><br><span class="line"> }</span><br><span class="line"> NSLog(@<span class="string">"Test %@"</span>, test);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>以下是全部的打印结果:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line">2019-06-06 14:25:14.767790+0800 TestDemo[3677:137719] Add key:Hello0 value:World0 to Cache</span><br><span class="line">2019-06-06 14:25:14.767904+0800 TestDemo[3677:137719] Add key:Hello1 value:World1 to Cache</span><br><span class="line">2019-06-06 14:25:14.767989+0800 TestDemo[3677:137719] Add key:Hello2 value:World2 to Cache</span><br><span class="line">2019-06-06 14:25:14.768062+0800 TestDemo[3677:137719] Add key:Hello3 value:World3 to Cache</span><br><span class="line">2019-06-06 14:25:14.768131+0800 TestDemo[3677:137719] Remove Object Hello World</span><br><span class="line">2019-06-06 14:25:14.768227+0800 TestDemo[3677:137719] Add key:Hello4 value:World4 to Cache</span><br><span class="line">2019-06-06 14:25:14.768333+0800 TestDemo[3677:137719] Remove Object World0</span><br><span class="line">2019-06-06 14:25:14.768415+0800 TestDemo[3677:137719] Add key:Hello5 value:World5 to Cache</span><br><span class="line">2019-06-06 14:25:14.768497+0800 TestDemo[3677:137719] Remove Object World1</span><br><span class="line">2019-06-06 14:25:14.768573+0800 TestDemo[3677:137719] Add key:Hello6 value:World6 to Cache</span><br><span class="line">2019-06-06 14:25:14.768641+0800 TestDemo[3677:137719] Remove Object World2</span><br><span class="line">2019-06-06 14:25:14.768704+0800 TestDemo[3677:137719] Add key:Hello7 value:World7 to Cache</span><br><span class="line">2019-06-06 14:25:14.768793+0800 TestDemo[3677:137719] Remove Object World3</span><br><span class="line">2019-06-06 14:25:14.768856+0800 TestDemo[3677:137719] Add key:Hello8 value:World8 to Cache</span><br><span class="line">2019-06-06 14:25:14.768941+0800 TestDemo[3677:137719] Remove Object World4</span><br><span class="line">2019-06-06 14:25:14.769004+0800 TestDemo[3677:137719] Add key:Hello9 value:World9 to Cache</span><br><span class="line">2019-06-06 14:25:14.769072+0800 TestDemo[3677:137719] Get value:(null) for key :Hello0</span><br><span class="line">2019-06-06 14:25:14.771311+0800 TestDemo[3677:137719] Get value:(null) for key :Hello1</span><br><span class="line">2019-06-06 14:25:14.771400+0800 TestDemo[3677:137719] Get value:(null) for key :Hello2</span><br><span class="line">2019-06-06 14:25:14.771474+0800 TestDemo[3677:137719] Get value:(null) for key :Hello3</span><br><span class="line">2019-06-06 14:25:14.771552+0800 TestDemo[3677:137719] Get value:(null) for key :Hello4</span><br><span class="line">2019-06-06 14:25:14.771650+0800 TestDemo[3677:137719] Get value:World5 for key :Hello5</span><br><span class="line">2019-06-06 14:25:14.771731+0800 TestDemo[3677:137719] Get value:World6 for key :Hello6</span><br><span class="line">2019-06-06 14:25:14.771817+0800 TestDemo[3677:137719] Get value:World7 for key :Hello7</span><br><span class="line">2019-06-06 14:25:14.771906+0800 TestDemo[3677:137719] Get value:World8 for key :Hello8</span><br><span class="line">2019-06-06 14:25:14.771982+0800 TestDemo[3677:137719] Get value:World9 for key :Hello9</span><br><span class="line">2019-06-06 14:25:14.772050+0800 TestDemo[3677:137719] Remove Object World6</span><br><span class="line">2019-06-06 14:25:14.772119+0800 TestDemo[3677:137719] Remove Object World7</span><br><span class="line">2019-06-06 14:25:14.772196+0800 TestDemo[3677:137719] Remove Object World8</span><br><span class="line">2019-06-06 14:25:14.772261+0800 TestDemo[3677:137719] Remove Object World9</span><br><span class="line">2019-06-06 14:25:14.772336+0800 TestDemo[3677:137719] Remove Object World5</span><br><span class="line">2019-06-06 14:25:14.772411+0800 TestDemo[3677:137719] Get value:(null) for key:World0</span><br><span class="line">2019-06-06 14:25:14.772491+0800 TestDemo[3677:137719] Get value:(null) for key:World1</span><br><span class="line">2019-06-06 14:25:14.772656+0800 TestDemo[3677:137719] Get value:(null) for key:World2</span><br><span class="line">2019-06-06 14:25:14.772858+0800 TestDemo[3677:137719] Get value:(null) for key:World3</span><br><span class="line">2019-06-06 14:25:14.773018+0800 TestDemo[3677:137719] Get value:(null) for key:World4</span><br><span class="line">2019-06-06 14:25:14.773193+0800 TestDemo[3677:137719] Get value:(null) for key:World5</span><br><span class="line">2019-06-06 14:25:14.773418+0800 TestDemo[3677:137719] Get value:(null) for key:World6</span><br><span class="line">2019-06-06 14:25:14.773570+0800 TestDemo[3677:137719] Get value:(null) for key:World7</span><br><span class="line">2019-06-06 14:25:14.773704+0800 TestDemo[3677:137719] Get value:(null) for key:World8</span><br><span class="line">2019-06-06 14:25:14.773846+0800 TestDemo[3677:137719] Get value:(null) for key:World9</span><br><span class="line">2019-06-06 14:25:14.773989+0800 TestDemo[3677:137719] Test Hello World</span><br></pre></td></tr></table></figure><ul><li><p>上面的代码创建了一个<code>NSCache</code>对象,设置了其最大可缓存对象的个数为5个,从输出可以看出,当我们要添加第六个对象时<code>NSCache</code>自动删除了我们添加的第一个对象并触发了<code>NSCacheDelegate</code>的回调方法,添加第七个时也是同样的,删除了缓存中的一个对象才能添加进去。</p></li><li><p>在第二个<code>for循环</code>中,我们通过<code>key</code>取出所有的缓存对象,前五个对象取出都为<code>nil</code>,因为在添加后面的对象时前面的被删除了,所以,当我们从缓存中获取对象时一定要判断是否为空,我们无法保证缓存中的某个对象不会被删除。</p></li><li><p>接着调用了<code>NSCache</code>的<code>removeAllObjects</code>方法,一旦调用该方法,<code>NSCache</code>就会将其中保存的所有对象都释放掉,所以,可以看到调用该方法后<code>NSCacheDelegate</code>的回调方法执行了五次,将<code>NSCache</code>中的所有缓存对象都清空了。</p></li><li><p>在最后一个<code>for循环</code>中,根据<code>key</code>获取缓存中的对象时可以发现都为空了,因为都被释放了。</p></li><li><p>!前面还创建了一个字符串的局部变量,在最开始将其加入到了缓存中,后来随着其他对象的添加,该字符串被缓存释放了,但由于局部变量对其持有强引用所以使用<code>test</code>还是可以访问到的,这是最基本的<code>ARC</code>知识,所以,<code>NSCache</code>在释放一个对象时只是不再指向这个对象,即,该对象的引用计数减一,如果有其他指针指向它,这个对象不会被释放。这也就是说cache中key持有对其他object对象的引用,所以不需要实现NSCopying协议。</p></li><li><p>上面就是<code>NSCache</code>的基本用法了,我们只需要设置对象和获取对象,其他事情<code>NSCache</code>都帮我们做完了,因此,实现缓存功能时,使用<code>NSCache</code>就是我们的不二之选。</p></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)viewWillAppear:(BOOL)animated</span><br><span class="line">{</span><br><span class="line"> self.cache = [[NSCache alloc] init];</span><br><span class="line"> [self.cache setCountLimit:<span class="number">5</span>];</span><br><span class="line"> self.cache.delegate = self;</span><br><span class="line"> [self.cache setObject:@<span class="string">"AA"</span> forKey:@<span class="string">"BBB"</span>];</span><br><span class="line"> [self.cache setObject:@<span class="string">"MMMM"</span> forKey:@<span class="string">"CCC"</span>];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)cache:(NSCache *)cache willEvictObject:(id)obj</span><br><span class="line">{</span><br><span class="line"> NSLog(@<span class="string">"REMOVE %@"</span>, obj);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>记住此时一定不要把代理像上一个类一样交给CacheTest来做,因为最后没有removeAllObject。</p><p>而delegate的属性是assign,容易造成野指针导致崩溃。</p><p><strong>点击Home键打印结果:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-06</span> <span class="number">14</span>:<span class="number">56</span>:<span class="number">40.166418</span>+<span class="number">0800</span> TestDemo[<span class="number">4151</span>:<span class="number">162111</span>] REMOVE MMMM</span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-06</span> <span class="number">14</span>:<span class="number">56</span>:<span class="number">40.166561</span>+<span class="number">0800</span> TestDemo[<span class="number">4151</span>:<span class="number">162111</span>] REMOVE AA</span><br></pre></td></tr></table></figure><p>当点击<code>home</code>键,程序进入后台后,可以发现<code>NSCacheDelegate</code>的回调函数触发了,所以,当程序进入后台,<code>NSCache</code>对象会自动释放所有的对象。如果在模拟器上模拟内存警告,也可以发现<code>NSCache</code>会释放所有的对象。所以<code>NSCache</code>删除缓存中的对象会在以下情形中发生。</p><ul><li>NSCache缓存对象自身被释放</li><li>手动调用removeObjectForKey:方法</li><li>手动调用removeAllObjects</li><li>缓存中对象的个数大于countLimit,或,缓存中对象的总cost值大于totalCostLimit</li><li>程序进入后台后</li><li>收到系统的内存警告</li></ul><p>转载自:<a href="https://www.jianshu.com/p/239226822bc6" target="_blank" rel="noopener">https://www.jianshu.com/p/239226822bc6</a></p>]]></content>
<summary type="html">
<h3 id="NSCache"><a href="#NSCache" class="headerlink" title="NSCache"></a>NSCache</h3><p>NSCache使用很方便,提供了类似可变字典的实现方式,但它比可变字典更适用于实现缓存。</p>
<ul>
<li>最重要的原因是<code>NSCache</code>是线程安全的,使用<code>NSMutableDictionary</code>自定义实现缓存的时候需要考虑加锁和释放锁,<code>NSCache</code>已经帮我们做好了这一步。</li>
<li>其次,内存不足时<code>NSCache</code>会自动释放存储的对象,不需要手动干预,如果是自定义实现需要监听内存状态然后做进一步删除对象的操作。</li>
<li>还有一点<code>NSCache</code>的键<code>key</code>不会被复制,所以<code>key</code>不需要实现<code>NSCopying</code>协议。</li>
</ul>
<p>以上三点就是<code>NSCache</code>相比于<code>NSMutableDictionary</code>实现缓存功能的优点,在需要实现缓存的时候应优先考虑使用<code>NSCache</code>。</p>
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
</entry>
<entry>
<title>iOS || 事件传递与响应者链中的hitTest方法和pointInside方法</title>
<link href="http://yoursite.com/2019/07/11/%E4%BA%8B%E4%BB%B6%E4%BC%A0%E9%80%92%E4%B8%8E%E5%93%8D%E5%BA%94%E8%80%85%E9%93%BE%E4%B8%AD%E7%9A%84hitTest%E6%96%B9%E6%B3%95%E5%92%8CpointInside%E6%96%B9%E6%B3%95/"/>
<id>http://yoursite.com/2019/07/11/事件传递与响应者链中的hitTest方法和pointInside方法/</id>
<published>2019-07-10T16:25:17.000Z</published>
<updated>2019-07-10T16:25:55.366Z</updated>
<content type="html"><![CDATA[<h3 id="主要概念"><a href="#主要概念" class="headerlink" title="主要概念"></a>主要概念</h3><h4 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h4><p>用户使用app的过程中,会产生各种各样的事件,iOS事件大体分为3种类型</p><ul><li>触摸事件</li><li>加速计事件</li><li>远程控制事件</li></ul><p>加速计事件可以用来做摇一摇等功能,而耳机控制音量大小等则属于远程控制事件。</p><a id="more"></a><h4 id="响应者对象"><a href="#响应者对象" class="headerlink" title="响应者对象"></a>响应者对象</h4><p>在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件。我们称之为“响应者对象”,例如UIApplication、UIViewController、UIView都继承自UIResponder,因此它们都是响应者度喜庆,都能接收并处理事件。</p><h5 id="UIResponder"><a href="#UIResponder" class="headerlink" title="UIResponder"></a>UIResponder</h5><p>触摸事件</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;</span><br><span class="line">- (<span class="keyword">void</span>)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;</span><br><span class="line">- (<span class="keyword">void</span>)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;</span><br><span class="line">- (<span class="keyword">void</span>)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;</span><br></pre></td></tr></table></figure><p>加速计事件</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;</span><br><span class="line">- (<span class="keyword">void</span>)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;</span><br><span class="line">- (<span class="keyword">void</span>)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;</span><br></pre></td></tr></table></figure><p>远程控制事件</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)remoteControlReceivedWithEvent:(UIEvent *)event;</span><br></pre></td></tr></table></figure><h5 id="UIView的触摸事件处理"><a href="#UIView的触摸事件处理" class="headerlink" title="UIView的触摸事件处理"></a>UIView的触摸事件处理</h5><p>UIView是UIResponder的子类,可以覆盖下列4个方法处理不同的触摸事件</p><ul><li>一根或者多根手指开始触摸view,系统会自动给调用view下面的方法</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event</span><br></pre></td></tr></table></figure><ul><li>一根或者多根手指在view上移动,系统会自动调用view的下面方法(随着手指的移动,会持续调用该方法)</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event</span><br></pre></td></tr></table></figure><ul><li>一根或者多根手指离开view,系统会自动调用view的下面方法</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event</span><br></pre></td></tr></table></figure><ul><li>触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程,系统会自动调用view的下面</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event</span><br></pre></td></tr></table></figure><p><strong>PS:</strong> touch中存放的都是 UITouch 对象。</p><h4 id="UITouch"><a href="#UITouch" class="headerlink" title="UITouch"></a>UITouch</h4><h5 id="UITouch-1"><a href="#UITouch-1" class="headerlink" title="UITouch"></a>UITouch</h5><ul><li>当用户用一根手指触摸屏幕时,会创建一个与手指相关联的UITouch对象</li><li>一根手指对应一个UITouch对象</li><li>UITouch作用:保存着跟手指相关的信息,比如触摸的位置、时间、阶段</li><li>当手指移动时,系统会更新同一个UITouch对象,使之能够一直保存该手指在的触摸位置。</li><li>当手指离开屏幕时,系统会销毁响应的UITouch对象</li></ul><h5 id="UITouch-重要属性"><a href="#UITouch-重要属性" class="headerlink" title="UITouch 重要属性"></a>UITouch 重要属性</h5><ul><li><p>触摸产生时所处的窗口</p><p><code>@property(nonatomic, readonly, retain) UIWindow *window;</code></p></li><li><p>触摸产生时所处的视图</p><p><code>@property(nonatomic, readonly, retain) UIView *view;</code></p></li><li><p>短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或者更多点击</p><p><code>@property(nonatomic, readonly) NSUInteger tapCount;</code></p></li><li><p>记录了触摸事件产生或变化时的时间,单位是秒</p><p><code>@property(nonatomic, readonly) NSTimeInterval timestamp;</code></p></li><li><p>当前触摸事件所处的状态</p><p><code>@property(nonatomic, readonly) UITouchPhase phase;</code></p></li></ul><h5 id="UITouch-重要方法"><a href="#UITouch-重要方法" class="headerlink" title="UITouch 重要方法"></a>UITouch 重要方法</h5><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">- (CGPoint)locationInView:(UIView *)view;</span><br><span class="line"><span class="comment">// 返回值表示触摸在view上的位置,这里返回的位置是针对view的坐标系的(以view的左上角为原点(0,0))</span></span><br><span class="line"><span class="comment">// 调用时传入的view参数为nil的话,返回的触摸点是在UIWindow的位置</span></span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">- (CGPoint)previousLocationInView:(UIView *)view;</span><br><span class="line"><span class="comment">// 该方法记录了前一个触摸点的位置</span></span><br></pre></td></tr></table></figure><h4 id="UIEvent"><a href="#UIEvent" class="headerlink" title="UIEvent"></a>UIEvent</h4><ul><li>每产生一个事件,就会产生一个UIEvent对象</li><li>UIEvent:称为事件对象,记录事件产生的时刻和类型</li></ul><h5 id="UIEvent-常见属性"><a href="#UIEvent-常见属性" class="headerlink" title="UIEvent 常见属性"></a>UIEvent 常见属性</h5><ul><li><p>事件类型</p><p><code>@property(nonatomic, readonly) UIEventType type;</code></p><p><code>@property(nonatomic, readonly) UIEventSubtype subtype;</code></p></li><li><p>事件产生的时间</p><p><code>@property(nonatomic, readonly) NSTimeInterval timestamp;</code></p></li><li><p>UIEvent 还提供了相应的方法可以获得在某个view上面的触摸对象(UITouch)一次完整的触摸过程,会经历三个状态:</p><p>触摸开始:- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event<br>触摸移动:- (void)touchesMoved:(NSSet )touches withEvent:(UIEvent )event<br>触摸结束:- (void)touchesEnded:(NSSet )touches withEvent:(UIEvent )event </p><p>触摸取消(<strong>可能会经历</strong>):- (void)touchesCancelled:(NSSet )touches withEvent:(UIEvent )event </p></li></ul><p>4个触摸事件处理方法中,都有NSSet *touches和UIEvent *event两个参数 </p><p>一次完整的触摸过程中,只会产生一个事件对象,4个触摸方法都是同一个event参数</p><ul><li><p>如果两根手指同时触摸一个view,那么view只会调用一次touchesBegan:withEvent:方法,touches参数中装着2个UITouch对象</p></li><li><p>如果这两根手指一前一后分开触摸同一个view,那么view会分别调用2次touchesBegan:withEvent:方法,并且每次调用时的touches参数中只包含一个UITouch对象</p></li></ul><p>根据touches中UITouch的个数可以判断出是单点触摸还是多点触摸</p><h3 id="事件传递"><a href="#事件传递" class="headerlink" title="事件传递"></a>事件传递</h3><ul><li>发生触摸事件后,系统会将该事件加入到一个由 UIApplication 管理的事件队列中。</li><li>UIApplication 会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)</li><li>主窗口会在视图层次结构中找到一个合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。</li><li>找到合适的视图控件后,就会调用视图控件的toucher方法来做具体的事件处理<ul><li>touchesBegin</li><li>touchesMoved</li><li>touchesEnded</li></ul></li></ul><h4 id="如何找到一个最合适的视图,如何判断"><a href="#如何找到一个最合适的视图,如何判断" class="headerlink" title="如何找到一个最合适的视图,如何判断"></a>如何找到一个最合适的视图,如何判断</h4><h5 id="hitTest"><a href="#hitTest" class="headerlink" title="hitTest"></a>hitTest</h5><p>其实系统就是通过 <code>-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent* )event</code>方法来寻找最合适view的。</p><p>该函数的内部实现:</p><ul><li>自己能否接收触摸事件(如果自己都不能接收那么子视图就不能接收处理事件)</li><li>触摸点是否在自己身上</li><li>从后往前遍历子控件,重复前面两个步骤</li><li>如果没有符合条件的子控件,那么就自己处理最合适</li></ul><p><img src="https://img-blog.csdnimg.cn/20190605154903358.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//作用:去寻找最适合的View</span></span><br><span class="line"><span class="comment">//什么时候调用:当一个事件传递给当前View,就会调用.</span></span><br><span class="line"><span class="comment">//返回值:返回的是谁,谁就是最适合的View(就会调用最适合的View的touch方法)</span></span><br><span class="line">-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{</span><br><span class="line"> NSLog(@<span class="string">"%s"</span>,__func__);</span><br><span class="line"> <span class="keyword">return</span> [super hitTest:point withEvent:event];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h5 id="PointInside"><a href="#PointInside" class="headerlink" title="PointInside"></a>PointInside</h5><p>系统通过<code>-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event</code>方法来判断触摸点是否在自己身上。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 作用:判断当前点在不在它调用View,(谁调用pointInside,这个View就是谁)</span></span><br><span class="line"><span class="comment"> * 什么时候调用:它是在hitTest方法当中调用的.</span></span><br><span class="line"><span class="comment"> * 注意:point点必须得要跟它方法调用者在同一个坐标系里面</span></span><br><span class="line"><span class="comment"> * @param point <#point description#></span></span><br><span class="line"><span class="comment"> * @param event <#event description#></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @return <#return value description#></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{</span><br><span class="line"><span class="comment">// NSLog(@"%s",__func__);</span></span><br><span class="line"><span class="comment">// return [super pointInside:point withEvent:event];</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// </span></span><br><span class="line"><span class="comment">// //如果返回NO就代表,当前点不在红色view(self)上面,那么当我们确实点击红色view,红色view也不会响应事件。</span></span><br><span class="line"><span class="comment">// return NO;</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//如果返回YES就代表,当前点在红色view(self)上面,那么即使我们没有点击红色view,红色view也会响应事件。</span></span><br><span class="line"> <span class="keyword">return</span> YES;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="响应者链"><a href="#响应者链" class="headerlink" title="响应者链"></a>响应者链</h3><h4 id="响应者链-1"><a href="#响应者链-1" class="headerlink" title="响应者链"></a>响应者链</h4><p>响应者链条:是由多个响应者对象连接起来的链条,响应者链刚好与事件的传递相反,两者形成一个环。</p><p>作用:能很清楚地看见每个响应者之间的联系,并且可以让一个事件多个对象处理。</p><p>响应者对象:能处理事件的对象。</p><ul><li><ol><li>找到最适合的响应视图后事件会从此视图开始沿着响应链nextResponder传递,直到找到处理事件的视图,如果没有处理的事件会被丢弃。 </li></ol></li><li><ol start="2"><li>如果找到了能处理该事件的视图,则返回该视图停止传递。</li></ol></li><li><ol start="3"><li>如果当前这个view是控制器的view,那么控制器就是上一个响应者;如果当前这个view不是控制器的view,那么父控件就是上一个响应者。</li></ol></li><li><ol start="4"><li>如果view的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给它的父视图<br>在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理。</li></ol></li><li><ol start="5"><li>如果window对象也不处理,则其将事件或消息传递给UIApplication对象,如果UIApplication也不能处理该事件或消息,则将其丢弃。</li></ol></li></ul>]]></content>
<summary type="html">
<h3 id="主要概念"><a href="#主要概念" class="headerlink" title="主要概念"></a>主要概念</h3><h4 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h4><p>用户使用app的过程中,会产生各种各样的事件,iOS事件大体分为3种类型</p>
<ul>
<li>触摸事件</li>
<li>加速计事件</li>
<li>远程控制事件</li>
</ul>
<p>加速计事件可以用来做摇一摇等功能,而耳机控制音量大小等则属于远程控制事件。</p>
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
</entry>
<entry>
<title>iOS || Grand Central Dispatch (GCD)</title>
<link href="http://yoursite.com/2019/07/11/Dispatch/"/>
<id>http://yoursite.com/2019/07/11/Dispatch/</id>
<published>2019-07-10T16:19:38.000Z</published>
<updated>2019-07-10T16:33:08.487Z</updated>
<content type="html"><![CDATA[<h3 id="进程和线程:"><a href="#进程和线程:" class="headerlink" title="进程和线程:"></a>进程和线程:</h3><p>进程是一个正在运行的应用程序,一个应用程序可以对应一个或多个进程。应用程序是一个没有生命的实体,只有运行之后,才能成为一个活动的实体,也就是进程。</p><p><strong>进程是操作系统分配资源的基本单元</strong>。进程在运行的过程中拥有独立的内存单元,一个进程崩溃后,不会对其他进程造成影响。</p><p><strong>线程是独立运行和独立调度的基本单位</strong>,线程才是程序真正的执行单元,负责代码的执行。一个进程可以有一个或多个线程,同一个进程的线程共享进程的内存资源。线程没有单独的地址空间,一个线程崩溃整个进程就会崩溃。</p><h3 id="多线程:"><a href="#多线程:" class="headerlink" title="多线程:"></a>多线程:</h3><p>事实上,同一时间内单核CPU只能执行一个线程,多线程是CPU快速的在多个线程之间进行切换(调度),造成了多个线程同时执行的假象。如果是多核CPU就可以同时处理多个线程了。多线程是为了同步完成多项任务,提高系统的资源利用率来提高系统效率。</p><p>但是多线程也会造成各种问题,比如多个线程更新相同的资源会导致数据不一致(数据竞争),停止等待事件的线程会导致多个线程相互持续等待(死锁)、使用太多线程会消耗大量内存等。</p><h3 id="多线程优缺点:"><a href="#多线程优缺点:" class="headerlink" title="多线程优缺点:"></a>多线程优缺点:</h3><p>多线程可以提高系统资源利用率,从而提高系统的效率。</p><p>缺点是开启多线程要花费时间和空间,开启过多的线程反而会降低性能,cpu频繁地在多个线程中调度会消耗大量的CPU资源,把CPU累死。</p><h3 id="多线程使用场景:"><a href="#多线程使用场景:" class="headerlink" title="多线程使用场景:"></a>多线程使用场景:</h3><p>实际开发中将一些耗时的操作放在子线程中执行,ios中默认有一个主线程,用来响应用户的手势和刷新UI,如果在主线程执行耗时操作会把页面卡死,直到执行完了这个操作才能操作界面。一定要在主线程刷新UI的原因:iOS为了保证效率,多线程是线程不安全的,在子线程刷新UI可能导致未知错误。</p><h3 id="iOS中多线程的方案,各自特点:"><a href="#iOS中多线程的方案,各自特点:" class="headerlink" title="iOS中多线程的方案,各自特点:"></a>iOS中多线程的方案,各自特点:</h3><p>Pthread是用c语言实现的,底层的多线程实现方案,需要程序员手动管理线程的生命周期(手动创建和销毁)。</p><p><strong>NSThread</strong> 面向对象,需要程序员手动创建线程,但不需要手动销毁。子线程间通信很难。</p><p>Cocoa框架提供了NSObject类的<strong>performSelectorInBackground</strong>:withObject 实例方法和 <strong>performSelectorOnMainThread</strong> 实例方法。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>) launchThreadByNSObject_performSelectorInBackground_withObject</span><br><span class="line">{</span><br><span class="line"> [self performSelectorInBackground:@selector(doWork) withObject:nil];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)doWork</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// ....</span></span><br><span class="line"> <span class="comment">// 做一些耗时操作,比如网络请求,数据库访问等。</span></span><br><span class="line"> [self performSelectorOnMainThread:@selector(doneWork) withObject:nil waitUntilDone:NO];</span><br><span class="line"> </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">-(<span class="keyword">void</span>)doneWork</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// 刷新主界面</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>GCD</strong>是异步执行任务的技术之一。一般将程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。由于线程管理是系统的一部分来实现的,因此可同意管理,也可执行任务,这样就比以前的线程更有效率。</p><p>使用GCD实现上述功能更为简洁。充分利用了设备的多核,自动管理线程生命周期,更为高效。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> 长时间处理,比如网络请求,数据库访问等。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> dispatch_async(dispatch_get_main_queue(), ^{</span><br><span class="line"> <span class="comment">/*界面刷新等只在主线程执行的处理*/</span></span><br><span class="line"> });</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h3 id="GCD的API"><a href="#GCD的API" class="headerlink" title="GCD的API"></a>GCD的API</h3><h4 id="Dispatch-Queue"><a href="#Dispatch-Queue" class="headerlink" title="Dispatch Queue"></a>Dispatch Queue</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 想要执行的任务</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>Dispatch Queue 就是执行处理的等待队列,程序员在Block语法内记述想执行的处理并将其追加到Dispatch Queue中。Dispatch Queue 按照追加的顺序(先进先出FIFO) 执行处理。</p><p>另外在执行处理时存在两种Dispatch Queue,一种是等待现在执行中处理的 Serial Dispatch Queue,它只使用一个线程;另一种是不等待现在执行中处理的 Concurrent Dispatch Queue,它使用多个线程并行执行多个追加处理。</p><p>以下是两种队列的测试结果:</p><ul><li><strong>Serial</strong>:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_queue_create(<span class="string">"hahaha"</span>, DISPATCH_QUEUE_SERIAL);</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"1"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"2"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"3"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"4"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"5"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"6"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"7"</span>);</span><br><span class="line"> });</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">31</span>:<span class="number">53.990446</span>+<span class="number">0800</span> Test[<span class="number">6938</span>:<span class="number">245001</span>] <span class="number">1</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">31</span>:<span class="number">53.990629</span>+<span class="number">0800</span> Test[<span class="number">6938</span>:<span class="number">245001</span>] <span class="number">2</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">31</span>:<span class="number">53.990718</span>+<span class="number">0800</span> Test[<span class="number">6938</span>:<span class="number">245001</span>] <span class="number">3</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">31</span>:<span class="number">53.990780</span>+<span class="number">0800</span> Test[<span class="number">6938</span>:<span class="number">245001</span>] <span class="number">4</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">31</span>:<span class="number">53.990856</span>+<span class="number">0800</span> Test[<span class="number">6938</span>:<span class="number">245001</span>] <span class="number">5</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">31</span>:<span class="number">53.990936</span>+<span class="number">0800</span> Test[<span class="number">6938</span>:<span class="number">245001</span>] <span class="number">6</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">31</span>:<span class="number">53.991013</span>+<span class="number">0800</span> Test[<span class="number">6938</span>:<span class="number">245001</span>] <span class="number">7</span></span><br></pre></td></tr></table></figure><ul><li><strong>Concurrent</strong>:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_queue_create(<span class="string">"hahaha"</span>, DISPATCH_QUEUE_CONCURRENT);</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"1"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"2"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"3"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"4"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"5"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"6"</span>);</span><br><span class="line"> });</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"7"</span>);</span><br><span class="line"> });</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">30</span>:<span class="number">34.914632</span>+<span class="number">0800</span> Test[<span class="number">6904</span>:<span class="number">243733</span>] <span class="number">3</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">30</span>:<span class="number">34.914632</span>+<span class="number">0800</span> Test[<span class="number">6904</span>:<span class="number">243732</span>] <span class="number">1</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">30</span>:<span class="number">34.914633</span>+<span class="number">0800</span> Test[<span class="number">6904</span>:<span class="number">243702</span>] <span class="number">2</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">30</span>:<span class="number">34.914649</span>+<span class="number">0800</span> Test[<span class="number">6904</span>:<span class="number">243734</span>] <span class="number">4</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">30</span>:<span class="number">34.914686</span>+<span class="number">0800</span> Test[<span class="number">6904</span>:<span class="number">243738</span>] <span class="number">5</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">20</span>:<span class="number">30</span>:<span class="number">34.914722</span>+<span class="number">0800</span> Test[<span class="number">6904</span>:<span class="number">243739</span>] <span class="number">6</span></span><br></pre></td></tr></table></figure><h4 id><a href="#" class="headerlink" title=" "></a> </h4><h4 id="系统标准提供的Dispatch-Queue"><a href="#系统标准提供的Dispatch-Queue" class="headerlink" title="系统标准提供的Dispatch Queue"></a>系统标准提供的Dispatch Queue</h4><p>分别是<code>Main Dispatch Queue</code> 和 <code>Global Dispatch Queue</code></p><p><code>Main Dispatch Queue</code> 是在主线程中执行的Dispatch Queue,主线程只有一个,所以它自然也是Serial Dispatch Queue。</p><p>另一个是<code>Global Dispatch Queue</code>,它是所有应用程序都能使用的Concurrent Dispatch Queue。</p><p><code>Global Dispatch Queue</code>有四个执行优先级,分别是高优先级(High Priority)、默认优先级(Default Priority)、低优先级(Low Priority)和后台优先级(Background Priority)。</p><h4 id="dispatch-set-target-queue"><a href="#dispatch-set-target-queue" class="headerlink" title="dispatch_set_target_queue"></a>dispatch_set_target_queue</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_queue_create(<span class="string">"Test"</span>, <span class="literal">NULL</span>);</span><br><span class="line"> <span class="keyword">dispatch_queue_t</span> globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, <span class="number">0</span>);</span><br><span class="line"> dispatch_set_target_queue(<span class="built_in">queue</span>, globalQueue);</span><br></pre></td></tr></table></figure><p><code>dispatch_set_target_queue</code> 可以变更处理的优先级。不仅如此,还可以作成Dispatch Queue 的执行阶层。如果在多个 Serial Dispatch Queue 中用dispatch_set_target_queue 函数指定目标为某一个 Serial Dispatch Queue,那么原本应并行执行的多个Serial Dispatch Queue,在目标Serial Dispatch Queue上只能同时执行一个处理。</p><p>在必须将不可并行执行的处理追加到多个 Serial Dispatch Queue 中时,如果使用dispatch_set_target_queue 函数将目标指定为某一个 Serial Dispatch Queue,即可防止处理并行执行。</p><h4 id="dispatch-after"><a href="#dispatch-after" class="headerlink" title="dispatch_after"></a>dispatch_after</h4><p>想在几秒后执行操作,可通过dispatch_after 函数来实现。</p><p>在3秒后将指定的 Block 追加到 <code>Main Dispatch Queue</code>中源码如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_time_t</span> time = dispatch_time(DISPATCH_TIME_NOW, <span class="number">3u</span>ll * NSEC_PER_SEC);</span><br><span class="line"></span><br><span class="line">dispatch_after(time, dispatch_get_main_queue(), ^{</span><br><span class="line"> NSLog(@<span class="string">"Wait at least three seconds."</span>);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p><strong>PS</strong>: dispatch_after函数并不是在指定的时间后执行处理,而是在指定时间追加处理到Dispatch Queue。</p><h4 id="Dispatch-Group"><a href="#Dispatch-Group" class="headerlink" title="Dispatch Group"></a>Dispatch Group</h4><p>在追加到 <code>Dispatch Queue</code> 中的多个处理全部结束后想执行结束处理,这种情况会经常出现。</p><p>只使用一个Serial Dispatch Queue 时,只要将想执行的处理全部追加到该Serial Dispatch Queue 中并在最后追加结束处理,即可实现。但是在使用Concurrent Dispatch Queue时或同时使用多个Dispatch Queue时,源代码就会变得复杂。</p><p>这是可以使用Dispatch Group。如下所示:追加3个Block到Global Dispatch Queue,这些Block如果全部执行完毕,就会执行Main Dispatch Queue 中结束处理用的Block。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">dispatch_group_t</span> group = dispatch_group_create();</span><br><span class="line"></span><br><span class="line">dispatch_group_async(group, <span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"1"</span>);</span><br><span class="line">});</span><br><span class="line">dispatch_group_async(group, <span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"2"</span>);</span><br><span class="line">});</span><br><span class="line">dispatch_group_async(group, <span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"3"</span>);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">dispatch_group_notify(group, dispatch_get_main_queue(), ^{</span><br><span class="line"> self.Label.text = @<span class="string">"完成"</span>;</span><br><span class="line"> NSLog(@<span class="string">"hahaha"</span>);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p><strong>运行结果:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">28</span>:<span class="number">10.728780</span>+<span class="number">0800</span> Test[<span class="number">7538</span>:<span class="number">275043</span>] <span class="number">3</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">28</span>:<span class="number">10.728780</span>+<span class="number">0800</span> Test[<span class="number">7538</span>:<span class="number">275044</span>] <span class="number">1</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">28</span>:<span class="number">10.728780</span>+<span class="number">0800</span> Test[<span class="number">7538</span>:<span class="number">275041</span>] <span class="number">2</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">28</span>:<span class="number">10.738775</span>+<span class="number">0800</span> Test[<span class="number">7538</span>:<span class="number">274962</span>] hahaha</span><br></pre></td></tr></table></figure><h4 id="dispatch-barrier-async"><a href="#dispatch-barrier-async" class="headerlink" title="dispatch_barrier_async"></a>dispatch_barrier_async</h4><p>访问数据库或文件时,使用Serial Dispatch Queue 可避免数据竞争问题。</p><p>写入处理确实不可与其他的写入处理以及包含读取处理的其他某些处理并行执行。但是如果读取处理只是与读取处理并行执行,那么多个并行执行就不会发生问题。</p><p>也就是说,为了高效率地进行访问,读取处理追加到 Concurrent Dispatch Queue 中,写入处理在任一个读取处理没有执行的状态下,追加到 Serial Dispatch Queue 中即可 (在写入处理结束之前,读取处理不可执行)。</p><p>利用Dispatch Group 和 dispatch_set_target_queue 函数可实现,但是源代码会很复杂。</p><p>我们可使用 dispatch_barrier_async 函数同 dispatch_queue_create 函数生成的 Concurrent Dispatch Queue 一起使用。</p><p>比如说如下代码可等待123read并行执行完之后,再执行write操作,然后此时只执行唯一的write操作,等write操作执行完后,再执行4567read操作。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_queue_create(<span class="string">"Test"</span>, DISPATCH_QUEUE_CONCURRENT);</span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"1read %@"</span>, [NSThread currentThread]);</span><br><span class="line">});</span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"2read %@"</span>, [NSThread currentThread]);</span><br><span class="line">});</span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"3read %@"</span>, [NSThread currentThread]);</span><br><span class="line">});</span><br><span class="line">dispatch_barrier_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"write %@"</span>, [NSThread currentThread]);</span><br><span class="line">});</span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"4read %@"</span>, [NSThread currentThread]);</span><br><span class="line">});</span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"5read %@"</span>, [NSThread currentThread]);</span><br><span class="line">});</span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"6read %@"</span>, [NSThread currentThread]);</span><br><span class="line">});</span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"7read %@"</span>, [NSThread currentThread]);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p><strong>执行结果:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">54</span>:<span class="number">05.186307</span>+<span class="number">0800</span> Test[<span class="number">7809</span>:<span class="number">288931</span>] <span class="number">1</span>read <NSThread: <span class="number">0x600002378180</span>></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">54</span>:<span class="number">05.186309</span>+<span class="number">0800</span> Test[<span class="number">7809</span>:<span class="number">288934</span>] <span class="number">2</span>read <NSThread: <span class="number">0x600002378140</span>></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">54</span>:<span class="number">05.186320</span>+<span class="number">0800</span> Test[<span class="number">7809</span>:<span class="number">288935</span>] <span class="number">3</span>read <NSThread: <span class="number">0x600002374900</span>></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">54</span>:<span class="number">05.186454</span>+<span class="number">0800</span> Test[<span class="number">7809</span>:<span class="number">288935</span>] write <NSThread: <span class="number">0x600002374900</span>></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">54</span>:<span class="number">05.186538</span>+<span class="number">0800</span> Test[<span class="number">7809</span>:<span class="number">288935</span>] <span class="number">4</span>read <NSThread: <span class="number">0x600002374900</span>></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">54</span>:<span class="number">05.186551</span>+<span class="number">0800</span> Test[<span class="number">7809</span>:<span class="number">288934</span>] <span class="number">5</span>read <NSThread: <span class="number">0x600002378140</span>></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">54</span>:<span class="number">05.186553</span>+<span class="number">0800</span> Test[<span class="number">7809</span>:<span class="number">288931</span>] <span class="number">6</span>read <NSThread: <span class="number">0x600002378180</span>></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">21</span>:<span class="number">54</span>:<span class="number">05.186569</span>+<span class="number">0800</span> Test[<span class="number">7809</span>:<span class="number">288933</span>] <span class="number">7</span>read <NSThread: <span class="number">0x600002374940</span>></span><br></pre></td></tr></table></figure><h4 id="dispatch-sync"><a href="#dispatch-sync" class="headerlink" title="dispatch_sync"></a>dispatch_sync</h4><p>意味着同步,也就是将指定的Block同步追加到 Dispatch Queue 中。在追加的 Block 结束之前,dispatch_sync 函数会一直等待。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</span><br><span class="line">dispatch_sync(<span class="built_in">queue</span>, ^{</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 执行处理</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>一旦调用 dispatch_sync 函数,那么在指定的处理执行结束之前,该函数不会返回。dispatch_sync 函数可简化为源代码,也可以说是简化版的dispatch_group_wait函数。</p><p>但 dispatch_sync 函数也很容易引起死锁。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_get_main_queue();</span><br><span class="line">dispatch_sync(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"hahaha"</span>);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>比如在主线程中执行指定的Block并等待其执行结束。而其实在主线程中正在执行这些源代码,所以无法追加到主线程中同步执行Block。也就是说假设主线程是TaskA,加入的线程是TaskB,因为是同步的,所以TaskA没有执行完的话,TaskB不会执行,而TaskA执行完必然意味着TaskB也要执行完成。所以发生了死锁。</p><p>同样在Serial Dispatch Queue 中也会引起相同的问题</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_queue_create(<span class="string">"hahaha"</span>, <span class="literal">NULL</span>);</span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> dispatch_sync(<span class="built_in">queue</span>, ^{</span><br><span class="line"> NSLog(@<span class="string">"haha"</span>);</span><br><span class="line"> });</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h4 id="dispatch-apply"><a href="#dispatch-apply" class="headerlink" title="dispatch_apply"></a>dispatch_apply</h4><p>dispatch_apply 是 dispatch_sync 函数和 Dispatch Group 的关联 API。该函数按指定的次数将指定的Block 追加到指定的 Dispatch Queue 中,并等待全部处理执行结束。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</span><br><span class="line">dispatch_apply(<span class="number">5</span>, <span class="built_in">queue</span>, ^(<span class="keyword">size_t</span> index) {</span><br><span class="line"> NSLog(@<span class="string">"%zu"</span>, index);</span><br><span class="line">});</span><br><span class="line">NSLog(@<span class="string">"done"</span>);</span><br></pre></td></tr></table></figure><p><strong>结果如下:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">31</span>:<span class="number">20.492494</span>+<span class="number">0800</span> Test[<span class="number">8500</span>:<span class="number">325942</span>] <span class="number">0</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">31</span>:<span class="number">20.492496</span>+<span class="number">0800</span> Test[<span class="number">8500</span>:<span class="number">326017</span>] <span class="number">2</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">31</span>:<span class="number">20.492494</span>+<span class="number">0800</span> Test[<span class="number">8500</span>:<span class="number">326018</span>] <span class="number">1</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">31</span>:<span class="number">20.492495</span>+<span class="number">0800</span> Test[<span class="number">8500</span>:<span class="number">326019</span>] <span class="number">4</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">31</span>:<span class="number">20.492499</span>+<span class="number">0800</span> Test[<span class="number">8500</span>:<span class="number">326023</span>] <span class="number">3</span></span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">31</span>:<span class="number">20.492637</span>+<span class="number">0800</span> Test[<span class="number">8500</span>:<span class="number">325942</span>] done</span><br></pre></td></tr></table></figure><p>因为在Global Dispatch Queue 中执行处理,所以各个处理的执行时间不定。但是输出结果中的done必定在最后的位置上。这是因为dispatch_apply 函数会等待全部处理执行结束。</p><h4 id="dispatch-suspend-dispatch-resume"><a href="#dispatch-suspend-dispatch-resume" class="headerlink" title="dispatch_suspend / dispatch_resume"></a>dispatch_suspend / dispatch_resume</h4><p>当追加大量处理到 Dispatch Queue 时,在追加处理的过程中,有时希望不执行已追加的处理。例如演算结果被Block截获时,一些处理会对这个演算结果造成影响。</p><p>这种情况下,只要挂起指定的 Dispatch Queue。当可以执行时再恢复。</p><p>dispatch_suspend 挂起和 dispatch_resume 恢复。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_queue_create(<span class="string">"com.test.gcd"</span>, DISPATCH_QUEUE_SERIAL);</span><br><span class="line"><span class="comment">//提交第一个block,延时5秒打印。</span></span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> sleep(<span class="number">5</span>);</span><br><span class="line"> NSLog(@<span class="string">"After 5 seconds..."</span>);</span><br><span class="line">});</span><br><span class="line"><span class="comment">//提交第二个block,也是延时5秒打印</span></span><br><span class="line">dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> sleep(<span class="number">5</span>);</span><br><span class="line"> NSLog(@<span class="string">"After 5 seconds again..."</span>);</span><br><span class="line">});</span><br><span class="line"><span class="comment">//延时一秒</span></span><br><span class="line">NSLog(@<span class="string">"sleep 1 second..."</span>);</span><br><span class="line">sleep(<span class="number">1</span>);</span><br><span class="line"><span class="comment">//挂起队列</span></span><br><span class="line">NSLog(@<span class="string">"suspend..."</span>);</span><br><span class="line">dispatch_suspend(<span class="built_in">queue</span>);</span><br><span class="line"><span class="comment">//延时10秒</span></span><br><span class="line">NSLog(@<span class="string">"sleep 10 second..."</span>);</span><br><span class="line">sleep(<span class="number">10</span>);</span><br><span class="line"><span class="comment">//恢复队列</span></span><br><span class="line">NSLog(@<span class="string">"resume..."</span>);</span><br><span class="line">dispatch_resume(<span class="built_in">queue</span>);</span><br></pre></td></tr></table></figure><p>打印结果:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">44</span>:<span class="number">01.254454</span>+<span class="number">0800</span> Test[<span class="number">8617</span>:<span class="number">332248</span>] sleep <span class="number">1</span> second...</span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">44</span>:<span class="number">02.255484</span>+<span class="number">0800</span> Test[<span class="number">8617</span>:<span class="number">332248</span>] suspend...</span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">44</span>:<span class="number">02.255662</span>+<span class="number">0800</span> Test[<span class="number">8617</span>:<span class="number">332248</span>] sleep <span class="number">10</span> second...</span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">44</span>:<span class="number">06.257416</span>+<span class="number">0800</span> Test[<span class="number">8617</span>:<span class="number">332298</span>] After <span class="number">5</span> seconds...</span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">44</span>:<span class="number">12.256036</span>+<span class="number">0800</span> Test[<span class="number">8617</span>:<span class="number">332248</span>] resume...</span><br><span class="line"><span class="number">2019</span><span class="number">-06</span><span class="number">-03</span> <span class="number">23</span>:<span class="number">44</span>:<span class="number">17.257411</span>+<span class="number">0800</span> Test[<span class="number">8617</span>:<span class="number">332297</span>] After <span class="number">5</span> seconds again...</span><br></pre></td></tr></table></figure><p>可以看出dispatch_suspend并不会立即暂停正在运行的block,而是在当前block执行完成后,暂停后续的block执行。</p><h4 id="Dispatch-Semaphore"><a href="#Dispatch-Semaphore" class="headerlink" title="Dispatch Semaphore"></a>Dispatch Semaphore</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dispatch_queue_t</span> <span class="built_in">queue</span> = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">dispatch_semaphore_t</span> semaphore = dispatch_semaphore_create(<span class="number">1</span>);</span><br><span class="line">NSMutableArray *<span class="built_in">array</span> = [[NSMutableArray alloc] init];</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">100</span>; i++)</span><br><span class="line">{</span><br><span class="line"> dispatch_async(<span class="built_in">queue</span>, ^{</span><br><span class="line"> dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);</span><br><span class="line"> <span class="comment">// 执行到此处semaphore的值恒为0</span></span><br><span class="line"> [<span class="built_in">array</span> addObject: [NSNumber numberWithInt:i]];</span><br><span class="line"> <span class="comment">// 排他控制结束</span></span><br><span class="line"> <span class="comment">// 通过dispatch_semaphore_signal 函数将semaphore计数值加1</span></span><br><span class="line"> <span class="comment">// 由最先通过wait函数等待semaphore计数值加一的线程继续执行。</span></span><br><span class="line"> dispatch_semaphore_signal(semaphore);</span><br><span class="line"> });</span><br><span class="line">}</span><br><span class="line">NSLog(@<span class="string">"完成"</span>);</span><br></pre></td></tr></table></figure><p>·<code>dispatch_semaphore_wait</code>函数会一直等待直到semaphore信号量值变为1,由于semaphore的计数值大于等于1,所以可以将其计数值减去1,wait函数执行返回。所以才有上面注释的恒为0的意思。</p><h4 id="dispatch-once"><a href="#dispatch-once" class="headerlink" title="dispatch_once"></a>dispatch_once</h4><p>保证在应用程序中只执行一次指定处理的API。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">dispatch_once_t</span> pred;</span><br><span class="line">dispatch_once (&pred, ^{</span><br><span class="line"> <span class="comment">/* </span></span><br><span class="line"><span class="comment"> * 初始化</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>这就是我们常说的单例模式。</p><h4 id="Dispatch-I-O"><a href="#Dispatch-I-O" class="headerlink" title="Dispatch I/O"></a>Dispatch I/O</h4><p>读取大文件时,如果将文件分成合适大小并使用 Global Dispatch Queue 并列读取的话,会增加读取速度。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">dispatch_async(queeu, ^{<span class="comment">/* 读取 0 ~ 8191 字节 */</span>});</span><br><span class="line">dispatch_async(queeu, ^{<span class="comment">/* 读取 8192 ~ 16383 字节 */</span>});</span><br><span class="line">dispatch_async(queeu, ^{<span class="comment">/* 读取 16384 ~ 24575 字节 */</span>});</span><br><span class="line">dispatch_async(queeu, ^{<span class="comment">/* 读取 24576 ~ 32767 字节 */</span>});</span><br><span class="line">dispatch_async(queeu, ^{<span class="comment">/* 读取 32769 ~ 40959 字节 */</span>});</span><br><span class="line">dispatch_async(queeu, ^{<span class="comment">/* 读取 40960 ~ 49151 字节 */</span>});</span><br><span class="line">dispatch_async(queeu, ^{<span class="comment">/* 读取 49152 ~ 57343 字节 */</span>});</span><br><span class="line">dispatch_async(queeu, ^{<span class="comment">/* 读取 57344 ~ 65535 字节 */</span>});</span><br></pre></td></tr></table></figure><p>可像上面这样,将文件分割为一块一块地进行读取处理。分割读取的数据通过使用Dispatch Data 可更为简单地进行结合和分割。</p><p>代码解读可参考:<a href="https://www.jianshu.com/p/da4710d76d33" target="_blank" rel="noopener">https://www.jianshu.com/p/da4710d76d33</a></p>]]></content>
<summary type="html">
<h3 id="进程和线程:"><a href="#进程和线程:" class="headerlink" title="进程和线程:"></a>进程和线程:</h3><p>进程是一个正在运行的应用程序,一个应用程序可以对应一个或多个进程。应用程序是一个没有生命的实体,只有运行之后
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
</entry>
<entry>
<title>iOS || Blocks</title>
<link href="http://yoursite.com/2019/07/11/iOS-Blocks/"/>
<id>http://yoursite.com/2019/07/11/iOS-Blocks/</id>
<published>2019-07-10T16:18:24.000Z</published>
<updated>2019-07-10T16:32:56.636Z</updated>
<content type="html"><![CDATA[<h3 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h3><p>Blocks时c语言的扩充功能,就是带有自动变量(局部变量)的匿名函数</p><h3 id="模式"><a href="#模式" class="headerlink" title="模式"></a>模式</h3><h4 id="语法:"><a href="#语法:" class="headerlink" title="语法:"></a>语法:</h4><p><code>^ 返回值类型 参数列表 表达式</code></p><p>例如:<code>^int (int count) {return count + 1;}</code></p><p>可省略返回值类型,Block语法将按照return语句的类型返回int型返回值</p><p><code>^(int count) {return count + 1;}</code></p><p>如果不使用参数,参数列表也可省略</p><p><code>^{printf("Blocks\n");}</code></p><a id="more"></a><h4 id="Block类型变量"><a href="#Block类型变量" class="headerlink" title="Block类型变量"></a>Block类型变量</h4><p><code>int (^block) (int) = ^(int count) {return count + 1;}</code></p><p><code>block(10)</code>进行调用</p><p>也可以typedef定义类型:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">int</span> <span class="params">(^<span class="keyword">block_t</span>)</span> <span class="params">(<span class="keyword">int</span>)</span></span>;</span><br><span class="line"><span class="keyword">block_t</span> block = ^(<span class="keyword">int</span> count) {<span class="keyword">return</span> count + <span class="number">1</span>;}</span><br><span class="line">block(<span class="number">10</span>);</span><br></pre></td></tr></table></figure><h4 id="Block截获自动变量值"><a href="#Block截获自动变量值" class="headerlink" title="Block截获自动变量值"></a>Block截获自动变量值</h4><p>也就时block中的带有自动变量。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> val = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">char</span> *fmt = <span class="string">"val = %d\n"</span>;</span><br><span class="line"><span class="keyword">void</span> (^blk)(<span class="keyword">void</span>) = ^{<span class="built_in">printf</span>(fmt, val);};</span><br><span class="line">fmt = <span class="string">"the value has changed %d"</span>;</span><br><span class="line">val = <span class="number">11</span>;</span><br><span class="line">blk();</span><br></pre></td></tr></table></figure><p>在上述代码中,Block语法的表达式使用的是它之前声明的自动变量fmt和val。Block中,Block表达式截获所使用的自动变量的值,即保存该自动变量的瞬间值。因为Block表达式保存了自动变量的值,所以在执行Block语法后,即使改写了Block中使用的自动变量的值也不会影响Block执行时自动变量的值。</p><p>打印出来后结果为<code>val = 10</code></p><p>这就是Block的截获。</p><h4 id="Block说明符"><a href="#Block说明符" class="headerlink" title="Block说明符"></a>Block说明符</h4><p>我们尝试改写截获的自动变量的值。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> val = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">void</span> (^blk)(<span class="keyword">void</span>) = ^{val = <span class="number">1</span>};</span><br><span class="line">blk();</span><br><span class="line">NSLog(@<span class="string">"%d"</span>, val);</span><br></pre></td></tr></table></figure><p>此时会报错,要想在block语法中将值赋给Block语法外的自动变量,需在自动变量前加个__block说明符。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">__block <span class="keyword">int</span> val = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">void</span> (^blk)(<span class="keyword">void</span>) = ^{val = <span class="number">1</span>;};</span><br><span class="line">blk();</span><br><span class="line">NSLog(@<span class="string">"%d"</span>, val);</span><br></pre></td></tr></table></figure><p>打印结果:<code>val = 1</code></p><h4 id="截获的自动变量:"><a href="#截获的自动变量:" class="headerlink" title="截获的自动变量:"></a>截获的自动变量:</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">NSMutableArray *a = [@[@<span class="number">1</span>, @<span class="number">2</span>, @<span class="number">3</span>] mutableCopy];</span><br><span class="line"><span class="keyword">void</span> (^blk)(<span class="keyword">void</span>) = ^{[a addObject:@<span class="number">4</span>];};</span><br><span class="line">blk();</span><br><span class="line">NSLog(@<span class="string">"%@"</span>, a);</span><br></pre></td></tr></table></figure><p>以上代码可以正确执行,该代码中截获的变量是NSMutableArray类的对象。如果用c语言描述,即是截获NSMutableArray类对象用的结构体实例指针。如果使用截获的值的话没有问题,但是不能对这个变量进行赋值,比如以下代码会报错,要想成功运行的话要给自动变量a前加__block。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">NSMutableArray *a = [@[@<span class="number">1</span>, @<span class="number">2</span>, @<span class="number">3</span>] mutableCopy];</span><br><span class="line"><span class="keyword">void</span> (^blk)(<span class="keyword">void</span>) = ^{NSArray *f = @[@<span class="number">1</span>]; a = f;};</span><br><span class="line">blk();</span><br><span class="line">NSLog(@<span class="string">"%@"</span>, a);</span><br></pre></td></tr></table></figure><h3 id="Blocks的实现"><a href="#Blocks的实现" class="headerlink" title="Blocks的实现"></a>Blocks的实现</h3><h4 id="Blocks的实质"><a href="#Blocks的实质" class="headerlink" title="Blocks的实质"></a>Blocks的实质</h4><p>Blocks的实质是objc的对象,转为c的本质就是一个类的对象结构体实例,结构体具有isa指针和blocks中引用的自动变量,作为结构体的成员变量,isa指针指向存储类信息的class_t结构体(存储着类的属性,成员变量,方法名称,方法实现(即函数指针))。</p><p>所以在截获变量时截获的自动变量存到block结构体实例中去了,之后再改变自动变量然后再调用blocks函数并不会使结果发生改变。</p><p>而之所以不能改变自动变量的值是因为blocks结构体中仅使用自动变量的值然后赋给结构体实例中的成员变量但是并不能改变它。所以改变时就会报错。</p><p><code>__block int val = 0;</code></p><p>那么__block的实现则比较复杂,它相当于为block声明符声明的变量另创建一个结构体,在结构体中将含有isa,flags,结构体size等信息外,还存有一个自身类型的指针forwarding成员变量指向自身,存有一个声明的val成员变量。</p><table><thead><tr><th align="center">名称</th><th align="center">实质</th></tr></thead><tbody><tr><td align="center">Block</td><td align="center">栈上Block的结构体实例</td></tr><tr><td align="center">__block</td><td align="center">栈上__block的结构体实例</td></tr></tbody></table><h4 id="Blocks的存储域"><a href="#Blocks的存储域" class="headerlink" title="Blocks的存储域"></a>Blocks的存储域</h4><h5 id="Block结构体存储位置:"><a href="#Block结构体存储位置:" class="headerlink" title="Block结构体存储位置:"></a>Block结构体存储位置:</h5><ul><li>记述全局变量的地方有Block语法</li><li>Block 语法的表达式中不使用应截获的自动变量</li></ul><p>以上两种情况将Block存于数据区,其他情况存于栈区。而何时将Block配置在堆上呢?看如下情况</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">int</span> <span class="params">(^<span class="keyword">blk_t</span>)</span><span class="params">(<span class="keyword">int</span>)</span></span>;</span><br><span class="line"><span class="keyword">blk_t</span> func(<span class="keyword">int</span> rate)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> ^(<span class="keyword">int</span> count){<span class="keyword">return</span> rate * count;};</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>像以下情况下Block也是作为返回值返给b的,所以也会被复制到堆上并被b所持有。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span>(^b)(<span class="keyword">void</span>) = ^{NSLog(@<span class="string">"hahaha"</span>);};</span><br></pre></td></tr></table></figure><p>该源代码返回配置在栈上的Block函数。即程序执行中从该函数返回函数调用方时变量作用域结束,因此栈上的Block也被废弃。但实际处理时会:(将Block作为函数值返回时,编译器会自动生成复制到堆上的代码)</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">blk_t</span> tmp = Block栈上的结构体实例</span><br><span class="line">tmp = _Block_copy(tmp);</span><br><span class="line"><span class="comment">// copy函数将栈上的Block复制到堆上。</span></span><br><span class="line"><span class="comment">// 复制后将堆上的地址作为指针赋值给变量tmp;</span></span><br><span class="line"><span class="keyword">return</span> objc_autoreleaseReturnValue(tmp);</span><br><span class="line"><span class="comment">// 将堆上的Block作为Objective-c对象</span></span><br><span class="line"><span class="comment">// 注册到autoreleasepool中,然后返回该对象</span></span><br></pre></td></tr></table></figure><p>大多数情况编译器会适当进行判断自动生成复制到堆上的代码,但有些情况需要使用<strong>copy实例方法</strong>手动生成代码。什么情况呢?</p><ul><li>向函数或者方法的参数中传递Block时。</li></ul><p>但是如果在方法或是函数中适当地复制了传递过来的参数,那么就不用在调用该方法或函数前手动复制了。以下方法或函数不用手动复制:</p><ul><li>Cocoa 框架的方法且方法名中含有usingBlock等。例如NSArry类的enumerateObjectUsingBlock实例方法</li><li>GCD的API。比如dispatch_async函数。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> id obj = [self getBlockArray];</span><br><span class="line"> <span class="function"><span class="keyword">typedef</span> <span class="title">void</span> <span class="params">(^<span class="keyword">blk_t</span>)</span> <span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> <span class="keyword">blk_t</span> blk = (<span class="keyword">blk_t</span>)[obj objectAtIndex:<span class="number">0</span>];</span><br><span class="line"> blk();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (id) getBlockArray</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">int</span> val = <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">return</span> [[NSArray alloc] initWithObjects:^{NSLog(@<span class="string">"blk0: %d"</span>, val);}, ^{NSLog(@<span class="string">"blk1: %d"</span>, val);}, nil];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>以上情况下使用会报错。因为getBlockArray函数执行结束后,栈上的Block会被废弃。可惜此时编译器无法判断是否需要复制,此时我们只能进行手动复制。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> id obj = [self getBlockArray];</span><br><span class="line"> <span class="function"><span class="keyword">typedef</span> <span class="title">void</span> <span class="params">(^<span class="keyword">blk_t</span>)</span> <span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> <span class="keyword">blk_t</span> blk = (<span class="keyword">blk_t</span>)[obj objectAtIndex:<span class="number">0</span>];</span><br><span class="line"> blk();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (id) getBlockArray</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">int</span> val = <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">return</span> [[NSArray alloc] initWithObjects:[^{NSLog(@<span class="string">"blk0: %d"</span>, val);} copy], [^{NSLog(@<span class="string">"blk1: %d"</span>, val);} copy], nil];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>此时按照预想的结果成功运行并打印出结果。</p><p>但是如果我们对已经存在于堆上的Block进行copy,代码如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> id obj = [self getBlockArray];</span><br><span class="line"> <span class="function"><span class="keyword">typedef</span> <span class="title">void</span> <span class="params">(^<span class="keyword">blk_t</span>)</span> <span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> <span class="keyword">blk_t</span> blk = (<span class="keyword">blk_t</span>)[obj objectAtIndex:<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">blk_t</span> c = [blk copy];</span><br><span class="line"> NSLog(@<span class="string">"%p"</span>, blk);</span><br><span class="line"> NSLog(@<span class="string">"%p"</span>, c);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (id) getBlockArray</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">int</span> val = <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">return</span> [[NSArray alloc] initWithObjects:[^{NSLog(@<span class="string">"blk0: %d"</span>, val);} copy], [^{NSLog(@<span class="string">"blk1: %d"</span>, val);} copy], nil];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>结果是并不会在进行一次深拷贝,只是浅拷贝,引用计数加一。</p><p><strong>总结一下何时栈上的Block会复制到堆上:</strong></p><ul><li>调用Block的copy实例方法。</li><li>Block作为函数返回值返回时。</li><li>将Block赋值给附有<code>__strong</code>修饰符id类型的类或者Block类型的成员变量时(编译器更新后赋值给block类型也会复制到栈上)。</li><li>方法名中含有usingBlock的Cocoa框架方法或GCD的API传递Block时。</li></ul><h5 id="block变量存储域"><a href="#block变量存储域" class="headerlink" title="__block变量存储域"></a>__block变量存储域</h5><p>使用<code>__block</code>变量的Block从栈复制到堆上时,<code>__block</code>变量存储域也会受影响。</p><table><thead><tr><th align="center">__block变量的配置存储域</th><th align="center">Block从栈复制到堆上的影响</th></tr></thead><tbody><tr><td align="center">栈</td><td align="center">从栈复制到堆上并被Block持有</td></tr><tr><td align="center">堆</td><td align="center">被Block持有</td></tr></tbody></table><ol><li><p>若在一个Block中使用<code>__block</code>变量,则当该Block从栈复制到堆时,使用的所有<code>__block</code>变量也必定配置在栈上。这些<code>__block</code>变量也全被从栈上复制到堆。此时,Block持有<code>__block</code>变量。即使在该Block已复制到堆的情形下,复制Block也对所使用的<code>__block</code>变量没有任何影响。</p></li><li><p>在多个Block中使用<code>__block</code>变量时,因为最先会将所有的Block配置在栈上,所以<code>__block</code>变量也会配置在栈上。在任何一个Block从栈复制到堆时,<code>__block</code>变量也会一并从栈复制到堆并被该Block所持有。当剩下的Block从栈复制到堆上时,被复制的Block持有<code>__block</code>变量,并增加<code>__block</code>变量的引用计数。</p></li></ol><p>下面再谈一下<code>__block</code>变量用结构体成员变量<code>__forwarding</code>的原因。此时,不管<code>__block</code>变量配置在堆上还是栈上,都能够正确地访问该变量。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">__block <span class="keyword">int</span> val = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">void</span> (^blk) (<span class="keyword">void</span>) = [^{NSLog(@<span class="string">"val = %d"</span>, val); val++;} copy];</span><br><span class="line">val++;</span><br><span class="line">blk();</span><br><span class="line">NSLog(@<span class="string">"val = %d"</span>,val);</span><br></pre></td></tr></table></figure><p><strong>结果打印出来分别为2,3。</strong></p><p>以下两种val++的源代码都可以转为如下形式:</p><p><code>++(val.__forwarding->val);</code></p><p>在Block从栈复制到堆上时,<code>__forwarding</code>指针原本指向自身,复制完后指向复制在堆上的<code>__block</code>变量。</p><p>所以通过该指针功能,无论在Block语法中、Block语法外使用<code>__block</code>变量,还是<code>__block</code>变量配置在栈上或是堆上,都可以顺利访问到同一个<code>__block</code>变量。</p><p>同时也刚好验证了之前说的使用<code>__block</code>变量的话会使得Block持有该变量的结构体,所以截获的也就不是定义Block前的值了,而是调用Block前的值。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"> [super viewDidLoad];</span><br><span class="line"><span class="keyword">int</span> val = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">void</span> (^blk) (<span class="keyword">void</span>) = ^{NSLog(@<span class="string">"val = %d"</span>, val);};</span><br><span class="line">val++;</span><br><span class="line">blk();</span><br><span class="line">NSLog(@<span class="string">"val = %d"</span>,val);</span><br></pre></td></tr></table></figure><p><strong>这个的结构就是1,2。</strong></p><h4 id="截获对象"><a href="#截获对象" class="headerlink" title="截获对象"></a>截获对象</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">block blk;</span><br><span class="line">{</span><br><span class="line"> id <span class="built_in">array</span> = [[NSMutableArray alloc] init];</span><br><span class="line"> blk = ^(id obj) {</span><br><span class="line"> [<span class="built_in">array</span> addObject:obj];</span><br><span class="line"> NSLog(@<span class="string">"array count = %ld"</span>, [<span class="built_in">array</span> count]);</span><br><span class="line"> };</span><br><span class="line">}</span><br><span class="line">blk([[NSObject alloc] init]);</span><br><span class="line">blk([[NSObject alloc] init]);</span><br><span class="line">blk([[NSObject alloc] init]);</span><br></pre></td></tr></table></figure><p>array已经超出其作用域,变量array应该被废弃,其强引用失效,因此赋值给变量array的NSMutableArray类的对象并定应该被释放并废弃。但该源代码运行正常,结果如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">array</span> count = <span class="number">1</span></span><br><span class="line"><span class="built_in">array</span> count = <span class="number">2</span></span><br><span class="line"><span class="built_in">array</span> count = <span class="number">3</span></span><br></pre></td></tr></table></figure><p>这就意味着赋值给变量array的NSMutableArray类的对象在Block的执行部分超出其变量作用域而存在</p><p>原因是在Block用的结构体中赋有了<code>__strong</code>修饰符的成员变量array。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> __<span class="title">main_block_impl_0</span> {</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> __<span class="title">block_impl</span> <span class="title">impl</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> __<span class="title">main_block_desc_0</span> *<span class="title">Desc</span>;</span></span><br><span class="line"> id __strong <span class="built_in">array</span>;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>虽然c语言结构体内不能附有<code>__strong</code>修饰符的变量。因为编译器不知道何时进行c语言结构体的初始化和废弃操作,不能很好地管理内存。</p><p>但是OC运行时库能够准确地把握Block从栈复制到堆以及堆上的Block被废弃的时机,因此Block用结构体中即使含有附有<code>__strong</code>修饰符或<code>__weak</code>修饰符的变量,也可以恰当进行初始化和废弃,为此需要增加<strong>copy</strong>(retain)和<strong>dispose</strong>(release)函数来给Block中的成员变量array赋值。</p><h4 id="避免循环引用:"><a href="#避免循环引用:" class="headerlink" title="避免循环引用:"></a>避免循环引用:</h4><p>即对象持有Block,Block又持有对象(self)。</p><p>除了<code>__weak</code>外,可使用<code>__block</code>修饰符避免循环引用,将<code>__block</code>修饰的变量指向self,然后在Block中用完self后将<code>__block</code>变量置为nil,但是必须要执行Block函数,不然仍会引起循环引用。</p><p><strong>PS</strong>:之前遇到的一个概念混淆,再提一点属性和成员变量的区别:</p><p>属性 = ivar(成员变量)+getter+setter(存取方法)</p>]]></content>
<summary type="html">
<h3 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h3><p>Blocks时c语言的扩充功能,就是带有自动变量(局部变量)的匿名函数</p>
<h3 id="模式"><a href="#模式" class="headerlink" title="模式"></a>模式</h3><h4 id="语法:"><a href="#语法:" class="headerlink" title="语法:"></a>语法:</h4><p><code>^ 返回值类型 参数列表 表达式</code></p>
<p>例如:<code>^int (int count) {return count + 1;}</code></p>
<p>可省略返回值类型,Block语法将按照return语句的类型返回int型返回值</p>
<p><code>^(int count) {return count + 1;}</code></p>
<p>如果不使用参数,参数列表也可省略</p>
<p><code>^{printf(&quot;Blocks\n&quot;);}</code></p>
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
</entry>
<entry>
<title>iOS多线程和网络</title>
<link href="http://yoursite.com/2019/07/11/iOS%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%92%8C%E7%BD%91%E7%BB%9C/"/>
<id>http://yoursite.com/2019/07/11/iOS多线程和网络/</id>
<published>2019-07-10T16:15:56.000Z</published>
<updated>2019-07-10T16:17:29.401Z</updated>
<content type="html"><![CDATA[<h4 id="提供的功能"><a href="#提供的功能" class="headerlink" title="提供的功能"></a>提供的功能</h4><ul><li>通过URL将数据下载到内存</li><li>通过URL将数据下载到文件系统</li><li>将数据上传到指定的URL</li><li>在后台完成上述操作(支持后台网络操作,除非用户强行关闭应用程序)</li></ul><a id="more"></a><p><strong>NSURLConnection和NSURLSession的关系示意图</strong></p><p><img src="https://img-blog.csdnimg.cn/20190602005847740.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>NSURLSession中的请求都看做一个请求任务(task)。</p><p><strong>NSURLSession的Task继承关系如下:</strong><br><img src="https://img-blog.csdnimg.cn/20190602005852734.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><ul><li>NSURLSessionTask 是一个抽象类,提供了一些基本的方法</li><li>NSURLSessionDataTask 是一个具体的 task 类,可以获取数据</li><li>NSURLSessionDownloadTask 是一个具体的 task 类,可以下载数据</li><li>NSURLSessionUploadTask 是一个具体的 task 类,可以上传数据</li><li>NSURLSessionStreamTasj 是一个具体的 task 类,以流的方式请求数据,使用较少</li></ul><p>每一个类都有对应的协议。</p><h3 id="代码体现"><a href="#代码体现" class="headerlink" title="代码体现"></a>代码体现</h3><h4 id="基本使用"><a href="#基本使用" class="headerlink" title="基本使用"></a>基本使用</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)sesssion { </span><br><span class="line"> <span class="comment">// 1. url </span></span><br><span class="line"> NSURL *url = [NSURL URLWithString:@<span class="string">"http://127.0.0.1/demo.json"</span>]; </span><br><span class="line"> <span class="comment">// 2. 如果使用 GET 请求,request 可以省略 </span></span><br><span class="line"> <span class="comment">// session - 苹果为了方便程序员的开发,提供了一个全局的 session 单例 (我们是直接获取的,不需要创建) </span></span><br><span class="line"> NSURLSession *session = [NSURLSession sharedSession]; </span><br><span class="line"> <span class="comment">// 3. 数据任务 - 所有的任务,都是由session 发起的 </span></span><br><span class="line"> NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { </span><br><span class="line"> <span class="comment">// 4.将得到数据进行返序列化 </span></span><br><span class="line"> NSLog(@<span class="string">"%@"</span>, [NSJSONSerialization JSONObjectWithData:data options:<span class="number">0</span> error:<span class="literal">NULL</span>]); }]; </span><br><span class="line"> <span class="comment">// 5. 启动任务(一定要启动任务) </span></span><br><span class="line"> [task resume];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>注意以上发起的DataTask任务中:</strong></p><p><code>- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;</code></p><ul><li>该方法中会自动将 url 转换为一个请求对象(NSURLRequest),并且该请求对象是 GET 请求方式</li><li>回调方法是在子线程中运行的,所以如果在回调方法中刷新 UI 必须回到主线程中</li><li>回调方法中有两个参数 response / error,这两个参数和 该消息的接受者(即 NSURLSessionDataTask 对象)中的 response / error 是指同一个内容,即地址相同</li><li>使用该方法的缺点是不能监听获取数据的进度,因为只有当全部请求完数据后,才会调用这个方法,也就是说,data 中的数据是请求的全部数据.</li></ul><p><code>// @param request 请求对象</code></p><p><code>- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;</code></p><p><strong>withRequest方法可以手动设置请求对象,这样就可以指定GET/POST中的任何一种方法了。而withURL方法只能使用GET方法。</strong></p><p>在第三方框架对于 NSURLSession 的基本的封装思路就是这样,给一个 url ,后直接启动就可以了。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)sesssionDemo { </span><br><span class="line"> <span class="comment">// 1. url </span></span><br><span class="line"> NSURL *url = [NSURL URLWithString:@<span class="string">"http://127.0.0.1/demo.json"</span>]; </span><br><span class="line"> <span class="comment">// 2. 启动会话 </span></span><br><span class="line"> [self taskWithURL:url];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)taskWithURL:(NSURL *)url { </span><br><span class="line"> <span class="comment">// 1. 全局会话发起数据任务 - 所有的任务,都是由session 发起的 </span></span><br><span class="line"> [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { </span><br><span class="line"> NSLog(@<span class="string">"%@"</span>, [NSJSONSerialization JSONObjectWithData:data options:<span class="number">0</span> error:<span class="literal">NULL</span>]); }] resume];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>但是使用单例类的缺点就是不能实时监控获取数据的情况。因为以上两种方法中只有当请求完全部的数据后才会调用回调方法,如果想要实时获取并监控请求进度,就要设置代理方法。</p><h4 id="NSURLSession下载进度跟进"><a href="#NSURLSession下载进度跟进" class="headerlink" title="NSURLSession下载进度跟进"></a>NSURLSession下载进度跟进</h4><p>下载进度的跟进是通过代理实现的。</p><p>需要跟踪进度,就需要使用代理,代理是一对一的关系,我就要使用一个自定义的会话。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@property(strong, nonatomic)NSURLSession *session;</span><br></pre></td></tr></table></figure><ul><li><p>注意delegate Queue如果是传代理方法在子线程中运行时,则UI的刷新要注意在主线程进行。</p></li><li><p>而主队列是<code>[NSOperationQueue mainQueue]</code></p></li><li><p>如何选择队列: 网络访问结束后,如果不需要做复杂的操作,可以指定主队列,这样不用考虑线程间通讯。</p></li><li><p>由于下载本身是异步的,不会阻塞主线程工作。</p></li><li><p>在主线程中代理的话,所有的代理回调,都是在主线程异步的,不会阻塞主线程执行!(主线程异步并不会开辟新的线程, 只是把队列任务放到异步执行, 等待主队列中的当前任务都完成, 主线程空闲的时候, 再来执行需要执行的任务)。</p></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// @param configuration 配置信息对象</span></span><br><span class="line"><span class="comment">// @param delegate 代理对象</span></span><br><span class="line"><span class="comment">// @param queue 代理方法在哪个线程中运行,如果传 nil 则会在子线程中运行代理方法</span></span><br><span class="line">+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)<span class="built_in">queue</span>;</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)sessionDownload { </span><br><span class="line"><span class="comment">// 1. url </span></span><br><span class="line">NSURL *url = [NSURL URLWithString:@<span class="string">"http://127.0.0.1/123.mp4"</span>]; </span><br><span class="line"><span class="comment">// 2. 下载 </span></span><br><span class="line"><span class="comment">// 进度跟进:代理,苹果的头文件中,代理都是定义在后面的 </span></span><br><span class="line"><span class="comment">// 注意:如果要跟进下载进度,不能使用全局会话 </span></span><br><span class="line"><span class="comment">// 这个方法是和下面那个方法是矛盾的,使用了这个方法下面那个必须实现的代理方法是不能使用的 </span></span><br><span class="line"><span class="comment">// </span></span><br><span class="line">[[self.session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { </span><br><span class="line"> <span class="comment">// </span></span><br><span class="line"> <span class="comment">// 这个是一个完成的输出 </span></span><br><span class="line"> <span class="comment">// </span></span><br><span class="line"> NSLog(@<span class="string">"%@ %@"</span>, location.path, [NSThread currentThread]); </span><br><span class="line"> <span class="comment">// </span></span><br><span class="line">}] resume];</span><br></pre></td></tr></table></figure><p>要想使用下面的代理方法的话:直接使用如下方法下载数据。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 直接启动任务,可以通过代理跟踪进度 </span></span><br><span class="line">[[self.session downloadTaskWithURL:url] resume];}</span><br></pre></td></tr></table></figure><p>以下是必须实现的协议方法,表示下载完成了</p><ul><li>location表示文件存储的路径</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>以下是断点续传,可以什么都不写,这个是用来实现下载跟进的</p><p>在恢复下载的时候可以调用该方法:</p><ul><li>fileOffset表示从什么地方开始下载</li><li>expectedTotalBytes表示文件的总大小。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(<span class="keyword">int64_t</span>)fileOffset expectedTotalBytes:(<span class="keyword">int64_t</span>)expectedTotalBytes{</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>以下方法是用来进行下载跟进的 ,下载进度的跟进存在的问题,存在一个峰值的问题。</p><ul><li><p>downloadTask 表示下载任务</p></li><li><p>bytesWritten 表示本次写入的数据大小</p></li><li><p>totalBytesWritten 下载的数据总大小</p></li><li><p>totalBytesExpectedToWrite 文件的总大小</p></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(<span class="keyword">int64_t</span>)bytesWritten totalBytesWritten:(<span class="keyword">int64_t</span>)totalBytesWritten totalBytesExpectedToWrite:(<span class="keyword">int64_t</span>)totalBytesExpectedToWrite{ <span class="comment">// 下载的进度 </span></span><br><span class="line"> <span class="keyword">float</span> progress = (<span class="keyword">float</span>)totalBytesWritten / totalBytesExpectedToWrite; </span><br><span class="line"> <span class="comment">// 打印下载的进度 </span></span><br><span class="line"> NSLog(@<span class="string">"progress = %f"</span>,progress);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="NSURLSession的断点续传问题"><a href="#NSURLSession的断点续传问题" class="headerlink" title="NSURLSession的断点续传问题"></a>NSURLSession的断点续传问题</h4><p>断点续传主要考虑的是将会话暂停继续还是将任务进行暂停继续。</p><p>NSURLSession 提供的断点续传存在的问题,不能”停”,应用程序不能终止,一旦终止,续传数据就丢失了,下次还需要重头再来!</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">@property (nonatomic, strong) NSURLSession *session;<span class="comment">/// 下载任务</span></span><br><span class="line"></span><br><span class="line">@property (nonatomic, strong) NSURLSessionDownloadTask *task;<span class="comment">/// 续传数据</span></span><br></pre></td></tr></table></figure><ul><li>启动下载任务</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">- (IBAction)start {</span><br><span class="line"><span class="comment">// 1. url </span></span><br><span class="line"> NSURL *url = [NSURL URLWithString:@<span class="string">"http://dldir1.qq.com/qqfile/QQforMac/QQ_V4.0.2.dmg"</span>];</span><br><span class="line"> <span class="comment">// 发起下载会话 </span></span><br><span class="line">self.task = [self.session downloadTaskWithURL:url]; </span><br><span class="line"> <span class="comment">// 启动任务</span></span><br><span class="line">[self.task resume]; </span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>暂停下载任务</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/// 暂停 - 下载任务</span></span><br><span class="line">- (IBAction)pause { </span><br><span class="line"> NSLog(@<span class="string">"暂停"</span>); </span><br><span class="line"> <span class="comment">// 使用需要续传的数据,暂停下载任务 </span></span><br><span class="line"> <span class="comment">// 暂停方法,只需要执行一次,被暂停就不用再次暂停 </span></span><br><span class="line"> <span class="comment">/** 1. 所有的任务都是由会话发起的 </span></span><br><span class="line"><span class="comment"> 2. 当任务启动后,会话会对任务进行强引用 </span></span><br><span class="line"><span class="comment"> 3. 一旦任务被取消,意味着会话不再引用任务,一个 weak 对象没有其他对象强引用,会被立即释放 </span></span><br><span class="line"><span class="comment"> 4. 如果属性 是 strong,除了会话之外,vc同样对任务强引用(session 为什么要使用强引用) </span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"> <span class="comment">// 这个是取消下载任务 (达到暂停的目的) </span></span><br><span class="line"> [self.task cancelByProducingResumeData:^(NSData *resumeData) { </span><br><span class="line"> NSLog(@<span class="string">"---> %tu"</span>, resumeData); </span><br><span class="line"> <span class="comment">// 记录续传数据 </span></span><br><span class="line"> self.resumeData = resumeData; </span><br><span class="line"> <span class="comment">// 将暂停时候的数据保存起来(如果不保存下次启动的时候是没有数据的) </span></span><br><span class="line"> <span class="comment">// 释放了下载任务 </span></span><br><span class="line"> self.task = nil; </span><br><span class="line"> <span class="comment">// 将下载任务释放避免多次暂停的问题 </span></span><br><span class="line"> }];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>继续下载任务</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">- (IBAction)resume { </span><br><span class="line"> <span class="comment">// 需要避免下载任务重复创建 </span></span><br><span class="line"> <span class="keyword">if</span> (self.resumeData == nil) { </span><br><span class="line"> NSLog(@<span class="string">"没有续传数据"</span>); </span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line"> } </span><br><span class="line"> <span class="comment">// 使用续传数据,重新实例化下载任务 </span></span><br><span class="line"> <span class="comment">// 一旦续传的下载任务被建立之后,续传数据就没有用了! </span></span><br><span class="line"> self.task = [self.session downloadTaskWithResumeData:self.resumeData]; self.resumeData = nil; </span><br><span class="line"> [self.task resume];</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h4 id="提供的功能"><a href="#提供的功能" class="headerlink" title="提供的功能"></a>提供的功能</h4><ul>
<li>通过URL将数据下载到内存</li>
<li>通过URL将数据下载到文件系统</li>
<li>将数据上传到指定的URL</li>
<li>在后台完成上述操作(支持后台网络操作,除非用户强行关闭应用程序)</li>
</ul>
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
</entry>
<entry>
<title>iOS-autoreleasePool的实现</title>
<link href="http://yoursite.com/2019/07/11/iOS-autoreleasePool%E7%9A%84%E5%AE%9E%E7%8E%B0/"/>
<id>http://yoursite.com/2019/07/11/iOS-autoreleasePool的实现/</id>
<published>2019-07-10T16:14:23.000Z</published>
<updated>2019-07-10T16:14:58.017Z</updated>
<content type="html"><![CDATA[<ul><li>每一个线程的autorelease就是一个指针的堆栈。</li><li>每一个指针代表一个要release的对象或者是POOL_SENTINEL(哨兵对象,代表一个autorelease的边界,释放一个autorelease pool需要将哨兵对象后的所有release节点对象释放)。</li><li>每一个pool token代表的就是这个pool所对应的POOL_SENTINEL的结点的内存位置,当这个pool被pop后,这个token后的所有的结点对应的对象内存都会被释放。</li></ul><a id="more"></a><ul><li>autoreleasePool的实现是通过AutoreleasePage结点实现的()</li><li>这个堆栈被划分成了一个以page为结点的双向链表。pages会在必要的时候动态增加或者删除</li><li>Thread_local storage(线程局部存储)指向hot page,即最新添加的autoreleased对象所在的那个page。</li></ul><p><strong>AutoreleasePoolPage内存结构如下所示:</strong></p><p><img src="https://img-blog.csdnimg.cn/20190531153033843.png" alt="在这里插入图片描述"></p><ol><li><p>magic 用来校验 AutoreleasePoolPage 的结构是否完整;</p></li><li><p>next 指向最新添加的 autoreleased 对象的下一个位置,初始化时指向 begin() ;</p></li><li><p>thread 指向当前线程;</p></li><li><p>parent 指向父结点,第一个结点的 parent 值为 nil ;</p></li><li><p>child 指向子结点,最后一个结点的 child 值为 nil ;</p></li><li><p>depth 代表深度,从 0 开始,往后递增 1;</p></li><li><p>hiwat 代表 high water mark 。</p></li><li><p>当 next == begin() 时,表示 AutoreleasePoolPage 为空;当 next == end() 时,表示 AutoreleasePoolPage 已满。此时再创建一个AutoreleasePoolPage结点。</p></li></ol><p>pool通过 <strong>push</strong> 和 <strong>pop</strong> 操作来添加autoreleasepool和移除autoreleasepool:</p><ul><li>push操作实际就是前next指针添加一个哨兵,然后再往哨兵的next后添加这个pool要release的对象。</li><li>pop操作会将内存地址在 pool token 之后的所有 autoreleased 对象都会被 release 。直到 pool token 所在 page 的 next 指向 pool token 为止。</li></ul><p><img src="https://img-blog.csdnimg.cn/20190531153041580.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>此时,如果执行 pop(token1) 操作,那么该 autoreleasepool 堆栈的内存结构将会变成如下图所示:</p><p><img src="https://img-blog.csdnimg.cn/20190531153049554.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>转载自:<a href="http://www.cocoachina.com/ios/20150610/12093.html" target="_blank" rel="noopener">http://www.cocoachina.com/ios/20150610/12093.html</a></p>]]></content>
<summary type="html">
<ul>
<li>每一个线程的autorelease就是一个指针的堆栈。</li>
<li>每一个指针代表一个要release的对象或者是POOL_SENTINEL(哨兵对象,代表一个autorelease的边界,释放一个autorelease pool需要将哨兵对象后的所有release节点对象释放)。</li>
<li>每一个pool token代表的就是这个pool所对应的POOL_SENTINEL的结点的内存位置,当这个pool被pop后,这个token后的所有的结点对应的对象内存都会被释放。</li>
</ul>
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
</entry>
<entry>
<title>iOS || 内存管理(MRC和ARC的区别以及实现)</title>
<link href="http://yoursite.com/2019/07/11/iOS-%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86-MRC%E5%92%8CARC%E7%9A%84%E5%8C%BA%E5%88%AB%E4%BB%A5%E5%8F%8A%E5%AE%9E%E7%8E%B0/"/>
<id>http://yoursite.com/2019/07/11/iOS-内存管理-MRC和ARC的区别以及实现/</id>
<published>2019-07-10T16:07:14.000Z</published>
<updated>2019-07-10T16:10:53.375Z</updated>
<content type="html"><![CDATA[<p>自动引用计数(ARC)是指内存管理中对引用采取自动计数的技术。</p><p>使用ARC,就无需再次键入retain或者release代码,这降低了程序崩溃,内存泄漏等风险的同时,很大程度上减少了开发程序的工作量。ARC技术使得编译器清楚目标对象,并能立刻释放那些不再被使用的对象。如此一来,应用程序将具有可预测性,且能流畅运行,速度也将大幅提升。</p><a id="more"></a><h2 id="MRC"><a href="#MRC" class="headerlink" title="MRC"></a>MRC</h2><p>人工引用计数(Manual Reference Counting)</p><h3 id="内存管理的思考方式:"><a href="#内存管理的思考方式:" class="headerlink" title="内存管理的思考方式:"></a>内存管理的思考方式:</h3><ul><li>自己生成的对象,自己持有</li><li>非自己生成的对象,自己也能持有</li><li>不需要自己持有的对象时释放</li><li>无法释放非自己持有的对象</li></ul><table><thead><tr><th align="center">对象操作</th><th align="center">oc方法</th></tr></thead><tbody><tr><td align="center">生成并持有对象</td><td align="center">alloc/new/copy/mutableCopy 等方法</td></tr><tr><td align="center">持有对象</td><td align="center">retain 方法</td></tr><tr><td align="center">释放对象</td><td align="center">release 方法</td></tr><tr><td align="center">废弃对象</td><td align="center">dealloc 方法</td></tr></tbody></table><h5 id="自己生成的对象,自己持有"><a href="#自己生成的对象,自己持有" class="headerlink" title="自己生成的对象,自己持有"></a>自己生成的对象,自己持有</h5><ul><li>alloc</li><li>new</li><li>copy</li><li>mutablecopy</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">id obj = [[NSObject alloc] init];</span><br><span class="line">id obj = [NSObject <span class="keyword">new</span>];</span><br><span class="line"><span class="comment">// 两者完全一致,生成并持有对象</span></span><br></pre></td></tr></table></figure><p>// NSCopying和NSMutableCopying</p><h5 id="非自己生成的对象,自己也能持有"><a href="#非自己生成的对象,自己也能持有" class="headerlink" title="非自己生成的对象,自己也能持有"></a>非自己生成的对象,自己也能持有</h5><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">id obj = [NSMutableArray <span class="built_in">array</span>];</span><br><span class="line"><span class="comment">// 取得的对象存在,但自己不持有</span></span><br><span class="line">[obj retain];</span><br><span class="line"><span class="comment">// 自己持有对象</span></span><br></pre></td></tr></table></figure><h5 id="不再需要自己持有的对象时释放"><a href="#不再需要自己持有的对象时释放" class="headerlink" title="不再需要自己持有的对象时释放"></a>不再需要自己持有的对象时释放</h5><p>自己持有的对象,一旦不再需要,持有者有义务释放该对象。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">id obj = [NSMutableArray <span class="built_in">array</span>];</span><br><span class="line"><span class="comment">// 取得的对象存在,但自己不持有</span></span><br><span class="line">[obj retain];</span><br><span class="line"><span class="comment">// 自己持有对象</span></span><br><span class="line">[obj release];</span><br><span class="line"><span class="comment">// 释放对象</span></span><br><span class="line"><span class="comment">// 对象不可再被访问</span></span><br></pre></td></tr></table></figure><p>array方法的实现</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">- (id) object</span><br><span class="line">{</span><br><span class="line">id obj = [[NSObject alloc] init];</span><br><span class="line"><span class="comment">// 自己持有对象</span></span><br><span class="line">[obj autorelease];</span><br><span class="line"><span class="comment">// 释放后取得的对象存在,但自己不持有该对象</span></span><br><span class="line"><span class="keyword">return</span> obj;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>release方法时调用后立即释放,而autorelease方法则是不立即释放而是注册到autoreleasepool中,在超出指定的生存范围时能够自动并正确释放(调用release)。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">id obj1 = [obj0 object];</span><br><span class="line"><span class="comment">// 取得对象存在但不持有</span></span><br><span class="line">[obj1 retain];</span><br><span class="line"><span class="comment">// 自己持有对象</span></span><br></pre></td></tr></table></figure><h5 id="无法释放非自己持有的对象"><a href="#无法释放非自己持有的对象" class="headerlink" title="无法释放非自己持有的对象"></a>无法释放非自己持有的对象</h5><ul><li>已经释放过的对象再一次释放。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">id obj = [NSObject alloc] init];</span><br><span class="line">[obj release];</span><br><span class="line">[obj release];</span><br></pre></td></tr></table></figure><ul><li>自己还未持有的对象进行释放</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">id obj1 = [obj0 object];</span><br><span class="line">[obj1 release];</span><br></pre></td></tr></table></figure><h3 id="alloc-retain-release-dealloc的实现"><a href="#alloc-retain-release-dealloc的实现" class="headerlink" title="alloc/retain/release/dealloc的实现"></a>alloc/retain/release/dealloc的实现</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">id obj = [NSObject alloc];</span><br><span class="line">+(id)alloc</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> [self allocWithZone: NSDefaultMallocZone()];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">+(id)allocWithZone:(NSZone*)z</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> NSAllocateObject(self, <span class="number">0</span>, z);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">obj_layout</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> NSUInteger retained;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> id <span class="title">NSAllocateObject</span> <span class="params">(Class aClass, NSUInteger extraBytes, NSZone *zone)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> size = 计算容纳对象所需内存大小;</span><br><span class="line"> id <span class="keyword">new</span> = NSZoneMalloc(zone, self);</span><br><span class="line"> <span class="built_in">memset</span>(<span class="keyword">new</span>, o, size);</span><br><span class="line"> <span class="keyword">new</span> = (id)&((struct obj_layput *)<span class="keyword">new</span>)[<span class="number">1</span>];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>NSDefaultMallocZone和NSZoneMalloc中包含的NSZone时防止内存碎片化而引入的结构,对内存分配的区域本身进行多重化管理,根据使用对象的目的,对象的大小分配内存,从而提高了内存管理的效率。</p><p>去掉NSZone后代码简化版</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">obj_layout</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> NSUInteger retained;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">+(id) alloc</span><br><span class="line">{</span><br><span class="line"><span class="keyword">int</span> size = <span class="keyword">sizeof</span>(struct obj_layout) + 对象大小;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">obj_layout</span> *<span class="title">p</span> = (<span class="title">struct</span> <span class="title">obj_layout</span> *)<span class="title">calloc</span>(1, <span class="title">size</span>);</span></span><br><span class="line"><span class="keyword">return</span> (id)(p+<span class="number">1</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>方法中的retain整数用来保持引用计数并将其写入对象内存头部。</p><p>对象的引用计数通过retainCount来实现</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">id obj = [[NSObject alloc] init];</span><br><span class="line">[obj retainCount];</span><br><span class="line"></span><br><span class="line">- (NSUInteger)retainCount</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> NSExtraRefCount(self) + <span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">inline</span> NSUInteger <span class="title">NSExtraRefCount</span><span class="params">(id anObject)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> ((struct obj_layout *)anObject)[<span class="number">-1</span>].retained;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>通过retain方法可使retained变量加1,通过release方法可使retained变量减1</strong></p><p>retain方法的实现:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">-(id)retain</span><br><span class="line">{</span><br><span class="line">NSIncrementExtraRefCount(self);</span><br><span class="line"><span class="keyword">return</span> self;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">NSIncrementExtraRefCount</span><span class="params">(id anObject)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (((struct obj_layout *) anObject)[<span class="number">-1</span>].retained == UINT_MAX - <span class="number">1</span>)</span><br><span class="line"> [NSException raise: NSInternalInconsistencyException format: @<span class="string">"....."</span>];</span><br><span class="line"> ((struct obj_layout *) anObject)[<span class="number">-1</span>].retained++;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>release方法的实现</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)release</span><br><span class="line">{</span><br><span class="line"><span class="keyword">if</span> (NSDecrementExtraRefCountWasZero(self))</span><br><span class="line">[self dealloc];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function">BOOL <span class="title">NSDecrementExtraRefCountWasZero</span> <span class="params">(id anObject)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> ((struct obj_layout *) anObject)[<span class="number">-1</span>].retained == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> YES;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> ((struct obj_layout *)anObject)[<span class="number">-1</span>].retained--;</span><br><span class="line"> <span class="keyword">return</span> NO;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>dealloc方法的实现</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">-(<span class="keyword">void</span>)dealloc</span><br><span class="line">{</span><br><span class="line">NSDeallocateObject(self);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">NSDeallocateObject</span> <span class="params">(id anObject)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">obj_layout</span> *<span class="title">o</span> = &((<span class="title">struct</span> <span class="title">obj_layout</span> *) <span class="title">anObject</span>)[-1];</span></span><br><span class="line"> <span class="built_in">free</span>(o);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 废弃alloc分配的内存块</span></span><br></pre></td></tr></table></figure><p>实际上苹果是通过散列表的形式实现引用计数的,散列表的键值为内存块地址的散列值。</p><p>散列表存储信息为引用计数以及内存块地址。</p><h3 id="autorelease"><a href="#autorelease" class="headerlink" title="autorelease"></a>autorelease</h3><p>autorelease会类似c语言中的自动变量来对待对象实例,超出作用域时则将对象释放。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="keyword">int</span> a;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>autorelease就是类似 <code>{ }</code> 的作用,使用方法如下:</p><ul><li>生成并持有NSAutoreleasePool对象</li><li>调用已分配对象的autorelease实例方法。</li><li>废弃NSAutoreleasePool对象。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];</span><br><span class="line">id obj = [[NSObject alloc] init];</span><br><span class="line">[obj autorelease];</span><br><span class="line">[pool drain]; <span class="comment">//等同于[obj release]</span></span><br></pre></td></tr></table></figure><p>在Cocoa框架中,相当于程序主循环的NSRunLoop或者在其他程序可运行的地方,对NSAutoreleasePool 对象进行生成、持有和废弃处理。因此开发者不一定非得使用NSAutoreleasePool对象来进行开发工作。</p><p>但是在大量产生autorelease对象时,只有不废弃NSAutoreleasePool对象,那么生成的对象就不能被释放,因此可能出现内存不足的情况。例如:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < 图像数; ++i)</span><br><span class="line">{</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 读入图像</span></span><br><span class="line"><span class="comment"> * 大量产生autorelease对象</span></span><br><span class="line"><span class="comment"> * 没有废弃NSAutoreleasePool 对象</span></span><br><span class="line"><span class="comment"> * 导致最终内存不足</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> [pool drain];</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 通过drain方法autorelease对象被release</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Cocoa框架中也有很多类方法返回autorelease对象,比如NSMutableArray类的arrayWithCapacity类方法。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">id <span class="built_in">array</span> = [NSMutableArray arrayWithCapacity:<span class="number">1</span>];</span><br></pre></td></tr></table></figure><p>等同于</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">id <span class="built_in">array</span> = [[[NSMutableArray alloc] initWithCapacity:<span class="number">1</span>] autorelease];</span><br></pre></td></tr></table></figure><h4 id="autorelease的实现"><a href="#autorelease的实现" class="headerlink" title="autorelease的实现"></a>autorelease的实现</h4><p><code>[obj autorelease]</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">-(id)autorelease</span><br><span class="line">{</span><br><span class="line">[NSAutoreleasePool addObject:self];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">+(<span class="keyword">void</span>)addObject:(id)anObj</span><br><span class="line">{</span><br><span class="line">NSAutorelease *pool = 取得正在使用的NSAutorelease对象;</span><br><span class="line"><span class="keyword">if</span> (pool != nil)</span><br><span class="line"> {</span><br><span class="line"> [pool addObject:anObj];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> NSLog(@<span class="string">"AutoreleasePool 对象非存在状态下调用"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果嵌套生成或持有多个NSAutoreleasePool对象,则会使用最内侧的对象。</p><p><code>[pool drain]</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)drain</span><br><span class="line">{</span><br><span class="line">[self dealloc];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>) dealloc</span><br><span class="line">{</span><br><span class="line">[self emptyPool];</span><br><span class="line">[<span class="built_in">array</span> release];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>) emtpyPool</span><br><span class="line">{</span><br><span class="line"><span class="keyword">for</span> (id obj in <span class="built_in">array</span>)</span><br><span class="line"> {</span><br><span class="line"> [obj release];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> </p><h2 id="ARC"><a href="#ARC" class="headerlink" title="ARC"></a>ARC</h2><p>与MRC的引用计数式内存管理在本质上没有太大变化,只是自动帮我们处理引用计数的部分。</p><p>通过__strong修饰符可以不必再次键入retain或者release,自动地实现了上述的四种内存管理思考方式。</p><p>但引用计数式内存管理会发生”循环引用”的问题。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> id test0 = [[Test alloc] init]; <span class="comment">/* 对象A */</span></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * test0 持有Test对象A的强引用</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> </span><br><span class="line"> id test1 = [[Test alloc] init]; <span class="comment">/* 对象B */</span></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * test1 持有Test对象B的强引用</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> [test0 setObject:test1];</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 此时持有Test对象B的强引用变量为test1和对象A的obj_成员变量</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> [test1 setObject:test0];</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 此时持有Test对象A的强引用变量为test0和对象B的_obj变量</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* 因为test0变量超出其作用域,强引用失效,所以自动释放对象A</span></span><br><span class="line"><span class="comment">*</span></span><br><span class="line"><span class="comment">* 因为test1变量超出其作用域,强引用失效,所以自动释放对象B</span></span><br><span class="line"><span class="comment">*</span></span><br><span class="line"><span class="comment">* 此时持有对象A的强引用变量为对象B的_obj,持有对象B的强引用变量为对象A的_obj</span></span><br><span class="line"><span class="comment">*</span></span><br><span class="line"><span class="comment">* 发生内存泄漏!(应当废弃的对象在超出其生命周期后依然存在)</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>同时像下面的情况,虽然只有一个对象,但对象持有其自身时也会发生循环引用。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">id test = [[Test alloc] init];</span><br><span class="line">[test setObject:test];</span><br></pre></td></tr></table></figure><p>使用弱引用__weak可以实现,弱引用不持有对象,只是持有该对象的强引用,如果该对象的所有强持有者都释放,则对象废弃,即使此时仍有弱持有者。</p><p> _unsafe_unretained 和weak的不同之处在于前者在赋值给带有strong修饰符的变量必须确保被赋值对象确实存在,不然其不会像weak一样被设置为nil而是造成悬浮指针。(存在是历史遗留问题,有了weak后基本不用它了)</p><p>strong修饰符类似于c++中的std::shared_ptr指针,而weak修饰符类似于c++中的std::weak_ptr,在c++中没有strong,weak强烈推荐使用这两个指针。</p><h4 id="ARC,MRC区别"><a href="#ARC,MRC区别" class="headerlink" title="ARC,MRC区别"></a>ARC,MRC区别</h4><p>说了这么多总结一下ARC,MRC的区别吧。MRC类似于c++中的普通指针,程序猿要手动的进行生成持有释放废弃操作,但是可以将其注册到autoreleasepool中(类似c++的作用域),在作用域消失时也就是autoreleasepool对象释放时会释放所有注册在它里面的对象。而ARC则是类似于c++的智能指针,不需要显示的对对象实例进行释放,出现了strong,weak等修饰符,采用自动引用计数的方法,使得当一个对象实例在强引用计数为0时,则废弃这个对象实例,释放其所占的内存块。</p><h3 id="ARC的规则:"><a href="#ARC的规则:" class="headerlink" title="ARC的规则:"></a>ARC的规则:</h3><ul><li>在ARC有效时编译代码一定要遵守以下规则,</li><li>不能使用NSAllocateObject/NSDeallocateObject</li><li>须遵守内存管理的命名规则<ul><li>init返回的必须是实例对象</li></ul></li><li>不要显式地调用dealloc</li><li>使用@autorelease块代替NSAutoreleasePool</li><li>不能使用NSZone</li><li>对象型变量不能作为C语言结构体成员</li><li>显式转换id和void*<ul><li>不能强制转换</li><li>如果只是想单纯地赋值可以通过__bridge转换,但可能造成悬空指针问题,不推荐。</li></ul></li></ul><h3 id="ARC中的属性:"><a href="#ARC中的属性:" class="headerlink" title="ARC中的属性:"></a>ARC中的属性:</h3><table><thead><tr><th align="center">属性声明</th><th align="center">所有权修饰符</th></tr></thead><tbody><tr><td align="center">assign</td><td align="center">_unsafe__unretained修饰符</td></tr><tr><td align="center">copy</td><td align="center">__strong修饰符</td></tr><tr><td align="center">retain</td><td align="center">__strong修饰符</td></tr><tr><td align="center">strong</td><td align="center">__strong修饰符</td></tr><tr><td align="center">unsafe_unretained</td><td align="center">_unsafe__unretained修饰符</td></tr><tr><td align="center">weak</td><td align="center">__weak修饰符</td></tr></tbody></table><ul><li><p><strong>assign:</strong>对应到__unsafe_unretained, 表明setter仅做赋值,不增加对象的引用计数,用于基本数据类型</p></li><li><p>__weak修饰符赋值后不会注册到autoreleasepool中,只会在使用时注册,而且每次使用都会注册一次,在autoreleasepool结束后会全部释放。</p></li><li><p><strong>copy:</strong>对应到__strong,但是赋值操作比较特殊:赋值时进行copy而非retain操作,原来的值可变则深拷贝,不可变则浅拷贝。</p></li></ul><h3 id="ARC的实现"><a href="#ARC的实现" class="headerlink" title="ARC的实现"></a>ARC的实现</h3><h4 id="strong"><a href="#strong" class="headerlink" title="__strong"></a>__strong</h4><p>先看如下一段代码:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"><span class="comment">// ARC中默认会在对象前添加一个修饰符__strong</span></span><br><span class="line">id obj = [[NSObject alloc] init];</span><br><span class="line"><span class="comment">//<==>等价于</span></span><br><span class="line">id __strong obj = [[NSObject alloc] init];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>根据runtime特性,它的实际调用如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"><span class="comment">// 消息转发</span></span><br><span class="line">id obj = objc_msgSend(NSObject,@selector(alloc));</span><br><span class="line">objc_msgSend(obj,@selector(init));</span><br><span class="line"><span class="comment">// 编译器在obj作用域结束时自动插入release</span></span><br><span class="line">objc_release(obj);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>当然这里是以<code>alloc/new/copy/mutableCopy</code>生成的对象,这种对象会被当前的变量所持有,引用计数会加1.那如果不是用被持有的方式生成对象呢?<br> 看下面这段代码:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line">id obj = [NSMutableArray <span class="built_in">array</span>];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这种方式生成的对象不会被obj持有,通常情况下会被注册到<code>autoreleasepool</code>中.但也有特殊情况,上面的代码可以转换成如下代码:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"><span class="comment">// 消息转发</span></span><br><span class="line">id obj = objc_msgSend(NSMutableArray,@selector(<span class="built_in">array</span>));</span><br><span class="line"><span class="comment">// 调用objc_retainAutoreleasedReturnValue函数</span></span><br><span class="line">objc_retainAutoreleasedReturnValue(obj);</span><br><span class="line"><span class="comment">// 编译器在obj作用域结束时自动插入release</span></span><br><span class="line">objc_release(obj);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里介绍两个相关函数:</p><ul><li>objc_retainAutoreleasedReturnValue():这个函数的作用是返回注册在<code>autoreleasepool</code>当中的对象.</li><li>objc_retainAutoreleaseReturnValue():这个函数一般是和<code>objc_retainAutoreleasedReturnValue()</code>成对出现的.目的是注册对象到<code>autoreleasepool</code>中.但<code>不仅限于此</code>.<br>为何说<code>不仅限于此</code>呢?原因在于,<code>objc_retainAutoreleaseReturnValue()</code>函数在发现对象调用了方法或者函数之后又调用了<code>objc_retainAutoreleasedReturnValue()</code>,那么就不会再把返回的对象注册到<code>autoreleasepool</code>中了,而是直接把对象传递过去.<br><strong>这样的好处显而易见</strong>:不用再去<code>autoreleasepool</code>中取出对象,传递出去,而是越过<code>autoreleasepool</code>直接传递,提升了性能.</li></ul><h4 id="weak"><a href="#weak" class="headerlink" title="__weak"></a>__weak</h4><p><code>weak</code>修饰符想必大家都非常熟悉,它有一个众所周知的特性:<code>用weak修饰的对象在销毁后会被自动置为nil</code>.另外还补充一点:<code>凡是用weak修饰过的对象,必定是注册到autoreleasepool中的对象</code>.<br> 看下面的代码:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"><span class="comment">// obj默认有__strong修饰</span></span><br><span class="line">id obj = [[NSObject alloc] init];</span><br><span class="line">id __weak obj1 = obj;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>实际过程如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"><span class="comment">// 省略obj的实现</span></span><br><span class="line">id obj1;</span><br><span class="line"><span class="comment">// 通过objc_initWeak初始化变量</span></span><br><span class="line">objc_initWeak(&obj1,obj);</span><br><span class="line"><span class="comment">// 通过objc_destroyWeak释放变量</span></span><br><span class="line">objc_destroyWeak(&obj1);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><code>objc_initWeak()</code>函数的作用是将obj1初始化为0,然后将obj作为参数传递到这个函数中<code>objc_storeWeak(&obj1,obj)</code> </li><li><code>objc_destroyWeak()</code>函数则将0作为参数来调用:<code>objc_storeWeak(&obj1,0)</code> </li><li><code>objc_storeWeak()</code>函数的作用是以<code>第二个参数(obj || 0)</code>作为key,<code>第一个参数(&obj1)</code>作为value,将第一个参数的地址注册到weak表中.当key为0,即从weak表中删除变量地址.</li></ul><p>那么weak表中的对象是如何被释放的呢?</p><ul><li>从weak表中获取废弃对象的键值记录.</li><li>将记录中所有包含__weak的变量地址,赋值为nil.</li><li>从weak表中删除该记录.</li><li>从引用计数表中删除对应的记录.</li></ul><p>这就是<strong>weak修饰的变量会在释放后自动置为nil的原因.<code>同时,因为weak修饰之后涉及到注册到weak表等相关操作,如果大量使用weak可能会造成不必要的CPU资源浪费,所以书里指出尽量在循环引用中使用weak</code>.<br> 这里不得不提到另外一个和</strong>weak相近的属性:<code>__unsafe_unretained</code>,它与weak的区别在于,释放对象后不会对其置为nil,在某些特定的场合下,需要延迟释放的时候,可以考虑用这个属性修饰.</p><p>好了,下一个问题,看如下代码:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line">id __weak obj1 = obj;</span><br><span class="line"><span class="comment">// 这里使用了obj1这个用weak修饰的变量</span></span><br><span class="line">NSLog(@<span class="string">"%@"</span>,obj1);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在weak变量被使用的情况下,实际过程如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line">id obj1;</span><br><span class="line">objc_initWeak(&obj1,obj);</span><br><span class="line">id tmp = objc_loadWeakRetained(&obj1);</span><br><span class="line">objc_autorelease(tmp);</span><br><span class="line">NSLog(@<span class="string">"%@"</span>,tmp);</span><br><span class="line">objc_destroyWeak(&obj1);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>从这段实现代码中我们可以看出如下几点:</p><ul><li>当我们使用weak修饰的对象时,实际过程中产生了一个<code>tmp</code>对象,因为<code>objc_loadWeakRetained()</code>函数会从weak表中取出weak修饰的对象,所以tmp会对这个取出的对象进行一次强引用.</li><li>因为上述原因,weak修饰的对象在当前变量作用域结束前都可以放心使用.</li><li><code>objc_autorelease()</code>会将tmp对象也注册到<code>autoreleasepool</code>中.所以当大量使用weak对象的时候,注册到<code>autoreleasepool</code>的对象会大量增加.解决方案就是用一个__strong修饰的临时变量来使用.</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line">id __weak obj1 = obj;</span><br><span class="line">id tmp = obj1;</span><br><span class="line"><span class="comment">// 后面使用tmp即可</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>延伸一下:为什么有循环引用block内用weakObject的时候最好能在block内套一层strongObject?</p><ul><li>在异步线程中weakObject可能会被销毁,所以需要套一层strong.</li><li>如果内部有耗时的循环语句,频繁使用weakObject也会增加内存损耗.</li></ul><p>!!! <strong>为什么访问weak修饰的对象就会访问注册到自动释放池的对象呢?</strong></p><p>因为weak不会引起对象的引用计数器变化,因此,该对象在运行过程中很有可能会被释放。所以,需要将对象注册到自动释放池中并在autoreleasePool销毁时释放对象占用的内存。</p><h4 id="autoreleasing"><a href="#autoreleasing" class="headerlink" title="__autoreleasing"></a>__autoreleasing</h4><p>它的主要作用就是将对象注册到<code>autoreleasepool</code>中.没啥好说的.</p><p>最后补充几种在ARC环境下获取引用计数的方法,但并不一定准确:<code>ARC的一些引用计数优化,以及多线程的中的竞态条件问题,有兴趣的可以自己去了解一下</code>.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">(<span class="number">1</span>) 使用_objc_rootRetainCount()私有函数</span><br><span class="line">OBJC_EXTERN <span class="keyword">int</span> _objc_rootRetainCount(id);</span><br><span class="line">@<span class="function">interface <span class="title">ViewController</span> <span class="params">()</span></span></span><br><span class="line">@end</span><br><span class="line">@implementation ViewController</span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> id obj = [[NSObject alloc] init];</span><br><span class="line"> NSLog(@<span class="string">"%d"</span>,_objc_rootRetainCount(obj));</span><br><span class="line">}</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">(<span class="number">2</span>) 使用KVC</span><br><span class="line">@<span class="function">interface <span class="title">ViewController</span> <span class="params">()</span></span></span><br><span class="line">@end</span><br><span class="line">@implementation ViewController</span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> id obj = [[NSObject alloc] init];</span><br><span class="line"> NSLog(@<span class="string">"%d"</span>,[[obj valueForKey:@<span class="string">"retainCount"</span>] integerValue]);</span><br><span class="line">}</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">(<span class="number">3</span>) 使用CFGetRetainCount()</span><br><span class="line">@<span class="function">interface <span class="title">ViewController</span> <span class="params">()</span></span></span><br><span class="line">@end</span><br><span class="line">@implementation ViewController</span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> id obj = [[NSObject alloc] init];</span><br><span class="line"> NSLog(@<span class="string">"%d"</span>,CFGetRetainCount((__bridge CFTypeRef)(obj)));</span><br><span class="line">}</span><br><span class="line">@end</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>自动引用计数(ARC)是指内存管理中对引用采取自动计数的技术。</p>
<p>使用ARC,就无需再次键入retain或者release代码,这降低了程序崩溃,内存泄漏等风险的同时,很大程度上减少了开发程序的工作量。ARC技术使得编译器清楚目标对象,并能立刻释放那些不再被使用的对象。如此一来,应用程序将具有可预测性,且能流畅运行,速度也将大幅提升。</p>
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
</entry>
<entry>
<title>ios || 深拷贝和浅拷贝+assign</title>
<link href="http://yoursite.com/2019/07/11/iOS-%E6%B7%B1%E6%8B%B7%E8%B4%9D%E5%92%8C%E6%B5%85%E6%8B%B7%E8%B4%9D/"/>
<id>http://yoursite.com/2019/07/11/iOS-深拷贝和浅拷贝/</id>
<published>2019-07-10T16:04:27.000Z</published>
<updated>2019-08-18T10:20:05.612Z</updated>
<content type="html"><![CDATA[<ul><li><p>浅拷贝:不拷贝对象本身,仅仅是拷贝指向对象的指针(copy)</p></li><li><p>深拷贝:直接拷贝整个对象的内存到另一块内存上去(mutableCopy)</p></li></ul><p>以下特殊情况:</p><ol><li>不可变情况下被拷贝指针重新赋值。<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">NSString *str1 = @<span class="string">"str1"</span>;</span><br><span class="line">NSString *str2 = [str1 copy];</span><br><span class="line"></span><br><span class="line">str1 = @<span class="string">"asdf"</span>;</span><br><span class="line"></span><br><span class="line">NSLog(@<span class="string">"\nstr1 = %@ str1P = %p \n str2 = %@ str2P = %p"</span>, str1, str1, str2, str2);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*输出结果,修改str2 同理</span></span><br><span class="line"><span class="comment"> str1 = asdf str1P = 0x10776b1a0</span></span><br><span class="line"><span class="comment"> str2 = str1 str2P = 0x10776b180</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure></li></ol><a id="more"></a><p>开始时str1和str2指向的是相同的内存空间,且两者都是不可变的所以系统只会生成一个指向同一内存空间的指针,但是如果重新给给str1或者str2赋值,之前内容不可变而且双方应互不影响,所以只能重新开出一块内存空间。</p><ol start="2"><li>可变情况下的浅拷贝</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">NSMutableArray *mArr1 = [@[@<span class="string">"123"</span>, @<span class="string">"456"</span>, @<span class="string">"asd"</span>] mutableCopy];</span><br><span class="line">NSMutableArray *mArr2 = [mArr1 copy];</span><br><span class="line"> </span><br><span class="line"> NSLog(@<span class="string">"\n mArr1 = %@ mArr1P = %p mArr1 class = %@ \n\n mArr2 = %@ mArr2P = %p mArr2 class = %@"</span>, mArr1, mArr1, [mArr1 class], mArr2, mArr2, [mArr2 class]);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*输出结果</span></span><br><span class="line"><span class="comment"> mArr1 = (</span></span><br><span class="line"><span class="comment"> 123,</span></span><br><span class="line"><span class="comment"> 456,</span></span><br><span class="line"><span class="comment"> asd</span></span><br><span class="line"><span class="comment"> )</span></span><br><span class="line"><span class="comment"> mArr1P = 0x60400025db20</span></span><br><span class="line"><span class="comment"> mArr1 class = __NSArrayM</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> mArr2 = (</span></span><br><span class="line"><span class="comment"> 123,</span></span><br><span class="line"><span class="comment"> 456,</span></span><br><span class="line"><span class="comment"> asd</span></span><br><span class="line"><span class="comment"> )</span></span><br><span class="line"><span class="comment"> mArr2P = 0x60400025dd30</span></span><br><span class="line"><span class="comment"> mArr2 class = __NSArrayI</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p>此时mArr1指向的内存空间是可变的,如果对mArr1进行修改,同一内存空间的内容就会发生<br>变化。遵循互不影响的原则,加上mArr2是不可变的(虽然指针类型是NSMutable但是是copy拷贝所以不可变,同时如果给mArr2增删元素系统会崩,因为是用copy拷贝则意味着其不可变),所以copy会开辟新的内存空间。</p><ol start="3"><li>用copy修饰一个属性后就限制了他是不可变数组(因为copy就是复制一个不可变内存的数组),mutableCopy是深拷贝重新赋内存,而如果调用copy或直接指向arr则不会。(但如果arr是mutable类型则仍是第二个问题,无论如何都是地址都是不同的,因为arr可变)</li></ol><p>注:copy属性修饰符是深拷贝,即为成员变量复制一块新的对象实例在别的内存并让成员变量持有它。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line">@property (nonatomic, copy) NSMutableArray *<span class="built_in">array</span>;</span><br><span class="line"><span class="comment">//</span></span><br><span class="line"> NSArray *arr = @[@<span class="string">"123"</span>, @<span class="string">"456"</span>, @<span class="string">"asd"</span>];</span><br><span class="line"> self.mArr = [arr mutableCopy];</span><br><span class="line"> NSLog(@<span class="string">"\n arrP = %p \n self.mArrP = %p, self.mArr class = %@"</span>, arr, self.mArr, [self.mArr class]);</span><br><span class="line"> <span class="comment">/* 输出结果</span></span><br><span class="line"><span class="comment"> arrP = 0x600000eed530 </span></span><br><span class="line"><span class="comment"> self.mArrP = 0x600000eee520</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p> 总结:</p><ul><li>用copy修饰的 或者赋值的 变量肯定是不可变的。</li><li>用copy赋值,要看源对象是否是可变的,来决定只拷贝指针,还是也拷贝对象到另一块内存空间</li><li>对象之间mutableCopy赋值,肯定会拷贝整个对象内存到另一块内存中</li><li>对象之间赋值之后,再改变,遵循互不影响的原则</li></ul><p><strong>PS</strong>:同时在加一点assign的用法:<br>assign修饰属性只能修饰基本变量类型以及基本的oc类型,不能修饰对象!!!</p><p>如果用assign修饰对象,当对象释放后(因为不存在强引用,离开作用域对象内存可能被回收),指针的地址还是存在的,也就是说指针并没有被置为nil,下次再访问该对象就会造成野指针异常。对象是分配在堆上的,堆上的内存由程序员手动释放。<br>所以assign修饰的是存在栈上的基本类型,系统会自动回收。</p>]]></content>
<summary type="html">
<ul>
<li><p>浅拷贝:不拷贝对象本身,仅仅是拷贝指向对象的指针(copy)</p>
</li>
<li><p>深拷贝:直接拷贝整个对象的内存到另一块内存上去(mutableCopy)</p>
</li>
</ul>
<p>以下特殊情况:</p>
<ol>
<li>不可变情况下被拷贝指针重新赋值。<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">NSString *str1 = @<span class="string">"str1"</span>;</span><br><span class="line">NSString *str2 = [str1 copy];</span><br><span class="line"></span><br><span class="line">str1 = @<span class="string">"asdf"</span>;</span><br><span class="line"></span><br><span class="line">NSLog(@<span class="string">"\nstr1 = %@ str1P = %p \n str2 = %@ str2P = %p"</span>, str1, str1, str2, str2);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*输出结果,修改str2 同理</span></span><br><span class="line"><span class="comment"> str1 = asdf str1P = 0x10776b1a0</span></span><br><span class="line"><span class="comment"> str2 = str1 str2P = 0x10776b180</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure>
</li>
</ol>
</summary>
</entry>
<entry>
<title>iOS的MVC设计模式和MVVM的异同点以及iOS中如何实现数据绑定</title>
<link href="http://yoursite.com/2019/07/11/iOS%E7%9A%84MVC%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%92%8CMVVM%E7%9A%84%E5%BC%82%E5%90%8C%E7%82%B9%E4%BB%A5%E5%8F%8AiOS%E4%B8%AD%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A/"/>
<id>http://yoursite.com/2019/07/11/iOS的MVC设计模式和MVVM的异同点以及iOS中如何实现数据绑定/</id>
<published>2019-07-10T16:03:05.000Z</published>
<updated>2019-07-10T16:04:01.241Z</updated>
<content type="html"><![CDATA[<h3 id="设计模式:MVC"><a href="#设计模式:MVC" class="headerlink" title="设计模式:MVC"></a>设计模式:MVC</h3><h5 id="在模型对象-model-中封装数据和基本行为"><a href="#在模型对象-model-中封装数据和基本行为" class="headerlink" title="在模型对象(model)中封装数据和基本行为"></a>在模型对象(model)中封装数据和基本行为</h5><ul><li>模型对象维护应用程序的数据,并定义操作数据的特定逻辑。</li><li>只要是加载的是包含有应用程序永久信息的数据,就将其放到model中。</li><li>理想状况下,模型对象同用于对其进行显示和编辑的用户界面之间不应该有任何直接的关联。</li></ul><h5 id="使用视图对象-view"><a href="#使用视图对象-view" class="headerlink" title="使用视图对象(view)"></a>使用视图对象(view)</h5><ul><li>视图对象可以响应用户操作,并懂得如何将自己展现在屏幕上。</li><li>视图对象通常从应用程序的模型对象获取数据用以展示,用户可以通过视图来修改模型对象的数据。</li><li>视图对象和模型对象虽然之间关系密切但不没有耦合,除非因为性能原因(比如视图需要对数据进行缓存),否则不应该将视图用于存储其所展示的数据。</li></ul><h5 id="控制器对象-Controller-联系起模型和视图"><a href="#控制器对象-Controller-联系起模型和视图" class="headerlink" title="控制器对象(Controller)联系起模型和视图"></a>控制器对象(Controller)联系起模型和视图</h5><ul><li>协调视图对象和模型对象,使视图得以知晓模型的变更而给予响应。</li><li>还可以为应用程序执行其他操作,比如为应用程序管理其他对象的生命周期,进行设置和协调任务。</li></ul><h5 id="作为复合设计模式的MVC:"><a href="#作为复合设计模式的MVC:" class="headerlink" title="作为复合设计模式的MVC:"></a>作为复合设计模式的MVC:</h5><p>Cocoa的MVC用到的模式有:组合(Composite)、命令(Command)、中介者(Mediator)、策略(Strategy)和观察者(Observer)</p><ul><li>组合:视图对象之间以协作的方式构成一个视图层次体系,其中既可以有复合视图(如表格视图),也可以有独立视图(如文本框)。每个层次的视图节点都可以响应用户操作并把自己绘制到屏幕上。</li><li>命令:“目标-动作”机制,视图对象可以推迟其他对象(比如控制器的执行)的执行,让其他对象发生了某些事件后执行。这是命令模式。</li><li>中介者:控制器对象起着中间人的作用,而这个中间人则采用了中介者模式,构成了视图和模型对象间传递数据的双向渠道。控制器对象将模型的变更传递给视图对象。</li><li>策略:控制器可以是视图对象的一个 “策略”。视图对象将自身隔离,以期维持其作为数据展示器的唯一职责,而将一切应用程序特有的界面行为决定委托给它的“策略”对象。</li><li>观察者:模型对象向它所关注的控制器等对象发出内部状态变化的通知。</li></ul><p><img src="https://img-blog.csdnimg.cn/20190524002728195.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><ul><li>三者之间的通信只能实现Controller和Model以及Controller和View之间的通信,两者作为Controller的属性。坚决不能有Model和View之间的通信,否则失去了分离的意义。</li><li>正常情况下是Controller控制View和Model,但View和Model也可以实现对Controller的反向通信。</li><li>View通过以下三种方式实现与Controller的通信<ol><li>action-target:用户与UI交互触发控制器。例如点击按钮实现页面跳转,网络请求。</li><li>delegate:View向Controller询问自己无法决定的事情或让Controller帮助自己做一些无法独立完成的事情。例如表格视图询问Controller自己是否可以滚动,如果Model数据量很少,Controller告诉表格不可以滚动;若还有未拉出的数据,则Controller告知可以滚动。</li><li>dataSource:视图让控制器给它将要显示的数据。(Controller从Model中获取数据)</li></ol></li><li>Model通过以下两种方式实现与Controller的通信:<ol><li>Notification:控制器注册监听某模型数据变化的广播频道,当此模型数据变化后向该控制器发送广播,告知模型变化情况。</li><li>KVO机制:模型作为控制器的属性,当模型属性被修改后,持有此模型属性的控制器就会收到通知。</li></ol></li><li>多个MVC的结合,例如可以在标签栏中设置多个标签,每个标签指针指向一个MVC。一个小的MVC可作为一个大MVC的V。一个大的model可以有多个小的MVC。</li></ul><h3 id="MVVM"><a href="#MVVM" class="headerlink" title="MVVM"></a>MVVM</h3><p>MVVM比起MVC最大的好处就是可以实现自动绑定,将数据绑定在UI组件上,当UI中的值发生变化时,那么它对应的模型中也跟随着发生变化,这就是双向绑定机制,原因在于它在视图层和数据模型层之间实现了一个绑定器,绑定器可以管理两个值,它一直监听组件UI的值,只要发生变化,它将会把值传输过去改变model中的值。绑定器比较灵活,还可以实现单向绑定。</p><ol><li>实际开发中的做法:让Controller拥有View和ViewModel属性,VM拥有Model属性;Controller或者View来接收ViewModel发送的Model改变的通知</li><li>用户的操作点击或者Controller的视图生命周期里面让ViewModel去执行请求,请求完成后ViewModel将返回数据模型化并保存,从而更新了Model;Controller和View是属于V部分,即实现V改变M(V绑定M)。如果不需要请求,这直接修改Model就是了。</li><li>第2步中的Model的改变,VM是知道的(因为持有关系),只需要Model改变后发一个通知;Controller或View接收到通知后(一般是Controller先接收再赋值给View),根据这个新Model去改变视图就完成了M改变V(M绑定V)<br>使用RAC(RactiveCocoa)框架实现绑定可以简单到一句话概括:ViewModel中创建好请求的信号RACSignal, Controller中订阅这个信号,在ViewModel完成请求后订阅者调用sendNext:方法,Controller里面订阅时写的block就收到回调了。</li></ol>]]></content>
<summary type="html">
<h3 id="设计模式:MVC"><a href="#设计模式:MVC" class="headerlink" title="设计模式:MVC"></a>设计模式:MVC</h3><h5 id="在模型对象-model-中封装数据和基本行为"><a href="#在模型对象-m
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
</entry>
<entry>
<title>c++类存储方式</title>
<link href="http://yoursite.com/2019/07/10/c-%E7%B1%BB%E5%AD%98%E5%82%A8%E6%96%B9%E5%BC%8F/"/>
<id>http://yoursite.com/2019/07/10/c-类存储方式/</id>
<published>2019-07-10T15:59:11.000Z</published>
<updated>2019-07-10T16:02:36.454Z</updated>
<content type="html"><![CDATA[<div id="cnblogs_post_body" class="blogpost-body"><h4>一、<span style="font-family: 'Microsoft YaHei';">C++成员函数在内存中的存储方式</span></h4><p> 用类去定义对象时,系统会为每一个对象分配存储空间。如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间。按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分配存储单元,如下图所示。</p><p> </p><p><img src="http://img.blog.csdn.net/20170301171347079" alt></p><p> </p><p> 能否只用一段空间来存放这个共同的函数代码段,在调用各对象的函数时,都去调用这个公用的函数代码。如下图所示。</p><p><img src="http://img.blog.csdn.net/20170301171352579" alt></p><p> 显然,这样做会大大节约存储空间。C++编译系统正是这样做的,<strong>因此每个对象所占用的存储空间只是该对象的数据部分(虚函数指针和虚基类指针也属于数据部分)所占用的存储空间,而不包括函数代码所占用的存储空间</strong>。</p><p> C++程序的内存格局通常分为四个区:<strong>全局数据区(data area),代码区(code area),栈区(stack area),堆区(heap area)(即自由存储区)</strong>。全局数据区存放全局变量,静态数据和常量;所有<strong>类成员函数和非成员函数代码存放在代码区</strong>;为运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区;余下的空间都被称为堆区。根据这个解释,我们可以得知在类的定义时,类成员函数是被放在代码区,而类的静态成员变量在类定义时就已经在全局数据区分配了内存,因而它是属于类的。对于非静态成员变量,我们是在类的实例化过程中(构造对象)才在栈区或者堆区为其分配内存,是为每个对象生成一个拷贝,所以它是属于对象的。</p><p> 应当说明,常说的“某某对象的成员函数”,是从逻辑的角度而言的,而成员函数的存储方式,是从物理的角度而言的,二者是不矛盾的。</p><p> 下面我们再来讨论下类的静态成员函数和非静态成员函数的区别:<strong>静态成员函数和非静态成员函数都是在类的定义时放在内存的代码区</strong>的,因而可以说它们都是属于类的,但是类为什么只能直接调用静态类成员函数,而非静态类成员函数(即使函数没有参数)只有类对象才能调用呢?原因是<strong>类的非静态类成员函数其实都内含了一个指向类对象的指针型参数(即this指针),因而只有类对象才能调用(此时this指针有实值)</strong>。</p><p>二、虚函数表</p><p>编译器处理虚函数的方法是:为每个类对象添加一个隐藏成员,隐藏成员中保存了一个指向函数地址数组的指针,称为虚表指针(vptr),这种数组成为虚函数表(virtual function table, vtbl),即,<strong>每个类使用一个虚函数表,每个类对象用一个虚表指针</strong>。</p><p>举个例子:基类对象包含一个虚表指针,指向基类中所有虚函数的地址表。派生类对象也将包含一个虚表指针,指向派生类虚函数表。<em>看下面两种情况:</em></p><ul><li><p>如果派生类重写了基类的虚方法,该派生类虚函数表将保存重写的虚函数的地址,而不是基类的虚函数地址。</p></li><li><p>如果基类中的虚方法没有在派生类中重写,那么派生类将继承基类中的虚方法,而且派生类中虚函数表将保存基类中未被重写的虚函数的地址。注意,如果派生类中定义了新的虚方法,则该虚函数的地址也将被添加到派生类虚函数表中。</p></li></ul><p>======================================================================================</p><p>转自:http://www.cnblogs.com/malecrab/p/5572730.html</p><p> </p><p><strong>1. 概述</strong></p><p>简单地说,每一个含有虚函数(无论是其本身的,还是继承而来的)的类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数对应的函数指针。例:</p><p><img src="https://images2015.cnblogs.com/blog/898333/201606/898333-20160609210402699-1501495771.png" alt></p><p> </p><p>其中:</p><p> </p><ul><li>B的虚函数表中存放着B::foo和B::bar两个函数指针。</li><li>D的虚函数表中存放的既有继承自B的虚函数B::foo,又有重写(override)了基类虚函数B::bar的D::bar,还有新增的虚函数D::quz。</li></ul><p> </p><p><em>提示:为了描述方便,本文在探讨对象内存布局时,将忽略内存对齐对布局的影响。</em></p><p> </p><h3>2. 虚函数表构造过程</h3><p>从编译器的角度来说,B的虚函数表很好构造,D的虚函数表构造过程相对复杂。下面给出了构造D的虚函数表的一种方式(仅供参考):</p><p><img src="https://images2015.cnblogs.com/blog/898333/201606/898333-20160609210418246-1188626035.png" alt></p><p> </p><p><em>提示:该过程是由编译器完成的,因此也可以说:虚函数替换过程发生在编译时。</em></p><p> </p><h3>3. 虚函数调用过程</h3><p>以下面的程序为例:</p><p><img src="https://images2015.cnblogs.com/blog/898333/201606/898333-20160609210434386-1391536209.png" alt></p><p> </p><p>编译器只知道pb是B*类型的指针,并不知道它指向的具体对象类型 :pb可能指向的是B的对象,也可能指向的是D的对象。</p><p> </p><p>但对于“pb->bar()”,编译时能够确定的是:此处operator->的另一个参数是B::bar(因为pb是B*类型的,编译器认为bar是B::bar),而B::bar和D::bar在各自虚函数表中的偏移位置是相等的。</p><p> </p><p>无论pb指向哪种类型的对象,只要能够确定被调函数在虚函数中的偏移值,待运行时,能够确定具体类型,并能找到相应vptr了,就能找出真正应该调用的函数。</p><p> </p><p><em>提示:本人曾在“<a href="http://www.cnblogs.com/malecrab/p/5572119.html" target="_blank" rel="noopener">C/C++杂记:深入理解数据成员指针、函数成员指针</a>”一文中提到:虚函数指针中的ptr部分为虚函数表中的偏移值(以字节为单位)加1。</em></p><p> </p><p>B::bar是一个虚函数指针, 它的ptr部分内容为9,它在B的虚函数表中的偏移值为8(8+1=9)。</p><p> </p><p>当程序执行到“pb->bar()”时,已经能够判断pb指向的具体类型了:</p><p> </p><ul><li>如果pb指向B的对象,可以获取到B对象的vptr,加上偏移值8((char*)vptr + 8),可以找到B::bar。</li><li>如果pb指向D的对象,可以获取到D对象的vptr,加上偏移值8((char*)vptr + 8) ,可以找到D::bar。</li><li>如果pb指向其它类型对象...同理...</li></ul><p> </p><h3>4. 多重继承</h3><p>当一个类继承多个类,且多个基类都有虚函数时,子类对象中将包含多个虚函数表的指针(即多个vptr),例:</p><p><img src="https://images2015.cnblogs.com/blog/898333/201606/898333-20160609210449511-346261020.png" alt></p><p> </p><p>其中:D自身的虚函数与B基类共用了同一个虚函数表,因此也称B为D的主基类(primary base class)。</p><p> </p><p>虚函数替换过程与前面描述类似,只是多了一个虚函数表,多了一次拷贝和替换的过程。</p><p> </p><p>虚函数的调用过程,与前面描述基本类似,区别在于基类指针指向的位置可能不是派生类对象的起始位置,以如下面的程序为例:</p><p><img src="https://images2015.cnblogs.com/blog/898333/201606/898333-20160609210505761-312956336.png" alt></p></div>]]></content>
<summary type="html">
<div id="cnblogs_post_body" class="blogpost-body"><h4>一、<span style="font-family: 'Microsoft YaHei';">C++成员函数在内存中的存储方式</span></h4>
<p> 用类去定
</summary>
<category term="c++" scheme="http://yoursite.com/categories/c/"/>
<category term="c++" scheme="http://yoursite.com/tags/c/"/>
</entry>
<entry>
<title>c++静态方法和静态成员</title>
<link href="http://yoursite.com/2019/07/10/c-%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E5%92%8C%E9%9D%99%E6%80%81%E6%88%90%E5%91%98/"/>
<id>http://yoursite.com/2019/07/10/c-静态方法和静态成员/</id>
<published>2019-07-10T15:35:56.000Z</published>
<updated>2019-07-10T15:36:41.595Z</updated>
<content type="html"><![CDATA[<h3 id="c-静态方法和静态成员"><a href="#c-静态方法和静态成员" class="headerlink" title="c++静态方法和静态成员"></a>c++静态方法和静态成员</h3><h4 id="便于实现同一类的不同对象之间数据共享"><a href="#便于实现同一类的不同对象之间数据共享" class="headerlink" title="便于实现同一类的不同对象之间数据共享"></a>便于实现同一类的不同对象之间数据共享</h4><p>静态成员的提出是为了解决数据共享的问题。实现共享有许多方法,如:设置全局性的变量或对象是一种方法。但是,全局变量或对象是有局限性的。这一章里,我们主要讲述类的静态成员来实现数据的共享。</p><a id="more"></a><p> 静态数据成员</p><p> 在类中,静态成员可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员。</p><p> 使用静态数据成员可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。</p><p> 静态数据成员的使用方法和注意事项如下:</p><p> 1、静态数据成员在定义或说明时前面加关键字static。//静态变量的定义</p><p> 2、静态成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式如下:</p><p> <数据类型><类名>::<静态数据成员名>=<值> //静态变量的初始化</p><p> 这表明:</p><ul><li>(1) 初始化在类体外进行,而前面不加static,(这点需要注意)以免与一般静态变量或对象相混淆。</li></ul><ul><li><p>(2) 初始化时不加该成员的访问权限控制符private,public等。</p></li><li><p>(3) 初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。</p></li></ul><p> 3、静态数据成员是静态存储的,它是静态生存期,必须对它进行初始化。</p><p> 4、引用静态数据成员时,采用如下格式:</p><p> <类名>::<静态成员名> //静态变量的使用方式</p><p> 如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员。</p><p> 下面举一例子,说明静态数据成员的应用:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StaticTest</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> StaticTest(<span class="keyword">int</span> a, <span class="keyword">int</span> b, <span class="keyword">int</span> c);</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">GetNumber</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">GetSum</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">f1</span><span class="params">(StaticTest &s)</span></span>;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> A, B, C;</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">int</span> Sum;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#include "StaticTest.h"</span><br><span class="line">#include <iostream></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> StaticTest::Sum = <span class="number">0</span>;<span class="comment">//静态成员在此初始化</span></span><br><span class="line"></span><br><span class="line">StaticTest::StaticTest(<span class="keyword">int</span> a, <span class="keyword">int</span> b, <span class="keyword">int</span> c)</span><br><span class="line">{</span><br><span class="line"> A = a;</span><br><span class="line"> B = b;</span><br><span class="line"> C = c;</span><br><span class="line"> Sum += A + B + C;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> StaticTest::GetNumber()</span><br><span class="line">{</span><br><span class="line"> cout << <span class="string">"Number = "</span> << endl;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> StaticTest::GetSum()</span><br><span class="line">{</span><br><span class="line"> cout << <span class="string">"Sum = "</span> << Sum <<endl;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> StaticTest::f1(StaticTest &s)</span><br><span class="line">{</span><br><span class="line"> </span><br><span class="line"> cout << s.A << endl;<span class="comment">//静态方法不能直接调用一般成员,可以通过对象引用实现调用</span></span><br><span class="line"> cout << Sum <<endl;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">#include "StaticTest.h"</span><br><span class="line">#include <stdlib.h></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="function">StaticTest <span class="title">M</span><span class="params">(<span class="number">3</span>, <span class="number">7</span>, <span class="number">10</span>)</span>, <span class="title">N</span><span class="params">(<span class="number">14</span>, <span class="number">9</span>, <span class="number">11</span>)</span></span>;</span><br><span class="line"> M.GetNumber();</span><br><span class="line"> N.GetSum();</span><br><span class="line"> M.GetNumber();</span><br><span class="line"> N.GetSum();</span><br><span class="line"> StaticTest::f1(M);</span><br><span class="line"> system(<span class="string">"pause"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h3 id="c-静态方法和静态成员"><a href="#c-静态方法和静态成员" class="headerlink" title="c++静态方法和静态成员"></a>c++静态方法和静态成员</h3><h4 id="便于实现同一类的不同对象之间数据共享"><a href="#便于实现同一类的不同对象之间数据共享" class="headerlink" title="便于实现同一类的不同对象之间数据共享"></a>便于实现同一类的不同对象之间数据共享</h4><p>静态成员的提出是为了解决数据共享的问题。实现共享有许多方法,如:设置全局性的变量或对象是一种方法。但是,全局变量或对象是有局限性的。这一章里,我们主要讲述类的静态成员来实现数据的共享。</p>
</summary>
<category term="c++" scheme="http://yoursite.com/categories/c/"/>
<category term="c++" scheme="http://yoursite.com/tags/c/"/>
</entry>
<entry>
<title>计算机图形学 || 基础光照之冯氏光照模型</title>
<link href="http://yoursite.com/2019/07/10/%E5%9F%BA%E7%A1%80%E5%85%89%E7%85%A7%E4%B9%8B%E5%86%AF%E6%B0%8F%E5%85%89%E7%85%A7%E6%A8%A1%E5%9E%8B/"/>
<id>http://yoursite.com/2019/07/10/基础光照之冯氏光照模型/</id>
<published>2019-07-10T15:34:18.000Z</published>
<updated>2019-07-10T15:35:28.675Z</updated>
<content type="html"><![CDATA[<h3 id="Basic"><a href="#Basic" class="headerlink" title="Basic:"></a>Basic:</h3><h4 id="1-Phong光照模型"><a href="#1-Phong光照模型" class="headerlink" title="1. Phong光照模型:"></a>1. Phong光照模型:</h4><p>组成分量:</p><ul><li>环境光照(Ambient Lighting)<ul><li>即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色。</li></ul></li></ul><a id="more"></a><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ambient</span></span><br><span class="line"><span class="keyword">float</span> ambientStrength = <span class="number">0.1</span>;</span><br><span class="line">vec3 ambient = ambientStrength * lightColor;</span><br></pre></td></tr></table></figure><p>[外链图片转存失败(img-xFNsmLz4-1562772901265)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.3.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.3.png)]</a></p><ul><li>漫反射光照(Diffuse Lighting)<ul><li>模拟光源对物体的方向性影响(Directional Impact)。它是冯氏光照模型中视觉上最显著的分量。物体的某一部分越是正对着光源,它就会越亮。</li></ul></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// diffuse</span></span><br><span class="line">vec3 norm = normalize(Normal);</span><br><span class="line">vec3 lightDir = normalize(lightPos - FragPos);</span><br><span class="line"><span class="keyword">float</span> diff = max(dot(norm, lightDir), <span class="number">0.0</span>);</span><br><span class="line">vec3 diffuse = diff * lightColor;</span><br></pre></td></tr></table></figure><p>[外链图片转存失败(img-hHmO2k6S-1562772901266)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.4.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.4.png)]</a></p><ul><li>镜面光照(Specular Lighting)<ul><li>模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。</li></ul></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// specular</span></span><br><span class="line"><span class="keyword">float</span> specularStrength = <span class="number">0.5</span>;</span><br><span class="line">vec3 viewDir = normalize(viewPos - FragPos);</span><br><span class="line">vec3 reflectDir = reflect(-lightDir, norm);</span><br><span class="line"><span class="comment">// 高光的反光度32</span></span><br><span class="line"><span class="keyword">float</span> spec = <span class="built_in">pow</span>(max(dot(viewDir, reflectDir), <span class="number">0.0</span>), <span class="number">32</span>);</span><br><span class="line">vec3 specular = specularStrength * spec * lightColor;</span><br></pre></td></tr></table></figure><p><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1dhbmdQZXJyeVdQWS9QSWNHby9tYXN0ZXIvaHc2LjUucG5n" alt="hw65"></p><h4 id="2-Gouraud-Shading:"><a href="#2-Gouraud-Shading:" class="headerlink" title="2. Gouraud Shading:"></a>2. Gouraud Shading:</h4><p>Gouraud 光照模型和 Phong 光照模型的区别在于: Gouraud 是在顶点着色器中实现的,而 Phong 是在片段着色器中实现。 相比较之下 Gouraud 光照模型做光照因为顶点数少于片段数,所以会更高效,开销更低。但顶点着色器中的最终颜色值仅仅是该顶点的颜色值,片段的颜色值是由插值光照颜色得来的,因此光照效果会显得不够真实。</p><ul><li>gouraud.vs</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#version 330 core</span></span><br><span class="line">layout (location = <span class="number">0</span>) in vec3 aPos;</span><br><span class="line">layout (location = <span class="number">1</span>) in vec3 aNormal;</span><br><span class="line">out vec3 LightingColor; <span class="comment">// resulting color from lighting calculations</span></span><br><span class="line">uniform vec3 lightPos;</span><br><span class="line">uniform vec3 viewPos;</span><br><span class="line">uniform vec3 lightColor;</span><br><span class="line">uniform mat4 model;</span><br><span class="line">uniform mat4 view;</span><br><span class="line">uniform mat4 projection;</span><br><span class="line">uniform <span class="keyword">float</span> ambientStrength;</span><br><span class="line">uniform <span class="keyword">float</span> diffuseStrength;</span><br><span class="line">uniform <span class="keyword">float</span> specularStrength;</span><br><span class="line">uniform <span class="keyword">int</span> reflectance;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> gl_Position = projection * view * model * vec4(aPos, <span class="number">1.0</span>); </span><br><span class="line"> <span class="comment">// gouraud shading</span></span><br><span class="line"> <span class="comment">// ------------------------</span></span><br><span class="line"> vec3 Position = vec3(model * vec4(aPos, <span class="number">1.0</span>));</span><br><span class="line"> vec3 Normal = mat3(transpose(inverse(model))) * aNormal;</span><br><span class="line"> <span class="comment">// ambient</span></span><br><span class="line"> vec3 ambient = ambientStrength * lightColor;</span><br><span class="line"> <span class="comment">// diffuse</span></span><br><span class="line"> vec3 norm = normalize(Normal);</span><br><span class="line"> vec3 lightDir = normalize(lightPos - Position);</span><br><span class="line"> <span class="keyword">float</span> diff = max(dot(norm, lightDir), <span class="number">0.0</span>);</span><br><span class="line"> vec3 diffuse = diffuseStrength * diff * lightColor;</span><br><span class="line"> <span class="comment">// specular</span></span><br><span class="line"> vec3 viewDir = normalize(viewPos - Position);</span><br><span class="line"> vec3 reflectDir = reflect(-lightDir, norm);</span><br><span class="line"> <span class="keyword">float</span> spec = <span class="built_in">pow</span>(max(dot(viewDir, reflectDir), <span class="number">0.0</span>), reflectance);</span><br><span class="line"> vec3 specular = specularStrength * spec * lightColor;</span><br><span class="line"> </span><br><span class="line"> LightingColor = ambient + diffuse + specular;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>gouraud.fs</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#version 330 core</span></span><br><span class="line">out vec4 FragColor;</span><br><span class="line">in vec3 LightingColor;</span><br><span class="line">uniform vec3 objectColor;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> FragColor = vec4(LightingColor * objectColor, <span class="number">1.0</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>[外链图片转存失败(img-Z67sCDhW-1562772901267)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.6.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.6.png)]</a></p><p>[外链图片转存失败(img-YPlIlHON-1562772901268)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.7.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.7.png)]</a></p><p>通过两张图比较可以明显看出区别,其中在 Gouraud 光照模型中可以看到“条纹”。可以看到立方体正面的右上角被高光照亮。由于右下角三角形的右上顶点是亮的,而三角形的其他两个顶点不是亮的,所以亮值内插到其他两个顶点。左上角的三角形也是如此。由于中间碎片的颜色不是直接来自光源,而是插值的结果,中间碎片的光照是不正确的,左上角和右下角的三角形在亮度上发生碰撞,导致两个三角形之间出现可见的条纹。</p><h4 id="3-使用GUI,使参数可调节,效果实时更改"><a href="#3-使用GUI,使参数可调节,效果实时更改" class="headerlink" title="3. 使用GUI,使参数可调节,效果实时更改"></a>3. 使用GUI,使参数可调节,效果实时更改</h4><h5 id="a-GUI里可以切换两种shading。"><a href="#a-GUI里可以切换两种shading。" class="headerlink" title="a. GUI里可以切换两种shading。"></a>a. GUI里可以切换两种shading。</h5><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">ImGui::NewFrame();</span><br><span class="line">{</span><br><span class="line"> ImGui::Begin(<span class="string">"HW6_WPY"</span>, &tool_active, ImGuiWindowFlags_MenuBar);</span><br><span class="line"> <span class="keyword">if</span> (ImGui::BeginMenuBar())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (ImGui::BeginMenu(<span class="string">"Menu"</span>))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (ImGui::MenuItem(<span class="string">"Phong Shading"</span>)) {</span><br><span class="line"> phong = <span class="literal">true</span>;</span><br><span class="line"> gouraud = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (ImGui::MenuItem(<span class="string">"Gouraud Shading"</span>)) {</span><br><span class="line"> gouraud = <span class="literal">true</span>;</span><br><span class="line"> phong = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (ImGui::MenuItem(<span class="string">"Close"</span>)) {</span><br><span class="line"> tool_active = <span class="literal">false</span>;</span><br><span class="line"> glfwSetWindowShouldClose(window, <span class="literal">true</span>);<span class="comment">//关闭窗口</span></span><br><span class="line"> }</span><br><span class="line"> ImGui::EndMenu();</span><br><span class="line"> }</span><br><span class="line"> ImGui::EndMenuBar();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>[外链图片转存失败(img-sXwX5NTE-1562772901268)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.8.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.8.png)]</a></p><p>[外链图片转存失败(img-29uGtkWr-1562772901269)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.9.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.9.png)]</a></p><h5 id="b-使用如进度条这样的控件,使ambient因子、diffuse因子、specular因子、反光度等参数可调节,光照效果实时更改。"><a href="#b-使用如进度条这样的控件,使ambient因子、diffuse因子、specular因子、反光度等参数可调节,光照效果实时更改。" class="headerlink" title="b. 使用如进度条这样的控件,使ambient因子、diffuse因子、specular因子、反光度等参数可调节,光照效果实时更改。"></a>b. 使用如进度条这样的控件,使ambient因子、diffuse因子、specular因子、反光度等参数可调节,光照效果实时更改。</h5><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (phong)</span><br><span class="line">{</span><br><span class="line"> ImGui::Text(<span class="string">"1.Phong Shading"</span>);</span><br><span class="line"> ImGui::Text(<span class="string">"change the ambient strength"</span>);</span><br><span class="line"> ImGui::SliderFloat(<span class="string">"ambient strength"</span>, &ambient, <span class="number">0.0f</span>, <span class="number">1.0f</span>);</span><br><span class="line"> ImGui::Text(<span class="string">"change the diffuse strength"</span>);</span><br><span class="line"> ImGui::SliderFloat(<span class="string">"diffuse strength"</span>, &diffuse, <span class="number">0.0f</span>, <span class="number">5.0f</span>);</span><br><span class="line"> ImGui::Text(<span class="string">"change the specular strength"</span>);</span><br><span class="line"> ImGui::SliderFloat(<span class="string">"specular strength"</span>, &specular, <span class="number">0.0f</span>, <span class="number">10.0f</span>);</span><br><span class="line"> ImGui::Text(<span class="string">"change the reflectance"</span>);</span><br><span class="line"> ImGui::SliderInt(<span class="string">"reflectance"</span>, &reflectance, <span class="number">2</span>, <span class="number">256</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">phongObject.setFloat(<span class="string">"ambientStrength"</span>, ambient);</span><br><span class="line">phongObject.setFloat(<span class="string">"diffuseStrength"</span>, diffuse);</span><br><span class="line">phongObject.setFloat(<span class="string">"specularStrength"</span>, specular);</span><br><span class="line">phongObject.setInt(<span class="string">"reflectance"</span>, reflectance);</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">uniform <span class="keyword">float</span> ambientStrength;</span><br><span class="line">uniform <span class="keyword">float</span> diffuseStrength;</span><br><span class="line">uniform <span class="keyword">float</span> specularStrength;</span><br><span class="line">uniform <span class="keyword">int</span> reflectance;</span><br></pre></td></tr></table></figure><p><strong>ambient因子:</strong></p><p>[外链图片转存失败(img-6L9x63Ca-1562772901269)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can11.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can11.png)]</a></p><p>[外链图片转存失败(img-oJuOBozY-1562772901270)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can12.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can12.png)]</a></p><p><strong>diffuse因子:</strong></p><p>[外链图片转存失败(img-Rb8KzeRc-1562772901270)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can21.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can21.png)]</a></p><p>[外链图片转存失败(img-cnUpmggP-1562772901270)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can22.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can22.png)]</a></p><p><strong>specular因子:</strong></p><p><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1dhbmdQZXJyeVdQWS9QSWNHby9tYXN0ZXIvY2FuMzEucG5n" alt="can31"></p><p>[外链图片转存失败(img-TLYg0rUe-1562772901272)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can32.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can32.png)]</a></p><p><strong>反光度:</strong></p><p>[外链图片转存失败(img-fL9wCWBw-1562772901272)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can41.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can41.png)]</a></p><p>[外链图片转存失败(img-wZt6ippZ-1562772901272)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can42.png)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/can42.png)]</a></p><h3 id="Bonus"><a href="#Bonus" class="headerlink" title="Bonus:"></a>Bonus:</h3><h4 id="当前光源为静止状态,尝试使光源在场景中来回移动,光照效果实时更改。"><a href="#当前光源为静止状态,尝试使光源在场景中来回移动,光照效果实时更改。" class="headerlink" title="当前光源为静止状态,尝试使光源在场景中来回移动,光照效果实时更改。"></a>当前光源为静止状态,尝试使光源在场景中来回移动,光照效果实时更改。</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">float</span> radius = <span class="number">1.0f</span>;</span><br><span class="line"><span class="keyword">float</span> X = <span class="built_in">sin</span>(glfwGetTime()) * radius;</span><br><span class="line"><span class="keyword">float</span> Z = <span class="built_in">cos</span>(glfwGetTime()) * radius;</span><br><span class="line">lightPos = glm::vec3(X, <span class="number">0.0f</span>, Z);</span><br></pre></td></tr></table></figure><p>[外链图片转存失败(img-zPYOHM7L-1562772901273)(<a href="https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.2.gif)]" target="_blank" rel="noopener">https://raw.githubusercontent.com/WangPerryWPY/PIcGo/master/hw6.2.gif)]</a><br>github地址:<a href="https://github.com/WangPerryWPY/Computer_Graphics/tree/master/HW6" target="_blank" rel="noopener">https://github.com/WangPerryWPY/Computer_Graphics/tree/master/HW6</a></p>]]></content>
<summary type="html">
<h3 id="Basic"><a href="#Basic" class="headerlink" title="Basic:"></a>Basic:</h3><h4 id="1-Phong光照模型"><a href="#1-Phong光照模型" class="headerlink" title="1. Phong光照模型:"></a>1. Phong光照模型:</h4><p>组成分量:</p>
<ul>
<li>环境光照(Ambient Lighting)<ul>
<li>即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色。</li>
</ul>
</li>
</ul>
</summary>
<category term="计算机图形学" scheme="http://yoursite.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9B%BE%E5%BD%A2%E5%AD%A6/"/>
<category term="c++" scheme="http://yoursite.com/tags/c/"/>
<category term="计算机图形学" scheme="http://yoursite.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9B%BE%E5%BD%A2%E5%AD%A6/"/>
</entry>
<entry>
<title>iOS应用生命周期</title>
<link href="http://yoursite.com/2019/07/10/iOS%E5%BA%94%E7%94%A8%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/"/>
<id>http://yoursite.com/2019/07/10/iOS应用生命周期/</id>
<published>2019-07-10T15:33:10.000Z</published>
<updated>2019-07-10T15:33:50.391Z</updated>
<content type="html"><![CDATA[<h2 id="IOS应用生命周期"><a href="#IOS应用生命周期" class="headerlink" title="IOS应用生命周期"></a>IOS应用生命周期</h2><h4 id="分为以下5种状态:"><a href="#分为以下5种状态:" class="headerlink" title="分为以下5种状态:"></a>分为以下5种状态:</h4><ul><li>Not running(非运行状态)<ul><li>应用程序没有运行或被系统终止</li></ul></li><li>Inactive(前台非活动状态)<ul><li>正在进入前台状态但是不能接受事件处理</li></ul></li><li>Active(前台活动状态)<ul><li>进入前台,能接受事件处理</li></ul></li><li>Background(后台状态)<ul><li>如果有可执行的代码则执行代码,没有或执行完毕则马上进入挂起状态。</li></ul></li><li>Suspended(挂起状态)<ul><li>冷冻状态,不能执行代码。如果系统内存不够,应用被终止。</li></ul></li></ul><a id="more"></a><p><img src="https://img-blog.csdnimg.cn/20190426151844410.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><h4 id="AppDelegate中状态跃迁的应用回调方法:"><a href="#AppDelegate中状态跃迁的应用回调方法:" class="headerlink" title="AppDelegate中状态跃迁的应用回调方法:"></a>AppDelegate中状态跃迁的应用回调方法:</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 应用程序启动并进行初始化调用该方法发出通知</span></span><br><span class="line"><span class="comment">// 实例化根视图控制器</span></span><br><span class="line">- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {</span><br><span class="line"> NSLog(@<span class="string">"%@"</span>, @<span class="string">"application: didFinishLaunchingWithOptions:"</span>);</span><br><span class="line"> <span class="keyword">return</span> YES;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 从活动状态进入非活动状态调用该方法。</span></span><br><span class="line"><span class="comment">// 此状态可以保存UI的状态</span></span><br><span class="line">- (<span class="keyword">void</span>)applicationWillResignActive:(UIApplication *)application {</span><br><span class="line"> NSLog(@<span class="string">"%@"</span>, @<span class="string">"applicationWillResignActive"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 应用程序进入后台调用该方法并发出通知</span></span><br><span class="line"><span class="comment">// 保存用户数据,释放一些资源(例如释放数据库资源)</span></span><br><span class="line">- (<span class="keyword">void</span>)applicationDidEnterBackground:(UIApplication *)application {</span><br><span class="line"> NSLog(@<span class="string">"%@"</span>, @<span class="string">"applicationDidEnterBackground"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 进入前台但还没有处于活动状态时调用该方法并发出通知</span></span><br><span class="line"><span class="comment">// 此阶段恢复用户数据</span></span><br><span class="line">- (<span class="keyword">void</span>)applicationWillEnterForeground:(UIApplication *)application {</span><br><span class="line"> NSLog(@<span class="string">"%@"</span>, @<span class="string">"applicationWillEnterForeground"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 进入前台并处于活动状态时调用该方法并发出通知。</span></span><br><span class="line"><span class="comment">// 此阶段可恢复UI的状态</span></span><br><span class="line">- (<span class="keyword">void</span>)applicationDidBecomeActive:(UIApplication *)application {</span><br><span class="line"> NSLog(@<span class="string">"%@"</span>, @<span class="string">"applicationDidBecomeActive"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 应用程序被终止调用该方法(内存清除时除外)</span></span><br><span class="line"><span class="comment">// 该阶段释放资源保存用户数据</span></span><br><span class="line">- (<span class="keyword">void</span>)applicationWillTerminate:(UIApplication *)application {</span><br><span class="line"> NSLog(@<span class="string">"%@"</span>, @<span class="string">"applicationWillTerminate"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="状态场景:"><a href="#状态场景:" class="headerlink" title="状态场景:"></a>状态场景:</h4><ul><li><p><strong>1. 非运行状态—应用启动场景</strong><br><img src="https://img-blog.csdnimg.cn/20190426152055882.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p></li><li><p><strong>2. 点击Home键—应用退出场景</strong></p></li></ul><p>该场景状态跃迁可分为两种情况,根据Info.plist中的属性设置<code>Application does not run in background</code>控制相应的状态:</p><ul><li><p>应用程序在后台运行或挂起<br><img src="https://img-blog.csdnimg.cn/20190426151953461.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190426152000668.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p></li><li><p>应用程序不可以在后台运行或挂起:</p></li></ul><p><img src="https://img-blog.csdnimg.cn/20190426152013330.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190426152019492.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><ul><li><strong>3. 挂起重新运行场景</strong></li></ul><p><img src="https://img-blog.csdnimg.cn/20190426152036288.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><ul><li><strong>4. 内存清除:应用终止场景</strong></li></ul><p>内存清除有两种情况:可能是系统强制清理内存,也可能是使用者从任务栏中手动清除。清除后再次运行应用程序上一次状态不会保存。<br><img src="https://img-blog.csdnimg.cn/2019042615204748.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>]]></content>
<summary type="html">
<h2 id="IOS应用生命周期"><a href="#IOS应用生命周期" class="headerlink" title="IOS应用生命周期"></a>IOS应用生命周期</h2><h4 id="分为以下5种状态:"><a href="#分为以下5种状态:" class="headerlink" title="分为以下5种状态:"></a>分为以下5种状态:</h4><ul>
<li>Not running(非运行状态)<ul>
<li>应用程序没有运行或被系统终止</li>
</ul>
</li>
<li>Inactive(前台非活动状态)<ul>
<li>正在进入前台状态但是不能接受事件处理</li>
</ul>
</li>
<li>Active(前台活动状态)<ul>
<li>进入前台,能接受事件处理</li>
</ul>
</li>
<li>Background(后台状态)<ul>
<li>如果有可执行的代码则执行代码,没有或执行完毕则马上进入挂起状态。</li>
</ul>
</li>
<li>Suspended(挂起状态)<ul>
<li>冷冻状态,不能执行代码。如果系统内存不够,应用被终止。</li>
</ul>
</li>
</ul>
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="iOS" scheme="http://yoursite.com/tags/iOS/"/>
</entry>
<entry>
<title>CSAPP||Datalab</title>
<link href="http://yoursite.com/2019/07/10/CSAPP-Datalab/"/>
<id>http://yoursite.com/2019/07/10/CSAPP-Datalab/</id>
<published>2019-07-10T15:31:27.000Z</published>
<updated>2019-07-10T15:32:50.791Z</updated>
<content type="html"><![CDATA[<h3 id="1-bitXor"><a href="#1-bitXor" class="headerlink" title="1. bitXor"></a>1. bitXor</h3><ul><li>bitXor - x^y using only ~ and & </li><li>Example: bitXor(4, 5) = 1</li><li>Legal ops: ~ &</li><li>Max ops: 14</li><li>Rating: 1</li></ul><a id="more"></a><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">bitXor</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> ~(x & y) & ~(~x & ~y);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-tmin"><a href="#2-tmin" class="headerlink" title="2. tmin"></a>2. tmin</h3><ul><li>tmin - return minimum two’s complement integer <ul><li>Legal ops: ! ~ & ^ | + << >></li><li>Max ops: 4</li><li>Rating: 1<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">tmin</span><span class="params">(<span class="keyword">void</span>)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span> << <span class="number">31</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul></li></ul><h3 id="3-isTmax"><a href="#3-isTmax" class="headerlink" title="3. isTmax"></a>3. isTmax</h3><ul><li>isTmax - returns 1 if x is the maximum, two’s complement number,<ul><li>and 0 otherwise </li><li>Legal ops: ! ~ & ^ | +</li><li>Max ops: 10</li><li>Rating: 1</li></ul></li></ul><p>解题思路:Tmax = ~(Tmax+1), 排除同样满足此条件的0xffffffff</p> <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">isTmax</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{ </span><br><span class="line"><span class="keyword">return</span> !(x ^ (~(x + <span class="number">1</span>))) & !!(~x);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 同理, Tmin = ~Tim + 1, 排除同样满足此条件的0x0<br> <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">isTmin</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"><span class="keyword">return</span> !(x ^ (~x + <span class="number">1</span>)) & !!(x);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h3 id="4-allOddBits"><a href="#4-allOddBits" class="headerlink" title="4. allOddBits"></a>4. allOddBits</h3><ul><li>allOddBits - return 1 if all odd-numbered bits in word set to 1<ul><li>where bits are numbered from 0 (least significant) to 31 (most significant)</li><li>Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1</li><li>Legal ops: ! ~ & ^ | + << >></li><li>Max ops: 12</li><li>Rating: 2</li></ul></li></ul><p>解题思路:</p><ul><li>x & 0xAAAAAAAA = 0xAAAAAAAA。</li><li>构造0xAAAAAAAA<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">allOddBits</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> a = <span class="number">0xAA</span> | <span class="number">0xAA</span> << <span class="number">8</span>;</span><br><span class="line">a = a | <span class="number">0xAA</span> << <span class="number">16</span>;</span><br><span class="line">a = a | <span class="number">0xAA</span> << <span class="number">24</span>;</span><br><span class="line"><span class="keyword">return</span> !((a&x)^a);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h3 id="5-negate"><a href="#5-negate" class="headerlink" title="5. negate"></a>5. negate</h3><ul><li>negate - return -x <ul><li>Example: negate(1) = -1.</li><li>Legal ops: ! ~ & ^ | + << >></li><li>Max ops: 5</li><li>Rating: 2</li></ul></li></ul><p>解题思路:</p><p>-x = x的补码,补码=反码+1</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">negate</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (~x+<span class="number">1</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="6-isAsciiDigit"><a href="#6-isAsciiDigit" class="headerlink" title="6. isAsciiDigit"></a>6. isAsciiDigit</h3><ul><li>isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters ‘0’ to ‘9’)</li><li>Example: isAsciiDigit(0x35) = 1.</li><li>isAsciiDigit(0x3a) = 0.</li><li>isAsciiDigit(0x05) = 0.</li><li>Legal ops: ! ~ & ^ | + << >></li><li>Max ops: 15</li><li>Rating: 3</li></ul><p><strong>解题思路:</strong></p><p>依据两个原理:</p><ul><li>计算机的减运算等于加补码,补码=反码+1</li><li>对于32位int来说,若一个数>=0,右移31位为0;若为负数,右移31位为1。<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">isAsciiDigit</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> left = x + (~(<span class="number">0x30</span>)+<span class="number">1</span>);</span><br><span class="line"><span class="keyword">int</span> right = (~x+<span class="number">1</span>) + <span class="number">0x39</span>;</span><br><span class="line"><span class="keyword">return</span> !(left >> <span class="number">31</span>) & !(right >> <span class="number">31</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h3 id="7-conditional"><a href="#7-conditional" class="headerlink" title="7. conditional"></a>7. conditional</h3><ul><li>conditional - same as x ? y : z <ul><li>Example: conditional(2,4,5) = 4</li><li>Legal ops: ! ~ & ^ | + << >></li><li>Max ops: 16</li><li>Rating: 3</li></ul></li></ul><p>解题思路:</p><ul><li>当x只取0x00000000或0xFFFFFFFF时,结果为(x & y) | (~x & z)。</li><li>只需要排除当x != 0时,x = 0xFFFFFFFF。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">conditional</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y, <span class="keyword">int</span> z)</span> </span>{</span><br><span class="line">x = (!!x) << <span class="number">31</span> >> <span class="number">31</span>;</span><br><span class="line"><span class="keyword">return</span> ((x & y) | (~x & z)); </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="8-isLessOrEqual"><a href="#8-isLessOrEqual" class="headerlink" title="8. isLessOrEqual"></a>8. isLessOrEqual</h3><ul><li>isLessOrEqual - if x <= y then return 1, else return 0 <ul><li>Example: isLessOrEqual(4,5) = 1.</li><li>Legal ops: ! ~ & ^ | + << >></li><li>Max ops: 24</li><li>Rating: 3</li></ul></li></ul><p>解题思路:</p><ul><li>理论上y-x >= 0即可。</li><li>但是如果x, y正负不同,相减可能会溢出。</li><li>所以分两种情况讨论,如果两个数符号相等,判断相减;如果两个数符号不同,判断符号。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">isLessOrEqual</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> a = !((x >> <span class="number">31</span>) ^ (y >> <span class="number">31</span>));</span><br><span class="line"><span class="keyword">return</span> (a & !((y + (~x + <span class="number">1</span>)) >> <span class="number">31</span>)) | (~a & !(y >> <span class="number">31</span>));</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="9-logicalNeg"><a href="#9-logicalNeg" class="headerlink" title="9. logicalNeg"></a>9. logicalNeg</h3><ul><li>logicalNeg - implement the ! operator, using all of <ul><li>the legal operators except !</li><li>Examples: logicalNeg(3) = 0, logicalNeg(0) = 1</li><li>Legal ops: ~ & ^ | + << >></li><li>Max ops: 12</li><li>Rating: 4 </li></ul></li></ul><p>解题思路:</p><p>0和-0的最高位为0,将正数转化为负数,那么只有0的最高位为0</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">logicalNeg</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> ~((x | (~x + <span class="number">1</span>)) >> <span class="number">31</span>) & <span class="number">0x1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="10-howManyBits"><a href="#10-howManyBits" class="headerlink" title="10. howManyBits"></a>10. howManyBits</h3><ul><li>howManyBits - return the minimum number of bits required to represent x in two’s complement<ul><li>Examples: howManyBits(12) = 5<ul><li>howManyBits(298) = 10<ul><li>howManyBits(-5) = 4</li><li>howManyBits(0) = 1</li><li>howManyBits(-1) = 1</li><li>howManyBits(0x80000000) = 32</li></ul></li></ul></li><li>Legal ops: ! ~ & ^ | + << >></li><li>Max ops: 90</li><li>Rating: 4</li></ul></li></ul><p>解题思路:</p><ul><li>补码的最高表示位前面的所有数字应该都是全0(正数)或是全1(负数)。</li><li>将原数与左移一位后的数字异或则最高的不同的那个位置为1,我们只需要找到这个最高的不同位即可。<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">howManyBits</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> temp = x ^ (x << <span class="number">1</span>);</span><br><span class="line"><span class="keyword">int</span> bit_16,bit_8,bit_4,bit_2,bit_1;</span><br><span class="line">bit_16 = !!(temp >> <span class="number">16</span>) << <span class="number">4</span>;</span><br><span class="line">temp = temp >> bit_16;</span><br><span class="line">bit_8 = !!(temp >> <span class="number">8</span>) << <span class="number">3</span>;</span><br><span class="line">temp = temp >> bit_8;</span><br><span class="line">bit_4 = !!(temp >> <span class="number">4</span>) << <span class="number">2</span>;</span><br><span class="line">temp = temp >> bit_4;</span><br><span class="line">bit_2 = !!(temp >> <span class="number">2</span>) << <span class="number">1</span>;</span><br><span class="line">temp = temp >> bit_2;</span><br><span class="line">bit_1 = !!(temp >> <span class="number">1</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">1</span> + bit_1 + bit_2 + bit_4 + bit_8 + bit_16;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h3 id="11-floatScale2"><a href="#11-floatScale2" class="headerlink" title="11. floatScale2"></a>11. floatScale2</h3><ul><li>floatScale2 - Return bit-level equivalent of expression 2*f for<ul><li>floating point argument f.</li><li>Both the argument and result are passed as unsigned int’s, but</li><li>they are to be interpreted as the bit-level representation of</li><li>single-precision floating point values.</li><li>When argument is NaN, return argument</li><li>Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while</li><li>Max ops: 30</li><li>Rating: 4</li></ul></li></ul><p>解题思路:</p><ul><li>IEEE浮点数格式一共分为三种形式,弱规范数,NAN以及一般的数。</li><li>NAN直接返回</li><li>弱规范数直接左移1位但要保留符号位。</li><li>一般数的话尾数不变,只移动指数位并保持符号位不变。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="title">floatScale2</span><span class="params">(<span class="keyword">unsigned</span> uf)</span> </span>{</span><br><span class="line"><span class="keyword">unsigned</span> a = (uf >> <span class="number">23</span>) & <span class="number">0xff</span>;</span><br><span class="line"><span class="keyword">unsigned</span> flag = uf >> <span class="number">31</span> << <span class="number">31</span>;</span><br><span class="line"><span class="keyword">int</span> temp = uf;</span><br><span class="line"><span class="keyword">if</span> (a == <span class="number">0xff</span>) </span><br><span class="line"><span class="keyword">return</span> uf;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (a == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">temp = uf << <span class="number">1</span>;</span><br><span class="line"><span class="comment">//temp = temp & (~(0xff << 23));</span></span><br><span class="line">temp = temp | flag;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> </span><br><span class="line">{</span><br><span class="line">temp = temp + (<span class="number">0x1</span><<<span class="number">23</span>);</span><br><span class="line">temp = temp | flag;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> temp;;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="12-floatFloat2Int"><a href="#12-floatFloat2Int" class="headerlink" title="12. floatFloat2Int"></a>12. floatFloat2Int</h3><ul><li>floatFloat2Int - Return bit-level equivalent of expression (int) f<ul><li>for floating point argument f.</li><li>Argument is passed as unsigned int, but</li><li>it is to be interpreted as the bit-level representation of a</li><li>single-precision floating point value.</li><li>Anything out of range (including NaN and infinity) should return</li><li>0x80000000u.</li><li>Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while</li><li>Max ops: 30</li><li>Rating: 4</li></ul></li></ul><p>解题思路:</p><ul><li>此题的解题关键在于分几种情况,先将符号位拿出单独讨论,当指数位-127>=32位时,溢出,返回0x80000000u,当指数位-127 < 0时,是小于1的小数,返回0即可。</li><li>剩下的情况一种是指数位-127>=23位时,将尾数位左移多出的位;当<23时,尾数位右移缺失的位。</li><li>再将最后的结果根据符号位的判断加上正负。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">floatFloat2Int</span><span class="params">(<span class="keyword">unsigned</span> uf)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> a = ((uf >> <span class="number">23</span>) & <span class="number">0xff</span>) - <span class="number">127</span>;</span><br><span class="line"><span class="keyword">int</span> flag = uf >> <span class="number">31</span>;</span><br><span class="line"><span class="keyword">if</span> (a >= <span class="number">32</span>)</span><br><span class="line"><span class="keyword">return</span> <span class="number">0x80000000</span>u;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (a < <span class="number">0</span>)</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"><span class="keyword">else</span> </span><br><span class="line">{</span><br><span class="line"><span class="keyword">int</span> temp = (uf | <span class="number">0x800000</span>) & <span class="number">0xffffff</span>;</span><br><span class="line"><span class="keyword">if</span> (a >= <span class="number">23</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">int</span> e = a - <span class="number">23</span>;</span><br><span class="line">temp = temp << e;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> </span><br><span class="line">{</span><br><span class="line"><span class="keyword">int</span> e = <span class="number">23</span> - a;</span><br><span class="line">temp = temp >> e;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> flag ? -temp : temp;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="13-floatPower2"><a href="#13-floatPower2" class="headerlink" title="13. floatPower2"></a>13. floatPower2</h3><ul><li>floatPower2 - Return bit-level equivalent of the expression 2.0^x<ul><li>(2.0 raised to the power x) for any 32-bit integer x.</li><li>The unsigned value that is returned should have the identical bit</li><li>representation as the single-precision floating-point number 2.0^x.</li><li>If the result is too small to be represented as a denorm, return</li><li>0.If too large, return +INF.</li><li>Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while </li><li>Max ops: 30 </li><li>Rating: 4</li></ul></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="title">floatPower2</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x > <span class="number">127</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> <span class="number">0x7f800000</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (x < <span class="number">-127</span>)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> <span class="number">0x0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> (x + <span class="number">127</span>) << <span class="number">23</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h3 id="1-bitXor"><a href="#1-bitXor" class="headerlink" title="1. bitXor"></a>1. bitXor</h3><ul>
<li>bitXor - x^y using only ~ and &amp; </li>
<li>Example: bitXor(4, 5) = 1</li>
<li>Legal ops: ~ &amp;</li>
<li>Max ops: 14</li>
<li>Rating: 1</li>
</ul>
</summary>
<category term="c" scheme="http://yoursite.com/categories/c/"/>
<category term="CSAPP" scheme="http://yoursite.com/tags/CSAPP/"/>
<category term="c" scheme="http://yoursite.com/tags/c/"/>
</entry>
<entry>
<title>计算机图形学 || Camera</title>
<link href="http://yoursite.com/2019/07/10/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9B%BE%E5%BD%A2%E5%AD%A6-Camera/"/>
<id>http://yoursite.com/2019/07/10/计算机图形学-Camera/</id>
<published>2019-07-10T15:22:12.000Z</published>
<updated>2019-07-10T15:23:19.032Z</updated>
<content type="html"><![CDATA[<h3 id="Basic:"><a href="#Basic:" class="headerlink" title="Basic:"></a>Basic:</h3><h4 id="1-投影-Projection"><a href="#1-投影-Projection" class="headerlink" title="1. 投影(Projection):"></a>1. 投影(Projection):</h4><ul><li><strong>把上次作业绘制的cube放置在(-1.5, 0.5, -1.5)位置,要求6个面颜色不一致。</strong></li></ul><a id="more"></a><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">float</span> vertices[] = {</span><br><span class="line"> <span class="comment">// 顶点位置 // 颜色坐标</span></span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> </span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> </span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> </span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> </span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> </span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span></span><br><span class="line"> </span><br><span class="line"> };</span><br></pre></td></tr></table></figure><p>将6个面分别设置为不同的颜色。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">model = glm::translate(model, glm::vec3(<span class="number">-1.5f</span>, <span class="number">0.5f</span>, <span class="number">-1.5f</span>));</span><br></pre></td></tr></table></figure><p>设置中心坐标为(-1.5, 0.5, -1.5)。</p><p><img src="https://img-blog.csdnimg.cn/20190418110034456.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><ul><li><strong>正交投影(orthographic projection):实现正交投影,使用多组(left, right, bottom, top, near, far)参数, 比较结果差异。</strong></li></ul><p>选择参数(-10.0f, 10.0f, -10.0f, 10.0f, 0.1f, 100.0f)</p><p><img src="https://img-blog.csdnimg.cn/20190418110046797.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>调节前四个参数也就是宽高,会发现投影的范围变大,物体在标准化坐标范围内的视觉效果也变小。</p><p><img src="https://img-blog.csdnimg.cn/20190418110059152.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>然后调节近平面和远平面的距离,开始时认为这个距离是相对到原点的距离,通过调节发现其实是到摄像机也就是view的距离。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">view = glm::translate(view, glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">-10.0f</span>));</span><br><span class="line">projection = glm::ortho(<span class="number">-10.0f</span>, <span class="number">10.0f</span>, <span class="number">-10.0f</span>, <span class="number">10.0f</span>, <span class="number">8.0f</span>, <span class="number">50.0f</span>);</span><br></pre></td></tr></table></figure><p>效果为:</p><p><img src="https://img-blog.csdnimg.cn/20190418110126364.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">view = glm::translate(view, glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">-10.0f</span>));</span><br><span class="line">projection = glm::ortho(<span class="number">-10.0f</span>, <span class="number">10.0f</span>, <span class="number">-10.0f</span>, <span class="number">10.0f</span>, <span class="number">9.0f</span>, <span class="number">50.0f</span>);</span><br></pre></td></tr></table></figure><p>效果为:</p><p><img src="https://img-blog.csdnimg.cn/20190418110137761.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>出现如上效果是因为设置的立方体边长为-2~2,9.0f意味着-10.0+9.0=-1.0的位置插入近平面,所以会截掉一部分。</p><ul><li><strong>透视投影(perspective projection):实现透视投影,使用多组参数,比较结果差异 。</strong></li></ul><p>将fov角设置为45度。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">view = glm::translate(view, glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">-15.0f</span>));</span><br><span class="line">projection = glm::perspective(glm::radians(<span class="number">45.0f</span>), (<span class="keyword">float</span>)SCR_WIDTH / (<span class="keyword">float</span>)SCR_HEIGHT, <span class="number">0.1f</span>, <span class="number">100.0f</span>);</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/20190418110154275.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>保持其他参数不变,将fov角调为30度。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">view = glm::translate(view, glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">-15.0f</span>));</span><br><span class="line">projection = glm::perspective(glm::radians(<span class="number">30.0f</span>), (<span class="keyword">float</span>)SCR_WIDTH / (<span class="keyword">float</span>)SCR_HEIGHT, <span class="number">0.1f</span>, <span class="number">100.0f</span>);</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/201904181102211.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>fov角度越小,透视投影出的立方体越大。</p><p>接着调整宽高比的大小。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">view = glm::translate(view, glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">-15.0f</span>));</span><br><span class="line">projection = glm::perspective(glm::radians(<span class="number">30.0f</span>), <span class="number">2</span> * (<span class="keyword">float</span>)SCR_WIDTH / (<span class="keyword">float</span>)SCR_HEIGHT, <span class="number">0.1f</span>, <span class="number">100.0f</span>);</span><br></pre></td></tr></table></figure><p>效果如下:</p><p><img src="https://img-blog.csdnimg.cn/20190418110238431.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>也就是将宽度所占的比重调高,显然可以看出物体沿屏幕高度方向被拉伸,所以要想保持合适的视觉效果最好宽高比就还是设置为屏幕的真正宽高比。</p><h4 id="2-视角变换-View-Changing"><a href="#2-视角变换-View-Changing" class="headerlink" title="2. 视角变换(View Changing):"></a>2. 视角变换(View Changing):</h4><ul><li><strong>把cube放置在(0, 0, 0)处,做透视投影,使摄像机围绕cube旋转,并且时刻看着cube中心。</strong></li></ul><p>用LookAt矩阵创建摄像机的观察空间。LookAt矩阵的三个参数分别是摄像机位置,目标位置,上向量。<br>$$<br>LookAt = \begin{bmatrix} \color{red}{R_x} & \color{red}{R_y} & \color{red}{R_z} & 0 \ \color{green}{U_x} & \color{green}{U_y} & \color{green}{U_z} & 0 \ \color{blue}{D_x} & \color{blue}{D_y} & \color{blue}{D_z} & 0 \ 0 & 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} 1 & 0 & 0 & -\color{purple}{P_x} \ 0 & 1 & 0 & -\color{purple}{P_y} \ 0 & 0 & 1 & -\color{purple}{P_z} \ 0 & 0 & 0 & 1 \end{bmatrix}<br>$$<br><strong>D是方向向量</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">glm::vec3 cameraTarget = glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>); <span class="comment">//目标位置</span></span><br><span class="line">glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);</span><br></pre></td></tr></table></figure><p><strong>R是右向量</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">glm::vec3 up = glm::vec3(<span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>); <span class="comment">//上向量</span></span><br><span class="line">glm::vec3 cameraRight = glm::normalize(glm::cross(up, cameraDirection));</span><br></pre></td></tr></table></figure><p><strong>U是上轴</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">glm::vec3 cameraUp = glm::cross(cameraDirection, cameraRight);</span><br></pre></td></tr></table></figure><p>当然这些都已经被LookAt封装好,我们只需要提供三个参数即可。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">glm::mat4 view;</span><br><span class="line">view = glm::lookAt(glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">3.0f</span>), </span><br><span class="line"> glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>), </span><br><span class="line"> glm::vec3(<span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>));</span><br></pre></td></tr></table></figure><p><strong>然后通过圆的sin,cos设置,使得摄像机围中心点绕x-z平面旋转。</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">float</span> radius = <span class="number">15.0f</span>;</span><br><span class="line"><span class="keyword">float</span> camX = <span class="built_in">sin</span>(glfwGetTime()) * radius;</span><br><span class="line"><span class="keyword">float</span> camZ = <span class="built_in">cos</span>(glfwGetTime()) * radius;</span><br><span class="line">view = glm::lookAt(glm::vec3(camX, <span class="number">0.0</span>, camZ), glm::vec3(<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>), glm::vec3(<span class="number">0.0</span>, <span class="number">1.0</span>, <span class="number">0.0</span>));</span><br></pre></td></tr></table></figure><p>截取其中两帧效果如下:</p><p><img src="https://img-blog.csdnimg.cn/20190418110313136.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190418110321637.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><h4 id="3-在GUI里添加菜单栏,可以选择各种功能。-Hint-使摄像机一直处于一个圆的位置。"><a href="#3-在GUI里添加菜单栏,可以选择各种功能。-Hint-使摄像机一直处于一个圆的位置。" class="headerlink" title="3. 在GUI里添加菜单栏,可以选择各种功能。 Hint: 使摄像机一直处于一个圆的位置。"></a>3. 在GUI里添加菜单栏,可以选择各种功能。 Hint: 使摄像机一直处于一个圆的位置。</h4><p>实现GUI功能如下:</p><ul><li>菜单点击start进入选择。</li><li>界面分为两部分,一部分是projection,另一部分是Camera。</li><li>Projection对应两个按钮,可以选择是正交投影还是透视投影。</li><li>Camera对应滑动块,可以调节摄像机距离物体中心的旋转半径。</li></ul><p><img src="https://img-blog.csdnimg.cn/20190418110333443.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190418110341717.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p><strong>配合ImGui的实现效果:</strong><br><img src="https://img-blog.csdnimg.cn/20190418110401814.gif" alt="在这里插入图片描述"></p><h4 id="4-思考题"><a href="#4-思考题" class="headerlink" title="4. 思考题"></a>4. 思考题</h4><ul><li><strong>在现实生活中,我们一般将摄像机摆放的空间View matrix和被拍摄的物体摆设的空间Model matrix分开,但是在OpenGL中却将两个合二为一设为ModelView matrix,通过上面的作业启发,你认为是为什么呢?在报告中写入。(Hints:你可能有不止一个摄像机)。</strong></li></ul><p><strong>坐标变换矩阵栈(ModelView)</strong></p><p>用来存储一系列的变换矩阵,栈顶就是当前坐标的变换矩阵,进入OpenGL管道的每个坐标(齐次坐标)都会先乘上这个矩阵,结果才是对应点在场景中的世界坐标。</p><blockquote><p>VertexData —>(Object Coordinates)—>ModelViewMatrix —>(Eye Coordinates)—> ProjectionMatrix —>(Clip Coordinates)—>Divide by w —>(Normalized Device Coordinates)—>ViewportTransform—>WindowCoordinates</p></blockquote><p>因为一个场景中可能存在多台摄像机,也就是多个视角的结合,如果为每一个都分配一个view可能容易比较混乱,ModelView是一个矩阵栈,可以存储model的各种变化以及不同的view视角,这样既不会造成视觉混乱同时也能减少计算量。</p><h3 id="Bonus:"><a href="#Bonus:" class="headerlink" title="Bonus:"></a>Bonus:</h3><h4 id="camera类"><a href="#camera类" class="headerlink" title="camera类:"></a>camera类:</h4><ul><li><strong>实现一个camera类,当键盘输入 w,a,s,d ,能够前后左右移动;当移动鼠标,能够视角移动(“look around”), 即类似FPS(First Person Shooting)的游戏场景。</strong> </li></ul><p>实现内容:</p><ul><li><p>键盘WASD按键移动。</p></li><li><p>鼠标移动实现视角移动</p></li><li><p>滚轮实现物体缩放。</p></li></ul><h5 id="(1)键盘WASD按键实现自由移动。"><a href="#(1)键盘WASD按键实现自由移动。" class="headerlink" title="(1)键盘WASD按键实现自由移动。"></a>(1)键盘WASD按键实现自由移动。</h5><ul><li>计算前一帧与当前帧的时间差。</li><li>因为图形程序和游戏通常会跟踪一个时间差(Deltatime)变量,它储存了渲染上一帧所用的时间。我们把所有速度都去乘以deltaTime值。结果就是,如果我们的deltaTime很大,就意味着上一帧的渲染花费了更多时间,所以这一帧的速度需要变得更高来平衡渲染所花去的时间。使用这种方法时,无论你的电脑快还是慢,摄像机的速度都会相应平衡,这样每个用户的体验就都一样了。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">float</span> currentFrame = glfwGetTime();</span><br><span class="line">deltaTime = currentFrame - lastFrame;</span><br><span class="line">lastFrame = currentFrame;</span><br></pre></td></tr></table></figure><ul><li>在cpp文件中调用Camera类来对键盘移动进行操作。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">processInput</span><span class="params">(GLFWwindow *window)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)</span><br><span class="line"> glfwSetWindowShouldClose(window, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)</span><br><span class="line"> camera.ProcessKeyboard(FORWARD, deltaTime);</span><br><span class="line"> <span class="keyword">if</span> (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)</span><br><span class="line"> camera.ProcessKeyboard(BACKWARD, deltaTime);</span><br><span class="line"> <span class="keyword">if</span> (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)</span><br><span class="line"> camera.ProcessKeyboard(LEFT, deltaTime);</span><br><span class="line"> <span class="keyword">if</span> (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)</span><br><span class="line"> camera.ProcessKeyboard(RIGHT, deltaTime);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>Camera类中键盘移动的函数实现。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">ProcessKeyboard</span><span class="params">(Camera_Movement direction, <span class="keyword">float</span> deltaTime)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">float</span> velocity = MovementSpeed * deltaTime;</span><br><span class="line"> <span class="keyword">if</span> (direction == FORWARD)</span><br><span class="line"> Position += Front * velocity;</span><br><span class="line"> <span class="keyword">if</span> (direction == BACKWARD)</span><br><span class="line"> Position -= Front * velocity;</span><br><span class="line"> <span class="keyword">if</span> (direction == LEFT)</span><br><span class="line"> Position -= Right * velocity;</span><br><span class="line"> <span class="keyword">if</span> (direction == RIGHT)</span><br><span class="line"> Position += Right * velocity;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>效果:</strong></p><p>通过移动AD键实现左右方向的移动:</p><p><img src="https://img-blog.csdnimg.cn/20190418110443410.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>通过移动WS键实现物体的前后移动:</p><p><img src="https://img-blog.csdnimg.cn/20190418110450354.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><h5 id="(2)利用鼠标实现视角移动"><a href="#(2)利用鼠标实现视角移动" class="headerlink" title="(2)利用鼠标实现视角移动"></a>(2)利用鼠标实现视角移动</h5><p>视角移动也就是实现对cameraFront向量的改变。</p><p>通过对欧拉角的改变来实现对方向向量的改变。</p><ul><li><p>欧拉角由俯仰角和偏航角还有滚转角(用不到)实现</p><ul><li>计算鼠标至上一帧的偏移量</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">mouse_callback</span><span class="params">(GLFWwindow* window, <span class="keyword">double</span> xpos, <span class="keyword">double</span> ypos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (firstMouse)</span><br><span class="line"> {</span><br><span class="line"> lastX = xpos;</span><br><span class="line"> lastY = ypos;</span><br><span class="line"> firstMouse = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">float</span> xoffset = xpos - lastX;</span><br><span class="line"> <span class="keyword">float</span> yoffset = lastY - ypos;</span><br><span class="line"> </span><br><span class="line"> lastX = xpos;</span><br><span class="line"> lastY = ypos;</span><br><span class="line"></span><br><span class="line"> camera.ProcessMouseMovement(xoffset, yoffset);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>将偏移量乘上sensitivity(灵敏度)加到pitch和yaw上。</li><li>设置偏航角限制。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">ProcessMouseMovement</span><span class="params">(<span class="keyword">float</span> xoffset, <span class="keyword">float</span> yoffset, GLboolean constrainPitch = <span class="literal">true</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> xoffset *= MouseSensitivity;</span><br><span class="line"> yoffset *= MouseSensitivity;</span><br><span class="line"></span><br><span class="line"> Yaw += xoffset;</span><br><span class="line"> Pitch += yoffset;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (constrainPitch)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (Pitch > <span class="number">89.0f</span>)</span><br><span class="line"> Pitch = <span class="number">89.0f</span>;</span><br><span class="line"> <span class="keyword">if</span> (Pitch < <span class="number">-89.0f</span>)</span><br><span class="line"> Pitch = <span class="number">-89.0f</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> updateCameraVectors();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>把偏移量加到全局变量pitch和yaw上:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">glm::vec3 front;</span><br><span class="line">front.x = <span class="built_in">cos</span>(glm::radians(Yaw)) * <span class="built_in">cos</span>(glm::radians(Pitch));</span><br><span class="line">front.y = <span class="built_in">sin</span>(glm::radians(Pitch));</span><br><span class="line">front.z = <span class="built_in">sin</span>(glm::radians(Yaw)) * <span class="built_in">cos</span>(glm::radians(Pitch));</span><br><span class="line">Front = glm::normalize(front);</span><br></pre></td></tr></table></figure></li></ul><p><strong>效果:</strong></p><p><img src="https://img-blog.csdnimg.cn/2019041811054195.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><h5 id="(3)滚轮实现物体的缩放"><a href="#(3)滚轮实现物体的缩放" class="headerlink" title="(3)滚轮实现物体的缩放"></a>(3)滚轮实现物体的缩放</h5><p>通过改变视野来实现,应用到透视矩阵上也就是fov角度的大小。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">ProcessMouseScroll</span><span class="params">(<span class="keyword">float</span> yoffset)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (Zoom >= <span class="number">1.0f</span> && Zoom <= <span class="number">45.0f</span>)</span><br><span class="line"> Zoom -= yoffset;</span><br><span class="line"> <span class="keyword">if</span> (Zoom <= <span class="number">1.0f</span>)</span><br><span class="line"> Zoom = <span class="number">1.0f</span>;</span><br><span class="line"> <span class="keyword">if</span> (Zoom >= <span class="number">45.0f</span>)</span><br><span class="line"> Zoom = <span class="number">45.0f</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/2019041811060459.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p><strong>最终实现效果:</strong></p><p><img src="https://img-blog.csdnimg.cn/201904181106164.gif" alt="在这里插入图片描述"><br><strong>代码地址</strong>:<a href="https://github.com/WangPerryWPY/Computer_Graphics/tree/master/HW5" target="_blank" rel="noopener">https://github.com/WangPerryWPY/Computer_Graphics/tree/master/HW5</a></p>]]></content>
<summary type="html">
<h3 id="Basic:"><a href="#Basic:" class="headerlink" title="Basic:"></a>Basic:</h3><h4 id="1-投影-Projection"><a href="#1-投影-Projection" class="headerlink" title="1. 投影(Projection):"></a>1. 投影(Projection):</h4><ul>
<li><strong>把上次作业绘制的cube放置在(-1.5, 0.5, -1.5)位置,要求6个面颜色不一致。</strong></li>
</ul>
</summary>
<category term="计算机图形学" scheme="http://yoursite.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9B%BE%E5%BD%A2%E5%AD%A6/"/>
<category term="c++" scheme="http://yoursite.com/tags/c/"/>
<category term="计算机x图形学" scheme="http://yoursite.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BAx%E5%9B%BE%E5%BD%A2%E5%AD%A6/"/>
</entry>
<entry>
<title>计算机图形学 || Translation</title>
<link href="http://yoursite.com/2019/07/10/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9B%BE%E5%BD%A2%E5%AD%A6-Translation/"/>
<id>http://yoursite.com/2019/07/10/计算机图形学-Translation/</id>
<published>2019-07-10T15:20:24.000Z</published>
<updated>2019-07-10T15:21:44.242Z</updated>
<content type="html"><![CDATA[<h3 id="Basic"><a href="#Basic" class="headerlink" title="Basic:"></a>Basic:</h3><h4 id="1-画一个立方体-cube-边长为4,-中心位置为-0-0-0-。分别启动和关闭深度测试glEnable-GL-DEPTH-TEST-、-glDisable-GL-DEPTH-TEST-,查看区别,并分析原因。"><a href="#1-画一个立方体-cube-边长为4,-中心位置为-0-0-0-。分别启动和关闭深度测试glEnable-GL-DEPTH-TEST-、-glDisable-GL-DEPTH-TEST-,查看区别,并分析原因。" class="headerlink" title="1. 画一个立方体(cube):边长为4, 中心位置为(0, 0, 0)。分别启动和关闭深度测试glEnable(GL_DEPTH_TEST) 、 glDisable(GL_DEPTH_TEST) ,查看区别,并分析原因。"></a>1. 画一个立方体(cube):边长为4, 中心位置为(0, 0, 0)。分别启动和关闭深度测试glEnable(GL_DEPTH_TEST) 、 glDisable(GL_DEPTH_TEST) ,查看区别,并分析原因。</h4><a id="more"></a><h4 id="着色器:"><a href="#着色器:" class="headerlink" title="着色器:"></a>着色器:</h4><ul><li>顶点着色器:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#version 330 core</span></span><br><span class="line">layout (location = <span class="number">0</span>) in vec3 aPos;</span><br><span class="line"><span class="comment">//layout (location = 1) in vec3 aColor;</span></span><br><span class="line">layout (location = <span class="number">1</span>) in vec2 aTexCoord;</span><br><span class="line"></span><br><span class="line">out vec3 ourColor;</span><br><span class="line"><span class="comment">// 增加纹理属性</span></span><br><span class="line">out vec2 TexCoord;</span><br><span class="line"><span class="comment">//增加变换属性</span></span><br><span class="line">uniform mat4 model;</span><br><span class="line">uniform mat4 view;</span><br><span class="line">uniform mat4 projection;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> gl_Position = projection * view * model * vec4(aPos, <span class="number">1.0</span>);</span><br><span class="line"> ourColor = vec3(<span class="number">1.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>);</span><br><span class="line"> TexCoord = aTexCoord;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>片段着色器:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#version 330 core</span></span><br><span class="line">out vec4 FragColor;</span><br><span class="line"></span><br><span class="line">in vec3 ourColor;</span><br><span class="line">in vec2 TexCoord;</span><br><span class="line"></span><br><span class="line">uniform sampler2D texture1;</span><br><span class="line">uniform sampler2D texture2;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// 将两种纹理进行混合</span></span><br><span class="line"> FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), <span class="number">0.2</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="建模:"><a href="#建模:" class="headerlink" title="建模:"></a>建模:</h4><ul><li>设置立方体的36个顶点:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">float</span> vertices[] = {</span><br><span class="line"> <span class="comment">// 顶点位置 // 纹理坐标</span></span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">1.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">2.0f</span>, <span class="number">-2.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>,</span><br><span class="line"> <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">-2.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>,</span><br><span class="line"> ...... ............</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="坐标设定:"><a href="#坐标设定:" class="headerlink" title="坐标设定:"></a>坐标设定:</h4><ul><li>设置观察(摄像机)矩阵和透视投影矩阵,因为设置的边长较大,所以要将视角拉向很远。</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 设置view和透视矩阵,因为默认摄像机和透视不变化所以开始就可以设置好</span></span><br><span class="line"> glm::mat4 view = glm::mat4(<span class="number">1.0f</span>);</span><br><span class="line"> glm::mat4 projection = glm::mat4(<span class="number">1.0f</span>);</span><br><span class="line"> view = glm::translate(view, glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">-15.0f</span>));</span><br><span class="line"> projection = glm::perspective(glm::radians(<span class="number">45.0f</span>), (<span class="keyword">float</span>)SCR_WIDTH / (<span class="keyword">float</span>)SCR_HEIGHT, <span class="number">0.1f</span>, <span class="number">100.0f</span>);</span><br><span class="line"> object1.use(); <span class="comment">// don't forget to activate/use the shader before setting uniforms!</span></span><br><span class="line"> object1.setMat4(<span class="string">"view"</span>, view);</span><br><span class="line"> object1.setMat4(<span class="string">"projection"</span>, projection);</span><br></pre></td></tr></table></figure><ul><li>设置模型矩阵:</li></ul><p>因为设计线性代数的矩阵运算,所以模型变换时要先缩放,后旋转最后位移。变为矩阵运算则刚好相反进行创建。最后发送给着色器,再这之前记得激活(每次使用前一定记得激活!!!)。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">object1.use();</span><br><span class="line">glm::mat4 model = glm::mat4(<span class="number">1.0f</span>); <span class="comment">// make sure to initialize matrix to identity matrix first</span></span><br><span class="line"><span class="comment">// 先缩放,后旋转,最后位移,矩阵乘法顺序相反</span></span><br><span class="line"><span class="comment">// 沿水平方向来回移动</span></span><br><span class="line">model = glm::translate(model, glm::vec3(<span class="number">1.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>));</span><br><span class="line"><span class="comment">// 沿着x = z轴持续旋转</span></span><br><span class="line">model = glm::rotate(model, rad_z , glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>));</span><br><span class="line"><span class="comment">// 持续放大缩小</span></span><br><span class="line"><span class="comment">//float scale_size = 2 * abs(cos((float)glfwGetTime()));</span></span><br><span class="line">model = glm::scale(model, glm::vec3(_s, _s, _s));</span><br><span class="line">object1.setMat4(<span class="string">"model"</span>, model);</span><br></pre></td></tr></table></figure><h4 id="纹理:"><a href="#纹理:" class="headerlink" title="纹理:"></a>纹理:</h4><ul><li>为了美观又为立方体添加了纹理效果:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">unsigned</span> <span class="keyword">int</span> texture1, texture2;</span><br><span class="line">texture1 = LoadTexture(<span class="string">"timg.jpg"</span>, <span class="number">0</span>);</span><br><span class="line">texture2 = LoadTexture(<span class="string">"rocket.png"</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 激活并绑定纹理单元</span></span><br><span class="line">glActiveTexture(GL_TEXTURE0);</span><br><span class="line">glBindTexture(GL_TEXTURE_2D, texture1);</span><br><span class="line">glActiveTexture(GL_TEXTURE1);</span><br><span class="line">glBindTexture(GL_TEXTURE_2D, texture2);</span><br><span class="line"><span class="comment">// 将纹理绑定到对应的纹理单元</span></span><br><span class="line">object1.use(); <span class="comment">// don't forget to activate/use the shader before setting uniforms!</span></span><br><span class="line">object1.setInt(<span class="string">"texture1"</span>, <span class="number">0</span>);</span><br><span class="line">object1.setInt(<span class="string">"texture2"</span>, <span class="number">1</span>);</span><br></pre></td></tr></table></figure><h4 id="深度测试:"><a href="#深度测试:" class="headerlink" title="深度测试:"></a>深度测试:</h4><ul><li>开启深度测试</li></ul><p><img src="https://img-blog.csdnimg.cn/20190410144514309.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述">- 未开启深度测试</p><p><img src="https://img-blog.csdnimg.cn/20190410144536453.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><h4 id="现象解释:"><a href="#现象解释:" class="headerlink" title="现象解释:"></a>现象解释:</h4><p>OpenGL是一个三角形一个三角形地来绘制你的立方体的,所以即便之前那里有东西它也会覆盖之前的像素。因为这个原因,有些三角形会被绘制在其它三角形上面,虽然它们本不应该是被覆盖的。</p><ul><li><strong>深度缓冲:</strong></li></ul><p>OpenGL存储它的所有深度信息于一个Z缓冲(Z-buffer)中,也被称为深度缓冲(Depth Buffer)。GLFW会自动生成这样一个缓冲(就像它也有一个颜色缓冲来存储输出图像的颜色)。深度值存储在每个片段里面(作为片段的<strong>z</strong>值),当片段想要输出它的颜色时,OpenGL会将它的深度值和z缓冲进行比较,如果当前的片段在其它片段之后,它将会被丢弃,否则将会覆盖。这个过程称为深度测试(Depth Testing),它是由OpenGL自动完成的。</p><p>通过glEnable函数来开启深度测试。glEnable和glDisable函数启用或禁用某个OpenGL功能。这个功能会一直保持启用/禁用状态,直到另一个调用来禁用/启用它。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">glEnable(GL_DEPTH_TEST);</span><br></pre></td></tr></table></figure><p>因为使用了深度测试,我们也想要在每次渲染迭代之前清除深度缓冲(否则前一帧的深度信息仍然保存在缓冲中)。就像清除颜色缓冲一样,可以通过在glClear函数中指定DEPTH_BUFFER_BIT位来清除深度缓冲:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);</span><br></pre></td></tr></table></figure><h4 id="2-平移-Translation-使画好的cube沿着水平或垂直方向来回移动。"><a href="#2-平移-Translation-使画好的cube沿着水平或垂直方向来回移动。" class="headerlink" title="2. 平移(Translation):使画好的cube沿着水平或垂直方向来回移动。"></a>2. 平移(Translation):使画好的cube沿着水平或垂直方向来回移动。</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">model = glm::translate(model, glm::vec3(<span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>));</span><br></pre></td></tr></table></figure><h4 id="3-旋转-Rotation-使画好的cube沿着XoZ平面的x-z轴持续旋转。"><a href="#3-旋转-Rotation-使画好的cube沿着XoZ平面的x-z轴持续旋转。" class="headerlink" title="3. 旋转(Rotation):使画好的cube沿着XoZ平面的x=z轴持续旋转。"></a>3. 旋转(Rotation):使画好的cube沿着XoZ平面的x=z轴持续旋转。</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">model = glm::rotate(model, (<span class="keyword">float</span>)glfwGetTime() * glm::radians(<span class="number">30.0f</span>), glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>));![img](pic/<span class="number">2.</span>gif)</span><br></pre></td></tr></table></figure><h4 id="4-放缩-Scaling-使画好的cube持续放大缩小。"><a href="#4-放缩-Scaling-使画好的cube持续放大缩小。" class="headerlink" title="4.放缩(Scaling):使画好的cube持续放大缩小。"></a>4.放缩(Scaling):使画好的cube持续放大缩小。</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">float</span> scale_size = <span class="number">2</span> * <span class="built_in">abs</span>(<span class="built_in">cos</span>((<span class="keyword">float</span>)glfwGetTime()));</span><br><span class="line">model = glm::scale(model, glm::vec3(scale_size, scale_size, scale_size));</span><br></pre></td></tr></table></figure><h4 id="5-在GUI里添加菜单栏,可以选择各种变换。"><a href="#5-在GUI里添加菜单栏,可以选择各种变换。" class="headerlink" title="5. 在GUI里添加菜单栏,可以选择各种变换。"></a>5. 在GUI里添加菜单栏,可以选择各种变换。</h4><h5 id="功能:"><a href="#功能:" class="headerlink" title="功能:"></a>功能:</h5><ul><li><strong>Translatin:</strong><ul><li>分别有x轴和y轴两个Slider,拖动进度条可以使物体沿两个轴移动。</li><li>因为z轴的移动视觉效果类似放缩,所以不做设计。</li></ul></li><li><strong>Rotation:</strong><ul><li>分别有三个按钮,对应x, y, z轴,点击可以使得立方体沿着对应轴旋转响应单位角度(设置为30度)。</li></ul></li><li><strong>Scale:</strong><ul><li>拖动Slider实现立方体的放缩,上限为2倍。</li></ul></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// imgui的Slider变化量</span></span><br><span class="line"><span class="keyword">float</span> _t_x = <span class="number">0</span>, _t_y = <span class="number">0</span>, _s = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">float</span> rad_x = <span class="number">0.0f</span>, rad_y = <span class="number">0.0f</span>, rad_z = <span class="number">0.0f</span>;</span><br><span class="line"><span class="keyword">bool</span> r_x = <span class="literal">false</span>, r_y = <span class="literal">false</span>, r_z = <span class="literal">false</span>;</span><br><span class="line"><span class="comment">// imgui的menu</span></span><br><span class="line"><span class="keyword">bool</span> tool_active = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">bool</span> basic = <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">bool</span> bonus = <span class="literal">false</span>;</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">ImGui::Text(<span class="string">"(1).Translation"</span>);</span><br><span class="line">ImGui::SliderFloat(<span class="string">"translation_X"</span>, &_t_x, <span class="number">-1</span>, <span class="number">1</span>);</span><br><span class="line">ImGui::SliderFloat(<span class="string">"translation_Y"</span>, &_t_y, <span class="number">-1</span>, <span class="number">1</span>);</span><br><span class="line"><span class="comment">//ImGui::SliderFloat("translation_Z", &_t_z, -1, 1);</span></span><br><span class="line">ImGui::Text(<span class="string">"(2).Rotation"</span>);</span><br><span class="line"><span class="comment">//ImGui::SliderFloat("Rotation", &_r, -1, 1);</span></span><br><span class="line"><span class="keyword">if</span> (ImGui::Button(<span class="string">"rotate by x"</span>))</span><br><span class="line">{</span><br><span class="line"> r_x = <span class="literal">true</span>;</span><br><span class="line"> rad_x += glm::radians(<span class="number">30.0f</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (ImGui::Button(<span class="string">"rotata by y"</span>))</span><br><span class="line">{</span><br><span class="line"> r_y = <span class="literal">true</span>;</span><br><span class="line"> rad_y += glm::radians(<span class="number">30.0f</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (ImGui::Button(<span class="string">"rotate by z"</span>))</span><br><span class="line">{</span><br><span class="line"> r_z = <span class="literal">true</span>;</span><br><span class="line"> rad_z += glm::radians(<span class="number">30.0f</span>);</span><br><span class="line">}</span><br><span class="line">ImGui::Text(<span class="string">"(3).Scale"</span>);</span><br><span class="line">ImGui::SliderFloat(<span class="string">"Scale"</span>, &_s, <span class="number">0</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">object1.use();</span><br><span class="line"><span class="comment">// 变换组合</span></span><br><span class="line">glm::mat4 model = glm::mat4(<span class="number">1.0f</span>); <span class="comment">// make sure to initialize matrix to identity matrix first</span></span><br><span class="line"><span class="comment">// 先缩放,后旋转,最后位移,矩阵乘法顺序相反</span></span><br><span class="line"><span class="comment">// 沿水平方向来回移动</span></span><br><span class="line">model = glm::translate(model, glm::vec3(_t_x, _t_y, <span class="number">0.0</span>));</span><br><span class="line"><span class="comment">// 沿着x = z轴持续旋转</span></span><br><span class="line"><span class="keyword">if</span> (r_x)</span><br><span class="line">{</span><br><span class="line"> model = glm::rotate(model, rad_x , glm::vec3(<span class="number">1.0f</span>, <span class="number">0.0f</span>, <span class="number">0.0f</span>));</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (r_y)</span><br><span class="line">{</span><br><span class="line"> model = glm::rotate(model, rad_y, glm::vec3(<span class="number">0.0f</span>, <span class="number">1.0f</span>, <span class="number">0.0f</span>));</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (r_z)</span><br><span class="line">{</span><br><span class="line"> model = glm::rotate(model, rad_z, glm::vec3(<span class="number">0.0f</span>, <span class="number">0.0f</span>, <span class="number">1.0f</span>));</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 持续放大缩小</span></span><br><span class="line"><span class="comment">//float scale_size = 2 * abs(cos((float)glfwGetTime()));</span></span><br><span class="line">model = glm::scale(model, glm::vec3(_s, _s, _s));</span><br><span class="line">object1.setMat4(<span class="string">"model"</span>, model);</span><br></pre></td></tr></table></figure><h5 id="实现效果:"><a href="#实现效果:" class="headerlink" title="实现效果:"></a>实现效果:</h5><p><img src="https://img-blog.csdnimg.cn/20190410144710319.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190410144718564.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190410144735332.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><h4 id="6-结合Shader谈谈对渲染管线的理解"><a href="#6-结合Shader谈谈对渲染管线的理解" class="headerlink" title="6. 结合Shader谈谈对渲染管线的理解"></a>6. 结合Shader谈谈对渲染管线的理解</h4><p><strong>shader的管线步骤如下:</strong></p><ul><li>vertex processor(vs)</li><li>Primitive assembly(图元装配)</li><li>Geometry processor(几何学处理)(包括将物体从三维透影到二维)</li><li>clipper</li><li>光栅化</li><li>fragment processor</li></ul><p><strong>在openGL中编写shader程序则主要包含以下步骤:</strong></p><ul><li>创建shader对象<ul><li>顶点shader</li><li>片元shader</li></ul></li><li>指定shader源代码</li><li>编译shader<ul><li>调试</li></ul></li><li>将shader对象与程序对象绑定</li><li>链接<ul><li>调试</li></ul></li><li>释放中间shader对象</li><li>通过glUseProgram将链接好的程序对象送到shader管线,这个shader将对之后的draw有效</li></ul><p><strong>shader对象调用顶点和片元的shader代码:</strong></p><ul><li>顶点shader代码中包含顶点buffer中的值被解释为其在buffer中位置(可能包含位置,法向,纹理等多个属性)。</li><li>main中把多个shader对象链接到一起形成最终的shader。</li><li>顶点shader运行成功后将会把物体从三维投射到二维(透射除法)</li><li>光栅化后每个片元执行片元shader的操作,输出的最终颜色由out的FragColor决定。</li></ul><h3 id="Bonus"><a href="#Bonus" class="headerlink" title="Bonus:"></a>Bonus:</h3><ul><li>功能:<ul><li>将basic和bonus分别以不同的menu在gui中区别出来。</li><li>bonus中实现了一个模拟的地球绕太阳旋转(用立方体表示的),地球具备自转和公转能力,太阳自转。</li><li>地球和太阳分别隶属不同的着色器,因为设置不同的纹理,太阳是太空和太阳结合的纹理属性,地球是地球表面贴图的纹理属性。</li></ul></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">Shader <span class="title">object1</span><span class="params">(<span class="string">"shader.vs"</span>, <span class="string">"shader.fs"</span>)</span></span>;</span><br><span class="line"><span class="function">Shader <span class="title">object2</span><span class="params">(<span class="string">"shader1.vs"</span>, <span class="string">"shader1.fs"</span>)</span></span>;</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">texture3 = LoadTexture(<span class="string">"地球.jpg"</span>, <span class="number">0</span>);</span><br><span class="line">texture4 = LoadTexture(<span class="string">"太阳.png"</span>, <span class="number">1</span>);</span><br><span class="line">glActiveTexture(GL_TEXTURE2);</span><br><span class="line">glBindTexture(GL_TEXTURE_2D, texture3);</span><br><span class="line">glActiveTexture(GL_TEXTURE3);</span><br><span class="line">glBindTexture(GL_TEXTURE_2D, texture4);</span><br><span class="line">object1.use(); <span class="comment">// don't forget to activate/use the shader before setting uniforms!</span></span><br><span class="line">object1.setInt(<span class="string">"texture1"</span>, <span class="number">0</span>);</span><br><span class="line">object1.setInt(<span class="string">"texture2"</span>, <span class="number">3</span>);</span><br><span class="line">object2.use();</span><br><span class="line">object2.setInt(<span class="string">"Texture"</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">object1.use();</span><br><span class="line"><span class="comment">// 变换组合</span></span><br><span class="line"><span class="comment">// 太阳</span></span><br><span class="line">glm::mat4 model = glm::mat4(<span class="number">1.0f</span>);</span><br><span class="line">model = glm::rotate(model, (<span class="keyword">float</span>)glfwGetTime() * glm::radians(<span class="number">30.0f</span>), glm::vec3(<span class="number">0.5f</span>, <span class="number">0.8f</span>, <span class="number">0.0f</span>));</span><br><span class="line">object1.setMat4(<span class="string">"model"</span>, model);</span><br><span class="line">glDrawArrays(GL_TRIANGLES, <span class="number">0</span>, <span class="number">36</span>);</span><br><span class="line">object2.use();</span><br><span class="line">glm::mat4 model1 = glm::mat4(<span class="number">1.0f</span>); <span class="comment">// make sure to initialize matrix to identity matrix first</span></span><br><span class="line"><span class="comment">// 公转</span></span><br><span class="line"><span class="keyword">float</span> X = <span class="built_in">sin</span>(glfwGetTime()) * <span class="number">5</span>;</span><br><span class="line"><span class="keyword">float</span> Z = <span class="built_in">cos</span>(glfwGetTime()) * <span class="number">5</span>;</span><br><span class="line">model1 = glm::translate(model1, glm::vec3(X, <span class="number">0.0f</span>, Z));</span><br><span class="line"><span class="comment">// 自转</span></span><br><span class="line">model1 = glm::rotate(model1, (<span class="keyword">float</span>)glfwGetTime() * glm::radians(<span class="number">45.0f</span>), glm::vec3(<span class="number">0.5f</span>, <span class="number">1.0f</span>, <span class="number">0.3f</span>));</span><br><span class="line"><span class="comment">// 地球比太阳小</span></span><br><span class="line">model1 = glm::scale(model1, glm::vec3(<span class="number">0.5f</span>, <span class="number">0.5f</span>, <span class="number">0.5f</span>));</span><br><span class="line">object2.setMat4(<span class="string">"model"</span>, model1);</span><br><span class="line">glDrawArrays(GL_TRIANGLES, <span class="number">0</span>, <span class="number">36</span>);</span><br></pre></td></tr></table></figure><h5 id="实现效果:-1"><a href="#实现效果:-1" class="headerlink" title="实现效果:"></a>实现效果:</h5><ul><li>略丑(捂脸)</li></ul><p><img src="https://img-blog.csdnimg.cn/20190410144756905.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190410144810441.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190410144819530.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>详细代码参考:<br><a href="https://github.com/WangPerryWPY/Computer_Graphics/tree/master/HW4" target="_blank" rel="noopener">https://github.com/WangPerryWPY/Computer_Graphics/tree/master/HW4</a></p>]]></content>
<summary type="html">
<h3 id="Basic"><a href="#Basic" class="headerlink" title="Basic:"></a>Basic:</h3><h4 id="1-画一个立方体-cube-边长为4,-中心位置为-0-0-0-。分别启动和关闭深度测试glEnable-GL-DEPTH-TEST-、-glDisable-GL-DEPTH-TEST-,查看区别,并分析原因。"><a href="#1-画一个立方体-cube-边长为4,-中心位置为-0-0-0-。分别启动和关闭深度测试glEnable-GL-DEPTH-TEST-、-glDisable-GL-DEPTH-TEST-,查看区别,并分析原因。" class="headerlink" title="1. 画一个立方体(cube):边长为4, 中心位置为(0, 0, 0)。分别启动和关闭深度测试glEnable(GL_DEPTH_TEST) 、 glDisable(GL_DEPTH_TEST) ,查看区别,并分析原因。"></a>1. 画一个立方体(cube):边长为4, 中心位置为(0, 0, 0)。分别启动和关闭深度测试glEnable(GL_DEPTH_TEST) 、 glDisable(GL_DEPTH_TEST) ,查看区别,并分析原因。</h4>
</summary>
<category term="计算机图形学" scheme="http://yoursite.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9B%BE%E5%BD%A2%E5%AD%A6/"/>
<category term="c++" scheme="http://yoursite.com/tags/c/"/>
<category term="计算机图形学" scheme="http://yoursite.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9B%BE%E5%BD%A2%E5%AD%A6/"/>
</entry>
<entry>
<title>外部排序 || c++实现多路归并的败者树算法</title>
<link href="http://yoursite.com/2019/07/10/c-%E5%AE%9E%E7%8E%B0%E5%A4%9A%E8%B7%AF%E5%BD%92%E5%B9%B6%E7%9A%84%E8%B4%A5%E8%80%85%E6%A0%91%E7%AE%97%E6%B3%95/"/>
<id>http://yoursite.com/2019/07/10/c-实现多路归并的败者树算法/</id>
<published>2019-07-10T15:18:58.000Z</published>
<updated>2019-07-10T15:20:01.810Z</updated>
<content type="html"><![CDATA[<h4 id="算法概念:"><a href="#算法概念:" class="headerlink" title="算法概念:"></a>算法概念:</h4><ul><li>如果我们要对大规模文件进行排序,不能一次装入内存中,只能从外存一次次读取分别排序,而外存的IO时间复杂度很高,所以我们应该尽量减少针对外存读写的次数。如果我们只是简单地进行二路归并的话,归并路数越少归并的次数就越多,每次归并都要进行一次IO操作。所以我们考虑尽量进行多路归并,而多路归并不同于简单地二次归并只需对两组数进行指针移动归并,为了降低多路归并中归并的时间复杂度。我们考虑使用败者树。</li></ul><a id="more"></a><ul><li>败者树和胜者树相对,就是树的每个结点存储的是比较失败的结点,胜利的结点接着去与更高层次的结点进行比较。</li><li>想法应用于竞技比赛就是当选出冠军后,再选择亚军只需要让曾经败给冠军的结点进行比较即可,类推季军…,从而得到全部所有的名次。</li></ul><h4 id="代码实现:"><a href="#代码实现:" class="headerlink" title="代码实现:"></a>代码实现:</h4><ul><li><p>LoserTree.hpp</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// LoserTree.hpp</span></span><br><span class="line"><span class="comment">// LoserTree</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Created by peiyu wang on 2019/4/1.</span></span><br><span class="line"><span class="comment">// Copyright © 2019 peiyu wang. All rights reserved.</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> LoserTree_hpp</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LoserTree_hpp</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><limits.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><ctime></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 宏定义 */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> MAXSIZE</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MAXSIZE 2000</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MAX 2500</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> K 5 <span class="comment">// k路归并</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MAXKEY INT_MAX</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MINKEY INT_MIN</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* k-路归并败者树类型定义 */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">int</span> KeyType;</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">int</span> LoserTree[K];</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ExNode</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> KeyType key;</span><br><span class="line">}; <span class="comment">// 外结点,只存放待归并记录的关键字</span></span><br><span class="line"><span class="keyword">typedef</span> ExNode External[K+<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 败者树函数列表 */</span></span><br><span class="line"><span class="comment">// 利用败者树ls将ke个输入归并段中的记录归并到输出归并段</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">K_Merge</span><span class="params">(FILE *fp, LoserTree ls, External b)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 从b[s]出发调整败者树</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Adjust</span><span class="params">(LoserTree ls, External b, <span class="keyword">int</span> s)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 依次从b[k-1...0]出发,调整ls为败者树</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">CreateLoserTree</span><span class="params">(LoserTree ls, External b)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">freadNum</span><span class="params">(FILE *fp, <span class="keyword">int</span> *i)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 从文件fp[i]中读取关键字到x</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">input</span><span class="params">(FILE *fp[K], <span class="keyword">int</span> *x, <span class="keyword">int</span> i)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将x输出到有序表fp</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">output</span><span class="params">(FILE *fp, <span class="keyword">int</span> x)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 生成MAX个随机数到fp用作测试</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">RandomNum</span><span class="params">(FILE *fp)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将随机数表fp分段排序后分别写入文件[0...k-1].txt中</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Cut_Sort</span><span class="params">(FILE *fp)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">/* LoserTree_hpp */</span></span></span><br></pre></td></tr></table></figure><ul><li>LoserTree.cpp:<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// LoserTree.cpp</span></span><br><span class="line"><span class="comment">// LoserTree</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Created by peiyu wang on 2019/4/1.</span></span><br><span class="line"><span class="comment">// Copyright © 2019 peiyu wang. All rights reserved.</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"LoserTree.hpp"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 利用败者树ls将k个输入归并段中的记录归并到输出归并段</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">K_Merge</span><span class="params">(FILE *fp_out, LoserTree ls, External b)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i, q;</span><br><span class="line"> FILE *fp_in[K] = {};</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < K; i++)</span><br><span class="line"> {</span><br><span class="line"> input(fp_in, &(b[i].key), i);</span><br><span class="line"> }</span><br><span class="line"> CreateLoserTree(ls, b);</span><br><span class="line"> <span class="keyword">while</span> (b[ls[<span class="number">0</span>]].key != MAXKEY)</span><br><span class="line"> {</span><br><span class="line"> q = ls[<span class="number">0</span>];</span><br><span class="line"> output(fp_out, b[q].key);</span><br><span class="line"> input(fp_in, &(b[q].key), q);</span><br><span class="line"> Adjust(ls, b, q);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//output(fp_out, b[ls[0]].key);</span></span><br><span class="line"> fclose(fp_out);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 从b[s]出发调整败者树</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Adjust</span><span class="params">(LoserTree ls, External b, <span class="keyword">int</span> s)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> t, tmp;</span><br><span class="line"> t = (s + K) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">while</span> (t > <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (b[s].key > b[ls[t]].key)</span><br><span class="line"> {</span><br><span class="line"> tmp = s;</span><br><span class="line"> s = ls[t];</span><br><span class="line"> ls[t] = tmp;</span><br><span class="line"> }</span><br><span class="line"> t /= <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line"> ls[<span class="number">0</span>] = s;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 依次从b[k-1...0]出发,调整ls为败者树</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">CreateLoserTree</span><span class="params">(LoserTree ls, External b)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i;</span><br><span class="line"> b[K].key = MINKEY;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < K; i++)</span><br><span class="line"> {</span><br><span class="line"> ls[i] = K;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (i = K - <span class="number">1</span>; i >= <span class="number">0</span>; i--)</span><br><span class="line"> {</span><br><span class="line"> Adjust(ls, b, i);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">freadNum</span><span class="params">(FILE *fp, <span class="keyword">int</span> *i)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> tmp;</span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> ((tmp = getc(fp)) != EOF)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> ((tmp >= <span class="string">'0'</span>&& tmp <= <span class="string">'9'</span>) || (tmp == <span class="string">'+'</span>) || (tmp == <span class="string">'-'</span>))</span><br><span class="line"> {</span><br><span class="line"> ungetc(tmp, fp);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (tmp != EOF)</span><br><span class="line"> {</span><br><span class="line"> count = <span class="built_in">fscanf</span>(fp, <span class="string">"%d"</span>, i);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> count;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 从文件fp[i]中读取关键字到x</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">input</span><span class="params">(FILE *fp[K], <span class="keyword">int</span> *x, <span class="keyword">int</span> i)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> tmp;</span><br><span class="line"> <span class="keyword">char</span> str1[<span class="number">100</span>], str2[<span class="number">100</span>], str3[<span class="number">100</span>] = <span class="string">".txt"</span>;</span><br><span class="line"> <span class="keyword">if</span> (!fp[i])</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">strcpy</span>(str1, <span class="string">"tmpfile/"</span>);</span><br><span class="line"> <span class="built_in">sprintf</span>(str2, <span class="string">"%d"</span>, i);</span><br><span class="line"> <span class="built_in">strcat</span>(str1, <span class="built_in">strcat</span>(str2, str3));</span><br><span class="line"> fp[i] = fopen(str1, <span class="string">"r"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(freadNum(fp[i], &tmp))</span><br><span class="line"> {</span><br><span class="line"> *x = tmp;</span><br><span class="line"> <span class="keyword">if</span> (tmp == MAXKEY)</span><br><span class="line"> fclose(fp[i]);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将x输出到有序表fp</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">output</span><span class="params">(FILE *fp, <span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">fprintf</span>(fp, <span class="string">"%d, "</span>, x);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 生成MAX个随机数到fp用作测试</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">RandomNum</span><span class="params">(FILE *fp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i, j, number, tag;</span><br><span class="line"> <span class="keyword">int</span> x[MAX + <span class="number">1</span>] = {<span class="number">0</span>};</span><br><span class="line"> srand((<span class="keyword">unsigned</span> <span class="keyword">int</span>)time(<span class="number">0</span>));</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">1</span>; i<= MAX; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> {</span><br><span class="line"> number = rand() % (<span class="number">4</span>*MAX - <span class="number">1</span>) + <span class="number">1</span>;</span><br><span class="line"> tag = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (j = <span class="number">1</span>; j <= x[<span class="number">0</span>]; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (number == x[j])</span><br><span class="line"> {</span><br><span class="line"> tag = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (tag == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> x[<span class="number">0</span>]++;</span><br><span class="line"> x[x[<span class="number">0</span>]] = number;</span><br><span class="line"> }</span><br><span class="line"> }<span class="keyword">while</span>(tag == <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">fprintf</span>(fp, <span class="string">"(%d), "</span>, MAX);</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">1</span>; i <= x[<span class="number">0</span>]; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">fprintf</span>(fp, <span class="string">"%d, "</span>, x[i]);</span><br><span class="line"> }</span><br><span class="line"> fclose(fp);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将随机数表fp分段排序后分别写入文件[0...k-1].txt中</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Cut_Sort</span><span class="params">(FILE *fp)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> FILE *fptr;</span><br><span class="line"> <span class="keyword">int</span> i, j;</span><br><span class="line"> KeyType tmp;</span><br><span class="line"> <span class="keyword">int</span> len, m, n;</span><br><span class="line"> <span class="keyword">char</span> str1[<span class="number">100</span>], str2[<span class="number">100</span>], str3[<span class="number">100</span>] = <span class="string">".txt"</span>;</span><br><span class="line"> freadNum(fp, &len);</span><br><span class="line"> m = len / K; <span class="comment">// m为一次可以处理的最大数字的个数</span></span><br><span class="line"> n = K + (len % m != <span class="number">0</span>); <span class="comment">// n为归并段个数</span></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">vector</span><KeyType> v;</span><br><span class="line"> <span class="built_in">strcpy</span>(str1, <span class="string">"./tmpfile/"</span>);</span><br><span class="line"> <span class="built_in">sprintf</span>(str2, <span class="string">"%d"</span>, i);</span><br><span class="line"> <span class="built_in">strcat</span>(str1, <span class="built_in">strcat</span>(str2, str3));</span><br><span class="line"> fptr = fopen(str1, <span class="string">"w+"</span>);</span><br><span class="line"> <span class="keyword">for</span> (j = <span class="number">1</span>; j <= m; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (freadNum(fp, &tmp) == <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> v.push_back(tmp);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> sort(v.begin(), v.end());</span><br><span class="line"> <span class="keyword">for</span> (j = <span class="number">0</span>; j < v.size(); j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">fprintf</span>(fptr, <span class="string">"%d, "</span>, v[j]);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">fprintf</span>(fptr, <span class="string">"%d"</span>, MAXKEY);</span><br><span class="line"> fclose(fptr);</span><br><span class="line"> }</span><br><span class="line"> fclose(fp);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul></li><li><p>main.cpp</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// main.cpp</span></span><br><span class="line"><span class="comment">// LoserTree</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Created by peiyu wang on 2019/4/1.</span></span><br><span class="line"><span class="comment">// Copyright © 2019 peiyu wang. All rights reserved.</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"LoserTree.hpp"</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">const</span> <span class="keyword">char</span> * argv[])</span> </span>{</span><br><span class="line"> FILE *fp;</span><br><span class="line"> LoserTree ls;</span><br><span class="line"> External b;</span><br><span class="line"> fp = fopen(<span class="string">"test.txt"</span>, <span class="string">"w+"</span>);</span><br><span class="line"> RandomNum(fp);</span><br><span class="line"> fp = fopen(<span class="string">"test.txt"</span>, <span class="string">"r"</span>);</span><br><span class="line"> Cut_Sort(fp);</span><br><span class="line"> fp = fopen(<span class="string">"Order.txt"</span>, <span class="string">"w+"</span>);</span><br><span class="line"> K_Merge(fp, ls, b);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"END\n"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h4 id="实现效果:"><a href="#实现效果:" class="headerlink" title="实现效果:"></a>实现效果:</h4><p>(初始化的文件以及排序后的文件)<img src="https://img-blog.csdnimg.cn/20190401173256112.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlcnJ5MDUyOA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>]]></content>
<summary type="html">
<h4 id="算法概念:"><a href="#算法概念:" class="headerlink" title="算法概念:"></a>算法概念:</h4><ul>
<li>如果我们要对大规模文件进行排序,不能一次装入内存中,只能从外存一次次读取分别排序,而外存的IO时间复杂度很高,所以我们应该尽量减少针对外存读写的次数。如果我们只是简单地进行二路归并的话,归并路数越少归并的次数就越多,每次归并都要进行一次IO操作。所以我们考虑尽量进行多路归并,而多路归并不同于简单地二次归并只需对两组数进行指针移动归并,为了降低多路归并中归并的时间复杂度。我们考虑使用败者树。</li>
</ul>
</summary>
<category term="算法" scheme="http://yoursite.com/categories/%E7%AE%97%E6%B3%95/"/>
<category term="算法" scheme="http://yoursite.com/tags/%E7%AE%97%E6%B3%95/"/>
<category term="c++" scheme="http://yoursite.com/tags/c/"/>
<category term="数据结构" scheme="http://yoursite.com/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
</entry>
<entry>
<title>读入文本中的数字(忽略掉非数字的无用字符)</title>
<link href="http://yoursite.com/2019/07/10/%E8%AF%BB%E5%85%A5%E6%96%87%E6%9C%AC%E4%B8%AD%E7%9A%84%E6%95%B0%E5%AD%97-%E5%BF%BD%E7%95%A5%E6%8E%89%E9%9D%9E%E6%95%B0%E5%AD%97%E7%9A%84%E6%97%A0%E7%94%A8%E5%AD%97%E7%AC%A6/"/>
<id>http://yoursite.com/2019/07/10/读入文本中的数字-忽略掉非数字的无用字符/</id>
<published>2019-07-10T15:17:33.000Z</published>
<updated>2019-07-10T15:18:26.779Z</updated>
<content type="html"><![CDATA[<ul><li>关于读取文本发现一个贼好用的组合 getc和ungetc组合进行字符是否合法的判断。<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">freadNum</span><span class="params">(FILE *fp, <span class="keyword">int</span> *i)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> tmp;</span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> ((tmp = getc(fp)) != EOF)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> ((tmp >= <span class="string">'0'</span>&& tmp <= <span class="string">'9'</span>) || (tmp == <span class="string">'+'</span>) || (tmp == <span class="string">'-'</span>))</span><br><span class="line"> {</span><br><span class="line"> ungetc(tmp, fp);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (tmp != EOF)</span><br><span class="line"> {</span><br><span class="line"> count = <span class="built_in">fscanf</span>(fp, <span class="string">"%d"</span>, i);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> count;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><a id="more"></a><ul><li>调用函数时:<br>main.cpp<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">FILE *fp;</span><br><span class="line">fp = fopen(<span class="string">"test.txt"</span>,<span class="string">"r"</span>);</span><br><span class="line"><span class="keyword">while</span> (freadNum(fp, &i))</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d"</span>, i);</span><br><span class="line">}</span><br><span class="line">fclose(fp);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<summary type="html">
<ul>
<li>关于读取文本发现一个贼好用的组合 getc和ungetc组合进行字符是否合法的判断。<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">freadNum</span><span class="params">(FILE *fp, <span class="keyword">int</span> *i)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"> <span class="keyword">int</span> tmp;</span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> ((tmp = getc(fp)) != EOF)</span><br><span class="line"> &#123;</span><br><span class="line"> <span class="keyword">if</span> ((tmp &gt;= <span class="string">'0'</span>&amp;&amp; tmp &lt;= <span class="string">'9'</span>) || (tmp == <span class="string">'+'</span>) || (tmp == <span class="string">'-'</span>))</span><br><span class="line"> &#123;</span><br><span class="line"> ungetc(tmp, fp);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> (tmp != EOF)</span><br><span class="line"> &#123;</span><br><span class="line"> count = <span class="built_in">fscanf</span>(fp, <span class="string">"%d"</span>, i);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> count;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
</summary>
<category term="c" scheme="http://yoursite.com/categories/c/"/>
<category term="c" scheme="http://yoursite.com/tags/c/"/>
</entry>
<entry>
<title>c++实现各种经典内部排序</title>
<link href="http://yoursite.com/2019/07/10/c-%E5%AE%9E%E7%8E%B0%E5%90%84%E7%A7%8D%E7%BB%8F%E5%85%B8%E5%86%85%E9%83%A8%E6%8E%92%E5%BA%8F/"/>
<id>http://yoursite.com/2019/07/10/c-实现各种经典内部排序/</id>
<published>2019-07-10T15:15:59.000Z</published>
<updated>2019-07-10T15:16:55.059Z</updated>
<content type="html"><![CDATA[<h4 id="经典的排序算法如下:"><a href="#经典的排序算法如下:" class="headerlink" title="经典的排序算法如下:"></a>经典的排序算法如下:</h4><ul><li>插入排序<ul><li>直接插入排序</li><li>折半插入排序</li><li>希尔排序</li></ul></li><li>交换排序<ul><li>冒泡排序</li><li>鸡尾酒排序(双向冒泡)</li><li>快速排序</li></ul></li><li>选择排序<ul><li>简单选择排序 </li><li>堆排序</li></ul></li><li>归并排序</li><li>基数排序 / 桶排序</li></ul><a id="more"></a><h4 id="代码实现:"><a href="#代码实现:" class="headerlink" title="代码实现:"></a>代码实现:</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// main.cpp</span></span><br><span class="line"><span class="comment">// sort</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Created by peiyu wang on 2019/3/28.</span></span><br><span class="line"><span class="comment">// Copyright © 2019 peiyu wang. All rights reserved.</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><ctime></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cstdlib></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="built_in">vector</span><<span class="keyword">int</span>> dlta = {<span class="number">7</span>, <span class="number">5</span>, <span class="number">3</span>, <span class="number">1</span>};</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 插入排序 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 直接插入排序</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">InsertSort</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">2</span>; i < v.size(); i++)</span><br><span class="line"> {</span><br><span class="line"> v[<span class="number">0</span>] = v[i];</span><br><span class="line"> <span class="keyword">int</span> j = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (j = i - <span class="number">1</span>; v[<span class="number">0</span>] < v[j] ;j--)</span><br><span class="line"> {</span><br><span class="line"> v[j+<span class="number">1</span>] = v[j];</span><br><span class="line"> }</span><br><span class="line"> v[j+<span class="number">1</span>] = v[<span class="number">0</span>];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 折半插入排序</span></span><br><span class="line"><span class="comment">// 在排好序的位置进行折半查找</span></span><br><span class="line"><span class="comment">// 减少了关键字的比较次数,可是移动的时间复杂度不变,所以仍为N*N</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Binary_InsertSort</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">2</span>; i < v.size(); i++)</span><br><span class="line"> {</span><br><span class="line"> v[<span class="number">0</span>] = v[i];</span><br><span class="line"> <span class="keyword">int</span> low = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> high = i - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> mid = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (low <= high)</span><br><span class="line"> {</span><br><span class="line"> mid = (low + high) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (v[mid] > v[<span class="number">0</span>])</span><br><span class="line"> {</span><br><span class="line"> high = mid - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> low = mid + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i - <span class="number">1</span>; j >= low; j--)</span><br><span class="line"> {</span><br><span class="line"> v[j+<span class="number">1</span>] = v[j];</span><br><span class="line"> }</span><br><span class="line"> v[low] = v[<span class="number">0</span>];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Shell_Insert</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v, <span class="keyword">int</span> dx)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (i = dx + <span class="number">1</span>; i < v.size(); i++)</span><br><span class="line"> {</span><br><span class="line"> v[<span class="number">0</span>] = v[i];</span><br><span class="line"> <span class="keyword">int</span> j = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (j = i - dx; j > <span class="number">0</span> && v[j] > v[<span class="number">0</span>] ;j -= dx)</span><br><span class="line"> {</span><br><span class="line"> v[j + dx] = v[j];</span><br><span class="line"> }</span><br><span class="line"> v[j + dx] = v[<span class="number">0</span>];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 希尔排序</span></span><br><span class="line"><span class="comment">// 缩小增量的方法进行排序</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Shell_Sort</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < dlta.size(); i++)</span><br><span class="line"> {</span><br><span class="line"> Shell_Insert(v, dlta[i]);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 交换排序 */</span></span><br><span class="line"><span class="comment">// 冒泡排序</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">BubbleSort</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="keyword">int</span>(v.size()) - <span class="number">1</span>; i >= <span class="number">2</span>; i--)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j < i; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (v[j] > v[j+<span class="number">1</span>])</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> tmp = v[j];</span><br><span class="line"> v[j] = v[j+<span class="number">1</span>];</span><br><span class="line"> v[j+<span class="number">1</span>] = tmp;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 快速排序</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">QuickSort</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v, <span class="keyword">int</span> low, <span class="keyword">int</span> high)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> min = low;</span><br><span class="line"> <span class="keyword">int</span> max = high;</span><br><span class="line"> v[<span class="number">0</span>] = v[low];</span><br><span class="line"> <span class="keyword">while</span> (low < high)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">while</span> (v[high] >= v[<span class="number">0</span>] && low < high)</span><br><span class="line"> {</span><br><span class="line"> high--;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span> (v[low] <= v[<span class="number">0</span>] && low < high)</span><br><span class="line"> {</span><br><span class="line"> low++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> tmp = v[low];</span><br><span class="line"> v[low] = v[high];</span><br><span class="line"> v[high] = tmp;</span><br><span class="line"> }</span><br><span class="line"> v[min] = v[low];</span><br><span class="line"> v[low] = v[<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">if</span> (low > <span class="number">1</span> + min)</span><br><span class="line"> QuickSort(v, min, low - <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (low < max - <span class="number">1</span>)</span><br><span class="line"> QuickSort(v, low + <span class="number">1</span>, max);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 鸡尾酒排序</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">CockTailSort</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="keyword">int</span>(v.size()) - <span class="number">1</span>; i >= (<span class="keyword">int</span>(v.size()) - <span class="number">1</span>) / <span class="number">2</span>; i--)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="keyword">int</span>(v.size()) - i; j < i; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (v[j] > v[j+<span class="number">1</span>])</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> tmp = v[j];</span><br><span class="line"> v[j] = v[j+<span class="number">1</span>];</span><br><span class="line"> v[j+<span class="number">1</span>] = tmp;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i; j > <span class="keyword">int</span>(v.size()) - i; j--)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (v[j] < v[j - <span class="number">1</span>])</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> tmp = v[j];</span><br><span class="line"> v[j] = v[j - <span class="number">1</span>];</span><br><span class="line"> v[j - <span class="number">1</span>] = tmp;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 选择排序 */</span></span><br><span class="line"><span class="comment">// 堆排序</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">CreateHeap</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v, <span class="keyword">int</span> root, <span class="keyword">int</span> max)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> t_max = v[root];</span><br><span class="line"> <span class="keyword">int</span> t_num = root;</span><br><span class="line"> <span class="keyword">if</span> (<span class="number">2</span> * root <= max)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (v[<span class="number">2</span> * root] > t_max)</span><br><span class="line"> {</span><br><span class="line"> t_num = <span class="number">2</span> * root;</span><br><span class="line"> t_max = v[t_num];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="number">2</span> * root + <span class="number">1</span> <= max && v[<span class="number">2</span> * root + <span class="number">1</span>] > t_max)</span><br><span class="line"> {</span><br><span class="line"> t_num = <span class="number">2</span> * root + <span class="number">1</span>;</span><br><span class="line"> t_max = v[t_num];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (t_num != root)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> tmp = v[root];</span><br><span class="line"> v[root] = t_max;</span><br><span class="line"> v[t_num] = tmp;</span><br><span class="line"> CreateHeap(v, t_num, max);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">HeapSort</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = (<span class="keyword">int</span>(v.size()) - <span class="number">1</span>) / <span class="number">2</span>; i >= <span class="number">1</span>; i--)</span><br><span class="line"> {</span><br><span class="line"> CreateHeap(v, i, <span class="keyword">int</span>(v.size()) - <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < <span class="keyword">int</span>(v.size()) - <span class="number">1</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> max = <span class="keyword">int</span>(v.size()) - i;</span><br><span class="line"> <span class="keyword">int</span> tmp = v[<span class="number">1</span>];</span><br><span class="line"> v[<span class="number">1</span>] = v[max];</span><br><span class="line"> v[max] = tmp;</span><br><span class="line"> CreateHeap(v, <span class="number">1</span> , max - <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 归并排序</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Merge</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v, <span class="keyword">int</span> low, <span class="keyword">int</span> high)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (low != high)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> mid = (low + high) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">int</span> i = low;</span><br><span class="line"> <span class="keyword">int</span> j = mid + <span class="number">1</span>;</span><br><span class="line"> <span class="built_in">vector</span><<span class="keyword">int</span>> v0;</span><br><span class="line"> <span class="keyword">while</span> (i <= mid && j <= high)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (v[i] > v[j])</span><br><span class="line"> {</span><br><span class="line"> v0.push_back(v[j]);</span><br><span class="line"> j++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> v0.push_back(v[i]);</span><br><span class="line"> i++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span> (i <= mid)</span><br><span class="line"> {</span><br><span class="line"> v0.push_back(v[i]);</span><br><span class="line"> i++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span> (j <= high)</span><br><span class="line"> {</span><br><span class="line"> v0.push_back(v[j]);</span><br><span class="line"> j++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">0</span>; k < high - low + <span class="number">1</span>; k++)</span><br><span class="line"> {</span><br><span class="line"> v[k + low] = v0[k];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">MergeSort</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &v, <span class="keyword">int</span> low, <span class="keyword">int</span> high)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (low != high)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> mid = (low + high) / <span class="number">2</span>;</span><br><span class="line"> <span class="comment">// 左边归并排序</span></span><br><span class="line"> MergeSort(v, low, mid);</span><br><span class="line"> <span class="comment">// 右边归并排序</span></span><br><span class="line"> MergeSort(v, mid + <span class="number">1</span>, high);</span><br><span class="line"> <span class="comment">// 左右归并</span></span><br><span class="line"> Merge(v, low, high);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">const</span> <span class="keyword">char</span> * argv[])</span> </span>{</span><br><span class="line"> <span class="comment">// insert code here...</span></span><br><span class="line"> srand(<span class="keyword">int</span>(time(<span class="number">0</span>)));</span><br><span class="line"> <span class="built_in">vector</span><<span class="keyword">int</span>> n;</span><br><span class="line"> <span class="keyword">int</span> num = <span class="number">0</span>, min = <span class="number">0</span>, max = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">cout</span> << <span class="string">"请输入你想排序的列表元素个数:"</span> << <span class="built_in">endl</span>;</span><br><span class="line"> <span class="built_in">cin</span> >> num;</span><br><span class="line"> n.push_back(<span class="number">0</span>);</span><br><span class="line"> <span class="built_in">cout</span> << <span class="string">"请输入你想产生的随机数的范围:"</span> << <span class="built_in">endl</span>;</span><br><span class="line"> <span class="built_in">cout</span> << <span class="string">"请输入最小值:"</span> << <span class="built_in">endl</span>;</span><br><span class="line"> <span class="built_in">cin</span> >> min;</span><br><span class="line"> <span class="built_in">cout</span> << <span class="string">"请输入最大值:"</span> << <span class="built_in">endl</span>;</span><br><span class="line"> <span class="built_in">cin</span> >> max;</span><br><span class="line"> <span class="keyword">while</span> (num--)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> tmp;</span><br><span class="line"> tmp = rand() % (max - min + <span class="number">1</span>) + min;</span><br><span class="line"> n.push_back(tmp);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">cout</span> << <span class="string">"随机产生的数组为:"</span> << <span class="built_in">endl</span>;</span><br><span class="line"> ostream_iterator<<span class="keyword">int</span>> out(<span class="built_in">cout</span>, <span class="string">" "</span>);</span><br><span class="line"> copy(n.begin() + <span class="number">1</span>, n.end(), out);</span><br><span class="line"> <span class="built_in">cout</span> << <span class="built_in">endl</span>;</span><br><span class="line"> <span class="comment">//Shell_Sort(n);</span></span><br><span class="line"> <span class="comment">//QuickSort(n, 1, int(n.size()) - 1);</span></span><br><span class="line"> <span class="comment">//HeapSort(n);</span></span><br><span class="line"> <span class="comment">//CockTailSort(n);</span></span><br><span class="line"> MergeSort(n, <span class="number">1</span>, <span class="keyword">int</span>(n.size()) - <span class="number">1</span>);</span><br><span class="line"> <span class="comment">//ostream_iterator<int> out(cout, " ");</span></span><br><span class="line"> <span class="built_in">cout</span> << <span class="string">"排序后的数组是:"</span> << <span class="built_in">endl</span>;</span><br><span class="line"> copy(n.begin() + <span class="number">1</span>, n.end(), out);</span><br><span class="line"> <span class="built_in">cout</span> << <span class="built_in">endl</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h4 id="经典的排序算法如下:"><a href="#经典的排序算法如下:" class="headerlink" title="经典的排序算法如下:"></a>经典的排序算法如下:</h4><ul>
<li>插入排序<ul>
<li>直接插入排序</li>
<li>折半插入排序</li>
<li>希尔排序</li>
</ul>
</li>
<li>交换排序<ul>
<li>冒泡排序</li>
<li>鸡尾酒排序(双向冒泡)</li>
<li>快速排序</li>
</ul>
</li>
<li>选择排序<ul>
<li>简单选择排序 </li>
<li>堆排序</li>
</ul>
</li>
<li>归并排序</li>
<li>基数排序 / 桶排序</li>
</ul>
</summary>
<category term="数据结构" scheme="http://yoursite.com/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
<category term="算法" scheme="http://yoursite.com/tags/%E7%AE%97%E6%B3%95/"/>
<category term="c++" scheme="http://yoursite.com/tags/c/"/>
<category term="数据结构" scheme="http://yoursite.com/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
</entry>
</feed>