-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
841 lines (423 loc) · 170 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Talk is cheap. Show me the code</title>
<link href="/atom.xml" rel="self"/>
<link href="https://lizhaobomb.github.io/"/>
<updated>2021-09-13T14:43:21.557Z</updated>
<id>https://lizhaobomb.github.io/</id>
<author>
<name>木子召</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>免费搭建无限容量个人网盘</title>
<link href="https://lizhaobomb.github.io/2021/09/13/%E5%85%8D%E8%B4%B9%E6%90%AD%E5%BB%BA%E6%97%A0%E9%99%90%E5%AE%B9%E9%87%8F%E4%B8%AA%E4%BA%BA%E7%BD%91%E7%9B%98/"/>
<id>https://lizhaobomb.github.io/2021/09/13/%E5%85%8D%E8%B4%B9%E6%90%AD%E5%BB%BA%E6%97%A0%E9%99%90%E5%AE%B9%E9%87%8F%E4%B8%AA%E4%BA%BA%E7%BD%91%E7%9B%98/</id>
<published>2021-09-13T14:36:35.000Z</published>
<updated>2021-09-13T14:43:21.557Z</updated>
<content type="html"><![CDATA[<h1 id="免费搭建无限容量个人网盘"><a href="#免费搭建无限容量个人网盘" class="headerlink" title="免费搭建无限容量个人网盘"></a>免费搭建无限容量个人网盘</h1><p>数据无价、慎重保存</p><p><a href="https://docimg1.docs.qq.com/image/Kt6mv5BRvnaUBSKcpYHMXw.png?w=1280&h=720.365296803653" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg1.docs.qq.com/image/Kt6mv5BRvnaUBSKcpYHMXw.png?w=1280&h=720.365296803653" class="lazyload"></a></p><p><a href="https://profreehost.com/" target="_blank" rel="noopener">https://profreehost.com</a></p><p>打开这个网站我们可以看到都是免费的,也是无限量的</p><p><a href="https://docimg7.docs.qq.com/image/O8nd9R8juvBDILE2LqmH2g.png?w=1280&h=720.365296803653" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg7.docs.qq.com/image/O8nd9R8juvBDILE2LqmH2g.png?w=1280&h=720.365296803653" class="lazyload"></a></p><p>我们先注册下,只需要一个邮箱就可以,注册很快,注册完去邮箱激活下</p><p><a href="https://docimg7.docs.qq.com/image/GJ6Vc6Hc6xlwtuugMXFpAw.png?w=1280&h=720.365296803653" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg7.docs.qq.com/image/GJ6Vc6Hc6xlwtuugMXFpAw.png?w=1280&h=720.365296803653" class="lazyload"></a></p><p>注册完成后在这里可以新建项目</p><p><a href="https://docimg9.docs.qq.com/image/uyuHY-he8Biepho3N9Urdg.png?w=1280&h=720.365296803653" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg9.docs.qq.com/image/uyuHY-he8Biepho3N9Urdg.png?w=1280&h=720.365296803653" class="lazyload"></a></p><p>新建项目有两种方式,一种免费的域名,一种是可以绑定自己的域名,我们就用第一种方式,在CREATE NEW WEBSITE 下填写一个二级域名</p><p><a href="https://docimg4.docs.qq.com/image/YzWxxs_XI5R9DX-9aumetA.png?w=1125&h=477" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg4.docs.qq.com/image/YzWxxs_XI5R9DX-9aumetA.png?w=1125&h=477" class="lazyload"></a></p><p>创建好后我们点击manage进入后台的一个管理界面</p><p><a href="https://docimg9.docs.qq.com/image/pUWeZ6cTgu-dBBTQ32O8lQ.png?w=1103&h=486" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg9.docs.qq.com/image/pUWeZ6cTgu-dBBTQ32O8lQ.png?w=1103&h=486" class="lazyload"></a></p><p>我们点击control panel,进入控制面板</p><p><a href="https://docimg2.docs.qq.com/image/-k4Aw4duAVNIz16P55CotA.png?w=1112&h=496" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg2.docs.qq.com/image/-k4Aw4duAVNIz16P55CotA.png?w=1112&h=496" class="lazyload"></a></p><p>往下滚动找到Softaculous Apps Installer 然后点进去安装WordPress</p><p><a href="https://docimg5.docs.qq.com/image/MmvRHQPScXoKrrRnilmi6w.png?w=1105&h=609" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg5.docs.qq.com/image/MmvRHQPScXoKrrRnilmi6w.png?w=1105&h=609" class="lazyload"></a></p><p>点击WordPress install</p><p><a href="https://docimg3.docs.qq.com/image/bSruegZkdU32ZNwVj9YayQ.png?w=1120&h=780" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg3.docs.qq.com/image/bSruegZkdU32ZNwVj9YayQ.png?w=1120&h=780" class="lazyload"></a></p><p>修改下账号和密码</p><p><a href="https://docimg8.docs.qq.com/image/hHtfTHFiA3AlulHCJd6i2A.png?w=1280&h=720.365296803653" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg8.docs.qq.com/image/hHtfTHFiA3AlulHCJd6i2A.png?w=1280&h=720.365296803653" class="lazyload"></a></p><p>最后点击安装,安装过程很快的,</p><p>之后我们再点击Online File Manager</p><p><a href="https://docimg2.docs.qq.com/image/AdA54HQVRWySPzQFi1wMMA.png?w=1091&h=519" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg2.docs.qq.com/image/AdA54HQVRWySPzQFi1wMMA.png?w=1091&h=519" class="lazyload"></a></p><p>然后点击htdocs这个文件夹,这里有很多刚才安装的WordPress的文件,我们就是利用这个文件夹来做我们的个人网盘,下一步就是要上传我们的代码了,VFM(Veno File Manager)这个压缩包我已经放到文末了,大家直接下载,解压,然后上传就行了</p><p><a href="https://docimg4.docs.qq.com/image/5e-R2F8dhANerSLp6ZAbTQ.png?w=947&h=613" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg4.docs.qq.com/image/5e-R2F8dhANerSLp6ZAbTQ.png?w=947&h=613" class="lazyload"></a></p><p>解压完是这个结构,我们主要用到了vfm这个文件夹里的东西,这里主要有两个文件夹和两个文件,都上传到htdocs目录下</p><p><a href="https://docimg6.docs.qq.com/image/ppxS1Z9uf0xWQ_EHmgLNwg.png?w=730&h=381" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg6.docs.qq.com/image/ppxS1Z9uf0xWQ_EHmgLNwg.png?w=730&h=381" class="lazyload"></a></p><p>在网站上点击左下角的upload Folder和upload file 分别上传两个文件夹和两个文件</p><p><a href="https://docimg8.docs.qq.com/image/KTldNPY2q14yUBQFiPyo2g.png?w=429&h=447" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg8.docs.qq.com/image/KTldNPY2q14yUBQFiPyo2g.png?w=429&h=447" class="lazyload"></a></p><p>其中这个文件夹文件比较多上传的有点慢大家耐心等待下,千万不要中断</p><p><a href="https://docimg9.docs.qq.com/image/RCkI7glijyiPhJH_HuUobQ.png?w=1280&h=720.365296803653" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg9.docs.qq.com/image/RCkI7glijyiPhJH_HuUobQ.png?w=1280&h=720.365296803653" class="lazyload"></a></p><p>index.php选择覆盖就行</p><p><a href="https://docimg4.docs.qq.com/image/isIxebD1zaljvDTmOX49NQ.png?w=1280&h=720.365296803653" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg4.docs.qq.com/image/isIxebD1zaljvDTmOX49NQ.png?w=1280&h=720.365296803653" class="lazyload"></a></p><p>到此就完成了所有的步骤,打开你自己创建的那个二级域名,就可以看到</p><p><a href="https://docimg2.docs.qq.com/image/7BcYNuSHIoyRB4MD_BjuxQ.png?w=1280&h=720.365296803653" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://docimg2.docs.qq.com/image/7BcYNuSHIoyRB4MD_BjuxQ.png?w=1280&h=720.365296803653" class="lazyload"></a></p><p>就可以上传自己的文件了</p><p>最后再强调下,数据无价,一定要慎重保存,项目可能会被封,然后数据就没了。。。。本教程仅做参考,数据丢失概不负责</p><p>Veno File Manager 在这里下载</p><p><a href="https://url20.ctfile.com/f/33495220-512347763-cafc26" target="_blank" rel="noopener">https://url20.ctfile.com/f/33495220-512347763-cafc26</a></p><p>(访问密码:2601)</p><p>不想看图文的可以看视频教程在这里</p><p><a href="https://url20.ctfile.com/f/33495220-512253011-a85302" target="_blank" rel="noopener">https://url20.ctfile.com/f/33495220-512253011-a85302</a></p><p>(访问密码:2601)</p>]]></content>
<summary type="html">
免费搭建无限容量个人网盘
数据无价、慎重保存
https://profreehost.com
打开这个网站我们可以看到都是免费的,也是无限量的
我们先注册下,只需要一个邮箱就可以,注册很快,注册完去邮箱激活下
注册完成后在这里可以新建项目
新建项目有两种方式,一种免费的域名,一种是可以绑定自己的域名,我们就用第一种方式,在CREATE NEW WEBSITE 下填写一个二级域名
创建好后我们点击manage进入后台的一个管理界面
我们点击control panel,进入控制面板
往下滚动找到Softaculous Apps Installer 然后点
</summary>
<category term="免费网盘" scheme="https://lizhaobomb.github.io/tags/%E5%85%8D%E8%B4%B9%E7%BD%91%E7%9B%98/"/>
<category term="不限量" scheme="https://lizhaobomb.github.io/tags/%E4%B8%8D%E9%99%90%E9%87%8F/"/>
<category term="服务器" scheme="https://lizhaobomb.github.io/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
</entry>
<entry>
<title>iOS内存管理01-定时器</title>
<link href="https://lizhaobomb.github.io/2020/03/12/iOS%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%8601-%E5%AE%9A%E6%97%B6%E5%99%A8/"/>
<id>https://lizhaobomb.github.io/2020/03/12/iOS%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%8601-%E5%AE%9A%E6%97%B6%E5%99%A8/</id>
<published>2020-03-11T16:10:00.000Z</published>
<updated>2020-03-13T14:24:46.583Z</updated>
<content type="html"><![CDATA[<h2 id="这一阶段我们主要来讲讲iOS内存管理方面的知识,面试的时候可能大家多多少少都会被问及这方面的问题,那我们就从常见的面试题开讲"><a href="#这一阶段我们主要来讲讲iOS内存管理方面的知识,面试的时候可能大家多多少少都会被问及这方面的问题,那我们就从常见的面试题开讲" class="headerlink" title="这一阶段我们主要来讲讲iOS内存管理方面的知识,面试的时候可能大家多多少少都会被问及这方面的问题,那我们就从常见的面试题开讲"></a>这一阶段我们主要来讲讲iOS内存管理方面的知识,面试的时候可能大家多多少少都会被问及这方面的问题,那我们就从常见的面试题开讲</h2><ul><li><p>使用<code>CADisplayLink</code>、<code>NSTimer</code>有什么注意点?</p></li><li><p>介绍下内存的几大区域</p></li><li><p>讲一下你对iOS内存管理的理解</p></li><li><p><code>ARC</code> 都帮我们做了什么?</p></li><li><p><code>weak指针</code> 的实现原理</p></li><li><p><code>autorelease</code> 对象在什么时机会被调用<code>release</code></p></li><li><p>方法里有局部对象,出了方法后会<code>立即释放</code>吗?</p></li></ul><p>我们一个一个来,今天我们就先来讲讲第一条使用<code>CADisplayLink</code>、<code>NSTimer</code>有什么注意点?</p><blockquote><p>主要就是<code>CADisplayLink</code>、<code>NSTimer</code>会对<code>target</code>产生<code>强引用</code>,如果<code>target</code>又对它们产生<code>强引用</code>,那么就会引发<code>循环引用</code></p></blockquote><p>循环引用大家都知道吧,这样就会导致内存泄漏,我们写代码来看看</p><p>首先我们看下<code>CADisplayLink</code>,我们新建一个<code>NavigationController</code>,然后点击一个按钮<code>push</code>到我们<code>ViewController</code>,<code>NavigationController</code>就一个按钮比较简单我就不写了,下面看下我们的<code>ViewController</code>里的代码</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@interface ViewController ()</span><br><span class="line">@property (strong, nonatomic) CADisplayLink *link;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation ViewController</span><br><span class="line"></span><br><span class="line">- (void)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> </span><br><span class="line"> // 保证调用频率和屏幕的刷帧频率一致,60FPS</span><br><span class="line"> self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkTest)];</span><br><span class="line"> [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];</span><br><span class="line"> </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (void)linkTest</span><br><span class="line">{</span><br><span class="line"> NSLog(@"%s", __func__);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (void)dealloc</span><br><span class="line">{</span><br><span class="line"> NSLog(@"%s", __func__);</span><br><span class="line"> [self.link invalidate];</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>可能有些同学没用过<code>CADisplayLink</code>,</p><blockquote><p>我们先简单了解下,<code>CADisplayLink</code>其实也是一个定时器,只不过这个定时器<code>不用你来设置时间</code>,它是要保证<code>调用频率</code>和<code>屏幕的刷帧频率一致</code>,通常来说大概是<code>60FPS</code>,当然如果你主线程要是做了很多耗时操作的话也可能就不到60了,也就是说我们的<code>linkTest方法</code>大概一秒钟会调用<code>60次</code>的样子, 那我们运行程序看下控制台的输出也证实了这一点</p></blockquote><p>那接下来我们来看问题</p><p>我们看到我们<code>displayLinkWithTarget</code>这个类方法会传入一个<code>self</code>,这样,<code>CADisplayLink</code>对象就会强引用<code>self</code>,而<code>self</code>强引用了<code>@property (strong, nonatomic) CADisplayLink *link</code>,所以就产生了<code>循环引用</code>,导致两者<code>都不会被释放</code>,可能我们很多同学也都会在<code>dealloc</code>方法里调用 <code>[self.link invalidate]</code> 其实是没有用的,我们点下返回键就可以看到,<code>dealloc</code>根本不用被调用,那如何解决呢,我们先来看看<code>Timer</code>是不是也有这个问题,给Controller添加一个属性</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@property (strong, nonatomic) NSTimer *timer;</span><br></pre></td></tr></table></figure></div><p>然后初始化并每隔一秒调用<code>timerTest</code>方法</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];</span><br><span class="line"></span><br><span class="line">- (void)timerTest</span><br><span class="line">{</span><br><span class="line"> NSLog(@"%s", __func__);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>我们运行程序看到,返回的时候<code>timer</code>并没有停止,<code>dealloc</code>也没有调用说明<code>timer</code>也存在这个问题,那接下来我们先来解决<code>timer</code>的问题,然后再解决<code>CADisplayLink</code>的问题</p><p>可能很多同学会说我来个弱指针<code>__weak typeof(self) weakSelf = self</code> ,把<code>weakSelf</code>传入<code>target</code>, 不就行了吗,那大家想想管用吗?我们运行下程序发下然并卵返回<code>timer</code>依旧跑着,<code>dealloc</code>也没调用,那为什么之前的都好使这次不好使了呢,之前是因为我们在<code>block</code>里的<code>循环引用</code>可以用<code>weakSelf</code>来解决,我们现在是没有<code>block</code>的,而且,<code>weakSelf</code>和<code>self</code>其实都是同一个内存地址,我们只是把它当做<code>参数</code>来传给<code>target</code>这个形参的,所以没用,依旧还是强引用,我们可以这样认为</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@interface NSTimer()</span><br><span class="line">@property(strong, nonatomic) id target</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight plain"><figcaption><span>内部强引用了```target```跟你外部传入强引用还是弱引用没有半毛钱关系,所以这是不能解决问题的,那怎么办?其实要是```NSTimer```的话有好几种解决方案,我们先来看看第一种方案</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">### 1、更换```timer```的初始化方法,用带```block```的方法,这个时候就可以用```weakSelf```了</span><br></pre></td></tr></table></figure></div><p>__weak typeof(self) weakSelf = self;<br>self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {<br> [weakSelf timerTest];<br> }];</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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">我们再运行下程序,我们看到```dealloc```调用了```timer```也停止了,所以问题也解决了</span><br><span class="line"></span><br><span class="line">### 2、那我们再换回第一种方法,是否可以解决呢,答案是肯定的,我们来引入一个OtherObject当target,我们来画个图来理解下</span><br><span class="line"></span><br><span class="line">![timer](https://upload-images.jianshu.io/upload_images/112869-8f7b22e60afe0ac9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)</span><br><span class="line"></span><br><span class="line">这样,```timer```强引用```OtherObject```,```OtherObject```弱引用```Controller```就这样就行了,那具体如何来做呢</span><br><span class="line"></span><br><span class="line">我们新建一个```XXProxy```类</span><br></pre></td></tr></table></figure></div><p>@interface XXProxy : NSObject</p><ul><li>(instancetype)proxyWithTarget:(id)target;<br>@property (weak, nonatomic) id target;<br>@end</li></ul><p>@implementation XXProxy</p><ul><li>(instancetype)proxyWithTarget:(id)target<br>{<br> XXProxy *proxy = [[XXProxy alloc] init];<br> proxy.target = target;<br> return proxy;<br>}<div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">然后修改我们的```Controller</span><br></pre></td></tr></table></figure></div></li></ul><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[XXProxy proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];</span><br></pre></td></tr></table></figure></div><p>这样就解决循环引用了,但是我们发现另一个问题,现在<code>target</code>里并没有<code>timerTest</code>这个方法,运行肯定会<code>crash</code>,当然我们也可以直接在<code>XXProxy</code> 类里写一个<code>timerTest</code></p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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">- (void)timerTest</span><br><span class="line">{</span><br><span class="line"> [self.target timerTest];</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>但是大家想没想过,<code>XXProxy</code>这个可能不止被一个<code>timer</code>用,要是有很多<code>timer</code>总不至于把所有的方法都写上吧,大家想想有没有什么更好的方法呢?其实,这个时候我们就可以用<code>消息转发机制</code>,之后可以给大家详细说说,其实消息转发是有<code>三个阶段</code>的<code>forwardInvocation</code>、<code>methodSignatureForSelector</code>、<code>forwardingTargetForSelector</code>,我们现在就直接用第三阶段了直接</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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">- (id)forwardingTargetForSelector:(SEL)aSelector</span><br><span class="line">{</span><br><span class="line"> return self.target;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>这样不管外界调用我什么方法我都直接转发给控制器对应的方法,这样是不是就一劳永逸了</p><p>现在我们运行下程序,我们可以看到dealloc是有调用的,所以问题解决<br>那我们现在再看下CADisplayLink是不是可以用相同的办法解决,我们修改下代码</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">// 保证调用频率和屏幕的刷帧频率一致,60FPS</span><br><span class="line">self.link = [CADisplayLink displayLinkWithTarget:[XXProxy proxyWithTarget:self] selector:@selector(linkTest)];</span><br><span class="line">[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];</span><br></pre></td></tr></table></figure></div><p>我们运行下程序,看下日志,同样解决问题了</p><h2 id="点此进入我的博客也会同步更新"><a href="#点此进入我的博客也会同步更新" class="headerlink" title="点此进入我的博客也会同步更新"></a><a href="https://lizhaobomb.github.io">点此进入我的博客也会同步更新</a></h2><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing "></a><a href="https://lizhaobomb.github.io">One More Thing </a></h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
这一阶段我们主要来讲讲iOS内存管理方面的知识,面试的时候可能大家多多少少都会被问及这方面的问题,那我们就从常见的面试题开讲
* 使用CADisplayLink、NSTimer有什么注意点?
* 介绍下内存的几大区域
* 讲一下你对iOS内存管理的理解
* ARC 都帮我们做了什么?
* weak指针 的实现原理
* autorelease 对象在什么时机会被调用release
* 方法里有局部对象,出了方法后会立即释放吗?
我们一个一个来,今天我们就先来讲讲第一条使
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="设计模式与架构" scheme="https://lizhaobomb.github.io/categories/iOS/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E6%9E%B6%E6%9E%84/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="内存管理" scheme="https://lizhaobomb.github.io/tags/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/"/>
<category term="定时器" scheme="https://lizhaobomb.github.io/tags/%E5%AE%9A%E6%97%B6%E5%99%A8/"/>
</entry>
<entry>
<title>iOS架构设计06-分层架构</title>
<link href="https://lizhaobomb.github.io/2020/03/11/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A106-%E5%88%86%E5%B1%82%E6%9E%B6%E6%9E%84/"/>
<id>https://lizhaobomb.github.io/2020/03/11/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A106-%E5%88%86%E5%B1%82%E6%9E%B6%E6%9E%84/</id>
<published>2020-03-10T16:10:00.000Z</published>
<updated>2020-03-12T13:41:49.731Z</updated>
<content type="html"><![CDATA[<p>今天我们来看看所谓的<code>三层</code>、<code>四层</code>架构是什么东西?我们可以画个图来分析下</p><p><a href="https://ae01.alicdn.com/kf/Ufb30c0d6b59c45a6bcf859c889fd86bbU.jpg" data-fancybox="group" data-caption="三层架构" class="fancybox"><img alt="三层架构" title="三层架构" data-src="https://ae01.alicdn.com/kf/Ufb30c0d6b59c45a6bcf859c889fd86bbU.jpg" class="lazyload"></a></p><p>其实所谓的这个<code>三层架构</code>,一般来说,把我们项目中所有的类,不管控制器也好,View也好,模型也好,或者一些工具类,这些类我们都把它分成三个层次</p><ul><li><p>界面层</p><blockquote><p>主要就是用来显示界面的<code>控制器</code>、<code>View</code></p></blockquote></li><li><p>业务层</p><blockquote><p>用来处理我们的业务的,比如我们有登录业务或者加载新闻列表业务,或者购物车等等,相当于我们说的一个功能</p></blockquote></li><li><p>数据层</p><blockquote><p>主要是指<code>网络数据</code>,<code>本地数据库</code></p></blockquote></li></ul><p>举个例子,假如我要显示一个<code>新闻页面</code>,那该如何对应这些层呢?</p><ul><li><p>首先,界面层</p><blockquote><p>新闻列表(TableView)肯定属于界面层,界面层要显示数据肯定要加载数据</p></blockquote></li><li><p>业务层</p><blockquote><p>我们可以交给业务层来加载,那业务层就会有一个叫加载新闻数据的业务,那它数据从哪里来呢?</p></blockquote></li><li><p>数据层</p><blockquote><p>这个时候就交给数据层来做,数据层数据可能来源于网络或者本地数据库,</p></blockquote></li></ul><h2 id="那这样分层有什么好处呢"><a href="#那这样分层有什么好处呢" class="headerlink" title="那这样分层有什么好处呢?"></a>那这样分层有什么好处呢?</h2><ul><li>好处就是</li></ul><blockquote><p>假设我们没有业务层这个东西,那就意味着,界面层直接去访问数据层,这样的话界面层就需要去关心,我们网络请求地址,参数,那假如是数据库的话,可能还需要关心数据库的底层实现(表,字段等等),但是我们一旦分层了就不需要这样了,界面层只关心我要加载数据只需要去调用业务层的加载新闻数据,至于这个数据是通过网络还是本地数据库统统不用关心</p></blockquote><h2 id="可能说的有点抽象,我们写个简单的demo来看看"><a href="#可能说的有点抽象,我们写个简单的demo来看看" class="headerlink" title="可能说的有点抽象,我们写个简单的demo来看看"></a>可能说的有点抽象,我们写个简单的demo来看看</h2><p>首先我们的<code>ViewController</code>肯定是属于界面层了这个毋庸置疑了,它需要去加载新闻列表数据,只需要调用下业务层的加载新闻数据</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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">[XXNewsService loadNews:@{} success:^(NSArray *newsData) {</span><br><span class="line"> </span><br><span class="line"> } failure:^(NSError *error) {</span><br><span class="line"> </span><br><span class="line"> }];</span><br></pre></td></tr></table></figure></div><p>我们新建一个XXNewsService</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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">@interface XXNewsService : NSObject</span><br><span class="line">+ (void)loadNews:(NSDictionary *)params success:(void (^)(NSArray *newsData))success failure:(void (^)(NSError *error))failure;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation XXNewsService</span><br><span class="line"></span><br><span class="line">+ (void)loadNews:(NSDictionary *)params success:(void (^)(NSArray *newsData))success failure:(void (^)(NSError *error))failure</span><br><span class="line">{</span><br><span class="line"> // 先取出本地数据</span><br><span class="line">// [XXDBTool loadLocalData....];</span><br><span class="line"> </span><br><span class="line"> // 如果没有本地数据,就加载网络数据</span><br><span class="line">// [XXHTTPTool GET:@"xxxx" params:nil success:^(id result) {</span><br><span class="line">// success(array);</span><br><span class="line">// } failure:failure];</span><br><span class="line">}</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><p>然后新建我们的数据层假设就是<code>XXHTTPTool</code>和<code>XXDBTool</code>,我就大概写一下</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@interface XXHTTPTool : NSObject</span><br><span class="line">+ (void)GET:(NSString *)URL params:(NSDictionary *)params success:(void (^)(id result))success failure:(void (^)(NSError *error))failure;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation XXHTTPTool</span><br><span class="line"></span><br><span class="line">+ (void)GET:(NSString *)URL params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure</span><br><span class="line">{</span><br><span class="line"> // 调用AFN</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><p>那四层是怎么回事呢,一般无非就是把数据层又拆出一层网络层,当然这个也不一定,看每个项目的具体情况<br><a href="https://ae01.alicdn.com/kf/Ue695f037d0bc433d8a13eee225d6bcd27.jpg" data-fancybox="group" data-caption="四层架构" class="fancybox"><img alt="四层架构" title="四层架构" data-src="https://ae01.alicdn.com/kf/Ue695f037d0bc433d8a13eee225d6bcd27.jpg" class="lazyload"></a></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>架构这种东西本身就是很抽象的,光靠说是说不清楚的,还是需要多做项目,然后应用起来,这个就先告一段落,接下来我打算写<code>内存管理</code>和<code>多线程</code>方面的东西了</p><p>明天我们来说说<code>内存管理</code></p><h2 id="点此进入我的博客也会同步更新"><a href="#点此进入我的博客也会同步更新" class="headerlink" title="点此进入我的博客也会同步更新"></a><a href="https://lizhaobomb.github.io">点此进入我的博客也会同步更新</a></h2><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing "></a><a href="https://lizhaobomb.github.io">One More Thing </a></h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
今天我们来看看所谓的三层、四层架构是什么东西?我们可以画个图来分析下
其实所谓的这个三层架构,一般来说,把我们项目中所有的类,不管控制器也好,View也好,模型也好,或者一些工具类,这些类我们都把它分成三个层次
* 界面层
主要就是用来显示界面的控制器、View
* 业务层
用来处理我们的业务的,比如我们有登录业务或者加载新闻列表业务,或者购物车等等,相当于我们说的一个功能
* 数据层
主要是指网络数据,本地数据库
举个例子,假如我要显示一个新闻页面,那该如何对应这些层呢?
* 首先,
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="设计模式与架构" scheme="https://lizhaobomb.github.io/categories/iOS/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E6%9E%B6%E6%9E%84/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="设计模式" scheme="https://lizhaobomb.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="架构" scheme="https://lizhaobomb.github.io/tags/%E6%9E%B6%E6%9E%84/"/>
</entry>
<entry>
<title>iOS架构设计05-MVVM</title>
<link href="https://lizhaobomb.github.io/2020/03/10/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A105-MVVM/"/>
<id>https://lizhaobomb.github.io/2020/03/10/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A105-MVVM/</id>
<published>2020-03-09T16:10:00.000Z</published>
<updated>2020-03-12T13:41:02.040Z</updated>
<content type="html"><![CDATA[<p>相信大家都听过这种架构,我们来看下图<br><a href="https://ae01.alicdn.com/kf/U0b0993732612493e95156a67d8f53b7dL.jpg" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://ae01.alicdn.com/kf/U0b0993732612493e95156a67d8f53b7dL.jpg" class="lazyload"></a><br>跟我们上篇文章说的MVP挺像的,中间的<code>Presenter</code>,变成了<code>ViewModel</code><br>这种架构其实也是三种角色</p><ul><li><p>Model</p></li><li><p>View</p></li><li><p>ViewModel</p></li></ul><p>这种架构,跟<code>MVP</code>的共同点:</p><blockquote><ul><li>都能达到<code>ViewController</code>的瘦身,</li><li><code>View</code>和<code>Model</code>的隔离,</li></ul></blockquote><p>跟<code>MVP</code>不同点</p><ul><li><code>双向绑定</code></li></ul><blockquote><p>就是我们的<code>View</code>一旦监听到了<code>ViewModel</code>里的数据变化可以<code>自动更新</code>,一提到<code>MVVM</code>我们大家肯定都会想到<code>RAC</code>这个框架,由于这个框架比较重,为了方便介绍这种架构,我选择另一种方案,<code>KVO</code>,这里我们要是自己写的话很麻烦,我就直接用<code>Facebook</code>开源的<code>KVOController</code>大家可以上<code>GitHub</code>去下载</p></blockquote><h2 id="下面我们来看下实例"><a href="#下面我们来看下实例" class="headerlink" title="下面我们来看下实例"></a>下面我们来看下实例</h2><p>我们还是沿用上篇文章的<code>Demo</code>来进行修改,首先我们把<code>Presenter</code>删掉,然后新建我们的<code>ViewModel</code>,<code>Presenter</code>里的大部分逻辑还是可以<code>copy</code>到<code>ViewModel</code>里的,还有一点就是因为<code>ViewModel</code>要绑定<code>Model</code>所以会把<code>Model</code>的属性都赋值给<code>ViewModel</code>,然后<code>View</code>只要监听<code>ViewModel</code>里的属性变化来改变自己就行了</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@interface XXAppViewModel : NSObject</span><br><span class="line">- (instancetype)initWithController:(UIViewController *)controller;</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@interface XXAppViewModel() <XXAppViewDelegate></span><br><span class="line">@property (weak, nonatomic) UIViewController *controller;</span><br><span class="line">@property (copy, nonatomic) NSString *name;</span><br><span class="line">@property (copy, nonatomic) NSString *image;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation XXAppViewModel</span><br><span class="line"></span><br><span class="line">- (instancetype)initWithController:(UIViewController *)controller</span><br><span class="line">{</span><br><span class="line"> if (self = [super init]) {</span><br><span class="line"> self.controller = controller;</span><br><span class="line"> </span><br><span class="line"> // 创建View</span><br><span class="line"> XXAppView *appView = [[XXAppView alloc] init];</span><br><span class="line"> appView.frame = CGRectMake(100, 100, 100, 150);</span><br><span class="line"> appView.delegate = self;</span><br><span class="line"> appView.viewModel = self;</span><br><span class="line"> [controller.view addSubview:appView];</span><br><span class="line"> </span><br><span class="line"> // 加载模型数据</span><br><span class="line"> XXApp *app = [[XXApp alloc] init];</span><br><span class="line"> app.name = @"QQ";</span><br><span class="line"> app.image = @"QQ";</span><br><span class="line"> </span><br><span class="line"> // 设置数据完成绑定</span><br><span class="line"> self.name = app.name;</span><br><span class="line"> self.image = app.image;</span><br><span class="line"> }</span><br><span class="line"> return self;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">#pragma mark - XXAppViewDelegate</span><br><span class="line">- (void)appViewDidClick:(XXAppView *)appView</span><br><span class="line">{</span><br><span class="line"> NSLog(@"viewModel 监听了 appView 的点击");</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>接下来我们修改下<code>ViewController</code>,把<code>Presenter</code>换成<code>ViewModel</code></p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@interface ViewController ()</span><br><span class="line">@property (strong, nonatomic) XXAppViewModel *viewModel;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation ViewController</span><br><span class="line"></span><br><span class="line">- (void)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> </span><br><span class="line"> self.viewModel = [[XXAppViewModel alloc] initWithController:self];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><p>最后我们来看下我们的<code>View</code>的修改的地方,因为要和<code>ViewModel</code>进行双向绑定,所以我们要有个<code>ViewModel</code>对象</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@property (weak, nonatomic) XXAppViewModel *viewModel;</span><br></pre></td></tr></table></figure></div><p>然后我们在<code>setViewModel</code>的时候做属性监听这里我们用的<code>KVOController</code></p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">- (void)setViewModel:(XXAppViewModel *)viewModel</span><br><span class="line">{</span><br><span class="line"> _viewModel = viewModel;</span><br><span class="line"> </span><br><span class="line"> __weak typeof(self) weakSelf = self;</span><br><span class="line"> [self.KVOController observe:viewModel keyPath:@"name" options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {</span><br><span class="line"> weakSelf.nameLabel.text = change[NSKeyValueChangeNewKey];</span><br><span class="line"> }];</span><br><span class="line"> </span><br><span class="line"> [self.KVOController observe:viewModel keyPath:@"image" options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {</span><br><span class="line"> weakSelf.iconView.image = [UIImage imageNamed:change[NSKeyValueChangeNewKey]];</span><br><span class="line"> }];</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>这样我们就完成了<code>双向绑定</code>,只要我们的<code>ViewModel</code>里的数据变化了,<code>View</code>就会监听到改动从而更新自己</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Demo只是很简单的一种阐述,很多公司里的都是<code>MVVM+RAC</code>,有时间我也会开个<code>RAC</code>的专栏来记录下这个框架的使用,还是那句话,架构这种东西没有唯一,选择适合自己的就行。</p><p>明天我们来说说<code>分层架构</code></p><h2 id="点此进入我的博客也会同步更新"><a href="#点此进入我的博客也会同步更新" class="headerlink" title="点此进入我的博客也会同步更新"></a><a href="https://lizhaobomb.github.io">点此进入我的博客也会同步更新</a></h2><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing "></a><a href="https://lizhaobomb.github.io">One More Thing </a></h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
相信大家都听过这种架构,我们来看下图
跟我们上篇文章说的MVP挺像的,中间的Presenter,变成了ViewModel
这种架构其实也是三种角色
* Model
* View
* ViewModel
这种架构,跟MVP的共同点:
* 都能达到ViewController的瘦身,
* View和Model的隔离,
跟MVP不同点
* 双向绑定
就是我们的View一旦监听到了ViewModel里的数据变化可以自动更新,一提到MVVM我们大家肯定都会想到RAC这个框架,由于这个框架比较重,为了方便介绍这种架构,我选择另一种方
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="设计模式与架构" scheme="https://lizhaobomb.github.io/categories/iOS/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E6%9E%B6%E6%9E%84/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="设计模式" scheme="https://lizhaobomb.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="架构" scheme="https://lizhaobomb.github.io/tags/%E6%9E%B6%E6%9E%84/"/>
</entry>
<entry>
<title>iOS架构设计04-MVP</title>
<link href="https://lizhaobomb.github.io/2020/03/09/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A104-MVP/"/>
<id>https://lizhaobomb.github.io/2020/03/09/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A104-MVP/</id>
<published>2020-03-08T16:10:00.000Z</published>
<updated>2020-03-09T15:06:01.267Z</updated>
<content type="html"><![CDATA[<p>上篇文章我们介绍了<code>MVC的变种</code>,今天我们来介绍下另一种常用的架构<code>MVP</code>,我们看下图其实这个架构和<code>Apple版MVC</code>很像,只不过<code>C</code>换成了<code>P</code><br><a href="https://ae01.alicdn.com/kf/U9d7b75264b8445989d9dd482769dd9c70.jpg" data-fancybox="group" data-caption="MVP" class="fancybox"><img alt="MVP" title="MVP" data-src="https://ae01.alicdn.com/kf/U9d7b75264b8445989d9dd482769dd9c70.jpg" class="lazyload"></a></p><p>那我们来看看MVP是哪三个角色</p><ul><li><p>Model </p><blockquote><p>对于<code>Model</code>层也是数据层。它区别于MVC架构中的<code>Mode</code>l,在这里不仅仅只是数据模型。在<code>MVP</code>架构中<code>Model</code>它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。</p></blockquote></li><li><p>View</p><blockquote><p>是显示数据<code>(model)</code>并且将用户指令<code>(events)</code>传送到<code>presenter</code>以便作用于那些数据的一个接口。<code>View</code>通常含有<code>Presenter</code>的引用。在这里通常指我们<code>ViewController</code></p></blockquote></li></ul><ul><li>Presenter<blockquote><p>我们看<code>Presenter</code>的意思是主持人,既然是主持人,那肯定要来主持工作了,对于<code>Presenter</code>层他是连接<code>View层</code>与<code>Model层</code>的桥梁并对业务逻辑进行处理。在<code>MVP</code>架构中<code>Model</code>与<code>View</code>无法直接进行交互。所以在<code>Presenter层</code>它会从<code>Model层</code>获得所需要的数据,进行一些适当的处理后交由<code>View层</code>进行显示。这样通过<code>Presenter</code>将<code>View</code>与<code>Model</code>进行隔离,使得<code>View</code>和<code>Model</code>之间不存在耦合,同时也将业务逻辑从<code>View</code>中抽离</p></blockquote></li></ul><h2 id="Demo实例讲解"><a href="#Demo实例讲解" class="headerlink" title="Demo实例讲解"></a>Demo实例讲解</h2><p>下面我们还是沿用MVC那个<code>Demo</code>来看,(主要功能就是我们自定义个<code>XXAppView</code>,用来显示上面一张图,下面一行字的控件)</p><p>这次首先我们创建我们的<code>Presenter</code></p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@interface XXAppPresenter() <XXAppViewDelegate></span><br><span class="line">@property (weak, nonatomic) UIViewController *controller;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation XXAppPresenter</span><br><span class="line"></span><br><span class="line">- (instancetype)initWithController:(UIViewController *)controller</span><br><span class="line">{</span><br><span class="line"> if (self = [super init]) {</span><br><span class="line"> self.controller = controller;</span><br><span class="line"> </span><br><span class="line"> // 创建View</span><br><span class="line"> XXAppView *appView = [[XXAppView alloc] init];</span><br><span class="line"> appView.frame = CGRectMake(100, 100, 100, 150);</span><br><span class="line"> appView.delegate = self;</span><br><span class="line"> [controller.view addSubview:appView];</span><br><span class="line"> </span><br><span class="line"> // 加载模型数据</span><br><span class="line"> XXApp *app = [[XXApp alloc] init];</span><br><span class="line"> app.name = @"QQ";</span><br><span class="line"> app.image = @"QQ";</span><br><span class="line"> </span><br><span class="line"> // 赋值数据</span><br><span class="line"> [appView setName:app.name andImage:app.image];</span><br><span class="line"> }</span><br><span class="line"> return self;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">#pragma mark - XXAppViewDelegate</span><br><span class="line">- (void)appViewDidClick:(MJAppView *)appView</span><br><span class="line">{</span><br><span class="line"> NSLog(@"presenter 监听了 appView 的点击");</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>接着我们修改下我们的<code>View</code>,这次我们的<code>View</code>不需要持有<code>Model</code>,直接暴露出需要的数据给外界,</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (void)setName:(NSString *)name andImage:(NSString *)image;</span><br></pre></td></tr></table></figure></div><p>最后我们来修改下<code>Controller</code>,这回我们点击事件<code>Delegate</code>不用<code>Controller</code>来遵循了,因为我们交由<code>Presenter</code>来主持管理了,所以由<code>Presenter</code>来遵循,那我们的<code>Controller</code>需要持有<code>Presenter</code>对象,那现在我们的<code>Controller</code>只负责初始化<code>Presenter</code>就可以了</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@interface ViewController ()</span><br><span class="line">@property (strong, nonatomic) XXAppPresenter *presenter;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation ViewController</span><br><span class="line"></span><br><span class="line">- (void)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> // 初始化我们的Presenter</span><br><span class="line"> self.presenter = [[MJAppPresenter alloc] initWithController:self];</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>那首先我们看看<code>MVP</code>的优缺点</p><ul><li>优点</li></ul><blockquote><p>对<code>Controller</code>进行瘦身,<code>View</code>和<code>Model</code>之间不存在耦合,同时也将业务逻辑从<code>View</code>中抽离,复用性更好</p></blockquote><ul><li>缺点</li></ul><blockquote><p>由于对视图的渲染放在了<code>Presenter</code>中,所以视图和<code>Presenter</code>的交互会过于频繁。还有一点需要明白,如果<code>Presenter</code>过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么<code>Presenter</code>也需要变更了</p></blockquote><p>之前我们也说了架构这种东西是没有唯一的,今天只是说了我理解和实现的一种方案,其实有很多种方案,我们定了这三个角色之后,这三个角色之间怎么交互,大概的交互流程规定好就可以,具体的细节,可以根据你的习惯或者项目的不同进行修改</p><p>今天就先介绍到这里,明天我们来看看<code>MVVM</code>,还有近期在学习<code>数据结构和算法</code>,<code>小程序</code>,<code>Flutter</code>,我会把笔记都记录下来的</p><h2 id="点此进入我的简书也会同步更新"><a href="#点此进入我的简书也会同步更新" class="headerlink" title="点此进入我的简书也会同步更新"></a><a href="https://www.jianshu.com/u/bd2d5387740e" target="_blank" rel="noopener">点此进入我的简书也会同步更新</a></h2><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing "></a><a href="https://lizhaobomb.github.io">One More Thing </a></h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
上篇文章我们介绍了MVC的变种,今天我们来介绍下另一种常用的架构MVP,我们看下图其实这个架构和Apple版MVC很像,只不过C换成了P
那我们来看看MVP是哪三个角色
* Model
对于Model层也是数据层。它区别于MVC架构中的Model,在这里不仅仅只是数据模型。在MVP架构中Model它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。
* View
是显示数据(model)并且将用户指令(events)传送到presenter以便作用于那些数据的一个接口。View通常含有Presenter的引用。在这里通常指我们
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="设计模式与架构" scheme="https://lizhaobomb.github.io/categories/iOS/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E6%9E%B6%E6%9E%84/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="设计模式" scheme="https://lizhaobomb.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="架构" scheme="https://lizhaobomb.github.io/tags/%E6%9E%B6%E6%9E%84/"/>
</entry>
<entry>
<title>iOS架构设计03-MVC-变种</title>
<link href="https://lizhaobomb.github.io/2020/03/08/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A103-MVC-%E5%8F%98%E7%A7%8D/"/>
<id>https://lizhaobomb.github.io/2020/03/08/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A103-MVC-%E5%8F%98%E7%A7%8D/</id>
<published>2020-03-07T16:10:00.000Z</published>
<updated>2020-03-08T15:15:49.156Z</updated>
<content type="html"><![CDATA[<p>上篇文章我们介绍了Apple版的MVC,今天我们来介绍下一种常用的MVC其实也是基于Apple版MVC的一个变种,首先我们来看下变种的MVC是什么样子的如下图<br><a href="https://ae01.alicdn.com/kf/Uae8f352e3fcd441fb41c8bcb811f349cB.jpg" data-fancybox="group" data-caption="MVC-变种" class="fancybox"><img alt="MVC-变种" title="MVC-变种" data-src="https://ae01.alicdn.com/kf/Uae8f352e3fcd441fb41c8bcb811f349cB.jpg" class="lazyload"></a></p><p>角色还是那三个角色</p><ul><li><p>Model </p><blockquote><p>这个地方不一样了哦,本来是我们的Controller负责和Model进行交互的,变种之后的View是可以拥有这个Model的,相当于View是知道Model的存在的,我们平时开发时可能就会产生这样的一个变种,这样的好处就是Controller的代码不会那么臃肿,我们把Model一些相关的操作封装到View里了</p></blockquote></li><li><p>View</p><blockquote><p>反馈一些事件给我们的Controller,上篇没有介绍如何反馈事件,像TableView是通过Delegate反馈给Controller的,我们一般也是用Delegate或者Block来反馈</p></blockquote></li><li><p>Controller</p><blockquote><p>还是拥有View,还是创建我们的Model,不同的是不用在Controller里更新View的数据了,这部分逻辑挪到View里了</p></blockquote></li></ul><h2 id="Demo实例讲解"><a href="#Demo实例讲解" class="headerlink" title="Demo实例讲解"></a>Demo实例讲解</h2><blockquote><p>下面我们来看下Demo,(主要功能就是我们自定义个XXAppView,用来显示上面一张图,下面一行字的控件)</p></blockquote><p>首先我们创建我们的Model,一共两个字段(name,image)</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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">@interface XXApp : NSObject</span><br><span class="line">@property (copy, nonatomic) NSString *name;</span><br><span class="line">@property (copy, nonatomic) NSString *image;</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><p>接着我们创建我们的View,这次我们的View会持有Model,我们定义一个Delegate用来把点击事件反馈给Controller</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@class XXApp, XXAppView;</span><br><span class="line"></span><br><span class="line">@protocol XXAppViewDelegate <NSObject></span><br><span class="line">@optional</span><br><span class="line">- (void)appViewDidClick:(XXAppView *)appView;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@interface XXAppView : UIView</span><br><span class="line">@property (strong, nonatomic) XXApp *app;</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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 XXAppView()</span><br><span class="line">@property (weak, nonatomic) UIImageView *iconView;</span><br><span class="line">@property (weak, nonatomic) UILabel *nameLabel;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation XXAppView</span><br><span class="line"></span><br><span class="line">- (instancetype)initWithFrame:(CGRect)frame</span><br><span class="line">{</span><br><span class="line"> if (self = [super initWithFrame:frame]) {</span><br><span class="line"> UIImageView *iconView = [[UIImageView alloc] init];</span><br><span class="line"> iconView.frame = CGRectMake(0, 0, 100, 100);</span><br><span class="line"> [self addSubview:iconView];</span><br><span class="line"> _iconView = iconView;</span><br><span class="line"> </span><br><span class="line"> UILabel *nameLabel = [[UILabel alloc] init];</span><br><span class="line"> nameLabel.frame = CGRectMake(0, 100, 100, 30);</span><br><span class="line"> nameLabel.textAlignment = NSTextAlignmentCenter;</span><br><span class="line"> [self addSubview:nameLabel];</span><br><span class="line"> _nameLabel = nameLabel;</span><br><span class="line"> }</span><br><span class="line"> return self;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (void)setApp:(XXApp *)app</span><br><span class="line">{</span><br><span class="line"> _app = app;</span><br><span class="line"> </span><br><span class="line"> self.iconView.image = [UIImage imageNamed:app.image];</span><br><span class="line"> self.nameLabel.text = app.name;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event</span><br><span class="line">{</span><br><span class="line"> if ([self.delegate respondsToSelector:@selector(appViewDidClick:)]) {</span><br><span class="line"> [self.delegate appViewDidClick:self];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><p>最后是我们的Controller,遵循View的Delegate来响应点击事件</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">@interface ViewController () <XXAppViewDelegate></span><br><span class="line"></span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation ViewController</span><br><span class="line"></span><br><span class="line">- (void)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> </span><br><span class="line"> // 创建view</span><br><span class="line"> XXAppView *appView = [[XXAppView alloc] init];</span><br><span class="line"> appView.frame = CGRectMake(100, 100, 100, 150);</span><br><span class="line"> appView.delegate = self;</span><br><span class="line"> [self.view addSubview:appView];</span><br><span class="line"> </span><br><span class="line"> // 加载模型数据,我们以QQ为例</span><br><span class="line"> XXApp *app = [[XXApp alloc] init];</span><br><span class="line"> app.name = @"QQ";</span><br><span class="line"> app.image = @"QQ";</span><br><span class="line"> </span><br><span class="line"> // 设置数据到view上</span><br><span class="line"> appView.app = app;</span><br><span class="line">//Apple版的MVC你要这么做 </span><br><span class="line">// appView.iconView.image = [UIImage imageNamed:app.image];</span><br><span class="line">// appView.nameLabel.text = app.name;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">#pragma mark - XXAppViewDelegate</span><br><span class="line">- (void)appViewDidClick:(MJAppView *)appView</span><br><span class="line">{</span><br><span class="line"> NSLog(@"控制器监听到了appView的点击");</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>那首先我们看看变种后的MVC的优缺点</p><ul><li>优点</li></ul><blockquote><p>对Controller进行瘦身,将View内部的细节封装起来了,外界不知道View内部的具体实现</p></blockquote><ul><li>缺点</li></ul><blockquote><p>View依赖于Model</p></blockquote><p>每一种架构都有他的支持者和反对者,所以说没有哪个架构是最好的,只有哪个架构是最适合的,所以都是MVC大家选自己适合的就行</p><p>今天就先介绍到这里,明天我们来看看MVP,还有近期在学习数据结构和算法,小程序,flutter,我会把笔记都记录下来的</p><h2 id="点此进入我的简书也会同步更新"><a href="#点此进入我的简书也会同步更新" class="headerlink" title="点此进入我的简书也会同步更新"></a><a href="https://www.jianshu.com/u/bd2d5387740e" target="_blank" rel="noopener">点此进入我的简书也会同步更新</a></h2><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing "></a><a href="https://lizhaobomb.github.io">One More Thing </a></h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
上篇文章我们介绍了Apple版的MVC,今天我们来介绍下一种常用的MVC其实也是基于Apple版MVC的一个变种,首先我们来看下变种的MVC是什么样子的如下图
角色还是那三个角色
* Model
这个地方不一样了哦,本来是我们的Controller负责和Model进行交互的,变种之后的View是可以拥有这个Model的,相当于View是知道Model的存在的,我们平时开发时可能就会产生这样的一个变种,这样的好处就是Controller的代码不会那么臃肿,我们把Model一些相关的操作封装到View里了
* View
反馈一些事件给我们的C
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="设计模式与架构" scheme="https://lizhaobomb.github.io/categories/iOS/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E6%9E%B6%E6%9E%84/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="设计模式" scheme="https://lizhaobomb.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="架构" scheme="https://lizhaobomb.github.io/tags/%E6%9E%B6%E6%9E%84/"/>
</entry>
<entry>
<title>iOS设计模式与架构02-MVC-Apple</title>
<link href="https://lizhaobomb.github.io/2020/03/07/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A102-MVC-Apple/"/>
<id>https://lizhaobomb.github.io/2020/03/07/iOS%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A102-MVC-Apple/</id>
<published>2020-03-06T16:10:00.000Z</published>
<updated>2020-03-07T15:06:44.142Z</updated>
<content type="html"><![CDATA[<p>大家肯定都听过<code>MVC</code>这种架构,首先我们来看下<code>Apple</code>版的<code>MVC</code>是什么样的,就是<code>Apple</code>官方所说的<code>MVC</code>是一个什么样的方案,我们可以看到<code>MVC</code>其实就是三个角色,<code>Model</code>,<code>View</code>,<code>Controller</code>,那这三个角色之间是一个什么样的关系呢,如果是<code>Apple</code>官方的<code>MVC</code>的话,大概是这个样子的<br><a href="https://ae01.alicdn.com/kf/Ub19ec07c1e4e4042a66fbe21492cc428j.jpg" data-fancybox="group" data-caption="Model-View-Controller" class="fancybox"><img alt="Model-View-Controller" title="Model-View-Controller" data-src="https://ae01.alicdn.com/kf/Ub19ec07c1e4e4042a66fbe21492cc428j.jpg" class="lazyload"></a></p><ul><li>首先<code>Controller</code>是持有<code>View</code>的,View也会通知<code>Controller</code>去处理一些业务逻辑,</li><li>其次<code>Controller</code>也持有<code>Model</code>,当<code>Model</code>变化时(比如加载网络数据了等等),<code>Controller</code>是知道的,所以又把最新的数据显示到<code>View</code>上</li><li>最后其实<code>Controller</code>是<code>Model</code>和<code>View</code>中间的一个桥梁,那我们可以看到<code>Apple</code>版的<code>MVC</code>的一个<code>特点</code>就是<code>View和Model之间是没有关联的,View不知道Model的存在,Model也不知道View的存在</code>,那大家最熟悉的应该就是我们<code>神奇万能</code>的<code>UITableView</code>了,<code>UITableView</code>算是把<code>Apple版</code>的<code>MVC</code>发挥的淋漓尽致</li></ul><h2 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h2><p>接下来我们用一个简单的例子来说明下,我们新建一个项目,比如是一个新闻类的项目,本地简单的模拟下网络加载数据然后展示到TableView上,我们首先创建一个<code>XXNews</code>的<code>Model</code></p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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">@interface XXNews : NSObject</span><br><span class="line">@property (copy, nonatomic) NSString *title;</span><br><span class="line">@property (copy, nonatomic) NSString *content;</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><p>,接着创建一个<code>XXNewsViewController</code>继承自<code>UITableViewController</code></p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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 XXNewsViewController ()</span><br><span class="line">@property (strong, nonatomic) NSMutableArray *newsData;</span><br><span class="line">//@property (strong, nonatomic) NSMutableArray *shopData;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation XXNewsViewController</span><br><span class="line">- (void)viewDidLoad {</span><br><span class="line"> [super viewDidLoad];</span><br><span class="line"> </span><br><span class="line"> [self loadNewsData];</span><br><span class="line">// [self loadShopData];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 本地模拟网络加载</span><br><span class="line">- (void)loadNewsData</span><br><span class="line">{</span><br><span class="line"> self.newsData = [NSMutableArray array];</span><br><span class="line"> </span><br><span class="line"> for (int i = 0; i < 20; i++) {</span><br><span class="line"> XXNews *news = [[XXNews alloc] init];</span><br><span class="line"> news.title = [NSString stringWithFormat:@"news-title-%d", i];</span><br><span class="line"> news.content = [NSString stringWithFormat:@"news-content-%d", i];</span><br><span class="line"> [self.newsData addObject:news];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {</span><br><span class="line"> return self.newsData.count;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">#pragma mark - Table view data source</span><br><span class="line">- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {</span><br><span class="line"> UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NewsCell" forIndexPath:indexPath];</span><br><span class="line"> </span><br><span class="line"> XXNews *news = self.NewsData[indexPath.row];</span><br><span class="line"> </span><br><span class="line"> cell.detailTextLabel.text = news.content;</span><br><span class="line"> cell.textLabel.text = news.title;</span><br><span class="line"> </span><br><span class="line"> return cell;</span><br><span class="line">}</span><br><span class="line">@end</span><br></pre></td></tr></table></figure></div><p>我们运行下项目来看看,数据显示出来了,<br><a href="https://ae01.alicdn.com/kf/U502147e7d38641d58a6ee1b73312ee86e.jpg" data-fancybox="group" data-caption="截图" class="fancybox"><img alt="截图" title="截图" data-src="https://ae01.alicdn.com/kf/U502147e7d38641d58a6ee1b73312ee86e.jpg" class="lazyload"></a></p><p>我们来看看<code>MVC</code>三个角色,</p><ul><li>Model(News),</li><li>View(TableView),</li><li>Controller(XXNewsViewController),</li></ul><p>那我们来验证下这个<code>MVC</code>跟我们上面说的是否一致</p><blockquote><p>我们看到<code>XXNewsViewController</code>拥有<code>newsData</code>(可以创建,加载这些模型数据),而且<code>XXNewsViewController</code>也拥有<code>View(TableView)</code>,然后,<code>View(TableView)</code>是不知道这个<code>Model(News)</code>的存在的,<code>Model(News)也不知道View(TableView)的存在</code>,</p></blockquote><blockquote><p>那View是如何显示Model的数据的呢?全靠<code>Controller</code>这个桥梁把<code>Model</code>的数据取出来,然后赋值给<code>View</code>对应的控件上,所以跟我们上面说的是一致的,这个呢就是<code>Apple版</code>的<code>MVC</code>了,接下来我们可以总结下这个架构的优缺点</p></blockquote><h2 id="优缺点"><a href="#优缺点" class="headerlink" title="优缺点"></a>优缺点</h2><ul><li><p>优点:<code>View</code>和<code>Model</code>可重复利用,(这也解释了<code>TableView</code>为啥这么万能:不关心<code>Model</code>,比如我们显示个商品的列表,只需换下<code>Model</code>,然后赋值对应的控件就行了,而不用换<code>TableView</code>)</p><ul><li>大家如果自定义View的时候想做的复用性很强的话,可以操考下TableView的设计</li></ul></li><li><p>缺点:Controller的代码过于臃肿</p></li></ul><h2 id="总结一下"><a href="#总结一下" class="headerlink" title="总结一下"></a>总结一下</h2><blockquote><p>架构这种东西呢,不是我三言两语能说清楚的,我在这里写的也只是些概念、Demo,还是需要大家多思考,多练习,不断的积累项目经验,才能悟出来更高的更深层次的东西</p></blockquote><h2 id="今天先到这里,明天接着更新MVC-变种"><a href="#今天先到这里,明天接着更新MVC-变种" class="headerlink" title="今天先到这里,明天接着更新MVC-变种"></a>今天先到这里,明天接着更新<code>MVC-变种</code></h2><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing"></a><a href="https://lizhaobomb.github.io">One More Thing</a></h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
大家肯定都听过MVC这种架构,首先我们来看下Apple版的MVC是什么样的,就是Apple官方所说的MVC是一个什么样的方案,我们可以看到MVC其实就是三个角色,Model,View,Controller,那这三个角色之间是一个什么样的关系呢,如果是Apple官方的MVC的话,大概是这个样子的
* 首先Controller是持有View的,View也会通知Controller去处理一些业务逻辑,
* 其次Controller也持有Model,当Model变化时(比如加载网络数据了等等),Controller是知道的,所以又把最新的数据显示到View上
* 最后其实Controller
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="设计模式与架构" scheme="https://lizhaobomb.github.io/categories/iOS/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E6%9E%B6%E6%9E%84/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="设计模式" scheme="https://lizhaobomb.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="架构" scheme="https://lizhaobomb.github.io/tags/%E6%9E%B6%E6%9E%84/"/>
</entry>
<entry>
<title>设计模式与架构01-简介</title>
<link href="https://lizhaobomb.github.io/2020/03/06/iOS%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E6%9E%B6%E6%9E%8401-%E7%AE%80%E4%BB%8B/"/>
<id>https://lizhaobomb.github.io/2020/03/06/iOS%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E6%9E%B6%E6%9E%8401-%E7%AE%80%E4%BB%8B/</id>
<published>2020-03-05T16:10:00.000Z</published>
<updated>2020-03-06T15:19:52.937Z</updated>
<content type="html"><![CDATA[<blockquote><p>其实一旦牵扯到这个话题,都是相对来说比较抽象的一个话题,当然这个需要结合我们更多的实战,如果你经历了更多的项目实战呢,对这个设计模式与架构可能会有一个比较全面或者比较深入的一个认识,如果你做的项目不是很多,那你对这个设计模式与架构理解可能不够,可能迷迷糊糊的,感受不到设计模式与架构给项目带来的好处,今天我们就来先来个开篇简单介绍下,常见的面试题以及何为架构</p></blockquote><h3 id="常见的面试题"><a href="#常见的面试题" class="headerlink" title="常见的面试题"></a>常见的面试题</h3><blockquote><p>1、讲讲 <code>MVC</code>、<code>MVVM</code>、<code>MVP</code>,以及你在项目里具体是怎么写的?</p></blockquote><blockquote><p>2、你自己用过哪些<code>设计模式</code>?</p></blockquote><blockquote><p>3、一般开始做一个项目,你的架构是如何思考的?</p></blockquote><h3 id="首先我们来认识下什么是架构?"><a href="#首先我们来认识下什么是架构?" class="headerlink" title="首先我们来认识下什么是架构?"></a>首先我们来认识下什么是架构?</h3><ul><li>架构(Architecture)<ul><li>软件开发中的<code>设计方案</code></li><li><code>类与类</code>之间的关系、<code>模块与模块</code>之间的关系、<code>客户端与服务端</code>的关系</li></ul></li></ul><blockquote><p>所以我们看架构可大可小,大到<code>客户端与服务端</code>的关系,小到<code>类与类之间</code>的关系,都在架构的范畴</p></blockquote><ul><li>经常听到的架构名词<ul><li><code>MVC</code>、<code>MVP</code>、<code>MVVM</code>、<code>VIPER</code>、<code>CDD</code> (接下来会主要介绍前三个,其它的其实也都是前三个的变种)</li><li><code>三层架构</code>、<code>四层架构</code> (大家不要慌,接下来都会介绍)</li><li>……</li></ul></li></ul><h2 id="今天先到这里,明天接着更新"><a href="#今天先到这里,明天接着更新" class="headerlink" title="今天先到这里,明天接着更新"></a>今天先到这里,明天接着更新</h2><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing"></a><a href="https://lizhaobomb.github.io">One More Thing</a></h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
其实一旦牵扯到这个话题,都是相对来说比较抽象的一个话题,当然这个需要结合我们更多的实战,如果你经历了更多的项目实战呢,对这个设计模式与架构可能会有一个比较全面或者比较深入的一个认识,如果你做的项目不是很多,那你对这个设计模式与架构理解可能不够,可能迷迷糊糊的,感受不到设计模式与架构给项目带来的好处,今天我们就来先来个开篇简单介绍下,常见的面试题以及何为架构
常见的面试题
1、讲讲 MVC、MVVM、MVP,以及你在项目里具体是怎么写的?
2、你自己用过哪些设计模式?
3、一般开始做一个项目,你的架构是如何思考的?
首先我们来认识下什么是架构?
* 架构(Architecture) *
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="设计模式与架构" scheme="https://lizhaobomb.github.io/categories/iOS/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E6%9E%B6%E6%9E%84/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="设计模式" scheme="https://lizhaobomb.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="架构" scheme="https://lizhaobomb.github.io/tags/%E6%9E%B6%E6%9E%84/"/>
</entry>
<entry>
<title>iOS性能优化09-安装包瘦身</title>
<link href="https://lizhaobomb.github.io/2020/03/05/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9609-%E5%AE%89%E8%A3%85%E5%8C%85%E7%98%A6%E8%BA%AB/"/>
<id>https://lizhaobomb.github.io/2020/03/05/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9609-%E5%AE%89%E8%A3%85%E5%8C%85%E7%98%A6%E8%BA%AB/</id>
<published>2020-03-04T16:10:00.000Z</published>
<updated>2020-03-05T15:49:48.814Z</updated>
<content type="html"><![CDATA[<p>我们开发完一个项目将来肯定是要进行编译,然后打包上传到APPStore提供给用户下载,那我们最终打包是什么格式呢?其实是一个IPA包,那首先我们来看看安装包的组成</p><h3 id="安装包(ipa)主要由可执行文件、资源组成"><a href="#安装包(ipa)主要由可执行文件、资源组成" class="headerlink" title="安装包(ipa)主要由可执行文件、资源组成"></a>安装包(<code>ipa</code>)主要由可执行文件、资源组成</h3><ul><li><p>资源(图片、音频、视频等)</p><ul><li><p>采取无损压缩:网上有很多,我常用的像 <a href="https://tinypng.com" target="_blank" rel="noopener">TinyPng</a>、<a href="https://squoosh.app/" target="_blank" rel="noopener">Squoosh</a>、<a href="https://www.tuhaokuai.com" target="_blank" rel="noopener">图好快</a> 等等</p></li><li><p>去除没用到的资源:大家可以试试GitHub上有个开源项目可以检测项目里没用的资源文件 <a href="https://github.com/tinymind/LSUnusedResources" target="_blank" rel="noopener">GitHub传送门</a></p></li></ul></li><li><p>可执行文件瘦身</p><ul><li><p>编译器优化 现在的新版<code>Xcode</code>已经自动给优化了,如果你的项目比较旧的话,可以去<code>XCode</code>设置这些选项,不确定的话最好都去搜下然后设置下 <code>Strip Linked Product</code>、<code>Make Strings Read-Only</code>、<code>Symbols Hidden by Default</code>设置为<code>YES</code><br><a href="https://ae01.alicdn.com/kf/Uc24885f572f84ceb87bc5e3f5812159bQ.jpg" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://ae01.alicdn.com/kf/Uc24885f572f84ceb87bc5e3f5812159bQ.jpg" class="lazyload"></a></p></li><li><p>去掉异常支持,<code>Enable C++ Exceptions</code>、<code>Enable Objective-C Exceptions</code>设置为<code>NO</code>, <code>Other C Flags</code>添加<code>-fno-exceptions</code></p></li><li><p>利用<a href="https://www.jetbrains.com/objc/" target="_blank" rel="noopener">AppCode</a>(这个软件是收费的,可以试用30天,当然有钱的大家可以支持下正版,没钱的话想办法也可以搞到)检测未使用的代码:<code>菜单栏 -> Code -> Inspect Code</code></p></li><li><p>编写<code>LLVM</code>插件检测出重复代码、未被调用的代码(这个比较高级,也比较复杂,涉及到的知识有点多,后面会用专门一篇文章来记录)</p></li><li><p>还有个东西叫<code>LinkMap</code>(可以查看可执行文件的具体组成),我们可以用<code>Xcode</code>来生成<code>LinkMap</code>文件<br><a href="https://ae01.alicdn.com/kf/U84b8d327052040e5a89a485d63a7dc144.jpg" data-fancybox="group" data-caption="LinkMap" class="fancybox"><img alt="LinkMap" title="LinkMap" data-src="https://ae01.alicdn.com/kf/U84b8d327052040e5a89a485d63a7dc144.jpg" class="lazyload"></a><br>不过系统生成的这个txt文件可能看着比较难分析,那么我们可以借助三方工具来分析<code>LinkMap</code>文件,<code>GItHub</code>上有开源<code>Mac OS</code>项目,大家下载完编译完就可以用了</p></li></ul></li><li><p><a href="https://github.com/huanxsd/LinkMap" target="_blank" rel="noopener">解析LinkMap文件工具传送门</a></p></li></ul><p>解析前</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line"># Sections:</span><br><span class="line"># AddressSize SegmentSection</span><br><span class="line">0x100000F300x00000553__TEXT__text</span><br><span class="line">0x1000014840x0000003C__TEXT__stubs</span><br><span class="line">0x1000014C00x00000074__TEXT__stub_helper</span><br><span class="line">0x1000015340x00000D26__TEXT__objc_methname</span><br><span class="line">0x10000225A0x00000070__TEXT__objc_classname</span><br><span class="line">0x1000022CA0x00000ADA__TEXT__objc_methtype</span><br><span class="line">0x100002DA40x00000090__TEXT__cstring</span><br><span class="line">0x100002E340x0000017E__TEXT__entitlements</span><br><span class="line">0x100002FB40x00000048__TEXT__unwind_info</span><br><span class="line">0x1000030000x00000018__DATA_CONST__got</span><br><span class="line">0x1000030180x00000020__DATA_CONST__cfstring</span><br><span class="line">0x1000030380x00000018__DATA_CONST__objc_classlist</span><br><span class="line">0x1000030500x00000020__DATA_CONST__objc_protolist</span><br><span class="line">0x1000030700x00000008__DATA_CONST__objc_imageinfo</span><br><span class="line">0x1000040000x00000050__DATA__la_symbol_ptr</span><br><span class="line">0x1000040500x00001308__DATA__objc_const</span><br><span class="line">0x1000053580x00000018__DATA__objc_selrefs</span><br><span class="line">0x1000053700x00000010__DATA__objc_classrefs</span><br><span class="line">0x1000053800x00000008__DATA__objc_superrefs</span><br><span class="line">0x1000053880x00000008__DATA__objc_ivar</span><br><span class="line">0x1000053900x000000F0__DATA__objc_data</span><br><span class="line">0x1000054800x00000188__DATA__data</span><br><span class="line"># Symbols:</span><br><span class="line"># AddressSize File Name</span><br><span class="line">0x100000F300x00000039[ 2] -[ViewController viewDidLoad]</span><br><span class="line">0x100000F700x00000080[ 3] -[AppDelegate application:didFinishLaunchingWithOptions:]</span><br><span class="line">0x100000FF00x00000120[ 3] -[AppDelegate application:configurationForConnectingSceneSession:options:]</span><br><span class="line">0x1000011100x0000006C[ 3] -[AppDelegate application:didDiscardSceneSessions:]</span><br><span class="line">0x1000011800x00000090[ 4] _main</span><br><span class="line">0x1000012100x000000A0[ 5] -[SceneDelegate scene:willConnectToSession:options:]</span><br><span class="line">0x1000012B00x00000040[ 5] -[SceneDelegate sceneDidDisconnect:]</span><br><span class="line">0x1000012F00x00000040[ 5] -[SceneDelegate sceneDidBecomeActive:]</span><br><span class="line">0x1000013300x00000040[ 5] -[SceneDelegate sceneWillResignActive:]</span><br><span class="line">0x1000013700x00000040[ 5] -[SceneDelegate sceneWillEnterForeground:]</span><br><span class="line">0x1000013B00x00000040[ 5] -[SceneDelegate sceneDidEnterBackground:]</span><br><span class="line">0x1000013F00x00000020[ 5] -[SceneDelegate window]</span><br><span class="line">0x1000014100x00000040[ 5] -[SceneDelegate setWindow:]</span><br><span class="line">0x1000014500x00000033[ 5] -[SceneDelegate .cxx_destruct]</span><br><span class="line">0x1000014840x00000006[ 6] _NSStringFromClass</span><br></pre></td></tr></table></figure></div><p>解析后:<br><a href="https://ae01.alicdn.com/kf/Ue44e074f9f6a4df78e2740c56b1536074.jpg" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://ae01.alicdn.com/kf/Ue44e074f9f6a4df78e2740c56b1536074.jpg" class="lazyload"></a></p><p>-</p><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing"></a>One More Thing</h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
我们开发完一个项目将来肯定是要进行编译,然后打包上传到APPStore提供给用户下载,那我们最终打包是什么格式呢?其实是一个IPA包,那首先我们来看看安装包的组成
安装包(ipa)主要由可执行文件、资源组成
* 资源(图片、音频、视频等)
* 采取无损压缩:网上有很多,我常用的像 TinyPng、Squoosh、图好快 等等
* 去除没用到的资源:大家可以试试GitHub上有个开源项目可以检测项目里没用的资源文件 GitHub传送门
* 可执行文件瘦身
* 编译器优化 现在的新
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="性能优化" scheme="https://lizhaobomb.github.io/categories/iOS/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="性能" scheme="https://lizhaobomb.github.io/tags/%E6%80%A7%E8%83%BD/"/>
<category term="瘦身" scheme="https://lizhaobomb.github.io/tags/%E7%98%A6%E8%BA%AB/"/>
</entry>
<entry>
<title>iOS性能优化08-启动优化02-分析</title>
<link href="https://lizhaobomb.github.io/2020/03/04/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9608-%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%9602-%E5%88%86%E6%9E%90/"/>
<id>https://lizhaobomb.github.io/2020/03/04/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9608-%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%9602-%E5%88%86%E6%9E%90/</id>
<published>2020-03-03T16:10:00.000Z</published>
<updated>2020-03-04T15:28:26.522Z</updated>
<content type="html"><![CDATA[<p>上一节我们已经把APP的启动大致概括为<code>dyld</code>,<code>runtime</code>, <code>main</code>这三阶段,那接下来我们具体看看这三个阶段都在做些什么事情</p><h3 id="第一阶段dyld(dynamic-link-editor),"><a href="#第一阶段dyld(dynamic-link-editor)," class="headerlink" title="第一阶段dyld(dynamic link editor),"></a>第一阶段<code>dyld(dynamic link editor)</code>,</h3><p>Apple的动态链接器,可以用来装载<code>Mach-O</code>文件(可执行文件、动态库等)</p><ul><li>启动APP时,<code>dyld</code>所做的事情有<ul><li>装载APP的可执行文件,同时会递归加载所有依赖的动态库</li><li>当<code>dyld</code>把<code>可执行文件</code>、<code>动态库</code>都装载完毕后,会通知<code>Runtime</code>进行下一步的处理</li></ul></li></ul><h3 id="第二阶段-runtime"><a href="#第二阶段-runtime" class="headerlink" title="第二阶段 runtime"></a>第二阶段 runtime</h3><ul><li>启动APP时,<code>runtime</code>所做的事情有<ul><li>调用<code>map_images</code>进行可执行文件内容的解析和处理</li><li>在<code>load_images</code>中调用<code>call_load_methods</code>,调用所有<code>Class</code>和<code>Category</code>的<code>+load</code>方法</li><li>进行各种objc结构的初始化(注册Objc类,初始化类对象等等)</li><li>调用C++静态初始化器和<code>__attribute__((constructor))</code>修饰的函数</li></ul></li></ul><p>到此为止,可执行文件和动态库中所有的符号<code>(Class,Protocol,Selector,IMP,...)</code>都已经按格式成功加载到内存中,被<code>runtime</code>所管理</p><h3 id="第三阶段-main"><a href="#第三阶段-main" class="headerlink" title="第三阶段 main"></a>第三阶段 main</h3><ul><li>总结一下<ul><li>APP的启动由<code>dyld</code>主导,将可执行文件加载到内存,顺便加载所有依赖的动态库</li><li>并由<code>runtime</code>负责加载成<code>objc</code>定义的结构</li><li>所有初始化工作结束后,<code>dyld</code>就会调用<code>main</code>函数</li><li>接下来就是<code>UIApplicationMain</code>函数,<code>APPDelegate</code>的<code>application:didFinishLaunchingWithOptions:</code>方法</li></ul></li></ul><p>接下来我们来看看如何进行优化</p><h2 id="APP的启动优化"><a href="#APP的启动优化" class="headerlink" title="APP的启动优化"></a>APP的启动优化</h2><p>按照不同的阶段来展开</p><ul><li><p>dyld</p><ul><li>减少动态库、合并一些动态库(定期清理不必要的动态库)</li><li>减少<code>Objc</code>类、分类的数量、减少<code>Selector</code>数量(定期清理不必要的类、分类)</li><li>减少<code>C++虚函数</code>的数量</li><li><code>Swift</code>尽量使用<code>Struct</code></li></ul></li><li><p>runtime</p><ul><li>用<code>+initialize</code>方法和<code>dispatch_once</code>取代所有的<code>__attribute__((constructor))</code>、<code>C++静态构造器</code>、Objc的<code>+load</code></li></ul></li><li><p>main</p><ul><li>在不影响用户体验的前提下,尽可能将一些操作延迟,不要全部都放在<code>finishLaunching</code>方法中</li><li>按需加载</li></ul></li></ul><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing"></a>One More Thing</h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
上一节我们已经把APP的启动大致概括为dyld,runtime, main这三阶段,那接下来我们具体看看这三个阶段都在做些什么事情
第一阶段dyld(dynamic link editor),
Apple的动态链接器,可以用来装载Mach-O文件(可执行文件、动态库等)
* 启动APP时,dyld所做的事情有 * 装载APP的可执行文件,同时会递归加载所有依赖的动态库
* 当dyld把可执行文件、动态库都装载完毕后,会通知Runtime进行下一步的处理
第二阶段 runtime
* 启动APP时,runtime所做的事情有 * 调用map_images进行可执
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="性能优化" scheme="https://lizhaobomb.github.io/categories/iOS/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="性能" scheme="https://lizhaobomb.github.io/tags/%E6%80%A7%E8%83%BD/"/>
<category term="耗电" scheme="https://lizhaobomb.github.io/tags/%E8%80%97%E7%94%B5/"/>
</entry>
<entry>
<title>iOS性能优化07-启动优化01-冷启动简介</title>
<link href="https://lizhaobomb.github.io/2020/03/03/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9607-%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%9601-%E5%86%B7%E5%90%AF%E5%8A%A8%E7%AE%80%E4%BB%8B/"/>
<id>https://lizhaobomb.github.io/2020/03/03/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9607-%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%9601-%E5%86%B7%E5%90%AF%E5%8A%A8%E7%AE%80%E4%BB%8B/</id>
<published>2020-03-02T16:10:00.000Z</published>
<updated>2020-03-03T15:24:47.654Z</updated>
<content type="html"><![CDATA[<h2 id="APP的启动可以分为2种:"><a href="#APP的启动可以分为2种:" class="headerlink" title="APP的启动可以分为2种:"></a>APP的启动可以分为2种:</h2><ul><li><p>冷启动(Cold Launch):从零开始启动APP</p></li><li><p>热启动 (Warm Launch):APP已经在内存中,在后台存活着,再次点击图标启动APP</p></li></ul><h2 id="APP启动时间的优化"><a href="#APP启动时间的优化" class="headerlink" title="APP启动时间的优化"></a>APP启动时间的优化</h2><p>那我们通常所说的启动时间优化都是再说的冷启动的时间优化,其实Xcode是提供给我们一种分析启动时间的方式,我们接下来试一试</p><ul><li><p>通过添加环境变量可以打印出APP的启动时间分析(<code>Edit Scheme -> Run -> Arguments</code>)</p><ul><li><p><code>DYLD_PRINT_STATISTICS</code>设置为<code>1</code></p><p><a href="https://ae01.alicdn.com/kf/U6741e3dbe662435580206747f8385eaeA.jpg" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://ae01.alicdn.com/kf/U6741e3dbe662435580206747f8385eaeA.jpg" class="lazyload"></a></p><p>我们可以看到控制台打印出了</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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">Total pre-main time: 238.11 milliseconds (100.0%)</span><br><span class="line"> dylib loading time: 173.78 milliseconds (72.9%)</span><br><span class="line"> rebase/binding time: 126687488.9 seconds (15889931.7%)</span><br><span class="line"> ObjC setup time: 15.16 milliseconds (6.3%)</span><br><span class="line"> initializer time: 62.59 milliseconds (26.2%)</span><br><span class="line"> slowest intializers :</span><br><span class="line"> libSystem.B.dylib : 6.66 milliseconds (2.7%)</span><br><span class="line"> libBacktraceRecording.dylib : 7.30 milliseconds (3.0%)</span><br><span class="line"> libMainThreadChecker.dylib : 40.12 milliseconds (16.8%)</span><br></pre></td></tr></table></figure></div></li><li><p>如果需要更详细的信息,那就将<code>DYLD_PRINT_STATISTICS_DETAILS</code>设置为<code>1</code></p><p>我们看到这次输出的信息比上次要详细很多</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line"> total time: 981.15 milliseconds (100.0%)</span><br><span class="line"> total images loaded: 334 (327 from dyld shared cache)</span><br><span class="line"> total segments mapped: 21, into 370 pages</span><br><span class="line"> total images loading time: 664.10 milliseconds (67.6%)</span><br><span class="line"> total load time in ObjC: 20.03 milliseconds (2.0%)</span><br><span class="line"> total debugger pause time: 402.89 milliseconds (41.0%)</span><br><span class="line"> total dtrace DOF registration time: 0.22 milliseconds (0.0%)</span><br><span class="line"> total rebase fixups: 17,951</span><br><span class="line"> total rebase fixups time: 2.27 milliseconds (0.2%)</span><br><span class="line"> total binding fixups: 460,826</span><br><span class="line"> total binding fixups time: 229.13 milliseconds (23.3%)</span><br><span class="line"> total weak binding fixups time: 0.03 milliseconds (0.0%)</span><br><span class="line"> total redo shared cached bindings time: 254.48 milliseconds (25.9%)</span><br><span class="line"> total bindings lazily fixed up: 0 of 0</span><br><span class="line"> total time in initializers and ObjC +load: 65.34 milliseconds (6.6%)</span><br><span class="line"> libSystem.B.dylib : 9.14 milliseconds (0.9%)</span><br><span class="line"> libBacktraceRecording.dylib : 7.73 milliseconds (0.7%)</span><br><span class="line"> libobjc.A.dylib : 1.55 milliseconds (0.1%)</span><br><span class="line"> CoreFoundation : 2.24 milliseconds (0.2%)</span><br><span class="line"> libMainThreadChecker.dylib : 38.86 milliseconds (3.9%)</span><br><span class="line"> libLLVMContainer.dylib : 2.13 milliseconds (0.2%)</span><br><span class="line">total symbol trie searches: 1116978</span><br><span class="line">total symbol table binary searches: 0</span><br><span class="line">total images defining weak symbols: 37</span><br><span class="line">total images using weak symbols: 92</span><br></pre></td></tr></table></figure></div></li></ul></li></ul><p>这些数据可能对大家来说不太直观,这其实只是提供给大家一个参考,一般我个人认为total time在<br>400~500ms之间就相对来说是比较正常的,如果时间太长就可能要进行相应的优化了,接下来我们来看看冷启动的大概分哪几个阶段</p><h2 id="APP冷启动阶段可以概括为3大阶段"><a href="#APP冷启动阶段可以概括为3大阶段" class="headerlink" title="APP冷启动阶段可以概括为3大阶段"></a>APP冷启动阶段可以概括为3大阶段</h2><ul><li>dyld</li><li>runtime</li><li>main</li></ul><p><a href="https://ae01.alicdn.com/kf/Ud91e5d552eb842a4aa60364d9be1a38eE.jpg" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://ae01.alicdn.com/kf/Ud91e5d552eb842a4aa60364d9be1a38eE.jpg" class="lazyload"></a></p><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing"></a>One More Thing</h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)<code>关注有福利可以使用免费梯子自由上网</code></p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
APP的启动可以分为2种:
* 冷启动(Cold Launch):从零开始启动APP
* 热启动 (Warm Launch):APP已经在内存中,在后台存活着,再次点击图标启动APP
APP启动时间的优化
那我们通常所说的启动时间优化都是再说的冷启动的时间优化,其实Xcode是提供给我们一种分析启动时间的方式,我们接下来试一试
* 通过添加环境变量可以打印出APP的启动时间分析(Edit Scheme -> Run -> Arguments)
* DYLD_PRINT_STATISTICS设置为1
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="性能优化" scheme="https://lizhaobomb.github.io/categories/iOS/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="性能" scheme="https://lizhaobomb.github.io/tags/%E6%80%A7%E8%83%BD/"/>
<category term="耗电" scheme="https://lizhaobomb.github.io/tags/%E8%80%97%E7%94%B5/"/>
</entry>
<entry>
<title>iOS性能优化06 - 耗电优化</title>
<link href="https://lizhaobomb.github.io/2020/03/02/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9606%20-%20%E8%80%97%E7%94%B5%E4%BC%98%E5%8C%96/"/>
<id>https://lizhaobomb.github.io/2020/03/02/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9606%20-%20%E8%80%97%E7%94%B5%E4%BC%98%E5%8C%96/</id>
<published>2020-03-01T16:10:00.000Z</published>
<updated>2020-03-02T16:14:35.185Z</updated>
<content type="html"><![CDATA[<h2 id="耗电的主要来源"><a href="#耗电的主要来源" class="headerlink" title="耗电的主要来源"></a>耗电的主要来源</h2><p><a href="https://ae01.alicdn.com/kf/Uc4ae257eb7b5461d8f9977c40207fc12K.jpg" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://ae01.alicdn.com/kf/Uc4ae257eb7b5461d8f9977c40207fc12K.jpg" class="lazyload"></a></p><ul><li><p>CPU处理,Processing</p></li><li><p>网络, Networking</p></li><li><p>定位,Location</p></li><li><p>图像,Graphics</p></li></ul><h2 id="耗电优化的几条建议"><a href="#耗电优化的几条建议" class="headerlink" title="耗电优化的几条建议"></a>耗电优化的几条建议</h2><ul><li><p>尽可能降低CPU、GPU功耗</p></li><li><p>少用定时器</p></li><li><p>优化I/O操作</p><ul><li>尽量不要频繁写入小数据,最好批量一次性写入</li><li>读写大量重要数据时,考虑使用<code>dispatch_io</code>, 其提供了基于GCD的异步操作文件I/O的API。用<code>dispatch_io</code>系统会优化磁盘访问</li><li>数据量比较大的,建议使用数据库(比如<code>SQLite</code>、<code>CoreData</code>)(可能好多同学都直接写一个<code>plist</code>文件或者用<code>NSKeyArchive</code>归档到一个文件里,当数据量大的时候不建议这样写,因为数据库毕竟对读数据或者写数据是有优化过的)</li></ul></li><li><p>网络优化</p><ul><li>减少、压缩网络数据(比如我们之前给服务器交互的时候可能用的是XML,XML的一个缺点就是体积比较大因为格式比较臃肿,现在我们改为JSON体积就会减少很多,当然现在有很多公司在用<a href="https://github.com/protocolbuffers/protobuf" target="_blank" rel="noopener">protocol buffers</a>更小更快更简单,感兴趣的同学可以点击链接研究)</li><li>如果多次请求的结果是相同的,尽量使用缓存</li><li>使用断点续传,否则网络不稳定时可能多次传输相同的内容</li><li>网络不可用时, 不要尝试执行网络请求</li><li>让用户可以取消长时间运行或者速度很慢的网络操作,设置合适的超时时间</li><li>批量传输,比如,下载视频流时,不要传输很小的数据包,直接下载整个文件或者一大块一大块的下载。如果下载广告,一次性多下载一些,然后再慢慢展示。如果下载电子邮件,一次性下载多封,不要一封一封地下载</li></ul></li><li><p>定位优化</p><ul><li>如果只是需要快速确定用户的位置,最好用<code>CLLocationManager</code>的<code>requestLocation</code>方法。定位完成后,会自动让定位硬件断电</li><li>如果不是导航应用,尽量不要实时更新位置,定位完毕就关掉定位服务</li><li>尽量降低定位精度,比如尽量不要使用精度最高的<code>kCLLocationAccuracyBest</code></li><li>需要后台定位时,尽量设置<code>pausesLocationUpdatesAutomatically</code>为<code>YES</code>,如果用户不太可能移动的时候系统会自动暂停位置更新</li><li>尽量不要使用<code>startMonitoringSignificantLocationChanges</code>,优先考虑<code>startMonitoringForRegion:</code></li></ul></li><li><p>硬件检测优化</p><ul><li>用户移动、摇晃、倾斜设备时,会产生动作(<code>motion</code>)事件,这些事件由加速度计、陀螺仪、磁力计等硬件检测。在不需要检测的场合,应该及时关闭这些硬件</li></ul></li></ul><h1 id="One-More-Thing"><a href="#One-More-Thing" class="headerlink" title="One More Thing"></a>One More Thing</h1><p><a href="https://docs.qq.com/sheet/DQkhZTVdhbVB2dEVO?c=A2A0A0" target="_blank" rel="noopener">点击查看 2020—课程列表 全网IT各种资源有需求的可以微我,或者你喜欢的课程都可以给我发链接剩下的我来搞定</a></p><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)</p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
耗电的主要来源
* CPU处理,Processing
* 网络, Networking
* 定位,Location
* 图像,Graphics
耗电优化的几条建议
* 尽可能降低CPU、GPU功耗
* 少用定时器
* 优化I/O操作
* 尽量不要频繁写入小数据,最好批量一次性写入
* 读写大量重要数据时,考虑使用dispatch_io, 其提供了基于GCD的异步操作文件I/O的API。用dispatch_io系统会优化磁盘访问
* 数据量比较大的,
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/categories/iOS/"/>
<category term="性能优化" scheme="https://lizhaobomb.github.io/categories/iOS/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="性能" scheme="https://lizhaobomb.github.io/tags/%E6%80%A7%E8%83%BD/"/>
<category term="耗电" scheme="https://lizhaobomb.github.io/tags/%E8%80%97%E7%94%B5/"/>
</entry>
<entry>
<title>iOS性能优化05-卡顿优化03-卡顿监测</title>
<link href="https://lizhaobomb.github.io/2020/03/01/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9605-%E5%8D%A1%E9%A1%BF%E4%BC%98%E5%8C%9603-%E5%8D%A1%E9%A1%BF%E7%9B%91%E6%B5%8B/"/>
<id>https://lizhaobomb.github.io/2020/03/01/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9605-%E5%8D%A1%E9%A1%BF%E4%BC%98%E5%8C%9603-%E5%8D%A1%E9%A1%BF%E7%9B%91%E6%B5%8B/</id>
<published>2020-02-29T16:20:47.000Z</published>
<updated>2020-03-04T15:34:11.060Z</updated>
<content type="html"><![CDATA[<ul><li><p>平时所说的”卡顿“主要是因为在主线程执行了比较耗时的操作阻塞了主线程造成的</p></li><li><p>可以添加Observer到主线程Runloop中,通过监听Runloop状态切换的耗时,以达到监控卡顿的目的</p></li></ul><p>下面我们来具体看看如何用代码实现</p><p>首先我们先看看Runloop的运行逻辑<br><a href="https://upload-images.jianshu.io/upload_images/112869-3d96c6551f26b3b1.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" data-fancybox="group" data-caption="Runloop运行逻辑" class="fancybox"><img alt="Runloop运行逻辑" title="Runloop运行逻辑" data-src="https://upload-images.jianshu.io/upload_images/112869-3d96c6551f26b3b1.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" class="lazyload"></a></p><p>我们知道我们主线程大部分的操作(比如点击事件的处理、view的绘制计算等等)都是在<code>source0</code>和<code>source1</code>之间,所以我们只要监控下<code>结束休眠处理source1一直到绕回来处理source0这种所消耗的时间</code>,如果发现这次Runloop所消耗的时间比较长,有可能就证明这些操作就比较耗时了,所以我们卡顿监测就是这样子一个效果,最好是能把导致耗时的代码是哪个方法监测出来,我们自己来写这个代码也是可以的,但是比较复杂,我从网上找了个写好的大家可以参考下源码</p><p><a href="https://github.com/UIControl/LXDAppFluecyMonitor" target="_blank" rel="noopener">源码链接</a></p><p>我们跑下demo看下<br>我们滑动列表会发现卡顿并且在控制台有输出监测到导致卡顿的方法调用栈</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">2020-03-01 22:42:24.696074+0800 LXDAppFluecyMonitor[8018:288367] Backtrace of Thread 771:</span><br><span class="line">======================================================================================</span><br><span class="line">libsystem_kernel.dylib 0x7fff523b8bba __semwait_signal + 10</span><br><span class="line">libsystem_c.dylib 0x7fff52348352 sleep + 41</span><br><span class="line">LXDAppFluecyMonitor 0x10bab858f -[ViewController tableView:cellForRowAtIndexPath:] + 351</span><br><span class="line">UIKitCore 0x7fff48297462 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 781</span><br><span class="line">UIKitCore 0x7fff4826043b -[UITableView _updateVisibleCellsNow:] + 3081</span><br><span class="line">UIKitCore 0x7fff4828055f -[UITableView layoutSubviews] + 194</span><br><span class="line">UIKitCore 0x7fff485784bd -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2478</span><br><span class="line">QuartzCore 0x7fff2b131db1 -[CALayer layoutSublayers] + 255</span><br><span class="line">QuartzCore 0x7fff2b137fa3 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 517</span><br><span class="line">QuartzCore 0x7fff2b1438da _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 80</span><br><span class="line">QuartzCore 0x7fff2b08a848 _ZN2CA7Context18commit_transactionEPNS_11TransactionEd + 324</span><br><span class="line">QuartzCore 0x7fff2b0bfb51 _ZN2CA11Transaction6commitEv + 643</span><br><span class="line">QuartzCore 0x7fff2afeb37f _ZN2CA7Display11DisplayLink14dispatch_itemsEyyy + 921</span><br><span class="line">QuartzCore 0x7fff2b0c3e03 _ZL22display_timer_callbackP12__CFMachPortPvlS1_ + 299</span><br><span class="line">CoreFoundation 0x7fff23b9503d __CFMachPortPerform + 157</span><br><span class="line">CoreFoundation 0x7fff23bd4bc9 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41</span><br><span class="line">CoreFoundation 0x7fff23bd4228 __CFRunLoopDoSource1 + 472</span><br><span class="line">CoreFoundation 0x7fff23bced64 __CFRunLoopRun + 2516</span><br><span class="line">CoreFoundation 0x7fff23bce066 CFRunLoopRunSpecific + 438</span><br><span class="line">GraphicsServices 0x7fff384c0bb0 GSEventRunModal + 65</span><br><span class="line">UIKitCore 0x7fff48092d4d UIApplicationMain + 1621</span><br><span class="line">LXDAppFluecyMonitor 0x10bab9a40 main + 112</span><br><span class="line">libdyld.dylib 0x7fff5227ec25 start + 1</span><br><span class="line"></span><br><span class="line">======================================================================================</span><br></pre></td></tr></table></figure></div><p>我们看到代码中在:</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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">- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {</span><br><span class="line"> UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: @"cell"];</span><br><span class="line"> cell.textLabel.text = [NSString stringWithFormat: @"%lu", indexPath.row];</span><br><span class="line"> if (indexPath.row > 0 && indexPath.row % 30 == 0) {</span><br><span class="line">// usleep(2000000);</span><br><span class="line"> sleep(2.0);</span><br><span class="line"> }</span><br><span class="line"> return cell;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>有人主动休眠了2s,那肯定会卡顿2s的导致的耗时</p><p>我们在<code>didSelectRowAtIndexPath</code>方法里再测试下</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">- (void)tableView: (UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath { </span><br><span class="line"> sleep(2.0);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>我们看到控制台也有输出卡顿的方法调用栈,</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><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></pre></td><td class="code"><pre><span class="line">=====================================================================================</span><br><span class="line">libsystem_kernel.dylib 0x7fff523b8bba __semwait_signal + 10</span><br><span class="line">libsystem_c.dylib 0x7fff52348352 sleep + 41</span><br><span class="line">LXDAppFluecyMonitor 0x10bab8640 -[ViewController tableView:didSelectRowAtIndexPath:] + 80</span><br><span class="line">UIKitCore 0x7fff4827a42b -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect:] + 855</span><br><span class="line">UIKitCore 0x7fff4827a0bd -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 97</span><br><span class="line">UIKitCore 0x7fff4827a8e8 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 334</span><br><span class="line">UIKitCore 0x7fff4809be5b _runAfterCACommitDeferredBlocks + 352</span><br><span class="line">UIKitCore 0x7fff4808c7b4 _cleanUpAfterCAFlushAndRunDeferredBlocks + 248</span><br><span class="line">UIKitCore 0x7fff480bc3a9 _afterCACommitHandler + 85</span><br><span class="line">CoreFoundation 0x7fff23bd3867 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23</span><br><span class="line">CoreFoundation 0x7fff23bce2fe __CFRunLoopDoObservers + 430</span><br><span class="line">CoreFoundation 0x7fff23bce97a __CFRunLoopRun + 1514</span><br><span class="line">CoreFoundation 0x7fff23bce066 CFRunLoopRunSpecific + 438</span><br><span class="line">GraphicsServices 0x7fff384c0bb0 GSEventRunModal + 65</span><br><span class="line">UIKitCore 0x7fff48092d4d UIApplicationMain + 1621</span><br><span class="line">LXDAppFluecyMonitor 0x10bab9a40 main + 112</span><br><span class="line">libdyld.dylib 0x7fff5227ec25 start + 1</span><br><span class="line"></span><br><span class="line">======================================================================================</span><br></pre></td></tr></table></figure></div><p>所以这个demo是完全可以监测卡顿的,那我们来简单看下代码的逻辑,方法调用栈的打印就不过多介绍了,因为比较复杂大家有兴趣可以参考源码里的<code>Backtrack</code>文件里的代码自己去研究下,接下来我们就看看作者的逻辑:</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">// 首先创建observer,监听所有Runloop状态</span><br><span class="line">_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &lxdRunLoopObserverCallback, &context);</span><br><span class="line">// 添加observer</span><br><span class="line">CFRunLoopAddObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);</span><br><span class="line">// 创建循环监听Runloop各种状态下的耗时,如果超过预定的值就认为是卡顿并打印出来</span><br><span class="line"> dispatch_async(lxd_fluecy_monitor_queue(), ^{</span><br><span class="line"> while (SHAREDMONITOR.isMonitoring) {</span><br><span class="line"> long waitTime = dispatch_semaphore_wait(self.semphore, dispatch_time(DISPATCH_TIME_NOW, lxd_wait_interval));</span><br><span class="line"> if (waitTime != LXD_SEMPHORE_SUCCESS) {</span><br><span class="line"> if (!SHAREDMONITOR.observer) {</span><br><span class="line"> SHAREDMONITOR.timeOut = 0;</span><br><span class="line"> [SHAREDMONITOR stopMonitoring];</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"> if (SHAREDMONITOR.currentActivity == kCFRunLoopBeforeSources || SHAREDMONITOR.currentActivity == kCFRunLoopAfterWaiting) {</span><br><span class="line"> if (++SHAREDMONITOR.timeOut < 5) {</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"> [LXDBacktraceLogger lxd_logMain];</span><br><span class="line"> [NSThread sleepForTimeInterval: lxd_restore_interval];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> SHAREDMONITOR.timeOut = 0;</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div><p>喜欢的朋友可以扫描关注我的公众号(多多点赞,多多打赏,您的支持是我写作的最大动力)</p><p><a href="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" data-fancybox="group" data-caption="iOS_DevTips" class="fancybox"><img alt="iOS_DevTips" title="iOS_DevTips" data-src="https://ae01.alicdn.com/kf/Udde8350c2b484ac6b4d7f9c3ea1c52822.jpg" class="lazyload"></a></p>]]></content>
<summary type="html">
* 平时所说的”卡顿“主要是因为在主线程执行了比较耗时的操作阻塞了主线程造成的
* 可以添加Observer到主线程Runloop中,通过监听Runloop状态切换的耗时,以达到监控卡顿的目的
下面我们来具体看看如何用代码实现
首先我们先看看Runloop的运行逻辑
我们知道我们主线程大部分的操作(比如点击事件的处理、view的绘制计算等等)都是在source0和source1之间,所以我们只要监控下结束休眠处理source1一直到绕回来处理source0这种所消耗的时间,如果发现这次Runloop所消耗的时间比较长,有可能就证明这些操作就比较耗时了,
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="性能优化" scheme="https://lizhaobomb.github.io/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>iOS性能优化04-卡顿优化02-GPU</title>
<link href="https://lizhaobomb.github.io/2020/02/29/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9604-%E5%8D%A1%E9%A1%BF%E4%BC%98%E5%8C%9602-GPU/"/>
<id>https://lizhaobomb.github.io/2020/02/29/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9604-%E5%8D%A1%E9%A1%BF%E4%BC%98%E5%8C%9602-GPU/</id>
<published>2020-02-28T16:20:47.000Z</published>
<updated>2020-02-29T15:37:25.294Z</updated>
<content type="html"><![CDATA[<ul><li><p>尽量减少视图数量和层次</p></li><li><p>尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示</p></li><li><p>减少透明的视图(alpha<1),不透明的就设置opaque为YES</p></li><li><p>GPU能处理的最大纹理尺寸是4096*4096,一旦超过这个尺寸,就会占用CPU资源进行处理,所以纹理尽量不要超过这个尺寸</p></li><li><p>尽量避免出现离屏渲染</p></li></ul><h2 id="离屏渲染"><a href="#离屏渲染" class="headerlink" title="离屏渲染"></a>离屏渲染</h2><ul><li><p>在OpenGL中,GPU有2种渲染模式</p><ul><li>On-Screen Rendering:当前屏幕渲染,在当前用于显示的屏幕缓冲区进行渲染操作</li><li>Off-Screen Rendering:离屏渲染,在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作</li></ul></li><li><p>离屏渲染消耗性能的原因</p><ul><li>需要创建新的缓冲区</li><li>离屏渲染的整个过程,需要多次切换上下文环境,先是从当前屏幕(On-Screen)切换到离屏(Off-Screen),等到离屏渲染结束后,将离屏缓冲区的渲染结果显示到屏幕上,又需要将上下文环境从离屏切换到当前屏幕</li></ul></li><li><p>哪些操作会触发离屏渲染?</p><ul><li>光栅化,layer.shouldRasterize = YES</li><li>遮罩,layer.mask</li><li>圆角,同时设置layer.maskToBounds = YES、layer.cornerRadius 大于0(考虑通过CoreGraphics绘制裁剪圆角,这个网上例子有很多我就不多说了,大家随便搜一搜都可以搜到,或者叫美工直接提供圆角图片)</li><li>阴影, layer.shadowXXX (但是如果设置了layer.shadowPath就不会产生离屏渲染了,不设置默认是环绕layer添加的)</li></ul></li></ul><p>喜欢的朋友可以扫描关注我的公众号(多谢支持)</p><p><a href="https://img.rruu.net/image/5e57d1ec32781" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://img.rruu.net/image/5e57d1ec32781" class="lazyload"></a></p>]]></content>
<summary type="html">
* 尽量减少视图数量和层次
* 尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示
* 减少透明的视图(alpha<1),不透明的就设置opaque为YES
* GPU能处理的最大纹理尺寸是4096*4096,一旦超过这个尺寸,就会占用CPU资源进行处理,所以纹理尽量不要超过这个尺寸
* 尽量避免出现离屏渲染
离屏渲染
* 在OpenGL中,GPU有2种渲染模式
* On-Screen Rendering:当前屏幕渲染,在当前用于显示的屏幕缓冲区进行渲染操作
* O
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="性能优化" scheme="https://lizhaobomb.github.io/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>iOS性能优化03-卡顿优化01-CPU</title>
<link href="https://lizhaobomb.github.io/2020/02/28/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9603-%E5%8D%A1%E9%A1%BF%E4%BC%98%E5%8C%9601-CPU/"/>
<id>https://lizhaobomb.github.io/2020/02/28/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9603-%E5%8D%A1%E9%A1%BF%E4%BC%98%E5%8C%9601-CPU/</id>
<published>2020-02-27T16:20:47.000Z</published>
<updated>2020-02-29T15:28:29.318Z</updated>
<content type="html"><![CDATA[<ul><li><p>尽量使用轻量级的对象,比如用不到事件处理的地方,可以考虑使用CALayer取代UIView</p></li><li><p>不要频繁的调用UIView的相关属性,比如frame、bounds、transform等属性,尽量减少不必要的修改</p></li><li><p>尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性</p></li><li><p>Autolayout会比直接设置frame消耗更多的CPU资源</p></li><li><p>图片的size,最好刚好跟UIImageView的size保持一致</p></li><li><p>控制一下线程的最大并发数量</p></li><li><p>尽量把耗时的操作放到子线程里(比如<code>文本处理</code>和<code>图片处理</code>)</p><ul><li><p>文本处理 (尺寸计算、绘制)</p><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 文字计算</span><br><span class="line"> [@"text" boundingRectWithSize:CGSizeMake(100, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:nil];</span><br></pre></td></tr></table></figure></div><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">Code</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 文字绘制</span><br><span class="line"> [@"text" drawWithRect:CGRectMake(0, 0, 100, 100) options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:nil];</span><br></pre></td></tr></table></figure></div></li></ul></li></ul><pre><code>- 图片处理(解码、绘制)我们一般都会用```imageView.image = [UIImage imageNamed:@"***"];```这种方式来获取图片,但这种方式是系统负责解码,而系统解码默认又是在主线程所以如果你的图片数据很大的时候就可能阻塞主线程从而造成卡顿,所以我们一般都是提前解码并且在子线程里进行,这样主线程就少了解码的操作到时候直接把解码的图片数据拿来用就好了,其实我们现在用的一些第三方图片处理库都有异步解码的功能了,我们来看一个例子(也是从三方库里拷贝过来的)代码有点多,其实核心步骤就是: 1.获取到图片的CGImage2.解码(解码的步骤就是)- 2.1 创建位图上下文- 2.2 把cgImage draw到上下文里,这样就完成了解码操作3.从上下文里获取刚解码过的图片4.最好再把解码过的图片包装成UIImage5.回到主线程的时候我们直接用解码过的图片就OK了(这样解码的操作都是在子线程里做的并不会阻塞主线程)</code></pre><p>下面我们来看看具体的代码实现 </p><pre><code>- (void)image{ UIImageView *imageView = [[UIImageView alloc] init]; imageView.frame = CGRectMake(100, 100, 100, 56); [self.view addSubview:imageView]; self.imageView = imageView; dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 获取CGImage CGImageRef cgImage = [UIImage imageNamed:@"***"].CGImage; // alphaInfo CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage) & kCGBitmapAlphaInfoMask; BOOL hasAlpha = NO; if (alphaInfo == kCGImageAlphaPremultipliedLast || alphaInfo == kCGImageAlphaPremultipliedFirst || alphaInfo == kCGImageAlphaLast || alphaInfo == kCGImageAlphaFirst) { hasAlpha = YES; } // bitmapInfo CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; // size size_t width = CGImageGetWidth(cgImage); size_t height = CGImageGetHeight(cgImage); // context CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, CGColorSpaceCreateDeviceRGB(), bitmapInfo); // draw CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); // get CGImage cgImage = CGBitmapContextCreateImage(context); // into UIImage UIImage *newImage = [UIImage imageWithCGImage:cgImage]; // release CGContextRelease(context); CGImageRelease(cgImage); // back to the main thread dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = newImage; }); });}</code></pre><p>喜欢的朋友可以扫描关注我的公众号(多谢支持)</p><p><a href="https://img.rruu.net/image/5e57d1ec32781" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://img.rruu.net/image/5e57d1ec32781" class="lazyload"></a></p>]]></content>
<summary type="html">
* 尽量使用轻量级的对象,比如用不到事件处理的地方,可以考虑使用CALayer取代UIView
* 不要频繁的调用UIView的相关属性,比如frame、bounds、transform等属性,尽量减少不必要的修改
* 尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性
* Autolayout会比直接设置frame消耗更多的CPU资源
* 图片的size,最好刚好跟UIImageView的size保持一致
* 控制一下线程的最大并发数量
* 尽量把耗时的操作放到子线程
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="性能优化" scheme="https://lizhaobomb.github.io/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>iOS性能优化02-产生卡顿的原因</title>
<link href="https://lizhaobomb.github.io/2020/02/27/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9602-%E5%8D%A1%E9%A1%BF%E4%BA%A7%E7%94%9F%E7%9A%84%E5%8E%9F%E5%9B%A0/"/>
<id>https://lizhaobomb.github.io/2020/02/27/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9602-%E5%8D%A1%E9%A1%BF%E4%BA%A7%E7%94%9F%E7%9A%84%E5%8E%9F%E5%9B%A0/</id>
<published>2020-02-27T13:20:47.000Z</published>
<updated>2020-02-28T16:55:06.768Z</updated>
<content type="html"><![CDATA[<ul><li>卡顿产生的主要原因CPU和GPU所花费的时间太长从而造成俗称的丢帧(掉帧)</li></ul><p>我们以下图为例,红色代表CPU,绿色代表GPU</p><p><a href="https://img.rruu.net/image/5e57d298d000f" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://img.rruu.net/image/5e57d298d000f" class="lazyload"></a></p><ol><li><p>首先把CPU把计算好的数据交给GPU去渲染,紧接着来一个VSync(垂直同步信号)就会把刚CPU计算好并且GPU渲染好的数据展示到屏幕上完成这一帧的显示,注意一旦发生一个VSync就会把GPU渲染到帧缓存里的数据显示到屏幕上,并且开始下一帧的操作,</p></li><li><p>我们第二帧的操作GPU花费的时间比较短还留出一段空闲时间等VSync的到来然后显示到屏幕上,但也有一种情况就是:</p></li><li><p>我们第三帧的操作,CPU计算完数据交给GPU去渲染,然而由于这次的数据比较多当VSync到来时,发现GPU还没有渲染完,上面我们也说了VSync一旦到来就会把GPU渲染到帧缓存里的数据显示到屏幕上,但是GPU并没有渲染完,所以只能显示上一帧的数据,也就意味着当前这帧数据丢失了,俗称丢帧或掉帧,而当前帧只能等下次VSync到来时再显示,因此就会造成卡顿(本来要显示当前帧结果只能显示前一帧)</p></li></ol><h1 id="卡顿解决的主要思路:"><a href="#卡顿解决的主要思路:" class="headerlink" title="卡顿解决的主要思路:"></a>卡顿解决的主要思路:</h1><ul><li>尽可能减少CPU、GPU资源消耗</li><li>一般我们要保证每秒60帧这样看起来就不会有什么问题了,那按照60FPS的刷帧率,每个16ms就会有一次VSync信号(为什么是16ms?因为1s=1000ms,1000ms/60~16ms)也就是说我们16ms内完成CPU和GPU操作就不会有什么卡顿问题了</li></ul><p>喜欢的朋友可以扫描关注我的公众号(多谢支持)</p><p><a href="https://img.rruu.net/image/5e57d1ec32781" data-fancybox="group" data-caption="" class="fancybox"><img alt="" title="" data-src="https://img.rruu.net/image/5e57d1ec32781" class="lazyload"></a></p>]]></content>
<summary type="html">
* 卡顿产生的主要原因CPU和GPU所花费的时间太长从而造成俗称的丢帧(掉帧)
我们以下图为例,红色代表CPU,绿色代表GPU
1. 首先把CPU把计算好的数据交给GPU去渲染,紧接着来一个VSync(垂直同步信号)就会把刚CPU计算好并且GPU渲染好的数据展示到屏幕上完成这一帧的显示,注意一旦发生一个VSync就会把GPU渲染到帧缓存里的数据显示到屏幕上,并且开始下一帧的操作,
2. 我们第二帧的操作GPU花费的时间比较短还留出一段空闲时间等VSync的到来然后显示到屏幕上,但也有一种情况就是:
3. 我们第三帧的操作,CPU计算完数据交
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="性能优化" scheme="https://lizhaobomb.github.io/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>iOS性能优化01-CPU和GPU</title>
<link href="https://lizhaobomb.github.io/2020/02/26/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9601-CPU%E5%92%8CGPU/"/>
<id>https://lizhaobomb.github.io/2020/02/26/iOS%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%9601-CPU%E5%92%8CGPU/</id>
<published>2020-02-26T13:20:47.000Z</published>
<updated>2020-02-29T15:28:15.631Z</updated>
<content type="html"><![CDATA[<h2 id="在屏幕成像的过程中-CPU和GPU起着至关重要的作用"><a href="#在屏幕成像的过程中-CPU和GPU起着至关重要的作用" class="headerlink" title="在屏幕成像的过程中,CPU和GPU起着至关重要的作用"></a>在屏幕成像的过程中,CPU和GPU起着至关重要的作用</h2><ul><li><p>CPU(Centeral Processing Unit,中央处理器)<br>对象的创建和销毁,对象属性的调整,布局计算,文本的计算和排版,图片的格式转换和解码、图像的绘制(Core Graphics)</p></li><li><p>GPU(Graphics Processing Unit,图形处理器)<br>纹理的渲染</p></li><li><p>CPU 和 GPU 工作原理</p><p> CPU –计算–>GPU–渲染–>帧缓存–读取–>视频控制器–显示–>屏幕</p></li></ul><ul><li>iOS中是双缓存机制,有前帧缓存,后帧缓存</li></ul><h1 id="屏幕成像原理"><a href="#屏幕成像原理" class="headerlink" title="屏幕成像原理"></a>屏幕成像原理</h1><p>垂直同步信号(VSync)水平同步信号(HSync)</p><p>屏幕要显示一帧画面之前首先会发送一个VSync,紧接着就是一行一行的HSync,当<br>发送最后一行HSync的时候,就会接着发送下一个VSync,这样周而复始就是我们看到的屏幕画面了</p><p>VSync</p><p>|—————-> HSync</p><p>|—————-></p><p>|—————-></p><p>|—————-></p>]]></content>
<summary type="html">
在屏幕成像的过程中,CPU和GPU起着至关重要的作用
* CPU(Centeral Processing Unit,中央处理器)
对象的创建和销毁,对象属性的调整,布局计算,文本的计算和排版,图片的格式转换和解码、图像的绘制(Core Graphics)
* GPU(Graphics Processing Unit,图形处理器)
纹理的渲染
* CPU 和 GPU 工作原理
CPU –计算–>GPU–渲染–>帧缓存–读取–>视频控制器–显示–>屏幕
* iOS中是双缓存机制,有前帧缓存,后帧缓存
屏幕成像原
</summary>
<category term="iOS" scheme="https://lizhaobomb.github.io/tags/iOS/"/>
<category term="性能优化" scheme="https://lizhaobomb.github.io/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>宏和const的区别</title>
<link href="https://lizhaobomb.github.io/2016/11/02/%E5%AE%8F%E5%92%8Cconst%E7%9A%84%E5%8C%BA%E5%88%AB/"/>
<id>https://lizhaobomb.github.io/2016/11/02/%E5%AE%8F%E5%92%8Cconst%E7%9A%84%E5%8C%BA%E5%88%AB/</id>
<published>2016-11-02T13:20:47.000Z</published>
<updated>2020-02-27T15:21:55.213Z</updated>
<content type="html"><![CDATA[<p>1、编译的时刻不一样<br>2、</p><p>const的简单实用</p><p>const作用:1.修饰右边基本变量或者指针变量 int a int *p<br> 2.被const修饰变量只读</p><p>int * const p; //p只读,*p可以改 </p><p>int const * p; //*p只读, p可以改</p><p>const int *p; // *p只读,p变量</p><p>const int *const p; //都是只读</p><p>int const *const p; //都是只读</p>]]></content>
<summary type="html">
1、编译的时刻不一样
2、
const的简单实用
const作用:1.修饰右边基本变量或者指针变量 int a int *p
2.被const修饰变量只读
int * const p; //p只读,*p可以改
int const * p; //*p只读, p可以改
const int *p; // *p只读,p变量
const int *const p; //都是只读
int const *const p; //都是只读
</summary>
<category term="宏" scheme="https://lizhaobomb.github.io/tags/%E5%AE%8F/"/>
<category term="const" scheme="https://lizhaobomb.github.io/tags/const/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="https://lizhaobomb.github.io/2016/10/08/hello-world/"/>
<id>https://lizhaobomb.github.io/2016/10/08/hello-world/</id>
<published>2016-10-08T14:35:23.000Z</published>
<updated>2016-10-08T14:35:23.000Z</updated>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="noopener">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="noopener">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="noopener">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">bash</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure></div><p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="noopener">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">bash</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure></div><p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="noopener">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">bash</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure></div><p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="noopener">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><div class="code-area-wrap"><div class="highlight-tools"><i class="fa fa-angle-down code-expand" aria-hidden="true"></i><div class="code_lang">bash</div><div class="copy-notice"></div><i class="fa fa-clipboard" aria-hidden="true"></i></div><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure></div><p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="noopener">Deployment</a></p>]]></content>
<summary type="html">
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
Quick Start
Create a new post
1
$ hexo new "My New Post"
More info: Writing
Run server
1
$ hexo s
</summary>
</entry>
</feed>