-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1047 lines (463 loc) · 58.9 KB
/
index.html
File metadata and controls
1047 lines (463 loc) · 58.9 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 muse use-motion" lang="zh-Hans">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
<link href="/css/main.css?v=5.1.3" rel="stylesheet" type="text/css" />
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.3">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.3">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.3">
<link rel="mask-icon" href="/images/logo.svg?v=5.1.3" color="#222">
<meta name="keywords" content="Hexo, NexT" />
<meta property="og:type" content="website">
<meta property="og:title" content="Lorne的个人笔记">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="Lorne的个人笔记">
<meta property="og:locale" content="zh-Hans">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Lorne的个人笔记">
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '/',
scheme: 'Muse',
version: '5.1.3',
sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
fancybox: true,
tabs: true,
motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
duoshuo: {
userId: '0',
author: '博主'
},
algolia: {
applicationID: '',
apiKey: '',
indexName: '',
hits: {"per_page":10},
labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
}
};
</script>
<link rel="canonical" href="http://yoursite.com/"/>
<title>Lorne的个人笔记</title>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container 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-brand-wrapper">
<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">Lorne的个人笔记</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>
</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-question-circle"></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>
</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">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/12/18/YYAsyncLayer异步渲染/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Lorne">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Lorne的个人笔记">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/12/18/YYAsyncLayer异步渲染/" itemprop="url">YYAsyncLayer异步渲染</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 title="创建于" itemprop="dateCreated datePublished" datetime="2017-12-18T17:35:22+08:00">
2017-12-18
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>在介绍YYAsyncLayer之前先复习下几个基础知识点:<br><strong>CALayer :</strong><br>layer有一个contents属性,它需要传入一个id(AnyObject!)类型,这是由于它在iOS平台需要 CGImage而Mac需要NSImage,在OC中需要用id类型强转一下,在Swift中你只需要直接赋一个 CGImage。UIImageView之所以能显示图片内部也是使用了这个contents属性<strong>的缘故<br>CATransaction:</strong><br>隐式动画主要作用于CALayer的可动画属性上面,UIView对应的layer是不可以的,只要你改变属性的 值,它不是突兀的直接改变过去,而是一个有一个动画的过程,这个时间等属性你可以通过事务 (CATransaction)来控制,如果你不自己提供一个事务,它的默认时间是0.25秒,当然这个可动画属性是 需要触发的,如果你一上来就设置一个值,可能看不到动画效果.(异步渲染虽然没用到,但API命名有 用)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">redLayer = CALayer()</span><br><span class="line"></span><br><span class="line">redLayer.backgroundColor = UIColor.redColor().CGColor redLayer.frame = CGRectMake(50, 100, 100, 100) self.view.layer.addSublayer(redLayer)</span><br><span class="line">NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: NSSelectorFromString("animate"), userInfo: nil, repeats: false)</span><br><span class="line"></span><br><span class="line">func animate() {</span><br><span class="line">CATransaction.begin()</span><br><span class="line">CATransaction.setAnimationDuration(12)</span><br><span class="line">var redC = CGFloat(arc4random() % 256 ) / 255.0</span><br><span class="line">var greenC = CGFloat(arc4random() % 256 ) / 255.0</span><br><span class="line">var blueC = CGFloat(arc4random() % 256 ) / 255.0</span><br><span class="line">self.redLayer.backgroundColor = UIColor(red: redC, green: greenC, blue: blueC, alpha:</span><br><span class="line">1).CGColor</span><br><span class="line"></span><br><span class="line">CATransaction.commit() </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>其他<br><a href="http://blog.csdn.net/hopedark/article/details/50174157" target="_blank" rel="noopener">事件处理机制与图像渲染过程</a><br><a href="http://blog.csdn.net/u014624597/article/details/28266509" target="_blank" rel="noopener">OSAtomic</a><br>项目结构</p>
<ul>
<li><strong>YYSentinel </strong></li>
<li><strong>YYTransaction </strong></li>
<li><strong>YYAsyncLayer </strong></li>
</ul>
<p>作者github给出的例子<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">@interface YYLabel : UIView @property NSString *text; @property UIFont *font;</span><br><span class="line">@end</span><br><span class="line">@implementation YYLabel</span><br><span class="line">- (void)setText:(NSString *)text {</span><br><span class="line">_text = text.copy;</span><br><span class="line">[[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];</span><br><span class="line">}</span><br><span class="line">- (void)setFont:(UIFont *)font {</span><br><span class="line">_font = font;</span><br><span class="line">[[YYTransaction transactionWithTarget:self</span><br><span class="line">selector:@selector(contentsNeedUpdated)] commit]; }</span><br><span class="line">- (void)layoutSubviews {</span><br><span class="line">[super layoutSubviews];</span><br><span class="line">[[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit]</span><br><span class="line">}</span><br><span class="line">- (void)contentsNeedUpdated {</span><br><span class="line">// do update</span><br><span class="line">[self.layer setNeedsDisplay]; }</span><br><span class="line">#pragma mark - YYAsyncLayer + (Class)layerClass {</span><br><span class="line">return YYAsyncLayer.class; }</span><br><span class="line">- (YYAsyncLayerDisplayTask *)newAsyncDisplayTask { // capture current state to display task NSString *text = _text;</span><br><span class="line">UIFont *font = _font;</span><br><span class="line">YYAsyncLayerDisplayTask *task = [YYAsyncLayerDisplayTask new]; task.willDisplay = ^(CALayer *layer) {</span><br><span class="line">//...</span><br><span class="line">};</span><br><span class="line">task.display = ^(CGContextRef context, CGSize size, BOOL(^isCancelled)(void)) { //需要异步绘制的代码</span><br><span class="line">if (isCancelled()) return;</span><br><span class="line">NSArray *lines = CreateCTLines(text, font, size.width); if (isCancelled()) return;</span><br><span class="line">for (int i = 0; i < lines.count; i++) {</span><br><span class="line">CTLineRef line = line[i];</span><br><span class="line">CGContextSetTextPosition(context, 0, i * font.pointSize * 1.5); CTLineDraw(line, context);</span><br><span class="line">if (isCancelled()) return;</span><br><span class="line">} };</span><br><span class="line">task.didDisplay = ^(CALayer *layer, BOOL finished) { if (finished) {</span><br><span class="line">// finished } else {</span><br><span class="line">// cancelled }</span><br><span class="line">};</span><br><span class="line">return task; }</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></p>
<p>接下来看看<br>[[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)]<br>commit];主要做了什么-<br>YYTransaction.h声明<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">@interface YYTransaction : NSObject /**</span><br><span class="line">创建和返回一个transaction通过一个定义的target和selector @param target 执行target,target会在runloop结束前被retain @param selector target的selector</span><br><span class="line">@return 1个新的transaction,或者有错误时返回nil</span><br><span class="line">*/</span><br><span class="line">+ (YYTransaction *)transactionWithTarget:(id)target selector:(SEL)selector; /**</span><br><span class="line">加入transaction到runloop</span><br><span class="line">*/</span><br><span class="line">- (void)commit;</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></p>
<p>1.YYTransaction.m主要实现一个监听触发回调功能<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">+ (YYTransaction *)transactionWithTarget:(id)target selector:(SEL)selector{//设置了代理 和方法指向</span><br><span class="line">if (!target || !selector) return nil; YYTransaction *t = [YYTransaction new]; t.target = target;</span><br><span class="line">t.selector = selector;</span><br><span class="line">return t;</span><br><span class="line">}</span><br><span class="line">- (void)commit {</span><br><span class="line">if (!_target || !_selector) return; //初始化runloop监听 YYTransactionSetup();//注册runloop监听 /*CFRunLoopRef runloop = CFRunLoopGetMain();</span><br><span class="line">CFRunLoopObserverRef observer; //注册runloop监听,在等待与退出前进行</span><br><span class="line">observer = CFRunLoopObserverCreate(CFAllocatorGetDefault(),</span><br><span class="line">kCFRunLoopBeforeWaiting | kCFRunLoopExit, true, // repeat</span><br><span class="line">0xFFFFFF, // after CATransaction(2000000) YYRunLoopObserverCallBack, NULL);</span><br><span class="line">//将监听加在所有mode上</span><br><span class="line">CFRunLoopAddObserver(runloop, observer, kCFRunLoopCommonModes); CFRelease(observer);*/</span><br><span class="line">//添加行为到set中</span><br><span class="line">[transactionSet addObject:self]; }</span><br><span class="line">static void YYRunLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {</span><br><span class="line">[currentSet enumerateObjectsUsingBlock:^(YYTransaction *transaction, BOOL *stop) { [transaction.target performSelector:transaction.selector];</span><br><span class="line">}];</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p>
<p>给YYLable实例设置成YYTransaction的target以及selector指向自己的实例方法。同时注册监听 kCFRunLoopBeforeWaiting( 即将进入休眠)、kCFRunLoopExit(即将推出Loop)用来触发selector 指向的实例方法contentsNeedUpdated。<br>2.YYAsyncLayer<br>YYLabel中contentsNeedUpdated方法调用 [self.layer setNeedsDisplay];,setNeedsDisplay会触发 layer的Display。先看<br>YYAsyncLayer.h头文件</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line">@interface YYAsyncLayer : CALayer</span><br><span class="line">@property BOOL displaysAsynchronously;</span><br><span class="line">@end</span><br><span class="line">@protocol YYAsyncLayerDelegate <NSObject></span><br><span class="line">@required</span><br><span class="line">/// This method is called to return a new display task when the layer's contents need update.</span><br><span class="line">- (YYAsyncLayerDisplayTask *)newAsyncDisplayTask;//YYLabel需要实现的方法,给YYAsyncLayer实 例方法返回几个带有状态block的Task</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@interface YYAsyncLayerDisplayTask : NSObject//附带的几个block可放入绘制代码</span><br><span class="line">@property (nullable, nonatomic, copy) void (^willDisplay)(CALayer *layer);</span><br><span class="line">@property (nullable, nonatomic, copy) void (^display)(CGContextRef context, CGSize size, BOOL(^isCancelled)(void));</span><br><span class="line">@property (nullable, nonatomic, copy) void (^didDisplay)(CALayer *layer, BOOL finished);</span><br><span class="line">@end</span><br><span class="line">.m中</span><br><span class="line">重写展示方法,设置contents内容 </span><br><span class="line">- (void)display {</span><br><span class="line">super.contents = super.contents;</span><br><span class="line">[self _displayAsync:_displaysAsynchronously];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (void)_displayAsync:(BOOL)async {//便于分析简化了代码 </span><br><span class="line"></span><br><span class="line">//获取delegate对象,这边默认是CALayer的delegate,持有它的uiview</span><br><span class="line">__strong id<YYAsyncLayerDelegate> delegate = self.delegate; //delegate的初始化方法</span><br><span class="line"></span><br><span class="line">YYAsyncLayerDisplayTask *task = [delegate newAsyncDisplayTask]; //没有展示block,就直接调用其他两个block返回</span><br><span class="line"></span><br><span class="line">if (!task.display) {</span><br><span class="line">if (task.willDisplay) task.willDisplay(self); self.contents = nil;</span><br><span class="line">if (task.didDisplay) task.didDisplay(self, YES); return;</span><br><span class="line">} //异步线程调用</span><br><span class="line"></span><br><span class="line">dispatch_async(YYAsyncLayerGetDisplayQueue(), ^{</span><br><span class="line">//获取当前画布</span><br><span class="line">UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); //返回主线程</span><br><span class="line">dispatch_async(dispatch_get_main_queue(), ^{</span><br><span class="line">//主线程设置contents内容进行展示</span><br><span class="line">self.contents = (__bridge id)(image.CGImage); //已经展示完成block,finish为yes</span><br><span class="line"> </span><br><span class="line">if (task.didDisplay) task.didDisplay(self, YES); });</span><br><span class="line">}); }</span><br></pre></td></tr></table></figure>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/12/06/Tagged pointer及64位下isa指针的优化/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Lorne">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Lorne的个人笔记">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/12/06/Tagged pointer及64位下isa指针的优化/" itemprop="url">Tagged pointer及64位下isa指针的优化</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 title="创建于" itemprop="dateCreated datePublished" datetime="2017-12-06T15:54:03+08:00">
2017-12-06
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<blockquote>
<p>看到个面试题:NSString在栈上所占内存大小?以及字符串为什么不能用"=="判断相等。特意去查了资料,做一下整理。</p>
</blockquote>
<p>苹果5s机型,由32位架构处理器变成了64位的。假设不在不做优化情况下,一个NSNumber对像,其值是一个整数。正常情况下,如果这个整数只是一个NSInteger的普通变量,那么它在32位CPU下占4字节,指针4字节(栈上),64位上直接翻倍(8+8)。所以一个iOS程序从32迁移到64位,NSNumber、NSDate一类对象所占内存直接翻倍。</p>
<p>所以苹果引入了 <strong>Tagged pointer</strong> 。 <strong>直接将8直接的64位指针,直接当一个特殊对象(没有isa指针)处理</strong> ,前60位存储数据,后4位:最后固定一位为1(二进制)+其他3位作为一个类表的索引(该索引是用来查找所属类是采用Tagged Pointer的哪个类)。</p>
<p>64位设备,苹果除了引入Tagged pointer来优化小的对象外, <strong>对于普通对象,其isa指针进行了优化</strong> 。</p>
<p><strong>在32位下,对象引用计数保存在一个外部表中,每个对象进行Retain操作,实际上包括以下5各步骤:</strong></p>
<p>1.获取全局的记录引用计数的hash表。</p>
<p>2.为了线程安全,给该hash表加锁。</p>
<p>3.查找到目标对象的引用计数值。</p>
<p>4.将该引用计数值加1,写会hash表</p>
<p>5.给该hash表解锁。</p>
<p>在64位下,isa指针也是64位,实际做为指针部分只用到33位,剩余31位类似Tagged pointer做了相应处理。其中19位保存对象引用计数,对引用计数的修改只需修改这个指针即可,只有当引用计数超出19位,才会将引用计数保存到外部表,而这种情况是很少的,所以这样的引用计数的更改效率会更高。</p>
<p>所以64位下会做以下5步骤:</p>
<p>1.检查isa指针上面的标记位,看引用计数是否保存在isa变量中,如果不是,则使用以前的步骤,否则执行第2步。</p>
<p>2.检查当前对象是否正在释放,如果是,则不做任何事情。</p>
<p>3.增加该对象的引用计数,但是并不马上写回到isa变量中。</p>
<p>4.检查增加后的引用计数的值是否能够被19表示,如果不是,则切换成以前的办法,否则执行第5步。</p>
<p>5.进行一个原子的写操作,将isa的值写回。</p>
<p>没有全局加锁操作,引用计数的更改更快了。</p>
<p>附isa的bit位含义</p>
<table>
<thead>
<tr>
<th>bit位</th>
<th>变量名</th>
<th>意义</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 bit</td>
<td>indexed</td>
<td>0表示普通的isa,1表示Tagged Pointer</td>
</tr>
<tr>
<td>1</td>
<td>has_assoc</td>
<td>表示在该对象是否有过associated对象,如果没有,在析构释放内存时可以更快</td>
</tr>
<tr>
<td>1</td>
<td>has_cxx_dtor</td>
<td>has_cxx_dtor 表示该对象是否有过C++或ARC的析构函数,如果没有,在析构释放内存时可以更快</td>
</tr>
<tr>
<td>30 bits</td>
<td>shiftcls</td>
<td>类的指针</td>
</tr>
<tr>
<td>9 bits</td>
<td>magic</td>
<td>其值固定为0xd2,用于在调试时分辨对象是否未完成初始化</td>
</tr>
<tr>
<td>1</td>
<td>weakly_referenced</td>
<td>表示该对象是否有过weak对象,如果没有,在析构释放内存时可以更快</td>
</tr>
<tr>
<td>1</td>
<td>deallocating</td>
<td>表示该对象是否正在析构</td>
</tr>
<tr>
<td>1</td>
<td>has_sidetable_rc</td>
<td>表示该对象的引用计数值是否大到无法直接在isa中保存</td>
</tr>
<tr>
<td>19 bits</td>
<td>extra_rc</td>
<td>表示该对象超过1的引用计数值,例如,如果该对象的引用计数是6,则extra_rc的值为5</td>
</tr>
</tbody>
</table>
<p>参考文章及书籍:</p>
<p>《iOS开发进阶》-第20章</p>
<p><a href="http://www.cocoachina.com/ios/20150918/13449.html" target="_blank" rel="noopener">http://www.cocoachina.com/ios/20150918/13449.html</a></p>
<p><a href="http://www.jianshu.com/p/c89c6a955772" target="_blank" rel="noopener">http://www.jianshu.com/p/c89c6a955772</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/11/01/iOS多线程整理/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Lorne">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Lorne的个人笔记">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/11/01/iOS多线程整理/" itemprop="url">iOS多线程整理</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 title="创建于" itemprop="dateCreated datePublished" datetime="2017-11-01T19:12:22+08:00">
2017-11-01
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<blockquote>
<p>开发过程中都会涉及多线程在这里做一个较全的备注整理</p>
</blockquote>
<h3 id="1-Grand-Central-Dispatch-GCD"><a href="#1-Grand-Central-Dispatch-GCD" class="headerlink" title="1.Grand Central Dispatch (GCD)"></a>1.Grand Central Dispatch (GCD)</h3><p> 在这之前先来了解GCD中两个核心概念:任务和队列</p>
<p><strong>任务</strong> :就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在GCD中是放在block中的。执行任务有两种方式:同步执行和异步执行。两者的主要区别是:是否具备开启新线程的能力。</p>
<p><em>同步执行(sync)</em>:只能在当前线程中执行任务,不具备开启新线程的能力</p>
<p><em>异步执行(async)</em>:可以在新的线程中执行任务,具备开启新线程的能力</p>
<p><strong>队列</strong> :这里的队列指任务队列,即用来存放任务的队列。队列是一种特殊的线性表,采用FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务。在GCD中有两种队列:串行队列和并行队列。</p>
<p><em>并行队列(Concurrent Dispatch Queue)</em>:可以让多个任务并行(同时)执行(自动开启多个线程同时执行任务)</p>
<p>并行功能只有在异步(dispatch_async)函数下才有效</p>
<p><em>串行队列(Serial Dispatch Queue)</em>:让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)</p>
<p><strong>GCD的使用步骤其实很简单,只有两步:</strong></p>
<ol>
<li>创建一个队列(串行队列或并行队列)</li>
<li>将任务添加到队列中,然后系统就会根据任务类型执行任务(同步执行或异步执行)</li>
</ol>
<h5 id="1-队列的创建方法"><a href="#1-队列的创建方法" class="headerlink" title="1 . 队列的创建方法"></a>1 . 队列的创建方法</h5><ul>
<li>可以使用dispatch_queue_create来创建对象,需要传入两个参数,第一个参数表示队列的唯一标识符,用于DEBUG,可为空;第二个参数用来识别是串行队列还是并行队列。DISPATCH_QUEUE_SERIAL表示串行队列,DISPATCH_QUEUE_CONCURRENT表示并行队列。</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">// 串行队列的创建方法</span><br><span class="line"></span><br><span class="line">dispatch\_queue\_t queue= dispatch\_queue\_create(&quot;test.queue&quot;, DISPATCH\_QUEUE\_SERIAL);</span><br><span class="line"></span><br><span class="line">// 并行队列的创建方法</span><br><span class="line"></span><br><span class="line">dispatch\_queue\_t queue= dispatch\_queue\_create(&quot;test.queue&quot;, DISPATCH\_QUEUE\_CONCURRENT);</span><br></pre></td></tr></table></figure>
<ul>
<li>对于并行队列,还可以使用dispatch_get_global_queue来创建 <strong>全局并行队列</strong> 。GCD默认提供了全局的并行队列,需要传入两个参数。第一个参数表示队列优先级,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT。第二个参数暂时没用,用0即可。</li>
</ul>
<h5 id="2-任务的创建方法"><a href="#2-任务的创建方法" class="headerlink" title="2. 任务的创建方法"></a>2. 任务的创建方法</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">// 同步执行任务创建方法</span><br><span class="line"></span><br><span class="line">dispatch\_sync(queue, ^{</span><br><span class="line"></span><br><span class="line"> NSLog(@&quot;%@&quot;,[NSThread currentThread]); // 这里放任务代码</span><br><span class="line"></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">// 异步执行任务创建方法</span><br><span class="line"></span><br><span class="line">dispatch\_async(queue, ^{</span><br><span class="line"></span><br><span class="line"> NSLog(@&quot;%@&quot;,[NSThread currentThread]); // 这里放任务代码</span><br><span class="line"></span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<p><strong>例子</strong> :</p>
<ul>
<li>并发队列+异步执行</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">- (void) asyncConcurrent</span><br><span class="line"></span><br><span class="line">{</span><br><span class="line"></span><br><span class="line"> dispatch\_queue\_t queue= dispatch\_queue\_create(&quot;test.queue&quot;, DISPATCH\_QUEUE\_CONCURRENT);</span><br><span class="line"></span><br><span class="line"> dispatch\_async(queue, ^{</span><br><span class="line"></span><br><span class="line"> NSLog(@&quot;1------%@&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> dispatch\_async(queue, ^{</span><br><span class="line"></span><br><span class="line"> NSLog(@&quot;2------%@&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>主队列(特殊队列) + 异步执行</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">- (void)asyncMain</span><br><span class="line"></span><br><span class="line">{</span><br><span class="line"></span><br><span class="line"> dispatch\_queue\_t queue = dispatch\_get\_main\_queue();</span><br><span class="line"></span><br><span class="line"> dispatch\_async(queue, ^{</span><br><span class="line"></span><br><span class="line"> NSLog(@&quot;1------%@&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line">//或者换一种写法</span><br><span class="line"></span><br><span class="line"> dispatch\_async(dispatch\_get\_main\_queue(), ^{</span><br><span class="line"></span><br><span class="line"> NSLog(@&quot;1------%@&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong>正常比较用的的多的例子:(</strong>线程间通讯<strong>)</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">dispatch\_async(dispatch\_get\_global\_queue(DISPATCH\_QUEUE\_PRIORITY\_DEFAULT, 0), ^{</span><br><span class="line"></span><br><span class="line"> NSLog(@&quot;1------%@&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line"> // 回到主线程</span><br><span class="line"></span><br><span class="line"> dispatch\_async(dispatch\_get\_main\_queue(), ^{</span><br><span class="line"></span><br><span class="line"> NSLog(@&quot;2-------%@&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line"> });</span><br></pre></td></tr></table></figure>
<p>});</p>
<p>附队列加任务组合</p>
<table>
<thead>
<tr>
<th></th>
<th>并行队列</th>
<th>串行队列</th>
<th>主队列</th>
</tr>
</thead>
<tbody>
<tr>
<td>同步(sync)</td>
<td>没有开启新线程,串行执行任务</td>
<td>没有开启新线程,串行执行任务</td>
<td>任务卡死</td>
</tr>
<tr>
<td>异步(async)</td>
<td>有开启新线程,并发执行任务</td>
<td>有开启1条新线程,串行执行任务</td>
<td>没有开启新线程,串行执行任务</td>
</tr>
</tbody>
</table>
<p>可以看出同步情况下同步下不会开启新线程,异步下不一定开启新线程,联想为什么JavaScript是单线程的却能让AJAX异步发送和回调请求。</p>
<h3 id="2-NSThread"><a href="#2-NSThread" class="headerlink" title="2.NSThread"></a>2.NSThread</h3><p>这里记录几个常用的API</p>
<p><strong> NSThread 有两种直接创建方式:</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument</span><br><span class="line"></span><br><span class="line">+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument</span><br><span class="line"></span><br><span class="line">第一个是实例方法,第二个是类方法</span><br><span class="line"></span><br><span class="line">1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];</span><br><span class="line"></span><br><span class="line">2、NSThread\* myThread = [[NSThread alloc] initWithTarget:self</span><br><span class="line"></span><br><span class="line"> selector:@selector(doSomething:)</span><br><span class="line"></span><br><span class="line"> object:nil];</span><br><span class="line"></span><br><span class="line">[myThread start];</span><br></pre></td></tr></table></figure>
<p>第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息</p>
<p>线程间通讯:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">-(void)doSomething:(id)parameter{</span><br><span class="line"></span><br><span class="line"> doSomething;//</span><br><span class="line"></span><br><span class="line"> [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>还有其他一些,实现麻烦不做介绍</p>
<h3 id="3-NSOperation(自定义NSOperation略)"><a href="#3-NSOperation(自定义NSOperation略)" class="headerlink" title="3.NSOperation(自定义NSOperation略)"></a>3.NSOperation(自定义NSOperation略)</h3><p>和GCD一样,NSOperation也是苹果提供给我们的一套多线程解决方案。实际上它也是基于GCD开发的,但是比GCD拥有更强的可控性和代码可读性。</p>
<p>NSOperation是一个抽象基类,基本没有什么实际使用价值。我们使用最多的是系统封装好的NSInvocationOperation和NSBlockOperation。</p>
<p>不过NSOperation一些通用的方法你要知道</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">NSOperation \* operation = [[NSOperation alloc]init];</span><br><span class="line"></span><br><span class="line">//开始执行</span><br><span class="line"></span><br><span class="line">[operation start];</span><br><span class="line"></span><br><span class="line">//取消执行</span><br><span class="line"></span><br><span class="line">[operation cancel];</span><br><span class="line"></span><br><span class="line">//执行结束后调用的Block</span><br><span class="line"></span><br><span class="line">[operation setCompletionBlock:^{</span><br><span class="line"></span><br><span class="line"> NSLog(@&quot;执行结束&quot;);</span><br><span class="line"></span><br><span class="line">}];</span><br></pre></td></tr></table></figure>
<h5 id="使用NSInvocationOperation-NSOPerationQueue"><a href="#使用NSInvocationOperation-NSOPerationQueue" class="headerlink" title="使用NSInvocationOperation + NSOPerationQueue"></a>使用NSInvocationOperation + NSOPerationQueue</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">- (void)testNSOperation</span><br><span class="line"></span><br><span class="line">{</span><br><span class="line"></span><br><span class="line">NSLog(@&quot;我在第%@个线程&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">//创建</span><br><span class="line"></span><br><span class="line">NSInvocationOperation \* invo = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(testNSInvocationOperation) object:nil];</span><br><span class="line"></span><br><span class="line">//执行</span><br><span class="line"></span><br><span class="line">[invo start];</span><br></pre></td></tr></table></figure>
<p>我们可以看到NSInvocationOperation其实是同步执行的,因此单独使用的话,这个东西也没有什么卵用,它需要配合我们后面介绍的NSOperationQueue去使用才能实现多线程调用,所以正确使用方法:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">NSInvocationOperation \* invo = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(testNSInvocationOperation) object:nil];</span><br><span class="line"></span><br><span class="line">NSOperationQueue \* queue = [[NSOperationQueue alloc]init];</span><br><span class="line"></span><br><span class="line">[queue addOperation:invo];</span><br></pre></td></tr></table></figure>
<h5 id="使用NSBlockOperation与-NSBlockOperation-NSOPerationQueue"><a href="#使用NSBlockOperation与-NSBlockOperation-NSOPerationQueue" class="headerlink" title="使用NSBlockOperation与 NSBlockOperation+NSOPerationQueue"></a>使用NSBlockOperation与 <strong>NSBlockOperation+NSOPerationQueue</strong></h5><p><strong>NSBlockOperation</strong>也是NSOperation的子类,支持并发的实行一个或多个block,使用起来简单又方便</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">NSBlockOperation \* blockOperation = [[NSBlockOperation</span><br><span class="line"></span><br><span class="line">blockOperationWithBlock:^{</span><br><span class="line"></span><br><span class="line">NSLog(@&quot;1在第%@个线程&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line">}];</span><br><span class="line"></span><br><span class="line">[blockOperation addExecutionBlock:^{</span><br><span class="line"></span><br><span class="line">NSLog(@&quot;2在第%@个线程&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line">}];</span><br><span class="line"></span><br><span class="line">[blockOperation addExecutionBlock:^{</span><br><span class="line"></span><br><span class="line">NSLog(@&quot;3在第%@个线程&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line">}];</span><br><span class="line"></span><br><span class="line">[blockOperation addExecutionBlock:^{</span><br><span class="line"></span><br><span class="line">NSLog(@&quot;4在第%@个线程&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line">}];</span><br><span class="line"></span><br><span class="line">[blockOperation addExecutionBlock:^{</span><br><span class="line"></span><br><span class="line">NSLog(@&quot;5在第%@个线程&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line">}];</span><br><span class="line"></span><br><span class="line">[blockOperation addExecutionBlock:^{</span><br><span class="line"></span><br><span class="line">NSLog(@&quot;6在第%@个线程&quot;,[NSThread currentThread]);</span><br><span class="line"></span><br><span class="line">}];</span><br><span class="line"></span><br><span class="line">[blockOperation start];</span><br></pre></td></tr></table></figure>
<p>通过三次不同结果的比较,我们可以看到,NSBlockOperation确实实现了多线程。但是我们可以看到,它并非是将所有的block都放到放到了子线程中。通过上面的打印记录我们可以发现,它会优先将block放到主线程中执行,若主线程已有待执行的代码,就开辟新的线程,但最大并发数为4(包括主线程在内)。如果block数量大于了4(不是固定值可能随运行环境变化),那么剩下的Block就会等待某个线程空闲下来之后被分配到该线程,且依然是优先分配到主线程。</p>
<p><strong>NSBlockOperation+NSOPerationQueue</strong></p>
<p>可以将我们把刚才写的NSBlockOperation也加到这个Queue中来</p>
<p> …原来的代码<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">//[blockOperation start];</span><br><span class="line"></span><br><span class="line">[queue addOperation:blockOperation];</span><br></pre></td></tr></table></figure></p>
<ul>
<li>当然更简洁办法</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"> NSOperationQueue \* queue = [[NSOperationQueue alloc]init];</span><br><span class="line"></span><br><span class="line">[queue addOperationWithBlock:^{</span><br><span class="line"></span><br><span class="line"> //这里是你想做的操作</span><br><span class="line"></span><br><span class="line">}];</span><br></pre></td></tr></table></figure>
<h5 id="NSOPerationQueue其他操作及注意事项:"><a href="#NSOPerationQueue其他操作及注意事项:" class="headerlink" title="NSOPerationQueue其他操作及注意事项:"></a>NSOPerationQueue其他操作及注意事项:</h5><ul>
<li>依赖关系</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[op2 addDependency:op1];</span><br><span class="line"></span><br><span class="line">[queue addOperation:op1];</span><br><span class="line"></span><br><span class="line">[queue addOperation:op2];</span><br></pre></td></tr></table></figure>
<p>使用依赖关系有三点需要注意</p>
<p>1.不要建立循环依赖,会造成死锁,原因同循环引用</p>
<p>2.使用依赖建议只使用NSInvocationOperation,NSInvocationOperation和NSBlockOperation混用会导致依赖关系无法正常实现。</p>
<p>3.依赖关系不光在同队列中生效,不同队列的NSOperation对象之前设置的依赖关系一样会生效</p>
<ul>
<li>NSOperationQueue提供暂停和取消两种操作。</li>
</ul>
<p>设置暂停只需要设置queue的 <strong>suspended</strong> 属性为YES或NO即可</p>
<p>取消你可以选择调用某个NSOperation的 <strong>cancle</strong> 方法,也可以调用Queue的 <strong>cancelAllOperations</strong> 方法来取消全部线程</p>
<p>这里需要强调的是,所谓的暂停和取消并不会立即暂停或取消当前操作,而是不在调用新的NSOperation。</p>
<ul>
<li>改变queue的maxConcurrentOperationCount可以设置最大并发数。</li>
</ul>
<p>这里依然有两点需要注意</p>
<p>1.最大并发数是有上限的,即使你设置为100,它也不会超过其上限,而这个上限的数目也是由具体运行环境决定的</p>
<p>2.设置最大并发数一定要在NSOperationQueue初始化后立即设置,因为上面说过,被放到队列中的NSOperation对象是由队列自己决定何时执行的,有可能你这边一添加立马就被执行。因此要想让设置生效一定要在初始化后立即设置</p>
<p>参考和摘录:</p>
<p><a href="http://www.jianshu.com/p/2d57c72016c6" target="_blank" rel="noopener">http://www.jianshu.com/p/2d57c72016c6</a></p>
<p><a href="http://www.jianshu.com/p/0c241a4918bf" target="_blank" rel="noopener">http://www.jianshu.com/p/0c241a4918bf</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</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-wrap sidebar-panel sidebar-panel-active">
<div class="site-overview">
<div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
<p class="site-author-name" itemprop="name">Lorne</p>
<p class="site-description motion-element" itemprop="description"></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>
</nav>
<div class="links-of-author motion-element">
</div>
</div>
</section>
</div>
</aside>
</div>
</main>
<footer id="footer" class="footer">
<div class="footer-inner">
<div class="copyright">© <span itemprop="copyrightYear">2017</span>
<span class="with-love">
<i class="fa fa-user"></i>
</span>
<span class="author" itemprop="copyrightHolder">Lorne</span>
</div>
<div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>
<span class="post-meta-divider">|</span>
<div class="theme-info">主题 — <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Muse</a> v5.1.3</div>
</div>
</footer>
<div class="back-to-top">
<i class="fa fa-arrow-up"></i>
</div>
</div>
<script type="text/javascript">
if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
window.Promise = null;
}
</script>
<script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
<script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
<script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
<script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
<script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
<script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
<script type="text/javascript" src="/js/src/utils.js?v=5.1.3"></script>
<script type="text/javascript" src="/js/src/motion.js?v=5.1.3"></script>
<script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.3"></script>