-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1172 lines (719 loc) · 202 KB
/
index.html
File metadata and controls
1172 lines (719 loc) · 202 KB
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
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html class="theme-next mist use-motion">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link href="/vendors/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
<link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
<link href="/vendors/font-awesome/css/font-awesome.min.css?v=4.4.0" rel="stylesheet" type="text/css" />
<link href="/css/main.css?v=5.0.1" rel="stylesheet" type="text/css" />
<meta name="keywords" content="Hexo, NexT" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.0.1" />
<meta name="description" content="Mkil 蚂蚁">
<meta property="og:type" content="website">
<meta property="og:title" content="Mkil-小蚂蚁">
<meta property="og:url" content="http://mkiltech.com/index.html">
<meta property="og:site_name" content="Mkil-小蚂蚁">
<meta property="og:description" content="Mkil 蚂蚁">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Mkil-小蚂蚁">
<meta name="twitter:description" content="Mkil 蚂蚁">
<script type="text/javascript" id="hexo.configuration">
var NexT = window.NexT || {};
var CONFIG = {
scheme: 'Mist',
sidebar: {"position":"left","display":"post"},
fancybox: true,
motion: true,
duoshuo: {
userId: 6328495837512992000,
author: 'Author'
}
};
</script>
<link rel="canonical" href="http://mkiltech.com/"/>
<title> Mkil-小蚂蚁 </title>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container one-collumn sidebar-position-left
page-home
">
<div class="headband"></div>
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">Mkil-小蚂蚁</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle"></p>
</div>
<div class="site-nav-toggle">
<button>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br />
首页
</a>
</li>
<li class="menu-item menu-item-categories">
<a href="/categories" rel="section">
<i class="menu-item-icon fa fa-fw fa-th"></i> <br />
分类
</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
归档
</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags" rel="section">
<i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
标签
</a>
</li>
</ul>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/blog/2016/09/gcd-advanced.html" itemprop="url">
Parse的底层多线程处理思路:GCD高级用法
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2016-09-27T19:21:50+08:00" content="2016-09-27">
2016-09-27
</time>
</span>
<span class="post-comments-count">
|
<a href="/blog/2016/09/gcd-advanced.html#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="/blog/2016/09/gcd-advanced.html" itemprop="commentsCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>【前言】从iOS7升到iOS8后,GCD 出现了一个重大的变化:在 iOS7 时,使用 GCD 的并行队列, <code>dispatch_async</code> 最大开启的线程一直能控制在6、7条,线程数都是个位数,然而 iOS8后,最大线程数一度可以达到40条、50条。然而在文档上并没有对这一做法的目的进行介绍。</p>
<p>笔者推测 Apple 的目的是想借此让开发者使用 <code>NSOperationQueue</code> :GCD 中 Apple 并没有提供控制并发数量的接口,而 <code>NSOperationQueue</code> 有。GCD 没有提供暂停、恢复、取消队列任务的接口,而 <code>NSOperationQueue</code> 有,如果想让 GCD 支持 <code>NSOperationQueue</code> 原生就支持的功能,需要使用许多GCD 的高级功能,大大提高了使用的难度。</p>
<p> <code>Apple</code> 始终有一个观念:尽可能选用高层 API,只在确有必要时才求助于底层。然而开发者并不买账,在我进行的一次 <a href="http://weibo.com/1692391497/D1pKjqaiW?type=comment" target="_blank" rel="external">调查</a> 中发现了一个有趣的现象:</p>
<p>大概 80%的iOS 开发者会支持使用 GCD 来完成操作队列的实现,而且有 60% 的开发已经在项目中使用。</p>
<p><img src="http://i65.tinypic.com/2vj1md2.jpg" alt="enter image description here"></p>
<p>更是有人这样表态:</p>
<p>假如不让他用 GCD:</p>
<p><img src="http://i66.tinypic.com/34g8qd1.jpg" alt="enter image description here"></p>
<p>这种现象一直存在,包括 ARC 与 MRC、SB建 UI 与纯代码建 UI、SQL 与 CoreData的争论。</p>
<p>但是因为是源码解析的文章,而 Parse 的 SDK 没有用一句的 NSOperation 的代码,GCD 一路用到底,让我也十分震惊。只能说明,写 <code>Parse</code> 的这位开发者是艺高人胆大。而且既然 <code>GCD</code> 的支持者如此之多,那么就谈一谈如何让 GCD 能支持 <code>NSOperationQueue</code> 原生就支持的功能。</p>
<p>今天虽然谈了NSOperation原生功能的 GCD 版本实现,但并不代表我支持像 Parse 这样 GCD 一路用到底。 业内一般的看法是这样的:</p>
<blockquote>
<p> <code>GCD</code> 虽然能够实现暂停和终止,但开发还是灵活些好,那些 <code>NSOperation</code> 用起来方便的就直接用 <code>NSOperation</code> 的方式,不然苹果多包那一层不是蛋疼,包括文章里提到的 <code>iOS8</code> 后控制线程数的问题,不一定项目就一定要GCD一路到底。有时候需要支持一些高层级封装功能比如: <code>KVO</code> 时 <code>NSOperation</code> 还是有它的优势的。 <code>GCD</code> 反而是处理些比较简单的操作或者是较系统级的比如:监视进程或者监视文件夹内文件的变化之类的比较合适。</p>
</blockquote>
<p>第一篇的目的是通过解读 Parse 源码来展示GCD两个高级用法: <code>Dispatch Source</code> (派发源)和 <code>Dispatch Semaphore</code> (信号量)。首先通过Parse 的“离线存储对象”操作,来介绍 <code>Dispatch Source</code> (派发源);然后通过Parse 的单元测试中使用的技巧“强制把异步任务转换为同步任务来方便进行单元测试”来介绍<code>Dispatch Semaphore</code> (信号量)。我已将思路浓缩为可运行的7个 Demo 中,详见仓库里的 Demo1到 Demo7。</p>
<p>如果对 GCD 不太熟悉,请先读下<a href="http://mkiltech.com/blog/2016/09/gcd-base.html">《GCD 基础篇》</a>。</p>
<h2 id="Parse-iOS-SDK介绍"><a href="#Parse-iOS-SDK介绍" class="headerlink" title="Parse-iOS-SDK介绍"></a>Parse-iOS-SDK介绍</h2><p> <a href="http://www.infoq.com/cn/news/2015/08/ios-weekly-ios841#rd" target="_blank" rel="external">《iOS开发周报:iOS 8.4.1 发布,iOS 8 时代谢幕》</a> 对 Facebook 旗下的 Parse有这样一段介绍:</p>
<blockquote>
<p>Parse-SDK-iOS-OSX:著名的 BaaS 公司 Parse 最近开源了它们的 iOS/OSX SDK。Parse 的服务虽然在国内可能访问速度不是很理想,但是它们在服务的稳定性和 SDK 质量上一直有非常优异的表现。此次开源的 SDK 对于日常工作是 SDK 开发的开发者来说,是一个难得的学习机会。Parse 的存取操作涉及到很多多线程的问题,从 Parse SDK 的源代码中可以看出,这个 SDK 的开发者对 iOS 开发多线程有着非常深厚的理解和功底,让人叹服。我个人推荐对此感兴趣的朋友可以尝试从阅读 internal 文件夹下的两个EventuallyQueue 文件开始着手,研究下 Parse 的底层多线程处理思路。</p>
</blockquote>
<p>类似的服务:<br> Apple 的 <a href="http://nshipster.cn/cloudkit/" target="_blank" rel="external">CloudKit</a> 、 国内的 <a href="https://leancloud.cn/?source=T6M35E4H" target="_blank" rel="external">LeanCloud(原名 <code>AVOS</code> )</a> 。</p>
<h2 id="Parse-的“离线存储对象”操作介绍"><a href="#Parse-的“离线存储对象”操作介绍" class="headerlink" title="Parse 的“离线存储对象”操作介绍"></a>Parse 的“离线存储对象”操作介绍</h2><p>大多数保存功能可以立刻执行,并通知应用“保存完毕”。不过若不需要知道保存完成的时间,则可使用“离线存储对象”操作(saveEventually 或 deleteEventually) 来代替,也就是:</p>
<p>如果用户目前尚未接入网络,“离线存储对象”操作(saveEventually 或 deleteEventually) 会缓存设备中的数据,并在网络连接恢复后上传。如果应用在网络恢复之前就被关闭了,那么当它下一次打开时,SDK 会自动再次尝试保存操作。</p>
<p>所有 saveEventually(或 deleteEventually)的相关调用,将按照调用的顺序依次执行。因此,多次对某一对象使用 saveEventually 是安全的。</p>
<p>国内的 <a href="https://leancloud.cn/?source=T6M35E4H" target="_blank" rel="external">LeanCloud(原名 <code>AVOS</code> )</a> 也提供了相同的功能,所以以上《Parse 的“离线存储对象”操作介绍》部分完全摘录自 LeanCloud 的文档。详见<a href="https://leancloud.cn/docs/ios_os_x_guide.html#离线存储对象" target="_blank" rel="external">《LeanCloud官方文档-iOS / OS X 数据存储开发指南–离线存储对象》</a> </p>
<p>(利益相关声明:本人目前就职于 <a href="https://leancloud.cn/?source=T6M35E4H" target="_blank" rel="external">LeanCloud(原名 <code>AVOS</code> )</a> )</p>
<h2 id="Parse-的“离线存储对象”实现介绍"><a href="#Parse-的“离线存储对象”实现介绍" class="headerlink" title="Parse 的“离线存储对象”实现介绍"></a>Parse 的“离线存储对象”实现介绍</h2><p>Parse 的“离线存储对象”操作(saveEventually 或 deleteEventually) 是通过 GCD 的 <code>Dispatch Source</code> (信号源)来实现的。下面对 <code>Dispatch Source</code> (信号源)进行一下介绍:</p>
<p>GCD中除了主要的 <code>Dispatch Queue</code> 外,还有不太引人注目的 <code>Dispatch Source</code> .它是BSD系内核惯有功能kqueue的包装。kqueue 是在 XNU 内核中发生各种事件时,在应用程序编程方执行处理的技术。其 CPU 负荷非常小,尽量不占用资源。kqueue 可以说是应用程序处理 XNU 内核中发生的各种事件的方法中最优秀的一种。</p>
<p> <code>Dispatch Source</code> 也使用在了 Core Foundation 框架的用于异步网络的API <code>CFSocket</code> 中。因为Foundation 框架的异步网络 API 是通过CFSocket实现的,所以可享受到仅使用 Foundation 框架的 <code>Dispatch Source</code> 带来的好处。</p>
<p>那么优势何在?使用的 <code>Dispatch Source</code> 而不使用 <code>dispatch_async</code> 的唯一原因就是利用联结的优势。</p>
<p>联结的大致流程:在任一线程上调用它的的一个函数 <code>dispatch_source_merge_data</code> 后,会执行 <code>Dispatch Source</code> 事先定义好的句柄(可以把句柄简单理解为一个 block )。</p>
<p>这个过程叫 <code>Custom event</code> ,用户事件。是 dispatch source 支持处理的一种事件。</p>
<blockquote>
<p>简单地说,这种事件是由你调用 <code>dispatch_source_merge_data</code> 函数来向自己发出的信号。</p>
</blockquote>
<p>下面介绍下使用步骤:</p>
<h2 id="Dispatch-Source-的使用步骤"><a href="#Dispatch-Source-的使用步骤" class="headerlink" title="Dispatch Source 的使用步骤"></a><code>Dispatch Source</code> 的使用步骤</h2><h3 id="第一步:创建一个Dispatch-Source"><a href="#第一步:创建一个Dispatch-Source" class="headerlink" title="第一步:创建一个Dispatch Source"></a>第一步:创建一个<code>Dispatch Source</code></h3> <figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 详见 Demo1、Demo2</span></div><div class="line"><span class="comment">// 指定DISPATCH_SOURCE_TYPE_DATA_ADD,做成Dispatch Source(分派源)。设定Main Dispatch Queue 为追加处理的Dispatch Queue</span></div><div class="line">_processingQueueSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, <span class="number">0</span>, <span class="number">0</span>,</div><div class="line"> dispatch_get_main_queue());</div></pre></td></tr></table></figure>
<p>下面对参数进行下解释:</p>
<p>其中自定义源累积事件中传递过来的值,累积的方式可以是相加的,正如上面代码中的 <code>DISPATCH_SOURCE_TYPE_DATA_ADD</code> ,也可以是逻辑或 <code>DISPATCH_SOURCE_TYPE_DATA_OR</code> 。这是最常见的两个 <code>Dispatch Source</code> 可以处理的事件。</p>
<p><code>Dispatch Source</code> 可处理的所有事件。如下表所示:</p>
<table>
<thead>
<tr>
<th></th>
<th>名称</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_DATA_ADD</code></td>
<td>变量增加</td>
</tr>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_DATA_OR</code></td>
<td>变量OR</td>
</tr>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_MACH_SEND</code></td>
<td>MACH端口发送</td>
</tr>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_MACH_RECV</code></td>
<td>MACH端口接收</td>
</tr>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_PROC</code></td>
<td>监测到与进程相关的事件</td>
</tr>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_READ</code></td>
<td>可读取文件映像</td>
</tr>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_SIGNAL</code></td>
<td>接收信号</td>
</tr>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_TIMER</code></td>
<td>定时器</td>
</tr>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_VNODE</code></td>
<td>文件系统有变更</td>
</tr>
<tr>
<td> <code>DISPATCH_SOURCE_TYPE_WRITE</code></td>
<td>可写入文件映像</td>
</tr>
</tbody>
</table>
<p>自定义源也需要一个队列,用来处理所有的响应句柄(block)。那么岂不是有两个队列了?没错,至于 <code>Dispatch Queue</code> 这个队列的线程执行与 <code>Dispatch Source</code>这个队列的线程执行的关系,下文会结合 Demo1和 Demo2进行详细论述。</p>
<h3 id="第二步:创建Dispatch-Source的事件处理方法"><a href="#第二步:创建Dispatch-Source的事件处理方法" class="headerlink" title="第二步:创建Dispatch Source的事件处理方法"></a>第二步:创建<code>Dispatch Source</code>的事件处理方法</h3><p>分派源提供了高效的方式来处理事件。首先注册事件处理程序,事件发生时会收到通知。如果在系统还没有来得及通知你之前事件就发生了多次,那么这些事件会被合并为一个事件。这对于底层的高性能代码很有用,但是OS应用开发者很少会用到这样的功能。类似地,分派源可以响应UNIX信号、文件系统的变化、其他进程的变化以及Mach Port事件。它们中很多都在Mac系统上很有用,但是iOS开发者通常不会用到。</p>
<p>不过,自定义源在iOS中很有用,尤其是在性能至关重要的场合进行进度反馈。如下所示,首先创建一个源:自定义源累积事件中传递过来的值。累积方式可以是相加( DISPATCH_SOURCE_TYPE_DATA_ADD ),<br>也可以是逻辑或( DISPATCH_SOURCE_DATA_OR )。自定义源也需要一个队列,用来处理所有的响应处理块。</p>
<p>创建源后,需要提供相应的处理方法。当源生效时会分派注册处理方法;当事件发生时会分派事件处理方法;当源被取消时会分派取消处理方法。自定义源通常只需要一个事件处理方法,可以像这样创建:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">/*</span></div><div class="line"> *省略部分: </div><div class="line"> 指定DISPATCH_SOURCE_TYPE_DATA_ADD,做成Dispatch Source(分派源)。设定Main Dispatch Queue 为追加处理的Dispatch Queue</div><div class="line"> 详见Demo1、Demo2</div><div class="line"> *</div><div class="line"> */</div><div class="line"> __block <span class="built_in">NSUInteger</span> totalComplete = <span class="number">0</span>;</div><div class="line"> dispatch_source_set_event_handler(_processingQueueSource, ^{</div><div class="line"> <span class="comment">//当处理事件被最终执行时,计算后的数据可以通过dispatch_source_get_data来获取。这个数据的值在每次响应事件执行后会被重置,所以totalComplete的值是最终累积的值。</span></div><div class="line"> <span class="built_in">NSUInteger</span> value = dispatch_source_get_data(_processingQueueSource);</div><div class="line"> totalComplete += value;</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"进度:%@"</span>, @((<span class="built_in">CGFloat</span>)totalComplete/<span class="number">100</span>));</div><div class="line"> });</div></pre></td></tr></table></figure>
<p>在同一时间,只有一个处理方法块的实例被分派。如果这个处理方法还没有执行完毕,另一个事件就发生了,事件会以指定方式(ADD或者OR)进行累积。通过合并事件的方式,系统即使在高负<br>载情况下也能正常工作。当处理事件件被最终执行时,计算后的数据可以通过 <code>dispatch_source_get_data</code> 来获取。这个数据的值在每次响应事件执行后会被重置,所以上面例子中 <code>totalComplete</code> 的值是最终累积的值。</p>
<h3 id="第三步:处理Dispatch-Source的暂停与恢复操作"><a href="#第三步:处理Dispatch-Source的暂停与恢复操作" class="headerlink" title="第三步:处理Dispatch Source的暂停与恢复操作"></a>第三步:处理<code>Dispatch Source</code>的暂停与恢复操作</h3><p>当追加大量处理到Dispatch Queue时,在追加处理的过程中,有时希望不执行已追加的处理。例如演算结果被Block截获时,一些处理会对这个演算结果造成影响。</p>
<p>在这种情况下,只要挂起Dispatch Queue即可。当可以执行时再恢复。</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">dispatch_suspend(queue);</div></pre></td></tr></table></figure>
<p> <code>dispatch_resume</code> 函数恢复指定的 <code>Dispatch Queue</code> .<br>这些函数对已经执行的处理没有影响。挂起后,追加到 <code>Dispatch Queue</code> 中但尚未执行的处理在此之后停止执行。而恢复则使得这些处理能够继续执行。</p>
<p>分派源创建时默认处于暂停状态,在分派源分派处理程序之前必须先恢复。因为忘记恢复分派源的状态而产生bug是常见的事儿。恢复的方法是调用 <code>dispatch_resume</code> :</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">dispatch_resume (source);</div></pre></td></tr></table></figure>
<p>为了方便理解 <code>dispatch_suspend</code> 函数的作用,这里提供一个 Demo:Demo3, 看下运行效果:</p>
<p>思考下NSLog的打印顺序为什么会是这样?</p>
<p>详见 Demo3(Demo<em>03</em>对DispatchQueue实现取消恢复操作_简单版):</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)viewDidLoad {</div><div class="line"> [<span class="keyword">super</span> viewDidLoad];</div><div class="line"> </div><div class="line"> <span class="built_in">dispatch_queue_t</span> queue1 = dispatch_queue_create(<span class="string">"com.iOSChengXuYuan.queue1"</span>, <span class="number">0</span>);</div><div class="line"> <span class="built_in">dispatch_queue_t</span> queue2 = dispatch_queue_create(<span class="string">"com.iOSChengXuYuan.queue2"</span>, <span class="number">0</span>);</div><div class="line"> dispatch_group_t group = dispatch_group_create();</div><div class="line"> </div><div class="line"> <span class="built_in">dispatch_async</span>(queue1, ^{</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"任务 1 : queue 1..."</span>);</div><div class="line"> sleep(<span class="number">1</span>);</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"✅完成任务 1"</span>);</div><div class="line"> });</div><div class="line"> </div><div class="line"> <span class="built_in">dispatch_async</span>(queue2, ^{</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"任务 1 : queue 2..."</span>);</div><div class="line"> sleep(<span class="number">1</span>);</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"✅完成任务 2"</span>);</div><div class="line"> });</div><div class="line"> </div><div class="line"> dispatch_group_async(group, queue1, ^{</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🚫正在暂停 1"</span>);</div><div class="line"> dispatch_suspend(queue1);</div><div class="line"> });</div><div class="line"> dispatch_group_async(group, queue2, ^{</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🚫正在暂停 2"</span>);</div><div class="line"> dispatch_suspend(queue2);</div><div class="line"> });</div><div class="line"> </div><div class="line"> dispatch_group_wait(group, DISPATCH_TIME_FOREVER);</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"=======等待两个queue完成, 再往下进行..."</span>);</div><div class="line"> <span class="built_in">dispatch_async</span>(queue1, ^{</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"任务 2 : queue 1"</span>);</div><div class="line"> });</div><div class="line"> <span class="built_in">dispatch_async</span>(queue2, ^{</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"任务 2 : queue 2"</span>);</div><div class="line"> });</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🔴为什么这个NSLog会在上面两个NSLog之前打印❓❓答:dispatch_suspend的作用‼️"</span>);</div><div class="line"> </div><div class="line"> dispatch_resume(queue1);</div><div class="line"> dispatch_resume(queue2);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>打印:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">44</span>:<span class="number">59.614</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116662</span>] 任务 <span class="number">1</span> : queue <span class="number">2.</span>..</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">44</span>:<span class="number">59.613</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116665</span>] 任务 <span class="number">1</span> : queue <span class="number">1.</span>..</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">45</span>:<span class="number">00.614</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116665</span>] ✅完成任务 <span class="number">1</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">45</span>:<span class="number">00.614</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116662</span>] ✅完成任务 <span class="number">2</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">45</span>:<span class="number">00.616</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116662</span>] 🚫正在暂停 <span class="number">2</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">45</span>:<span class="number">00.615</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116665</span>] 🚫正在暂停 <span class="number">1</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">45</span>:<span class="number">00.616</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116515</span>] =======等待两个queue完成, 再往下进行...</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">45</span>:<span class="number">00.616</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116515</span>] 🔴为什么这个<span class="built_in">NSLog</span>会在上面两个<span class="built_in">NSLog</span>之前打印❓❓答:dispatch_suspend的作用‼️</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">45</span>:<span class="number">00.617</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116665</span>] 任务 <span class="number">2</span> : queue <span class="number">1</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-06</span> <span class="number">02</span>:<span class="number">45</span>:<span class="number">00.619</span> CYLDispatchQueueSuspendTest[<span class="number">1610</span>:<span class="number">116665</span>] 任务 <span class="number">2</span> : queue <span class="number">2</span></div></pre></td></tr></table></figure>
<p>思考下NSLog的打印顺序为什么会是这样?答:dispatch_suspend的作用!</p>
<p>详见 Demo3(Demo<em>03</em>对DispatchQueue实现取消恢复操作_简单版)。</p>
<h3 id="第四步:向Dispatch-Source发送事件"><a href="#第四步:向Dispatch-Source发送事件" class="headerlink" title="第四步:向Dispatch Source发送事件"></a>第四步:向<code>Dispatch Source</code>发送事件</h3><p>恢复源后,就可以像下面的代码片段这样,通过 <code>dispatch_source_merge_data</code> 向分派源发送事件:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//2.</span></div><div class="line"><span class="comment">//恢复源后,就可以通过dispatch_source_merge_data向Dispatch Source(分派源)发送事件:</span></div><div class="line"><span class="comment">//详见Demo1、Demo2</span></div><div class="line"><span class="built_in">dispatch_queue_t</span> queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</div><div class="line"> <span class="keyword">for</span> (<span class="built_in">NSUInteger</span> index = <span class="number">0</span>; index < <span class="number">100</span>; index++) {</div><div class="line"> <span class="built_in">dispatch_async</span>(queue, ^{</div><div class="line"> dispatch_source_merge_data(_processingQueueSource, <span class="number">1</span>);</div><div class="line"> usleep(<span class="number">20000</span>);<span class="comment">//0.02秒</span></div><div class="line"> });</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>上面代码在每次循环中执行加1操作。也可以传递已处理记录的数目或已写入的字节数。在任何线程中都可以调用 <code>dispatch_source_merge_data</code> 。需要注意的是,不可以传递0值(事件不会被触发),同样也不可以传递负数。</p>
<h1 id="GCD真的不能像OperationQueue那样终止任务?"><a href="#GCD真的不能像OperationQueue那样终止任务?" class="headerlink" title="GCD真的不能像OperationQueue那样终止任务?"></a>GCD真的不能像OperationQueue那样终止任务?</h1><h3 id="完整例子Demo1:让-Dispatch-Source-“帮”-Dispatch-Queue-实现暂停和恢复功能"><a href="#完整例子Demo1:让-Dispatch-Source-“帮”-Dispatch-Queue-实现暂停和恢复功能" class="headerlink" title="完整例子Demo1:让 Dispatch Source “帮” Dispatch Queue 实现暂停和恢复功能"></a>完整例子Demo1:让 Dispatch Source “帮” Dispatch Queue 实现暂停和恢复功能</h3><p>本节配套代码在 <code>Demo1</code> 中(Demo<em>01</em>对DispatchSource实现取消恢复操作_main队列版)。</p>
<p>先写一段代码演示下DispatchSource的基本用法:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//</span></div><div class="line"><span class="comment">// .m</span></div><div class="line"><span class="comment">// CYLDispatchSourceTest</span></div><div class="line"><span class="comment">//</span></div><div class="line"><span class="comment">// Created by 微博@iOS程序犭袁( http://weibo.com/luohanchenyilong/) on 15/9/1.</span></div><div class="line"><span class="comment">// Copyright (c) 2015年 https://github.com/ChenYilong . All rights reserved.</span></div><div class="line"><span class="comment">//</span></div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)viewDidLoad {</div><div class="line"> [<span class="keyword">super</span> viewDidLoad];</div><div class="line"> <span class="comment">//1.</span></div><div class="line"> <span class="comment">// 指定DISPATCH_SOURCE_TYPE_DATA_ADD,做成Dispatch Source(分派源)。设定Main Dispatch Queue 为追加处理的Dispatch Queue</span></div><div class="line"> _processingQueueSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, <span class="number">0</span>, <span class="number">0</span>,</div><div class="line"> dispatch_get_main_queue());</div><div class="line"> __block <span class="built_in">NSUInteger</span> totalComplete = <span class="number">0</span>;</div><div class="line"> dispatch_source_set_event_handler(_processingQueueSource, ^{</div><div class="line"> <span class="comment">//当处理事件被最终执行时,计算后的数据可以通过dispatch_source_get_data来获取。这个数据的值在每次响应事件执行后会被重置,所以totalComplete的值是最终累积的值。</span></div><div class="line"> <span class="built_in">NSUInteger</span> value = dispatch_source_get_data(_processingQueueSource);</div><div class="line"> totalComplete += value;</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"进度:%@"</span>, @((<span class="built_in">CGFloat</span>)totalComplete/<span class="number">100</span>));</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🔵线程号:%@"</span>, [<span class="built_in">NSThread</span> currentThread]);</div><div class="line"> });</div><div class="line"> <span class="comment">//分派源创建时默认处于暂停状态,在分派源分派处理程序之前必须先恢复。</span></div><div class="line"> [<span class="keyword">self</span> resume];</div><div class="line"> </div><div class="line"> <span class="comment">//2.</span></div><div class="line"> <span class="comment">//恢复源后,就可以通过dispatch_source_merge_data向Dispatch Source(分派源)发送事件:</span></div><div class="line"> <span class="built_in">dispatch_queue_t</span> queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</div><div class="line"> <span class="built_in">dispatch_async</span>(queue, ^{</div><div class="line"> <span class="keyword">for</span> (<span class="built_in">NSUInteger</span> index = <span class="number">0</span>; index < <span class="number">100</span>; index++) {</div><div class="line"> dispatch_source_merge_data(_processingQueueSource, <span class="number">1</span>);</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"♻️线程号:%@"</span>, [<span class="built_in">NSThread</span> currentThread]);</div><div class="line"> usleep(<span class="number">20000</span>);<span class="comment">//0.02秒</span></div><div class="line"> }</div><div class="line"> });</div><div class="line">}</div></pre></td></tr></table></figure>
<p>则输出日志:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.346</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] ✅恢复Dispatch Source(分派源)</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.348</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.372</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.401</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.424</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.444</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.473</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.493</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.515</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 进度:<span class="number">0.07000000000000001</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.515</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff373428140</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.516</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 进度:<span class="number">0.08</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.516</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.535</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff373428140</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">48.556</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 进度:<span class="number">0.09</span></div><div class="line"><span class="comment">/*================省略中间====================*/</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.630</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff373428140</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.630</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.654</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 进度:<span class="number">0.97</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.654</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff373428140</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.654</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.676</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 进度:<span class="number">0.98</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.676</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff373428140</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.676</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.699</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.708</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 进度:<span class="number">0.99</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.708</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff373428140</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.722</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 进度:<span class="number">1</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.722</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874681</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff373428140</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">50</span>:<span class="number">50.722</span> CYLDispatchSourceTest[<span class="number">8331</span>:<span class="number">874889</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7ff3735abe40</span>>{number = <span class="number">2</span>, name = (null)}</div></pre></td></tr></table></figure>
<p>耗时:2.376</p>
<p>这段代码还可以进行如下优化:</p>
<p>将创建异步的操作放在 for 循环内部:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)viewDidLoad {</div><div class="line"> [<span class="keyword">super</span> viewDidLoad];</div><div class="line"> <span class="comment">//1.</span></div><div class="line"> <span class="comment">// 指定DISPATCH_SOURCE_TYPE_DATA_ADD,做成Dispatch Source(分派源)。设定Main Dispatch Queue 为追加处理的Dispatch Queue</span></div><div class="line"> _processingQueueSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, <span class="number">0</span>, <span class="number">0</span>,</div><div class="line"> dispatch_get_main_queue());</div><div class="line"> __block <span class="built_in">NSUInteger</span> totalComplete = <span class="number">0</span>;</div><div class="line"> dispatch_source_set_event_handler(_processingQueueSource, ^{</div><div class="line"> <span class="comment">//当处理事件被最终执行时,计算后的数据可以通过dispatch_source_get_data来获取。这个数据的值在每次响应事件执行后会被重置,所以totalComplete的值是最终累积的值。</span></div><div class="line"> <span class="built_in">NSUInteger</span> value = dispatch_source_get_data(_processingQueueSource);</div><div class="line"> totalComplete += value;</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"进度:%@"</span>, @((<span class="built_in">CGFloat</span>)totalComplete/<span class="number">100</span>));</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🔵线程号:%@"</span>, [<span class="built_in">NSThread</span> currentThread]);</div><div class="line"></div><div class="line"> });</div><div class="line"> <span class="comment">//分派源创建时默认处于暂停状态,在分派源分派处理程序之前必须先恢复。</span></div><div class="line"> [<span class="keyword">self</span> resume];</div><div class="line"> </div><div class="line"> <span class="comment">//2.</span></div><div class="line"> <span class="comment">//恢复源后,就可以通过dispatch_source_merge_data向Dispatch Source(分派源)发送事件:</span></div><div class="line"> <span class="built_in">dispatch_queue_t</span> queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</div><div class="line"> <span class="keyword">for</span> (<span class="built_in">NSUInteger</span> index = <span class="number">0</span>; index < <span class="number">100</span>; index++) {</div><div class="line"> <span class="built_in">dispatch_async</span>(queue, ^{</div><div class="line"> dispatch_source_merge_data(_processingQueueSource, <span class="number">1</span>);</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"♻️线程号:%@"</span>, [<span class="built_in">NSThread</span> currentThread]);</div><div class="line"> usleep(<span class="number">20000</span>);<span class="comment">//0.02秒</span></div><div class="line"> });</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>执行结果:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div></pre></td><td class="code"><pre><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.153</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] ✅恢复Dispatch Source(分派源)</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.154</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871174</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663616c50</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.156</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871177</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663417370</span>>{number = <span class="number">4</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.156</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871176</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66359ac80</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.163</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871184</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6635507b0</span>>{number = <span class="number">5</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.164</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871185</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663618c90</span>>{number = <span class="number">6</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.164</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871186</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663596920</span>>{number = <span class="number">7</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.174</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871187</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663465d20</span>>{number = <span class="number">8</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.174</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871175</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634404f0</span>>{number = <span class="number">9</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.182</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.09</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.174</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871174</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663616c50</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.187</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.184</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871188</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66348e850</span>>{number = <span class="number">10</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.184</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871177</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663417370</span>>{number = <span class="number">4</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.191</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.13</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.187</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871192</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66348db80</span>>{number = <span class="number">11</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.191</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871189</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6635121b0</span>>{number = <span class="number">12</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.191</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871176</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66359ac80</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.196</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.192</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871184</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6635507b0</span>>{number = <span class="number">5</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.192</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871185</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663618c90</span>>{number = <span class="number">6</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.192</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871186</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663596920</span>>{number = <span class="number">7</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.194</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871190</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6635138b0</span>>{number = <span class="number">13</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.196</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871187</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663465d20</span>>{number = <span class="number">8</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.196</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871175</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634404f0</span>>{number = <span class="number">9</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.206</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.21</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.207</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.210</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.23</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.201</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871193</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663487830</span>>{number = <span class="number">14</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.207</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871194</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634662c0</span>>{number = <span class="number">15</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.207</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871195</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663618160</span>>{number = <span class="number">16</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.211</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.210</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871196</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663566720</span>>{number = <span class="number">17</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.211</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871174</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663616c50</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="comment">/*==========省略20行带有的 ♻️的打印内容(没有重复的线程号)========*/</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.239</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871196</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663566720</span>>{number = <span class="number">17</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.239</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871174</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663616c50</span>>{number = <span class="number">2</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.239</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871191</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663597ca0</span>>{number = <span class="number">18</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.245</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871202</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663617c00</span>>{number = <span class="number">24</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.247</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.249</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.5</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.249</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.248</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871203</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663531ab0</span>>{number = <span class="number">25</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.249</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.51</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.249</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.250</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871204</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66344bbf0</span>>{number = <span class="number">26</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.250</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.52</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.251</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.251</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.53</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.250</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871205</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663461d90</span>>{number = <span class="number">27</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.251</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871206</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66341d370</span>>{number = <span class="number">28</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.252</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.252</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.54</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.251</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871207</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634196e0</span>>{number = <span class="number">29</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.253</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.254</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.57</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.254</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.255</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.58</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.252</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871208</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66341bd50</span>>{number = <span class="number">30</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.253</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871209</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66361a070</span>>{number = <span class="number">31</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.253</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871210</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663618020</span>>{number = <span class="number">32</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.255</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.255</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871211</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663612c90</span>>{number = <span class="number">33</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.256</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.59</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.257</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.256</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871212</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6635996d0</span>>{number = <span class="number">34</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.259</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.6</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.259</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.259</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871213</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66340bd30</span>>{number = <span class="number">35</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.260</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.61</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.264</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.262</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871214</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66354f4b0</span>>{number = <span class="number">36</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.264</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.62</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.264</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.264</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871215</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663531010</span>>{number = <span class="number">37</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.270</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.63</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.270</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871216</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66360c6e0</span>>{number = <span class="number">38</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.270</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.270</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871176</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66359ac80</span>>{number = <span class="number">3</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.270</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">0.64</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.271</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871198</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb663576ab0</span>>{number = <span class="number">20</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.271</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.271</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871189</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6635121b0</span>>{number = <span class="number">12</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.271</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871188</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66348e850</span>>{number = <span class="number">10</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.271</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871192</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66348db80</span>>{number = <span class="number">11</span>, name = (null)}</div><div class="line"><span class="comment">/*==========省略30行带有的 ♻️的打印内容(没有重复的线程号)========*/</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.277</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871222</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66361ca00</span>>{number = <span class="number">43</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.278</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871223</span>] ♻️线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb66360c620</span>>{number = <span class="number">44</span>, name = (null)}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.290</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.293</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 进度:<span class="number">1</span></div><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-03</span> <span class="number">16</span>:<span class="number">48</span>:<span class="number">10.293</span> CYLDispatchSourceTest[<span class="number">8301</span>:<span class="number">871133</span>] 🔵线程号:<<span class="built_in">NSThread</span>: <span class="number">0x7fb6634077a0</span>>{number = <span class="number">1</span>, name = main}</div></pre></td></tr></table></figure>
<p>耗时:0.14秒,与之前的2.376秒相比,时间是后者的17倍 ,性能相差很大。</p>
<h3 id="DispatchSource能通过合并事件的方式确保在高负载下正常工作"><a href="#DispatchSource能通过合并事件的方式确保在高负载下正常工作" class="headerlink" title="DispatchSource能通过合并事件的方式确保在高负载下正常工作"></a>DispatchSource能通过合并事件的方式确保在高负载下正常工作</h3><p>然而上例中也因为并发执行,速度相当快,调用 <code>dispatch_source_merge_data</code> 后所触发的 <code>dispatch_source_set_event_handler</code> 的频率也大大减少,有时只会在结束时触发一次。</p>
<p>如果你细心观察下上例中的打印🔵(小蓝点)♻️(小绿点)个数是不一的,但 <code>totalComplete</code> 的值,或者进度条从0.0到1.0的执行是正常,但是🔵(小蓝点)为什么没有被打印?这是因为:</p>
<blockquote>
<p>DispatchSource能通过合并事件的方式确保在高负载下正常工作</p>
</blockquote>
<p>在同一时间,只有一个处理 block 的实例被分配,如果这个处理方法还没有执行完毕,另一个事件就发生了,事件会以指定方式(ADD或 OR)进行累积。DispatchSource能通过合并事件(block)的方式确保在高负载下正常工作。当处理事件被最终执行时,计算后的数据可以通过 <code>dispatch_source_get_data</code> 来获取。这个数据的值在每次响应时间执行后会被重置,所以上面的例子中进度条 <code>totalComplete</code> 的值是最终积累的值,而 block 不是每次都执行的,但打印🔵(小蓝点)♻️(小绿点)个数不一。但能确保进度条能从0.0到1.0的正常执行。</p>
<p>下面我们来演示下如何控制Dispatch Source(分派源),让它随时暂停,随时恢复:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)didReceiveMemoryWarning {</div><div class="line"> [<span class="keyword">super</span> didReceiveMemoryWarning];</div><div class="line"> [<span class="keyword">self</span> changeStatus:<span class="keyword">self</span>.running];</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)changeStatus:(<span class="built_in">BOOL</span>)shouldPause {</div><div class="line"> <span class="keyword">if</span> (shouldPause) {</div><div class="line"> [<span class="keyword">self</span> pause];</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> [<span class="keyword">self</span> resume];</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)resume {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">self</span>.running) {</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"✅恢复Dispatch Source(分派源)"</span>);</div><div class="line"> <span class="keyword">self</span>.running = <span class="literal">YES</span>;</div><div class="line"> dispatch_resume(_processingQueueSource);</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)pause {</div><div class="line"> <span class="keyword">if</span> (!<span class="keyword">self</span>.running) {</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🚫暂停Dispatch Source(分派源)"</span>);</div><div class="line"> <span class="keyword">self</span>.running = <span class="literal">NO</span>;</div><div class="line"> dispatch_suspend(_processingQueueSource);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>并取消打印线程的 <code>NSLog</code> ,然后使用下图中的快捷键迅速触发 <code>didReceiveMemoryWarning</code> 以切换Dispatch Source(分派源)的状态:</p>
<p><img src="http://i61.tinypic.com/6thjmf.jpg" alt="enter image description here"></p>
<p><img src="http://i59.tinypic.com/suyt0o.jpg" alt="enter image description here"></p>
<p>详见 <code>Demo1</code> 实现(Demo<em>01</em>对DispatchSource实现取消恢复操作_main队列版)。</p>
<h3 id="Dispatch-Source-与-Dispatch-Queue-两者在线程执行上的关系"><a href="#Dispatch-Source-与-Dispatch-Queue-两者在线程执行上的关系" class="headerlink" title="Dispatch Source 与 Dispatch Queue 两者在线程执行上的关系"></a>Dispatch Source 与 Dispatch Queue 两者在线程执行上的关系</h3><p>本节配套代码在 <code>Demo2</code> 中(Demo<em>02</em>对DispatchSource实现取消恢复操作_global队列版)。</p>
<p>答案是:没有关系。两者会独立运行。 Dispatch Queue 像一个生产任务的生产者,而 Dispatch Source 像处理任务的消费者。可以一边异步生产,也可一边异步消费。你可以在任意线程上调用 <code>dispatch_source_merge_data</code> 以触发 <code>dispatch_source_set_event_handler</code> 。而句柄的执行线程,取决于你创建句柄时所指定的线程,如果你像下面这样创建,那么句柄会在主线程执行:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 指定DISPATCH_SOURCE_TYPE_DATA_ADD,做成Dispatch Source(分派源)。设定Main Dispatch Queue 为追加处理的 Dispatch Queue</span></div><div class="line">_processingQueueSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, <span class="number">0</span>, <span class="number">0</span>,</div><div class="line"> dispatch_get_main_queue());</div></pre></td></tr></table></figure>
<p>如果你像下面这样创建,那么句柄会在异步线程执行:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 指定DISPATCH_SOURCE_TYPE_DATA_ADD,做成Dispatch Source(分派源)。设定 global Dispatch Queue 为追加处理的Dispatch Queue</span></div><div class="line">_processingQueueSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, <span class="number">0</span>, <span class="number">0</span>,</div><div class="line"> dispatch_get_global_queue(<span class="number">0</span>, <span class="number">0</span>));</div></pre></td></tr></table></figure>
<p>详见 <code>Demo2</code> 实现(Demo<em>02</em>对DispatchSource实现取消恢复操作_global队列版)</p>
<h3 id="让-Dispatch-Source-与-Dispatch-Queue-同时实现暂停和恢复"><a href="#让-Dispatch-Source-与-Dispatch-Queue-同时实现暂停和恢复" class="headerlink" title="让 Dispatch Source 与 Dispatch Queue 同时实现暂停和恢复"></a>让 Dispatch Source 与 Dispatch Queue 同时实现暂停和恢复</h3><p>本节代码详见 Demo4(Demo<em>04</em>对DispatchQueue实现取消恢复操作_综合版)</p>
<p>你可能已经发现了:上面的代码是有问题的,它只是一种“假暂停”的状态。for 循环还是要执行100遍,循环的次数并没有因你暂停了派发源而暂停,这在实际开发中是不允许的,因为真正的性能瓶颈永远会是在这里,这样的暂停毫无意义。那么如何让 for 循环随时可以暂停?</p>
<p>实际上 <code>Dispatch Queue</code> 没有“取消”这一概念。一旦将处理追加到 <code>Dispatch Queue</code> 中,就没有方法可将该处理去除,也没有方法可在执行中取消该处理。编程人员要么在处理中导入取消这一概念。</p>
<p>要么放弃取消,或者使用 <code>NSOperationQueue</code> 等其他方法。</p>
<p> <code>Dispatch Source</code> 与 <code>Dispatch Queue</code> 不同,是可以取消的。而且取消时必须执行的处理可指定为回调用的Block形式。</p>
<p> <code>Dispatch Source</code> 是如何执行取消的?打个比方:</p>
<p> <code>Dispatch Queue</code> 就好像瓜农种瓜,只要种了瓜,就走上了一条不归路:不管有没有人买,你都必须要好好施肥,好好浇水。没有放弃的余地。</p>
<p> <code>Dispatch Source</code> 就好像买瓜的人,比如你在瓜农种瓜时,告诉瓜农,“你的瓜熟一个我买一个”,等瓜成熟了,你开始买,不断得买,陆续买了100个,突然你感觉吃够了,你不买了,但是瓜还是在不断得成熟着,然后只能烂在地里了。等你突然又想买的时候,地里已经有1000个瓜,你要买,必须全买。。。</p>
<p>回到代码里,也就是说 <code>Dispatch Source</code> 的暂停,只是暂停调用 <code>dispatch_source_set_event_handler</code> , <code>Dispatch Queue</code> 中的for循环并没有因此暂停,它还是在一直运行着,等你恢复 <code>Dispatch Source</code> 的时候, <code>Dispatch Queue</code> 可能已经运行结束。然后你就会像上面的gif图中那样,从“进度:0.9”暂停,恢复时直接跳到“进度:1”,跳过了中间的“进度:0.91”、“进度:0.92”、“进度:0.93”等等。所以说这是一种“假暂停”。</p>
<p>那么如何在处理中导入取消这一概念?代码如下:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">dispatch_queue_t</span> queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</div><div class="line">__block <span class="built_in">BOOL</span> isCanceled = <span class="literal">NO</span>;</div><div class="line"><span class="built_in">dispatch_async</span>(queue, ^{</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (isCanceled) {</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="built_in">NSData</span> *thumbnailData = [<span class="built_in">NSURLConnection</span> sendSynchronousRequest:request];</div><div class="line"> ...</div><div class="line">});</div></pre></td></tr></table></figure>
<p>完整的代码则需要做如下修改:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)viewDidLoad {</div><div class="line"> [<span class="keyword">super</span> viewDidLoad];</div><div class="line"> <span class="comment">//1.</span></div><div class="line"> <span class="comment">// 指定DISPATCH_SOURCE_TYPE_DATA_ADD,做成Dispatch Source(分派源)。设定Main Dispatch Queue 为追加处理的Dispatch Queue</span></div><div class="line"> _processingQueueSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, <span class="number">0</span>, <span class="number">0</span>,</div><div class="line"> dispatch_get_main_queue());</div><div class="line"> __block <span class="built_in">NSUInteger</span> totalComplete = <span class="number">0</span>;</div><div class="line"> dispatch_source_set_event_handler(_processingQueueSource, ^{</div><div class="line"> <span class="comment">//当处理事件被最终执行时,计算后的数据可以通过dispatch_source_get_data来获取。这个数据的值在每次响应事件执行后会被重置,所以totalComplete的值是最终累积的值。</span></div><div class="line"> <span class="built_in">NSUInteger</span> value = dispatch_source_get_data(_processingQueueSource);</div><div class="line"> totalComplete += value;</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"进度:%@"</span>, @((<span class="built_in">CGFloat</span>)totalComplete/CYLTotalNumber));</div><div class="line"> });</div><div class="line"> <span class="comment">//分派源创建时默认处于暂停状态,在分派源分派处理程序之前必须先恢复。</span></div><div class="line"> [<span class="keyword">self</span> resume];</div><div class="line"> </div><div class="line"> </div><div class="line"> <span class="comment">//2.</span></div><div class="line"> <span class="comment">//恢复源后,就可以通过dispatch_source_merge_data向Dispatch Source(分派源)发送事件:</span></div><div class="line"> <span class="comment">//为了便于观察,将_queue做成“串行队列”</span></div><div class="line"> _queue = dispatch_queue_create(<span class="string">"com.ioschengxuyuan.queue1"</span>, <span class="number">0</span>);</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🔴类名与方法名:%s(在第%d行),描述:%@"</span>, __PRETTY_FUNCTION__, __LINE__, <span class="string">@"启动队列"</span>);</div><div class="line"> <span class="keyword">for</span> (<span class="built_in">NSUInteger</span> index = <span class="number">0</span>; index < CYLTotalNumber; index++) {</div><div class="line"> <span class="built_in">dispatch_async</span>(_queue, ^{</div><div class="line"> <span class="keyword">if</span> (!<span class="keyword">self</span>.running) {</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> dispatch_source_merge_data(_processingQueueSource, <span class="number">1</span>);</div><div class="line"> usleep(<span class="number">200000</span>);<span class="comment">//0.2秒</span></div><div class="line"> });</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)didReceiveMemoryWarning {</div><div class="line"> [<span class="keyword">super</span> didReceiveMemoryWarning];</div><div class="line"> [<span class="keyword">self</span> changeStatus:<span class="keyword">self</span>.running];</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)changeStatus:(<span class="built_in">BOOL</span>)shouldPause {</div><div class="line"> <span class="keyword">if</span> (shouldPause) {</div><div class="line"> [<span class="keyword">self</span> pause];</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> [<span class="keyword">self</span> resume];</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)resume {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">self</span>.running) {</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"✅恢复Dispatch Source(分派源)以及_queue"</span>);</div><div class="line"> <span class="keyword">self</span>.running = <span class="literal">YES</span>;</div><div class="line"> dispatch_resume(_processingQueueSource);</div><div class="line"> <span class="keyword">if</span> (_queue) {</div><div class="line"> dispatch_resume(_queue);</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)pause {</div><div class="line"> <span class="keyword">if</span> (!<span class="keyword">self</span>.running) {</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🚫暂停Dispatch Source(分派源)以及_queue"</span>);</div><div class="line"> <span class="keyword">self</span>.running = <span class="literal">NO</span>;</div><div class="line"> dispatch_suspend(_processingQueueSource);</div><div class="line"> dispatch_suspend(_queue);</div><div class="line">}</div></pre></td></tr></table></figure>
<p><img src="http://i61.tinypic.com/33m06er.jpg" alt="enter image description here"></p>
<p>详见 Demo4(Demo<em>04</em>对DispatchQueue实现取消恢复操作_综合版)</p>
<h2 id="Parse-“离线存储对象”操作的代码摘录"><a href="#Parse-“离线存储对象”操作的代码摘录" class="headerlink" title="Parse “离线存储对象”操作的代码摘录"></a>Parse “离线存储对象”操作的代码摘录</h2><p>句柄如下:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">dispatch_source_set_event_handler(_processingQueueSource, ^{</div><div class="line"> [<span class="keyword">self</span> _runCommands];</div><div class="line">});</div></pre></td></tr></table></figure>
<p>何时会调用句柄? 下面将 Parse 里涉及调用句柄的语句罗列一下, 因为摘录的代码不完整,可能并不能看出使用的完整过程。所以可以大致预览一下,详情可以查看Parse 源码,并且我已将这些逻辑浓缩为可运行的 Demo,也可搭配理解。</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)start {</div><div class="line"> dispatch_source_set_event_handler(_processingQueueSource, ^{</div><div class="line"> [<span class="keyword">self</span> _runCommands];</div><div class="line"> });</div><div class="line"> [<span class="keyword">self</span> resume];</div><div class="line">}</div></pre></td></tr></table></figure>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)resume {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">self</span>.running) {</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">self</span>.running = <span class="literal">YES</span>;</div><div class="line"> dispatch_resume(_processingQueueSource);</div><div class="line"> dispatch_source_merge_data(_processingQueueSource, <span class="number">1</span>);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>监听网络状态,一旦网络重连上之后,设置 connected属性为 YES,并重写其 setter 方法,调用 <code>dispatch_source_merge_data</code> 进行发送消息的操作:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/*! Manually sets the network connection status. */</span></div><div class="line">- (<span class="keyword">void</span>)setConnected:(<span class="built_in">BOOL</span>)connected {</div><div class="line"> BFTaskCompletionSource *barrier = [BFTaskCompletionSource taskCompletionSource];</div><div class="line"> <span class="built_in">dispatch_async</span>(_processingQueue, ^{</div><div class="line"> <span class="built_in">dispatch_sync</span>(_synchronizationQueue, ^{</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">self</span>.connected != connected) {</div><div class="line"> _connected = connected;</div><div class="line"> <span class="keyword">if</span> (connected) {</div><div class="line"> dispatch_source_merge_data(_processingQueueSource, <span class="number">1</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> });</div><div class="line"> barrier.result = <span class="literal">nil</span>;</div><div class="line"> });</div><div class="line"> <span class="keyword">if</span> (connected) {</div><div class="line"> <span class="built_in">dispatch_async</span>(_synchronizationQueue, ^{</div><div class="line"> <span class="keyword">if</span> (_retryingSemaphore) {</div><div class="line"> dispatch_semaphore_signal(_retryingSemaphore);</div><div class="line"> }</div><div class="line"> });</div><div class="line"> }</div><div class="line"> [barrier.task waitForResult:<span class="literal">nil</span>];</div><div class="line">}</div></pre></td></tr></table></figure>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)_didEnqueueCommand:(<span class="keyword">id</span><PFNetworkCommand>)command</div><div class="line"> withIdentifier:(<span class="built_in">NSString</span> *)identifier</div><div class="line"> taskCompletionSource:(BFTaskCompletionSource *)taskCompletionSource {</div><div class="line"> PFAssertIsOnDispatchQueue(_synchronizationQueue);</div><div class="line"></div><div class="line"> _taskCompletionSources[identifier] = taskCompletionSource;</div><div class="line"> dispatch_source_merge_data(_processingQueueSource, <span class="number">1</span>);</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (_retryingSemaphore) {</div><div class="line"> dispatch_semaphore_signal(_retryingSemaphore);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="Dispatch-Semaphore-信号量"><a href="#Dispatch-Semaphore-信号量" class="headerlink" title="Dispatch Semaphore 信号量"></a><code>Dispatch Semaphore</code> 信号量</h2><p>为了展示作用,举个反例:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">dispatch_queue_t</span> queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</div><div class="line"><span class="built_in">NSMutableArray</span> *array = [[<span class="built_in">NSMutableArray</span> alloc] init];</div><div class="line">dispatch_group_t group = dispatch_group_create();</div><div class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">100000</span>; ++i) {</div><div class="line"> dispatch_group_async(group, queue, ^{</div><div class="line"> [array addObject:[<span class="built_in">NSNumber</span> numberWithInt:i]];</div><div class="line"> });</div><div class="line">}</div><div class="line">dispatch_group_wait(group, DISPATCH_TIME_FOREVER);</div><div class="line"><span class="built_in">NSLog</span>(<span class="string">@"%@"</span>, @([array count]));</div></pre></td></tr></table></figure>
<p>运行结果绝对大跌眼镜:</p>
<p>我运行了三次,三次结果均不一致:</p>
<ol>
<li><p>第一次:崩溃。。。</p>
<p><img src="http://i67.tinypic.com/29vxt9w.jpg" alt="enter image description here"></p>
</li>
</ol>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">CYLDispatchSemaphoreTest(<span class="number">10384</span>,<span class="number">0x112d43000</span>) malloc: *** error <span class="keyword">for</span> object <span class="number">0x7f898487ca00</span>: pointer being freed was not allocated</div><div class="line">*** set a breakpoint <span class="keyword">in</span> malloc_error_break to debug</div><div class="line">(lldb)</div></pre></td></tr></table></figure>
<ol>
<li><p>第二次:不够。。</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-07</span> <span class="number">00</span>:<span class="number">42</span>:<span class="number">20.145</span> CYLDispatchSemaphoreTest[<span class="number">10417</span>:<span class="number">779722</span>] <span class="number">99996</span></div></pre></td></tr></table></figure>
</li>
<li><p>第三次:还是不够。。。</p>
</li>
</ol>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="number">2015</span><span class="number">-09</span><span class="number">-07</span> <span class="number">00</span>:<span class="number">42</span>:<span class="number">52.734</span> CYLDispatchSemaphoreTest[<span class="number">10438</span>:<span class="number">780505</span>] <span class="number">99949</span></div></pre></td></tr></table></figure>
<p>这种资源抢夺的情况,一般的做法是使用串行队列,或者像下面一样的同步队列,得以解决:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">dispatch_queue_t</span> queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="number">0</span>);</div><div class="line"> <span class="built_in">NSMutableArray</span> *array = [[<span class="built_in">NSMutableArray</span> alloc] init];</div><div class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">100000</span>; ++i) {</div><div class="line"> <span class="built_in">dispatch_sync</span>(queue, ^{</div><div class="line"> [array addObject:[<span class="built_in">NSNumber</span> numberWithInt:i]];</div><div class="line"> });</div><div class="line"></div><div class="line"> }</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"%@"</span>, @([array count]));</div></pre></td></tr></table></figure>
<p>下面展示下展示使用 <code>dispatch_semaphore_t</code> 的解决方案:</p>
<p> <code>dispatch_semaphore_t</code> 的作用之一就是解决这种资源抢夺的情况,下面展示下使用 <code>dispatch_semaphore_t</code> 实现一个资源锁:</p>
<p>以下源码详见 Demo6(Demo<em>06</em>展示dispatch_semaphore_t基本用法)</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)viewDidLoad {</div><div class="line"> [<span class="keyword">super</span> viewDidLoad];</div><div class="line"> <span class="comment">//因为用到了dispatch_barrier_async,该函数只能搭配自定义并行队列dispatch_queue_t使用。所以不能使用:dispatch_get_global_queue</span></div><div class="line"> <span class="built_in">dispatch_queue_t</span> queue = dispatch_queue_create(<span class="string">"com.ioschengxuyuan.gcd.ForBarrier"</span>, DISPATCH_QUEUE_CONCURRENT);</div><div class="line"> <span class="comment">/*</span></div><div class="line"> *</div><div class="line"> *生成Dispatch Semaphore</div><div class="line"> Dispatch Semaphore 的计数初始值设定为“1”</div><div class="line"> (该初始值的1与下文中两个函数dispatch_semaphore_wait与dispatch_semaphore_signal进行的减1、加1里的1没有必然联系。</div><div class="line"> </div><div class="line"> 就算初始值是100,两个函数dispatch_semaphore_wait与dispatch_semaphore_signal还是会减“1”、加“1”)。</div><div class="line"> 保证可访问 NSMutableArray 类对象的线程</div><div class="line"> 同时只能有1个</div><div class="line"> *</div><div class="line"> */</div><div class="line"> dispatch_semaphore_t semaphore = dispatch_semaphore_create(<span class="number">1</span>) ;</div><div class="line"> <span class="built_in">NSMutableArray</span> *array = [[<span class="built_in">NSMutableArray</span> alloc] init];</div><div class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">100000</span>; ++i) {</div><div class="line"> <span class="built_in">dispatch_async</span>(queue, ^{</div><div class="line"> <span class="comment">/*</span></div><div class="line"> *</div><div class="line"> *等待Dispatch Semaphore</div><div class="line"> *一直等待,直到Dispatch Semaphore的计数值达到大于等于1</div><div class="line"> */</div><div class="line"> dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) ;</div><div class="line"> <span class="comment">/*</span></div><div class="line"> *由于Dispatch Semaphore的计数值达到大于等于1</div><div class="line"> *所以将Dispatch Semaphore的计数值减去1</div><div class="line"> *dispatch_semaphore_wait 函数执行返回。</div><div class="line"> *即执行到此时的</div><div class="line"> *Dispatch Semaphore 的计数值恒为0</div><div class="line"> *</div><div class="line"> *由于可访问NSMutaleArray类对象的线程</div><div class="line"> *只有一个</div><div class="line"> *因此可安全地进行更新</div><div class="line"> *</div><div class="line"> */</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🔴%@"</span>,[<span class="built_in">NSThread</span> currentThread]);</div><div class="line"> [array addObject:[<span class="built_in">NSNumber</span> numberWithInt:i]];</div><div class="line"> <span class="comment">/*</span></div><div class="line"> *</div><div class="line"> *排他控制处理结束,</div><div class="line"> *所以通过dispatch_semaphore_signal函数</div><div class="line"> *将Dispatch Semaphore的计数值加1</div><div class="line"> *如果有通过dispatch_semaphore_wait函数</div><div class="line"> *等待Dispatch Semaphore的计数值增加的线程,</div><div class="line"> ★就由最先等待的线程执行。</div><div class="line"> */</div><div class="line"> dispatch_semaphore_signal(semaphore);</div><div class="line"> });</div><div class="line"> }</div><div class="line"> <span class="comment">/*</span></div><div class="line"> *</div><div class="line"> 等为数组遍历添加元素后,检查下数组的成员个数是否正确</div><div class="line"> *</div><div class="line"> */</div><div class="line"> dispatch_barrier_async(queue, ^{</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"🔴类名与方法名:%s(在第%d行),描述:%@"</span>, __PRETTY_FUNCTION__, __LINE__, @([array count]));</div><div class="line"> });</div><div class="line">}</div></pre></td></tr></table></figure>
<p>为了加深对dispatch_semaphore_t基本用法的理解,再给一个示例 Demo:</p>
<p>思考下为何会如何打印:<br>然后再分别试一下第三行和第四行:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"> dispatch_semaphore_t semaphore = dispatch_semaphore_create(<span class="number">0</span>);</div><div class="line"><span class="comment">// dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);</span></div></pre></td></tr></table></figure>
<p>然后观察下打印。</p>
<p>详见 Demo5(Demo<em>05</em>展示dispatch_semaphore_t基本用法)</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)viewDidLoad {</div><div class="line"> [<span class="keyword">super</span> viewDidLoad];</div><div class="line"> </div><div class="line"> dispatch_semaphore_t semaphore = dispatch_semaphore_create(<span class="number">0</span>);</div><div class="line"><span class="comment">// dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);</span></div><div class="line"> </div><div class="line"> dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, <span class="number">1</span>ull * <span class="built_in">NSEC_PER_SEC</span>);<span class="comment">//等待一秒</span></div><div class="line"> <span class="comment">//dispatch_time_t time = DISPATCH_TIME_FOREVER;//永久等待</span></div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"begin ==> 车库开始营业了!"</span>);</div><div class="line"> <span class="comment">/*</span></div><div class="line"> *</div><div class="line"> 如果 semphore 的值等于0,就阻塞1秒钟,才会往下照常进行;</div><div class="line"> 如果大于等于1则往下进行并将 semphore 进行减1处理。</div><div class="line"> *</div><div class="line"> */</div><div class="line"> <span class="keyword">long</span> result = dispatch_semaphore_wait(semaphore, time);</div><div class="line"> <span class="keyword">if</span> (result == <span class="number">0</span>) {</div><div class="line"> <span class="comment">/*</span></div><div class="line"> *</div><div class="line"> *由子Dispatch Semaphore的计数值达到大于等于1</div><div class="line"> *或者在待机中的指定时间内</div><div class="line"> *Dispatch Semaphore的计数值达到大于等于1</div><div class="line"> 所以Dispatch Semaphore的计数值减去1</div><div class="line"> 可执行需要进行排他控制的处理.</div><div class="line"> 可以理解为:没有阻塞的线程了。</div><div class="line"> 就好比:车库有一个或一个以上的车位,只来了一辆车,所以“无需等待”</div><div class="line"> *</div><div class="line"> */</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"result = 0 ==> 有车位,无需等待!==> 在这里可安全地执行【需要排他控制的处理(比如只允许一条线程为mutableArray进行addObj操作)】"</span>);</div><div class="line"> dispatch_semaphore_signal(semaphore);<span class="comment">//使用signal以确保编译器release掉dispatch_semaphore_t时的值与初始值一致, 否则会EXC_BAD_INSTRUCTION ,见http://is.gd/EaJgk5</span></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">/*</span></div><div class="line"> *</div><div class="line"> *由于Dispatch Semaphore的计数值为0</div><div class="line"> .因此在达到指定时间为止待机</div><div class="line"> 这个else里发生的事情,就好比:车库没车位,来了一辆车,等待了半个小时后,做出的一些事情。</div><div class="line"> 比如:忍受不了,走了。。</div><div class="line"> *</div><div class="line"> */</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"result != 0 ==> timeout,deadline,忍受不了,走了。。"</span>);</div><div class="line"> </div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<h3 id="在项目中的应用:强制把异步任务转换为同步任务来方便进行单元测试"><a href="#在项目中的应用:强制把异步任务转换为同步任务来方便进行单元测试" class="headerlink" title="在项目中的应用:强制把异步任务转换为同步任务来方便进行单元测试"></a>在项目中的应用:强制把异步任务转换为同步任务来方便进行单元测试</h3><p>下面是 Parse 的一段代码:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"> <span class="class"><span class="keyword">@interface</span> <span class="title">PFEventuallyQueueTestHelper</span> : <span class="title">NSObject</span> </span>{</div><div class="line"> dispatch_semaphore_t events[PFEventuallyQueueEventCount];</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)clear;</div><div class="line">- (<span class="keyword">void</span>)notify:(PFEventuallyQueueTestHelperEvent)event;</div><div class="line">- (<span class="built_in">BOOL</span>)waitFor:(PFEventuallyQueueTestHelperEvent)event;</div></pre></td></tr></table></figure>
<p>注释是这样写的:</p>
<blockquote>
<p>PFEventuallyQueueTestHelper gets notifications of various events happening in the command cache,<br>// so that tests can be synchronized. See CommandTests.m for examples of how to use this.</p>
</blockquote>
<p>强制把异步任务转换为同步任务来方便进行单元测试。这个用途信号量是最合适的用途。但注意并不推荐应用到除此之外的其它场景!</p>
<p>这种异步转同步便于单元测试的用法类似于下面的写法:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#define WAIT_FOREVER [self waitForStatus:XCTAsyncTestCaseStatusSucceeded timeout:DBL_MAX];</span></div><div class="line"><span class="meta">#define NOTIFY [self notify:XCTAsyncTestCaseStatusSucceeded];</span></div></pre></td></tr></table></figure>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)testInstallationMutated {</div><div class="line"> <span class="built_in">NSDictionary</span> *dict = [<span class="keyword">self</span> jsonWithFileName:<span class="string">@"TestInstallationSave"</span>];</div><div class="line"> <span class="built_in">AVInstallation</span> *installation = [<span class="built_in">AVInstallation</span> currentInstallation];</div><div class="line"> [installation objectFromDictionary:dict];</div><div class="line"> [installation setObject:@(<span class="literal">YES</span>) forKey:<span class="string">@"enableNoDisturb"</span>];</div><div class="line"> [installation saveInBackgroundWithBlock:^(<span class="built_in">BOOL</span> succeeded, <span class="built_in">NSError</span> *error) {</div><div class="line"> <span class="built_in">XCTAssertNil</span>(error);</div><div class="line"> NOTIFY;</div><div class="line"> }];</div><div class="line"> WAIT;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>信号量属性底层工具,他虽然非常强大,但在多数需要使用它的场合,最好从设计角度重新考虑,看是否可以不用,应该优先考虑使用诸如操作队列这样的高级工具。通常可以通过增加一个分派队列配合 <code>dispatch_suspend</code> ,或者通过其它方式分解操作来避免使用信号量。信号量并非不好,只是它本身是锁,能不使用就不用。尽量用 cocoa 框架中的高级抽象,信号量非常接近底层。所以除了上面的例子是最佳应用场景外,不推荐应用到除此之外的其它场景!</p>
<p> <a href="http://www.cnblogs.com/snailHL/p/3906112.html" target="_blank" rel="external">《关于dispatch_semaphore的使用》</a> 中有这样的描述:</p>
<p>关于信号量,一般可以用停车来比喻。</p>
<blockquote>
<p> 停车场剩余4个车位,那么即使同时来了四辆车也能停的下。如果此时来了五辆车,那么就有一辆需要等待。</p>
<p> 信号量的值就相当于剩余车位的数目,dispatch_semaphore_wait函数就相当于来了一辆车,</p>
<p> dispatch_semaphore_signal,就相当于走了一辆车。停车位的剩余数目在初始化的时候就已经指明了(dispatch_semaphore_create(long value))</p>
<p> 调用一次dispatch_semaphore_signal,剩余的车位就增加一个;调用一次dispatch_semaphore_wait剩余车位就减少一个;</p>
<p> 当剩余车位为0时,再来车(即调用dispatch_semaphore_wait)就只能等待。有可能同时有几辆车等待一个停车位。有些车主</p>
<p> 没有耐心,给自己设定了一段等待时间,这段时间内等不到停车位就走了,如果等到了就开进去停车。而有些车主就像把车停在这,</p>
<p> 所以就一直等下去。</p>
</blockquote>
<p> <a href="http://m.blog.csdn.net/blog/choudang/38121827" target="_blank" rel="external">《GCD dispatch_semaphore 信号量 协调线程同步》</a> 也有类似的比喻:</p>
<blockquote>
<p>以一个停车场是运作为例。为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开两辆,则又可以放入两辆,如此往复。<br></p> 在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。<br>更进一步,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程(车辆)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: Wait(等待) 和 Release(释放)。 当一个线程调用Wait(等待)操作时,它要么通过然后将信号量减一,要么一直等下去,直到信号量大于一或超时。Release(释放)实际上是在信号量上执行加操作,对应于车辆离开停车场,该操作之所以叫做“释放”是因为加操作实际上是释放了由信号量守护的资源。<p></p>
</blockquote>
<p>这个比喻里可以用一个表格来表示:</p>
<table>
<thead>
<tr>
<th>喻体</th>
<th>本体</th>
<th>代码</th>
</tr>
</thead>
<tbody>
<tr>
<td>车位</td>
<td>信号量</td>
<td><code>dispatch_semaphore_t</code> </td>
</tr>
<tr>
<td>剩余几个车位</td>
<td>最大并发线程</td>
<td><code>dispatch_semaphore_t</code> </td>
</tr>
<tr>
<td>看门人起的作用</td>
<td>信号量的作用</td>
<td><code>dispatch_semaphore_t</code> </td>
</tr>
<tr>
<td>车</td>
<td>线程</td>
<td>代码 </td>
</tr>
<tr>
<td>耐心的极限时间</td>
<td>超时时间</td>
<td><code>dispatch_semaphore_wait</code> </td>
</tr>
<tr>
<td>逛街结束走了,离开车位</td>
<td>signal+1</td>
<td><code>dispatch_semaphore_signal</code> </td>
</tr>
</tbody>
</table>
<h3 id="使用Dispatch-Semaphore控制并发线程数量"><a href="#使用Dispatch-Semaphore控制并发线程数量" class="headerlink" title="使用Dispatch Semaphore控制并发线程数量"></a>使用<code>Dispatch Semaphore</code>控制并发线程数量</h3><p>正如文章开头所说:从 iOS7 升到 iOS8 后,GCD 出现了一个重大的变化:在 iOS7 时,使用 GCD 的并行队列, <code>dispatch_async</code> 最大开启的线程一直能控制在6、7条,线程数都是个位数,然而 iOS8后,最大线程数一度可以达到40条、50条。然而在文档上并没有对这一做法的目的进行介绍。</p>
<p>笔者推测 Apple 的目的是想借此让开发者使用 <code>NSOperationQueue</code> :GCD 中 Apple 并没有提供控制并发数量的接口,而 <code>NSOperationQueue</code> 有,如果需要使用 GCD 实现,需要使用 GCD 的一项高级功能:<code>Dispatch Semaphore</code>信号量。</p>
<p>详见 Demo7(Demo<em>07</em>展示dispatch_semaphore_t控制线程并发数量的用法)</p>
<p>Demo7中使用了 <a href="http://mp.weixin.qq.com/s?__biz=MzAxNDAzMzk0MQ==&mid=203702345&idx=1&sn=226f6f784d37b89718f6949c9214e1e6&scene=1&srcid=kl2ZmcSfYHuB6bMvYPEq#rd" target="_blank" rel="external">这篇博文</a> 中的例子。</p>
<p><code>Dispatch Semaphore</code>信号量的使用在上文中已经介绍过,那么就直接上 Demo:</p>
<p>主要做的就是将上文中 <code>dispatch_semaphore_t</code> 的个数设置为一个可变参数:这样就达到了控制并行线程数量的目的:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/*</span></div><div class="line"> *</div><div class="line"> 简单版本:无专门控制并发等待的线程,缺点阻塞主线程,可以跑一下 demo,你会发现主屏幕上的按钮是不可点击的</div><div class="line"> *</div><div class="line"> */</div><div class="line"><span class="keyword">void</span> dispatch_async_limit(<span class="built_in">dispatch_queue_t</span> queue,<span class="built_in">NSUInteger</span> limitSemaphoreCount, dispatch_block_t block) {</div><div class="line"> <span class="comment">//控制并发数的信号量</span></div><div class="line"> <span class="keyword">static</span> dispatch_semaphore_t limitSemaphore;</div><div class="line"> <span class="comment">//专门控制并发等待的线程</span></div><div class="line"></div><div class="line"> </div><div class="line"> <span class="comment">//使用 dispatch_once而非 lazy 模式,防止可能的多线程抢占问题</span></div><div class="line"> <span class="keyword">static</span> <span class="built_in">dispatch_once_t</span> onceToken;</div><div class="line"> <span class="built_in">dispatch_once</span>(&onceToken, ^{</div><div class="line"> limitSemaphore = dispatch_semaphore_create(limitSemaphoreCount);</div><div class="line"> });</div><div class="line"> </div><div class="line"></div><div class="line"> <span class="comment">//可用信号量后才能继续,否则等待</span></div><div class="line"> dispatch_semaphore_wait(limitSemaphore, DISPATCH_TIME_FOREVER);</div><div class="line"> <span class="built_in">dispatch_async</span>(queue, ^{</div><div class="line"> !block ? : block();</div><div class="line"> <span class="comment">//在该工作线程执行完成后释放信号量</span></div><div class="line"> dispatch_semaphore_signal(limitSemaphore);</div><div class="line"> });</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>你可能发现,这段代码有问题阻塞了当前线程,Demo7中也给出了改良版,可以看下。</p>
<h3 id="为-NSURLSession-添加同步方法"><a href="#为-NSURLSession-添加同步方法" class="headerlink" title="为 NSURLSession 添加同步方法"></a>为 NSURLSession 添加同步方法</h3><p>NSURLSession 取消了同步方法,但是可以借助信号量来实现:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">+ (<span class="built_in">NSData</span> *)sendSynchronousRequest:(<span class="built_in">NSURLRequest</span> *)request returningResponse:(<span class="built_in">NSURLResponse</span> *__autoreleasing *)response error:(<span class="built_in">NSError</span> *__autoreleasing *)error {</div><div class="line"> __block <span class="built_in">NSData</span> *data = <span class="literal">nil</span>;</div><div class="line"> dispatch_semaphore_t semaphore = dispatch_semaphore_create(<span class="number">0</span>);</div><div class="line"></div><div class="line"> [[[<span class="built_in">NSURLSession</span> sharedSession] dataTaskWithRequest:request completionHandler:^(<span class="built_in">NSData</span> *taskData, <span class="built_in">NSURLResponse</span> *taskResponse, <span class="built_in">NSError</span> *taskError) {</div><div class="line"> data = taskData;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (response)</div><div class="line"> *response = taskResponse;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (error)</div><div class="line"> *error = taskError;</div><div class="line"></div><div class="line"> dispatch_semaphore_signal(semaphore);</div><div class="line"> }] resume];</div><div class="line"></div><div class="line"> dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);</div><div class="line"></div><div class="line"> <span class="keyword">return</span> data;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>但是也要思考下为什么 Apple 取消了同步方法:同步方法的风险远远超过受益。</p>
<p>要注意:</p>
<ul>
<li>除非万不得已,否则永远不要尝试在主线程上发送同步的网络请求</li>
<li>尽量只在后台线程中独占线程发送同步的网络请求</li>
</ul>
<p>风险如下所示:</p>
<h4 id="导致Watchdog超时"><a href="#导致Watchdog超时" class="headerlink" title="导致Watchdog超时"></a>导致Watchdog超时</h4><p>关于Watchdog超时:</p>
<p>在 <a href="https://developer.apple.com/library/ios/qa/qa1693/_index.html" target="_blank" rel="external"> <strong><em>QA1693:Synchronous Networking On The Main Thread</em></strong> </a><br>文档中描述了Watchdog机制,包括生效场景和表现。如果我们的应用程序对一些特定的UI事件(比如启动、挂起、恢复、结束)响应不及时,Watchdog会把我们的应用程序干掉,并生成一份响应的crash报告。</p>
<p>这份crash报告的有趣之处在于异常代码:“0x8badf00d”,即“ate bad food”。<br>如果说特定的UI事件比较抽象,那么用代码来直接描述的话,对应的就是(创建一个工程时Xcode自动生成的)UIApplicationDelegate的几个方法:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">- (<span class="built_in">BOOL</span>)application:(<span class="built_in">UIApplication</span> *)application didFinishLaunchingWithOptions:(<span class="built_in">NSDictionary</span> *)launchOptions {</div><div class="line"> <span class="keyword">return</span> <span class="literal">YES</span>;</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)applicationWillResignActive:(<span class="built_in">UIApplication</span> *)application {</div><div class="line"> <span class="comment">// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.</span></div><div class="line"> <span class="comment">// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.</span></div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)applicationDidEnterBackground:(<span class="built_in">UIApplication</span> *)application {</div><div class="line"> <span class="comment">// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.</span></div><div class="line"> <span class="comment">// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.</span></div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)applicationWillEnterForeground:(<span class="built_in">UIApplication</span> *)application {</div><div class="line"> <span class="comment">// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.</span></div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)applicationDidBecomeActive:(<span class="built_in">UIApplication</span> *)application {</div><div class="line"> <span class="comment">// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.</span></div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)applicationWillTerminate:(<span class="built_in">UIApplication</span> *)application {</div><div class="line"> <span class="comment">// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.</span></div><div class="line">}</div></pre></td></tr></table></figure>
<p>所以当遇到Watchdog日志时,可以检查下上面几个方法是否有比较重的阻塞UI的动作。</p>
<p><a href="https://developer.apple.com/library/ios/qa/qa1693/_index.html" target="_blank" rel="external"> <strong><em>QA1693:Synchronous Networking On The Main Thread</em></strong> </a> 举的例子就是在主线程进行同步网络请求。如果我们是在公司的Wifi环境下使用则一切顺利,但当应用程序发布出去面向很大范围的用户,在各种网络环境下运行,则不可避免地会出现一片Watchdog超时报告。<br>另一种可能出现问题的场景就是数据量比较大的情况下进行的数据库版本迁移(同样是在主线程上)。</p>
<h4 id="失去了-cancel-的机会:"><a href="#失去了-cancel-的机会:" class="headerlink" title="失去了 cancel 的机会:"></a>失去了 cancel 的机会:</h4><p>不能像异步那样进行下面的操作:</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">-(<span class="keyword">IBAction</span>)cancelUpload:(<span class="keyword">id</span>)sender {</div><div class="line"> <span class="keyword">if</span> (_uploadTask.state == <span class="built_in">NSURLSessionTaskStateRunning</span>) {</div><div class="line"> [_uploadTask cancel];</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p> <a href="http://blog.csdn.net/jasonblog/article/details/19031517" target="_blank" rel="external">《iOS应用的crash日志的分析基础》</a> </p>
<p>参考链接: <a href="https://github.com/ParsePlatform/Parse-SDK-iOS-OSX" target="_blank" rel="external">GitHub:Parse-SDK-iOS-OSX源码</a> </p>
<hr>
<p>支持原创:<a href="https://github.com/ChenYilong/ParseSourceCodeStudy/blob/master/01_Parse%E7%9A%84%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%A4%84%E7%90%86%E6%80%9D%E8%B7%AF/Parse%E7%9A%84%E5%BA%95%E5%B1%82%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%A4%84%E7%90%86%E6%80%9D%E8%B7%AF.md" target="_blank" rel="external"><strong><em>Parse源码浅析系列(一)—Parse的底层多线程处理思路:GCD高级用法</em></strong></a> </p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/blog/2016/09/gcd-base.html" itemprop="url">
GCD 基础篇
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2016-09-27T19:04:20+08:00" content="2016-09-27">
2016-09-27
</time>
</span>
<span class="post-comments-count">
|
<a href="/blog/2016/09/gcd-base.html#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="/blog/2016/09/gcd-base.html" itemprop="commentsCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>GCD有四个概念:串行队列、并行队列、同步、异步四者。</p>
<p>如下简介:</p>
<p>这里不仅给出了不确定性,而且也给出了确定性。对于初学者而言,有时候因为那些不确定的东西所造成的疑问会像没有闸却在疾驰的汽车一样让人惊慌失措,而“确定性”就如同这救命的车闸一样,它能让你豁然开朗。</p>
<table>
<thead>
<tr>
<th>名称</th>
<th>功能特点</th>
<th>确定性解释</th>
<th>不确定性解释</th>
</tr>
</thead>
<tbody>
<tr>
<td>同步</td>
<td>完成需要做的任务后才会返回,进行下一任务</td>
<td>“任务”,在 GCD 里指的是 Block;在 performSelector 方法中,对应 selector 方法。<p></p>同步方法,功能类似 <code>dispatch_group_wait</code> ,而 group 指的是所有线程,包括主线程。</td>
<td><p></p> 不一定是多线程</td>
</tr>
<tr>
<td>异步</td>
<td>不会等待任务完成才返回,会立即返回。</td>
<td>异步是多线程的代名词,因为必定会开启新的线程,线程的申请是由异步负责,起到开分支的作用。</td>
<td>–</td>
</tr>
<tr>
<td>串行队列</td>
<td>任务依次执行</td>
<td>同一时间队列中只有一个任务在执行,每个任务只有在前一个任务执行完成后才能开始执行。</td>
<td>你不知道在一个Block(任务)执行结束到下一个Block(任务)开始执行之间的这段时间时间是多长,<img src="/images/GCD-Base/Serial-Queue-480x272.png" alt="enter image description here"></td>
</tr>
<tr>
<td>并行队列</td>
<td>任务并发执行</td>
<td>你唯一能保证的是,这些任务会按照被添加的顺序开始执行。但是任务可以以任何顺序完成</td>
<td>你不知道在执行下一个任务是从什么时候开始,或者说任意时刻有多个Block(任务)运行,这个完全是取决于GCD。<img src="/images/GCD-Base/Concurrent-Queue-480x272.png" alt="enter image description here"></td>
</tr>
<tr>
<td>全局队列</td>
<td>隶属于并行队列</td>
<td>不要与 barrier 栅栏方法搭配使用, barrier 只有与自定义的并行队列一起使用,才能让 barrier 达到我们所期望的栅栏功能。与 串行队列或者 global 队列 一起使用,barrier 的表现会和 dispatch_sync 方法一样。</td>
<td>–</td>
</tr>
<tr>
<td>主队列</td>
<td>隶属于串行队列</td>
<td>不能与 sync 同步方法搭配使用,会造成死循环</td>
<td>–</td>
</tr>
</tbody>
</table>
<p>串行队列、并行队列、同步、异步四者的组合:</p>
<p>GCD提供了dispatch queues(调度队列)来执行代码段,这些队列以FIFO(先进先出)的方式来管理你用GCD提交的任务。这保证了你先提交的任务现执行,即第一个任务添加到队列中就第一个开始执行,第二个添加的任务将第二个执行,知道队列的最后一个任务。</p>
<table>
<thead>
<tr>
<th>—</th>
<th>同步</th>
<th>异步 </th>
</tr>
</thead>
<tbody>
<tr>
<td>串行队列</td>
<td>不会新建线程,依然在当前线程上<p></p>类似同步锁,是同步锁的替代方案<p></p>✅ 常用</td>
<td>会新建线程,只开一条线程<p></p>一条线程就够了<p></p> 每次使用 createDispatch 方法就会新建一条线程,多次调用该方法,会创建多条线程,多条线程间会并行执行</td>
</tr>
<tr>
<td>并行队列</td>
<td>不会新建线程,依然在当前线程上<p></p></td>
<td>会新建线程,可以开多条线程<p></p> iOS7-SDK 时代一般是5、6条, iOS8-SDK 以后可以50、60条 <p></p> ✅ 常用</td>
</tr>
</tbody>
</table>
<p>参考链接: <a href="http://stackoverflow.com/questions/10984732/why-cant-we-use-a-dispatch-sync-on-the-current-queue" target="_blank" rel="external"><strong><em>Why can’t we use a dispatch_sync on the current queue?</em></strong></a> </p>
<h2 id="串行队列中的同步与异步的区别"><a href="#串行队列中的同步与异步的区别" class="headerlink" title="串行队列中的同步与异步的区别"></a>串行队列中的同步与异步的区别</h2><p>串行队列能确保顺序执行任务,他们两个的唯一区别在于<code>dispatch_sync</code>只会在 block 完全执行完之后返回,<code>dispatch_async</code> 不能确保会在 block 完全执行完之后返回,唯一能确定的是会在被添加到queue 队列后返回。</p>
<p>下面的代码:</p>
<pre><code>dispatch_async(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_async(_serialQueue, ^{ printf("3"); });
printf("4");
</code></pre><p>可能会打印 <code>2413</code> 、 <code>2143</code> 、 <code>1234</code> ,但有一点是可以确认的: <code>1</code> 总是在 <code>3</code> 之前。</p>
<p>可能的打印:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line"></div><div class="line">----------</div><div class="line"></div><div class="line">2</div><div class="line">4</div><div class="line">1</div><div class="line">3</div><div class="line"></div><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line"></div><div class="line">----------</div><div class="line">2</div><div class="line">4</div><div class="line">1</div><div class="line">3</div></pre></td></tr></table></figure>
<p>然而下面的代码:</p>
<pre><code>dispatch_sync(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_sync(_serialQueue, ^{ printf("3"); });
printf("4");
</code></pre><p>总会打印:<code>1234</code></p>
<p>参考链接: <a href="http://stackoverflow.com/questions/19822700/difference-between-dispatch-async-and-dispatch-sync-on-serial-queue/19822753?stw=2#19822753" target="_blank" rel="external"><strong><em>Difference between dispatch_async and dispatch_sync on serial queue?</em></strong></a> </p>
<p>支持原创:<a href="http://stackoverflow.com/questions/19822700/difference-between-dispatch-async-and-dispatch-sync-on-serial-queue/19822753?stw=2#19822753" target="_blank" rel="external"><strong><em>GCD 扫盲篇</em></strong></a></p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/blog/2016/09/QR-Code-custommade.html" itemprop="url">
ios开发-OC使用CIFilter生成二维码图片
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2016-09-25T16:27:39+08:00" content="2016-09-25">
2016-09-25
</time>
</span>
<span class="post-comments-count">
|
<a href="/blog/2016/09/QR-Code-custommade.html#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="/blog/2016/09/QR-Code-custommade.html" itemprop="commentsCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型:比如:字符,数字,日文,中文等等。</p>
<p>在iOS7之后,苹果自身集成了二维码的生成和读取功能。生成二维码包括以下步骤</p>
<ul>
<li>使用CIFilter滤镜类生成二维码</li>
<li>对生成的二维码进行加工,使其更清晰<br>经过上面两步得到会得到原始的二维码图片,在这基础上可以进行以下个性化定制</li>
<li>自定义二维码背景色、填充色</li>
<li>自定义定位角标</li>
<li>在二维码中心插入小图片</li>
</ul>
<h2 id="二维码生成"><a href="#二维码生成" class="headerlink" title="二维码生成"></a>二维码生成</h2><p>本文通过类的方式来生成个性化二维码定制。</p>
<h4 id="初始化二维码信息尺寸和默认值"><a href="#初始化二维码信息尺寸和默认值" class="headerlink" title="初始化二维码信息尺寸和默认值"></a>初始化二维码信息尺寸和默认值</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">instancetype</span>)init</div><div class="line">{</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">self</span> = [<span class="keyword">super</span> init]) {</div><div class="line"> <span class="comment">//默认值</span></div><div class="line"> _info = <span class="string">@"http://mkiltech.com"</span>;</div><div class="line"> _backgroundColor = [<span class="built_in">UIColor</span> whiteColor];</div><div class="line"> _fillColor = [<span class="built_in">UIColor</span> blackColor];</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">self</span>;</div><div class="line">}</div><div class="line"></div><div class="line">- (<span class="keyword">void</span>)setInfo:(<span class="built_in">NSString</span> *)info withSize:(<span class="built_in">CGFloat</span>)size</div><div class="line">{</div><div class="line"> _info = info;</div><div class="line"> </div><div class="line"> <span class="built_in">CGFloat</span> scale = [<span class="built_in">UIScreen</span> mainScreen].scale;</div><div class="line"> <span class="built_in">CGRect</span> rect = <span class="built_in">CGRectMake</span>(<span class="number">0</span>, <span class="number">0</span>, size, size);</div><div class="line"> _size = <span class="built_in">CGRectGetWidth</span>(rect) * scale;</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<h4 id="使用CIFilter滤镜类生成二维码"><a href="#使用CIFilter滤镜类生成二维码" class="headerlink" title="使用CIFilter滤镜类生成二维码"></a>使用CIFilter滤镜类生成二维码</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)generateQRCodeFilter</div><div class="line">{</div><div class="line"> <span class="built_in">CIFilter</span> *filter = [<span class="built_in">CIFilter</span> filterWithName:<span class="string">@"CIQRCodeGenerator"</span>];</div><div class="line"> [filter setDefaults];</div><div class="line"> <span class="built_in">NSData</span> *data = [_info dataUsingEncoding:<span class="built_in">NSUTF8StringEncoding</span>];</div><div class="line"> [filter setValue:data forKey:<span class="string">@"inputMessage"</span>]; <span class="comment">//通过kvo方式给一个字符串,生成二维码</span></div><div class="line"> [filter setValue:<span class="string">@"H"</span> forKey:<span class="string">@"inputCorrectionLevel"</span>]; <span class="comment">//设置二维码的纠错水平,越高纠错水平越高,可以污损的范围越大</span></div><div class="line"> </div><div class="line"> <span class="comment">//设置背景颜色和填充颜色 默认白色背景黑色填充</span></div><div class="line"> </div><div class="line"> <span class="built_in">CIColor</span> *color1 = [<span class="built_in">CIColor</span> colorWithCGColor:_fillColor.CGColor];</div><div class="line"> <span class="built_in">CIColor</span> *color2 = [<span class="built_in">CIColor</span> colorWithCGColor:_backgroundColor.CGColor];</div><div class="line"> <span class="built_in">NSDictionary</span> *parameters = [<span class="built_in">NSDictionary</span> dictionaryWithObjectsAndKeys: filter.outputImage ,<span class="string">@"inputImage"</span>,</div><div class="line"> color1,<span class="string">@"inputColor0"</span>,</div><div class="line"> color2,<span class="string">@"inputColor1"</span>,<span class="literal">nil</span>];</div><div class="line"> <span class="built_in">CIFilter</span> *newFilter = [<span class="built_in">CIFilter</span> filterWithName:<span class="string">@"CIFalseColor"</span> withInputParameters:parameters];</div><div class="line"> </div><div class="line"> _outPutImage = [newFilter outputImage]; <span class="comment">//拿到二维码图片</span></div><div class="line">}</div></pre></td></tr></table></figure>
<h4 id="对生成的二维码进行加工,使其更清晰"><a href="#对生成的二维码进行加工,使其更清晰" class="headerlink" title="对生成的二维码进行加工,使其更清晰"></a>对生成的二维码进行加工,使其更清晰</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div></pre></td><td class="code"><pre><div class="line">- (<span class="built_in">UIImage</span> *)createNonInterpolatedUIImageFormCIImage:(<span class="built_in">CIImage</span> *)image withSize:(<span class="built_in">CGFloat</span>) size {</div><div class="line"> <span class="built_in">CGRect</span> extent = <span class="built_in">CGRectIntegral</span>(image.extent);</div><div class="line"> <span class="built_in">CGFloat</span> scale = MIN(size/<span class="built_in">CGRectGetWidth</span>(extent), size/<span class="built_in">CGRectGetHeight</span>(extent));</div><div class="line"> </div><div class="line"> <span class="comment">// 1.创建bitmap;</span></div><div class="line"> size_t width = <span class="built_in">CGRectGetWidth</span>(extent) * scale;</div><div class="line"> size_t height = <span class="built_in">CGRectGetHeight</span>(extent) * scale;</div><div class="line"> <span class="comment">//创建一个DeviceRGB颜色空间</span></div><div class="line"> <span class="built_in">CGColorSpaceRef</span> cs = <span class="built_in">CGColorSpaceCreateDeviceRGB</span>();</div><div class="line"> <span class="comment">//CGBitmapContextCreate(void * _Nullable data, size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow, CGColorSpaceRef _Nullable space, uint32_t bitmapInfo)</span></div><div class="line"> <span class="comment">//width:图片宽度像素</span></div><div class="line"> <span class="comment">//height:图片高度像素</span></div><div class="line"> <span class="comment">//bitsPerComponent:每个颜色的比特值,例如在rgba-32模式下为8</span></div><div class="line"> <span class="comment">//bitmapInfo:指定的位图应该包含一个alpha通道。</span></div><div class="line"></div><div class="line"> <span class="built_in">CGContextRef</span> bitmapRef = <span class="built_in">CGBitmapContextCreate</span>(<span class="literal">nil</span>, width, height, <span class="number">8</span>, <span class="number">0</span>, cs, (<span class="built_in">CGBitmapInfo</span>)kCGImageAlphaPremultipliedLast);</div><div class="line"> <span class="built_in">CIContext</span> *context = [<span class="built_in">CIContext</span> contextWithOptions:<span class="literal">nil</span>];</div><div class="line"> <span class="comment">//创建CoreGraphics image</span></div><div class="line"> <span class="built_in">CGImageRef</span> bitmapImage = [context createCGImage:image fromRect:extent];</div><div class="line"> </div><div class="line"> <span class="built_in">CGContextSetInterpolationQuality</span>(bitmapRef, kCGInterpolationNone);</div><div class="line"> <span class="built_in">CGContextScaleCTM</span>(bitmapRef, scale, scale);</div><div class="line"> <span class="built_in">CGContextDrawImage</span>(bitmapRef, extent, bitmapImage);</div><div class="line"> </div><div class="line"> <span class="comment">// 2.保存bitmap到图片</span></div><div class="line"> <span class="built_in">CGImageRef</span> scaledImage = <span class="built_in">CGBitmapContextCreateImage</span>(bitmapRef);</div><div class="line"> <span class="built_in">CGContextRelease</span>(bitmapRef); <span class="built_in">CGImageRelease</span>(bitmapImage);</div><div class="line"> </div><div class="line"> <span class="comment">//原图</span></div><div class="line"> <span class="built_in">UIImage</span> *outputImage = [<span class="built_in">UIImage</span> imageWithCGImage:scaledImage];</div><div class="line"> <span class="keyword">return</span> outputImage;</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="获取二维码定位图案位置"><a href="#获取二维码定位图案位置" class="headerlink" title="获取二维码定位图案位置"></a>获取二维码定位图案位置</h2><p>二维码一共有40个尺寸。官方叫版本Version。Version 1是21 x 21的矩阵,Version 2是 25 x 25的矩阵,Version 3是29的尺寸,每增加一个version,就会增加4的尺寸,公式是:(V-1)<em>4 + 21(V是版本号) 最高Version 40,(40-1)</em>4+21 = 177,所以最高是177 x 177 的正方形。</p>
<p>下面我们看看一个二维码的样例:<br><img src="/images/QRCode/QR-Code-Overview.jpeg" alt="Alt text"></p>
<p><strong>定位图案</strong></p>
<ul>
<li>Position Detection Pattern是定位图案,用于标记二维码的矩形大小。这三个定位图案有白边叫Separators for Postion Detection Patterns。之所以三个而不是四个意思就是三个就可以标识一个矩形了。</li>
<li>Timing Patterns也是用于定位的。原因是二维码有40种尺寸,尺寸过大了后需要有根标准线,不然扫描的时候可能会扫歪了。</li>
<li>Alignment Patterns 只有Version 2以上(包括Version2)的二维码需要这个东东,同样是为了定位用的。</li>
</ul>
<p><strong>功能性数据</strong></p>
<ul>
<li>Format Information 存在于所有的尺寸中,用于存放一些格式化数据的。</li>
<li>Version Information 在 >= Version 7以上,需要预留两块3 x 6的区域存放一些版本信息。</li>
</ul>
<p><strong>数据码和纠错码</strong></p>
<ul>
<li>除了上述的那些地方,剩下的地方存放 Data Code 数据码 和 Error Correction Code 纠错码。</li>
</ul>
<h4 id="获取Version"><a href="#获取Version" class="headerlink" title="获取Version"></a>获取Version</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">- (<span class="built_in">CGFloat</span>)fetchVersion {</div><div class="line"> </div><div class="line"> <span class="keyword">return</span> ((_outPutImage.extent.size.width - <span class="number">21</span>)/<span class="number">4.0</span> + <span class="number">1</span>);</div><div class="line">}</div></pre></td></tr></table></figure>
<h4 id="换算成绘制坐标"><a href="#换算成绘制坐标" class="headerlink" title="换算成绘制坐标"></a>换算成绘制坐标</h4><h4 id="定位图案外层坐标"><a href="#定位图案外层坐标" class="headerlink" title="定位图案外层坐标"></a>定位图案外层坐标</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div></pre></td><td class="code"><pre><div class="line">- (<span class="built_in">UIBezierPath</span> *) outerPositionPathWidth:(<span class="built_in">CGFloat</span>)width withVersion:(<span class="built_in">CGFloat</span> )version wihtPosition:(<span class="built_in">MKQRPosition</span>) position</div><div class="line">{</div><div class="line"> <span class="built_in">CGFloat</span> zonePathWidth = width/((version - <span class="number">1</span>) * <span class="number">4</span> + <span class="number">21</span>);</div><div class="line"> <span class="built_in">CGFloat</span> positionFrameWidth = zonePathWidth * outerPositionPathOriginLength;</div><div class="line"> <span class="built_in">CGPoint</span> topLeftPoint = <span class="built_in">CGPointMake</span>(zonePathWidth * <span class="number">1.5</span>, zonePathWidth * <span class="number">1.5</span>);</div><div class="line"> <span class="built_in">CGRect</span> rect = <span class="built_in">CGRectMake</span>(topLeftPoint.x - <span class="number">0.2</span>, topLeftPoint.y - <span class="number">0.2</span>, positionFrameWidth, positionFrameWidth);</div><div class="line"> </div><div class="line"> rect = <span class="built_in">CGRectIntegral</span>(rect);</div><div class="line"> rect = <span class="built_in">CGRectInset</span>(rect, <span class="number">1</span>, <span class="number">1</span>);</div><div class="line"> <span class="built_in">UIBezierPath</span> *path;</div><div class="line"> <span class="built_in">CGFloat</span> offset;</div><div class="line"> <span class="keyword">switch</span> (position) {</div><div class="line"> <span class="keyword">case</span> TopLeft:</div><div class="line"> </div><div class="line"> path = [<span class="built_in">UIBezierPath</span> bezierPathWithRect:rect];</div><div class="line"> path.lineWidth = zonePathWidth + <span class="number">1.5</span>;</div><div class="line"> path.lineCapStyle = kCGLineCapSquare;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> TopRight:</div><div class="line"> </div><div class="line"> offset = width - positionFrameWidth - topLeftPoint.x * <span class="number">2</span>;</div><div class="line"> rect = <span class="built_in">CGRectOffset</span>(rect, offset, <span class="number">0</span>);</div><div class="line"> path = [<span class="built_in">UIBezierPath</span> bezierPathWithRect:rect];</div><div class="line"> path.lineWidth = zonePathWidth + <span class="number">1.5</span>;</div><div class="line"> path.lineCapStyle = kCGLineCapSquare;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> BottomLeft:</div><div class="line"> </div><div class="line"> offset = width - positionFrameWidth - topLeftPoint.x * <span class="number">2</span>;</div><div class="line"> rect = <span class="built_in">CGRectOffset</span>(rect, <span class="number">0</span>, offset);</div><div class="line"> path = [<span class="built_in">UIBezierPath</span> bezierPathWithRect:rect];</div><div class="line"> path.lineWidth = zonePathWidth + <span class="number">1.5</span>;</div><div class="line"> path.lineCapStyle = kCGLineCapSquare;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> QuietZone:</div><div class="line"> rect = <span class="built_in">CGRectMake</span>(zonePathWidth * <span class="number">0.5</span>, zonePathWidth * <span class="number">0.5</span>, width - zonePathWidth, width - zonePathWidth);</div><div class="line"> path = [<span class="built_in">UIBezierPath</span> bezierPathWithRect:rect];</div><div class="line"> path.lineWidth = zonePathWidth + [<span class="built_in">UIScreen</span> mainScreen].scale;</div><div class="line"> path.lineCapStyle = kCGLineCapSquare;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">default</span>:</div><div class="line"> </div><div class="line"> path = [<span class="built_in">UIBezierPath</span> bezierPath];</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> path;</div><div class="line"> </div><div class="line">}</div></pre></td></tr></table></figure>
<h4 id="定位图案内层坐标包括中心图片位置"><a href="#定位图案内层坐标包括中心图片位置" class="headerlink" title="定位图案内层坐标包括中心图片位置"></a>定位图案内层坐标包括中心图片位置</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line">- (<span class="built_in">CGRect</span>)innerPositionRectWidth:(<span class="built_in">CGFloat</span> )width withVersion:(<span class="built_in">CGFloat</span> )version wihtPosition:(<span class="built_in">MKQRPosition</span>) position</div><div class="line">{</div><div class="line"> <span class="built_in">CGFloat</span> leftMargin = width * <span class="number">3</span> / ((version - <span class="number">1</span>) * <span class="number">4</span> + <span class="number">21</span>);</div><div class="line"> <span class="built_in">CGFloat</span> tileWidth = leftMargin;</div><div class="line"> <span class="built_in">CGFloat</span> centerImageWith = width * <span class="number">7</span> / ((version - <span class="number">1</span>) * <span class="number">4</span> + <span class="number">21</span>);</div><div class="line"> </div><div class="line"> <span class="built_in">CGRect</span> rect = <span class="built_in">CGRectMake</span>(leftMargin + <span class="number">1.5</span>, leftMargin + <span class="number">1.5</span>, leftMargin - <span class="number">3</span>, leftMargin - <span class="number">3</span>);</div><div class="line"> rect = <span class="built_in">CGRectIntegral</span>(rect);</div><div class="line"> rect = <span class="built_in">CGRectInset</span>(rect, <span class="number">-1</span>, <span class="number">-1</span>);</div><div class="line"> </div><div class="line"> <span class="built_in">CGFloat</span> offset;</div><div class="line"> <span class="keyword">switch</span> (position) {</div><div class="line"> <span class="keyword">case</span> TopLeft:</div><div class="line"> </div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> TopRight:</div><div class="line"> </div><div class="line"> offset = width - tileWidth - leftMargin*<span class="number">2</span>;</div><div class="line"> rect = <span class="built_in">CGRectOffset</span>(rect, offset, <span class="number">0</span>);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> BottomLeft:</div><div class="line"> </div><div class="line"> offset = width - tileWidth - leftMargin * <span class="number">2</span>;</div><div class="line"> rect = <span class="built_in">CGRectOffset</span>(rect, <span class="number">0</span>, offset);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> Center:</div><div class="line"> </div><div class="line"> rect = <span class="built_in">CGRectMake</span>(<span class="built_in">CGPointZero</span>.x, <span class="built_in">CGPointZero</span>.y, centerImageWith, centerImageWith);</div><div class="line"> offset = width/<span class="number">2</span> - centerImageWith/<span class="number">2</span>;</div><div class="line"> rect = <span class="built_in">CGRectOffset</span>(rect, offset, offset);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">default</span>:</div><div class="line"> rect = <span class="built_in">CGRectZero</span>;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> </div><div class="line"> <span class="keyword">return</span> rect;</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="效果图"><a href="#效果图" class="headerlink" title="效果图"></a>效果图</h2><p><img src="/images/QRCode/QRCodeRendering.png" alt="Alt text"></p>
<p>完整代码请前往 <a href="https://github.com/ymkil/MKQRCode" target="_blank" rel="external">https://github.com/ymkil/MKQRCode</a> 如果满意的话,给个星哦!!<br>转载请注明出处。</p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</section>
</div>
</div>
<div class="sidebar-toggle">
<div class="sidebar-toggle-line-wrap">
<span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
<span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
<span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
</div>
</div>
<aside id="sidebar" class="sidebar">
<div class="sidebar-inner">
<section class="site-overview sidebar-panel sidebar-panel-active ">
<div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
<img class="site-author-image" itemprop="image"
src="/images/avatar.jpg"
alt="MKIL" />
<p class="site-author-name" itemprop="name">MKIL</p>
<p class="site-description motion-element" itemprop="description">Mkil 蚂蚁</p>
</div>
<nav class="site-state motion-element">
<div class="site-state-item site-state-posts">
<a href="/archives">
<span class="site-state-item-count">3</span>
<span class="site-state-item-name">日志</span>
</a>
</div>