-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
1181 lines (1042 loc) · 111 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
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Camel</title>
<subtitle>qmk</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://qmkcamel.github.io/"/>
<updated>2017-05-15T07:51:09.000Z</updated>
<id>https://qmkcamel.github.io/</id>
<author>
<name>qmkCamel</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Apple File System</title>
<link href="https://qmkcamel.github.io/2017/05/15/Apple%20File%20System/"/>
<id>https://qmkcamel.github.io/2017/05/15/Apple File System/</id>
<published>2017-05-14T16:00:00.000Z</published>
<updated>2017-05-15T07:51:09.000Z</updated>
<content type="html"><![CDATA[<p>在升级了10.3之后,你会发现存储空间貌似多了起来。其实这些都是APFS的功劳。</p>
<h2 id="下面我们来简单聊聊APFS带来了哪些改变。"><a href="#下面我们来简单聊聊APFS带来了哪些改变。" class="headerlink" title="下面我们来简单聊聊APFS带来了哪些改变。"></a>下面我们来简单聊聊APFS带来了哪些改变。</h2><p>SSD相对于机械硬盘来说,没有磁头这个概念,能及时访问到硬盘内的任何一处,不需要担心<code>磁盘碎片</code>带来的性能下降。</p>
<h4 id="文件克隆(Clone)-复制不再占用空间"><a href="#文件克隆(Clone)-复制不再占用空间" class="headerlink" title="文件克隆(Clone),复制不再占用空间"></a>文件克隆(Clone),复制不再占用空间</h4><p>在APFS中,复制只会创造一个新的标记,并不会真的完整复制。如果需要修改其中一个文件,APFS会保留相同的部分,只存储变化的部分。文件在存储的时候,系统会将修改部分和未被修改的部分拼接在一起,形成新的文件。<br>在iOS中,由于沙盒机制的影响,在A应用的文件如果需要被B应用调用的话,需要在复制一遍,这一问题在APFS中被解决。</p>
<h4 id="磁盘快照(Snapshot)"><a href="#磁盘快照(Snapshot)" class="headerlink" title="磁盘快照(Snapshot)"></a>磁盘快照(Snapshot)</h4><p>快照是基于增量的,只有文件发生变化的那一部分会占用更多的空间。</p>
<h4 id="空间共享(Space-Sharing)"><a href="#空间共享(Space-Sharing)" class="headerlink" title="空间共享(Space Sharing)"></a>空间共享(Space Sharing)</h4><p>将传统的分区虚拟为 Container,只要几个容器在一个APFS磁盘下,可以自由变大和缩小。<br><img src="http://ohujsjvgi.bkt.clouddn.com/14948327817341.jpg" alt=""></p>
<h4 id="提升了服务质量(I-O-QoS)"><a href="#提升了服务质量(I-O-QoS)" class="headerlink" title="提升了服务质量(I/O QoS)"></a>提升了服务质量(I/O QoS)</h4><p>提供了 Extensible Block Allocator等技术。对数据的不同访问划分到不同的优先级中,优先处理用户感知明显的操作。</p>
<h4 id="安全"><a href="#安全" class="headerlink" title="安全"></a>安全</h4><p>做了统一整合,提供了三种磁盘加密方式</p>
<ul>
<li>无加密</li>
<li>单密钥加密</li>
<li>多密钥加密:可以用密钥A给设备加密,用额外的密钥B给部分数据加密</li>
</ul>
<h3 id="Crash-Pretection"><a href="#Crash-Pretection" class="headerlink" title="Crash Pretection"></a>Crash Pretection</h3><p>APFS 引入了 Copy on write 机制,编辑文件时原有数据不会被当即修改,修改会有一个临时文件,只有确定文件修改完成后才会覆盖旧的文件。再也不用担心文件没有保存了。</p>
<h2 id="苹果为什么要更新APFS"><a href="#苹果为什么要更新APFS" class="headerlink" title="苹果为什么要更新APFS ?"></a>苹果为什么要更新APFS ?</h2><h4 id="支持最新的软硬件技术"><a href="#支持最新的软硬件技术" class="headerlink" title="支持最新的软硬件技术"></a>支持最新的软硬件技术</h4><p>现在的HFS+和前任HFS(Hierarchical File System)当时是针对软盘和机械硬盘设计的,已经不能在最新的存储技术上有好的发挥,反而有些地方已经成为了累赘。同时针对移动互联网的使用场景和形态做了数据安全性的优化。</p>
<h4 id="协调统一生态系统"><a href="#协调统一生态系统" class="headerlink" title="协调统一生态系统"></a>协调统一生态系统</h4><p>在全系产品上做到统一,都使用APFS,对开发者会更友好一点。</p>
<h2 id="ref"><a href="#ref" class="headerlink" title="ref"></a>ref</h2><p>1.<a href="https://sspai.com/post/38377" target="_blank" rel="external">升级iOS 10.3之后存储空间变多了?这都是APFS的功劳</a><br>2.<a href="https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/APFS_Guide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40016999-CH1-DontLinkElementID_27" target="_blank" rel="external">Apple File System Guide</a><br>3.<a href="https://zh.wikipedia.org/wiki/固态硬盘" target="_blank" rel="external">固态硬盘</a><br>4.<a href="https://zh.wikipedia.org/wiki/%E9%97%AA%E5%AD%98#NAND_Flash" target="_blank" rel="external">闪存</a></p>
]]></content>
<summary type="html">
<p>在升级了10.3之后,你会发现存储空间貌似多了起来。其实这些都是APFS的功劳。</p>
<h2 id="下面我们来简单聊聊APFS带来了哪些改变。"><a href="#下面我们来简单聊聊APFS带来了哪些改变。" class="headerlink" title="下面
</summary>
<category term="File System" scheme="https://qmkcamel.github.io/tags/File-System/"/>
</entry>
<entry>
<title>如何用Reveal查看任意APP界面</title>
<link href="https://qmkcamel.github.io/2017/03/30/%E5%A6%82%E4%BD%95%E7%94%A8Reveal%E6%9F%A5%E7%9C%8B%E4%BB%BB%E6%84%8FAPP%E7%95%8C%E9%9D%A2/"/>
<id>https://qmkcamel.github.io/2017/03/30/如何用Reveal查看任意APP界面/</id>
<published>2017-03-29T16:00:00.000Z</published>
<updated>2017-05-03T06:22:58.000Z</updated>
<content type="html"><![CDATA[<ul>
<li><p>一个越狱的 iOS 设备</p>
</li>
<li><p>通过 Cydia 安装 OpenSSH 和 Cydia Substrate</p>
</li>
<li><p>获取你要查看的 APP 的bundle ID,并生成固定格式的plist文件</p>
</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">plist</span> <span class="attr">version</span>=<span class="string">"1.0"</span>></span></div><div class="line"><span class="tag"><<span class="name">dict</span>></span></div><div class="line"> <span class="tag"><<span class="name">key</span>></span>Filter<span class="tag"></<span class="name">key</span>></span></div><div class="line"> <span class="tag"><<span class="name">dict</span>></span></div><div class="line"> <span class="tag"><<span class="name">key</span>></span>Bundles<span class="tag"></<span class="name">key</span>></span></div><div class="line"> <span class="tag"><<span class="name">array</span>></span></div><div class="line"> <span class="tag"><<span class="name">string</span>></span>com.tencent.weread<span class="tag"></<span class="name">string</span>></span></div><div class="line"> <span class="tag"><<span class="name">string</span>></span>com.duokan.reader<span class="tag"></<span class="name">string</span>></span></div><div class="line"> <span class="tag"></<span class="name">array</span>></span></div><div class="line"> <span class="tag"></<span class="name">dict</span>></span></div><div class="line"><span class="tag"></<span class="name">dict</span>></span></div><div class="line"><span class="tag"></<span class="name">plist</span>></span></div></pre></td></tr></table></figure>
<ul>
<li>拷贝 Reveal.framework 到手机上 默认密码是alpine 代码中的IP地址是iOS设备的地址</li>
</ul>
<figure class="highlight elixir"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">scp -r /Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/Reveal.framework </div><div class="line">root<span class="variable">@172</span>.<span class="number">16.1</span>.<span class="number">120</span><span class="symbol">:/System/Library/Frameworks</span></div></pre></td></tr></table></figure>
<p><img src="http://ohujsjvgi.bkt.clouddn.com/14931173766045.jpg" alt="上传成功图"></p>
<ul>
<li>同理 拷贝 libReveal.dylib </li>
</ul>
<figure class="highlight elixir"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">scp -r /Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/libReveal.dylib </div><div class="line">root<span class="variable">@172</span>.<span class="number">16.1</span>.<span class="number">120</span><span class="symbol">:/Library/MobileSubstrate/DynamicLibraries</span></div></pre></td></tr></table></figure>
<ul>
<li>拷贝自己生成的plist文件到 [email protected]:/Library/MobileSubstrate/DynamicLibraries</li>
</ul>
<h3 id="ref"><a href="#ref" class="headerlink" title="ref"></a>ref</h3><p>1.<a href="http://www.jianshu.com/p/4dc8f94ca27c" target="_blank" rel="external">Reveal看界面</a><br>2.<a href="http://www.jianshu.com/p/060745d5ecc2" target="_blank" rel="external">Reveal看界面</a><br>3.<a href="http://blog.csdn.net/zhouzhoujianquan/article/details/52964559" target="_blank" rel="external">简洁Reveal看界面</a><br>4.<a href="https://zhuanlan.zhihu.com/p/19646002" target="_blank" rel="external">iOS安全开发防护摘要</a></p>
]]></content>
<summary type="html">
<ul>
<li><p>一个越狱的 iOS 设备</p>
</li>
<li><p>通过 Cydia 安装 OpenSSH 和 Cydia Substrate</p>
</li>
<li><p>获取你要查看的 APP 的bundle ID,并生成固定格式的plist文件</p>
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
<category term="越狱" scheme="https://qmkcamel.github.io/tags/%E8%B6%8A%E7%8B%B1/"/>
</entry>
<entry>
<title>Infer 使用笔记</title>
<link href="https://qmkcamel.github.io/2017/03/07/Infer%E4%BD%BF%E7%94%A8%E7%AC%94%E8%AE%B0/"/>
<id>https://qmkcamel.github.io/2017/03/07/Infer使用笔记/</id>
<published>2017-03-06T16:00:00.000Z</published>
<updated>2017-03-07T09:58:49.000Z</updated>
<content type="html"><![CDATA[<p>Facebook 的 Infer 是一个由 OCaml 编写的静态分析工具。<br>这种查错工具并不是简单纠正一下语法,而是一种代码静态分析工具。它可以在不运行代码(一般开发者的调试方式都是编译、运行,查看结果,然后人工分析代码)的方式下,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描,来验证代码是否存在问题或满足技术指标。</p>
<p>下文示例主要以一个iOS开发者的角度来阐述。</p>
<h3 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h3><p>Infer根植于两大基本理论之上,其一是<a href="https://en.wikipedia.org/wiki/Hoare_logic" target="_blank" rel="external">霍尔逻辑</a>,一种用于推理计算机程序正确性的形式系统,另一个是<a href="https://en.wikipedia.org/wiki/Abstract_interpretation" target="_blank" rel="external">抽象解释</a>,该理论用于测度程序语义的逼近结果,此外还涉及其它一些研究成果,例如Separation Logic和Bi-abduction。 </p>
<h3 id="Infer工作流"><a href="#Infer工作流" class="headerlink" title="Infer工作流"></a>Infer工作流</h3><ol>
<li><p>捕获阶段<br> 把代码转译为Infer自己的中间语言来做静态分析。转译依赖于编译。转译之后的中间文件存储在infer-out 文件夹中。</p>
</li>
<li><p>分析阶段<br> 中间文件被分析,如果出现了错误,会停住,不会继续执行,所以会比较坑。所以一般的流程是这样的</p>
<ul>
<li>Infer 对你的项目代码做静态分析</li>
<li>分析遇到 error 并报给你</li>
<li>修复该问题代码</li>
<li><p>且再次运行 Infer 对你的项目代码做静态分析(回跳第一步)</p>
<p>当 Infer 分析代码后,会将发现的问题记录并保存到文件 infer-out/bugs.txt 中。</p>
</li>
</ul>
</li>
</ol>
<p>在 infer-out 文件夹下,Infer 还将生成一个文件 report.csv,其中包含所有 Infer 在静态分析过程中发现的错误,警告和相关信息,当然他们都是 csv 格式的。</p>
<h3 id="基本用法"><a href="#基本用法" class="headerlink" title="基本用法"></a>基本用法</h3><ul>
<li>安装</li>
</ul>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">brew install infer</div></pre></td></tr></table></figure>
<ul>
<li>使用</li>
</ul>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">infer -- xcodebuild -target HelloWorldApp -configuration Debug </div><div class="line">-sdk iphonesimulator</div><div class="line"></div><div class="line">// 值得注意的是Infer区分增量和非增量分析,默认是增量分析,非增量分析如下</div><div class="line">infer --reactive -- xcodebuild -target HelloWorldApp -configuration Debug </div><div class="line">-sdk iphonesimulator</div><div class="line">// 或者clean之后再做分析</div><div class="line">xcodebuild -target HelloWorldApp -configuration Debug -sdk iphonesimulator clean</div><div class="line"></div><div class="line">// pod项目 其中 N.xcworkspace 是你的 workspace 名称, NSchema 是你需要检查的 Schema 名称.git </div><div class="line">infer -- xcodebuild -workspace N.xcworkspace -scheme NSchema</div></pre></td></tr></table></figure>
<ul>
<li>可以指定分析哪些文件,即whitelist和blacklist</li>
</ul>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">//项目根目录下创建一个‘.inferconfig’的文件,格式如下</div><div class="line">{</div><div class="line"> <span class="string">"infer-whitelist-path-regex"</span>:[</div><div class="line"> ],</div><div class="line"> <span class="string">"infer-blacklist-path-regex"</span>:[</div><div class="line"> <span class="string">"Pods/AFNetworking"</span>,</div><div class="line"> <span class="string">"Pods/SDWebImage"</span></div><div class="line"> ]</div><div class="line">}</div></pre></td></tr></table></figure>
<h3 id="Jenkins集成"><a href="#Jenkins集成" class="headerlink" title="Jenkins集成"></a>Jenkins集成</h3><p>自动化是一个很好的东西,可以机器干的开发工程师一般不会自己去干,所以很容易就会想到把这个检查的流程自动化起来。由于我们的项目目前使用的是Jenkins,所以就想把他集成到可持续构建之中。在集成的过程中也遇到了一些问题。</p>
<h4 id="问题1-Infer-command-not-found"><a href="#问题1-Infer-command-not-found" class="headerlink" title="问题1 Infer command not found"></a>问题1 Infer command not found</h4><p>运行环境是一个Mac OS的slave节点。<br>当我在terminal中运行Infer的命令时候是正常的。但是当我Jenkins的构建过程中通过shell执行,却遇到了“Infer command not found”的错误。感觉像是PATH的问题,所以在命令行中加入了<code>export PATH=******</code>顺利解决。至于我们的PATH值怎么得来呢,直接粗暴一点的解决,在terminal中直接<code>echo $PATH</code>就能得到了。</p>
<h4 id="问题2-“ERROR-“etree”-Python-package-not-found-ERROR-You-need-to-install-it-to-use-Infer-with-–pmd-xml”"><a href="#问题2-“ERROR-“etree”-Python-package-not-found-ERROR-You-need-to-install-it-to-use-Infer-with-–pmd-xml”" class="headerlink" title="问题2 “ERROR: “etree” Python package not found.ERROR: You need to install it to use Infer with –pmd-xml”"></a>问题2 “ERROR: “etree” Python package not found.ERROR: You need to install it to use Infer with –pmd-xml”</h4><p>由于项目中已经集成了OCLint,结果用PMD plug-in来展示。所以想着直接用这个会稍微好一点。而正好Infer也是支持的(虽然默认是三种格式的报告,csv,json,plain txt)。但是在用的时候遇到了“‘etree’ Python package not found”的问题。由于对Python不是很熟悉,想当然的以为是Python版本过低造成的。在直接用<code>brew install python</code>安装了2.7.13版本(Mac OS自带的是2.7.10)之后还是依然报错。那么现在问题就比较明朗了,直接用<code>pip instlal lxml</code>安装lxml这个包之后顺利解决。</p>
<p>最后我们实际使用的shell如下 </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">export</span> PATH=/Users/builder/bin:/usr/<span class="built_in">local</span>/bin:/usr/<span class="built_in">local</span>/bin:/usr/bin:/bin:/usr/sbin:/sbin</div><div class="line">PROJECT_PATH=<span class="variable">${WORKSPACE}</span>;</div><div class="line"><span class="built_in">cd</span> <span class="variable">$PROJECT_PATH</span>;</div><div class="line">infer --reactive --pmd-xml -- xcodebuild -workspace HelloWorld.xcworkspace -scheme HelloWorld</div></pre></td></tr></table></figure>
<h3 id="Infer-bug-类型"><a href="#Infer-bug-类型" class="headerlink" title="Infer bug 类型"></a>Infer bug 类型</h3><h4 id="C-and-Objective-C"><a href="#C-and-Objective-C" class="headerlink" title="C and Objective-C"></a>C and Objective-C</h4><ul>
<li>Null dereference //空指针</li>
<li>Memory leak //内存泄露</li>
<li>Premature nil termination argument //过早nil导致的问题</li>
<li>Resource leak //资源代表文件,socket,链接等等,使用后需要关闭</li>
</ul>
<h4 id="only-in-Objective-C"><a href="#only-in-Objective-C" class="headerlink" title="only in Objective-C"></a>only in Objective-C</h4><ul>
<li>Ivar not null checked //和 null dereference很像</li>
<li>Paramter not null checked //和 null derefence很像</li>
<li>Retail cycle</li>
</ul>
<h3 id="linters-bug-types"><a href="#linters-bug-types" class="headerlink" title="linters bug types"></a>linters bug types</h3><blockquote>
<p>Linters check syntax of program, it could be about a property , or about code inside one method , or that a class or method have certain properties .<br> The Linter are run default when you run Infer.<br> Soon will have DSL(Domain Specific Lauguage) to extend.</p>
</blockquote>
<ul>
<li>assign pointer warning </li>
<li>bad pointer comparsion</li>
<li>C++ reference captured in Objective-C block</li>
<li>direction access atomic property </li>
<li>global variable initialized with function or method call </li>
<li>registered observer being deallocated</li>
<li>strong delegate warning </li>
<li><p>unavailable api in support SDK </p>
<ul>
<li><p>need pass to Infer the option –iphoneos-target-sdk-version version. </p>
<figure class="highlight brainfuck"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="comment">infer</span> <span class="literal">-</span><span class="literal">-</span><span class="comment">iphoneos</span><span class="literal">-</span><span class="comment">target</span><span class="literal">-</span><span class="comment">sdk</span><span class="literal">-</span><span class="comment">version</span> <span class="comment">8</span><span class="string">.</span><span class="comment">0</span> <span class="literal">-</span><span class="literal">-</span><span class="comment">reactive</span> <span class="literal">-</span><span class="literal">-</span> <span class="comment">xcodebuild</span> <span class="literal">-</span><span class="comment">target</span> <span class="comment">HelloWorldApp</span> <span class="literal">-</span><span class="comment">sdk</span> <span class="comment">iphonesimulator</span></div></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ul>
<h3 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h3><ul>
<li>支持多语言(Java,Objective-C,C)和多平台(Android,iOS,Make)</li>
<li>作者称不久就会可扩展</li>
</ul>
<h3 id="局限性"><a href="#局限性" class="headerlink" title="局限性"></a>局限性</h3><ul>
<li>目前不支持Swift </li>
<li>nonsupport bug types (前三只有部分,没有覆盖全)<ul>
<li>array bounds errors</li>
<li>cast exception (转换异常)</li>
<li>leaking of tainted data (脏数据泄露) </li>
<li>concurrency race conditions (竞态条件)</li>
</ul>
</li>
<li>语言特性的欠缺<ul>
<li>Concurrency, including Java’s Concurrency Utilities and iOS’s Grand Central Dispatch</li>
<li>Dynamic dispatch</li>
<li>Reflection</li>
<li>Android lifecycles</li>
<li>Arithmetic</li>
<li>and more </li>
</ul>
</li>
</ul>
<h3 id="FAQ"><a href="#FAQ" class="headerlink" title="FAQ"></a>FAQ</h3><ul>
<li>compare to Clang Static Analyzer<ul>
<li>Infer does some things different, in particular reasoning that spans across multiple files</li>
<li>CSA checks for more kinds of issues and is also more mature than Infer when it comes to iOS </li>
</ul>
</li>
</ul>
<h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p><a href="https://en.wikipedia.org/wiki/Hoare_logic" target="_blank" rel="external">Hoare logic</a><br><a href="https://en.wikipedia.org/wiki/Abstract_interpretation" target="_blank" rel="external">Abstract interpretation</a><br><a href="http://fbinfer.com/docs/separation-logic-and-bi-abduction.html" target="_blank" rel="external">Separation logic and bi-abduction</a><br><a href="https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html" target="_blank" rel="external">Xcodebuild</a><br><a href="https://github.com/facebook/infer/issues/312" target="_blank" rel="external">blacklist</a></p>
]]></content>
<summary type="html">
<p>Facebook 的 Infer 是一个由 OCaml 编写的静态分析工具。<br>这种查错工具并不是简单纠正一下语法,而是一种代码静态分析工具。它可以在不运行代码(一般开发者的调试方式都是编译、运行,查看结果,然后人工分析代码)的方式下,通过词法分析、语法分析、控制流、数
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
<category term="工具" scheme="https://qmkcamel.github.io/tags/%E5%B7%A5%E5%85%B7/"/>
</entry>
<entry>
<title>UIView 和 CALayer</title>
<link href="https://qmkcamel.github.io/2016/11/15/UIView%E5%92%8CCALayer/"/>
<id>https://qmkcamel.github.io/2016/11/15/UIView和CALayer/</id>
<published>2016-11-14T16:00:00.000Z</published>
<updated>2017-04-20T08:28:53.000Z</updated>
<content type="html"><![CDATA[<p><code>UIView</code>继承自<code>UIResponder</code>,可以响应事件,属于UIKit框架,属于比较高层次的抽象,主要是对显示的内容的管理,是对<code>CALayer</code>的一个封装。</p>
<p><code>CALayer</code>继承自<code>NSObject</code>,属于QuarzCore框架,不能响应事件,主要是处理内容的绘制和动画</p>
<p>这样设计可能的原因有如下:</p>
<ul>
<li>和用户的一些触摸事件是可以放到比较高的抽象层来处理的</li>
<li>UIView 和 NSView 的实现是不一样的,但是 Core Animation 是基本上可以重用的,可以重用 Core Animation 部分。</li>
</ul>
<h2 id="Tips"><a href="#Tips" class="headerlink" title="Tips"></a>Tips</h2><ul>
<li>view is the layer’s delegate </li>
<li><p>当一个view第一次出现或者它的一部分需要重绘的时候,会调用view的drawRect方法。有四种方式会引起view的update </p>
<ul>
<li>移动或者移除部分遮挡你view的view</li>
<li>把一个hidden的view设置为hidden = NO</li>
<li>把一个view滑出屏幕之外,然后再滑进来</li>
<li>在你的view上显示的调用 setNeedsDisplay 或者 setNeedsDisplayInRect</li>
</ul>
</li>
<li><p>UIKit 和 CoreAnimation 使用左上角做原点,CoreGrapics使用左下角做原点(Core Graphics源于Mac OS X系统,在Mac OS X中,坐标原点在左下方并且正y坐标是朝上的,而在iOS中,原点坐标是在左上方并且正y坐标是朝下的。在大多数情况下,这不会出现任何问题,因为图形上下文的坐标系统是会自动调节补偿的。但是创建和绘制一个CGImage对象时就会暴露出倒置问题。)</p>
</li>
<li><p>每一个view背后都有一个layer,对view的修改实质上是对layer的修改</p>
</li>
<li>CALayer 的同一个属性值,会分别保存在模型层 modelLayer ,和展现层 presentationLayer 中。当我们修改属性值时,是修改的模型层的数值,动画时系统根据模型层的变化,生成的过渡值,是保存在展现层中的。(layer还有一个渲染层,做动画的时候一般不会care他)</li>
</ul>
<h2 id="显式动画和隐式动画"><a href="#显式动画和隐式动画" class="headerlink" title="显式动画和隐式动画"></a>显式动画和隐式动画</h2><ul>
<li>显式的执行一个动画</li>
<li>系统添加上的动画。当我们改变 CALayer 的一个可动画的属性值时,就会触发系统的隐式动画。</li>
</ul>
]]></content>
<summary type="html">
<p><code>UIView</code>继承自<code>UIResponder</code>,可以响应事件,属于UIKit框架,属于比较高层次的抽象,主要是对显示的内容的管理,是对<code>CALayer</code>的一个封装。</p>
<p><code>CALayer
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
</entry>
<entry>
<title>APP启动速度</title>
<link href="https://qmkcamel.github.io/2016/10/07/APP%E5%90%AF%E5%8A%A8%E9%80%9F%E5%BA%A6/"/>
<id>https://qmkcamel.github.io/2016/10/07/APP启动速度/</id>
<published>2016-10-06T16:00:00.000Z</published>
<updated>2017-04-07T03:09:07.000Z</updated>
<content type="html"><![CDATA[<blockquote>
<ol>
<li><a href="https://developer.apple.com/videos/play/wwdc2016/406/" target="_blank" rel="external">2016 WWDC session 406</a></li>
<li><a href="https://gold.xitu.io/entry/57c3d611a633bd005d7b3b62" target="_blank" rel="external">Ref</a></li>
<li><a href="http://blog.sunnyxx.com/2014/08/30/objc-pre-main/" target="_blank" rel="external">main函数之前发生了什么</a></li>
<li>这里说的启动速度是在main函数之前的启动速度,和didfinishLaunch这里面的启动时间不一样。</li>
</ol>
</blockquote>
<p>Apple建议一个完整的App启动时间应该保证在<strong>400ms</strong>之内,若超过<strong>20s</strong>还没有完全启动,进程会被系统杀死。</p>
<h2 id="知识回顾"><a href="#知识回顾" class="headerlink" title="知识回顾"></a>知识回顾</h2><h3 id="动态链接库和静态链接库有什么区别"><a href="#动态链接库和静态链接库有什么区别" class="headerlink" title="动态链接库和静态链接库有什么区别"></a>动态链接库和静态链接库有什么区别</h3><p>动态库特点:</p>
<ol>
<li>共享:多个应用程序可以使用同一个动态库,启动多个应用程序的时候只需要把动态库加载内存中一份就可以</li>
<li>开发模块好:要求开发者对功能划分比较好</li>
<li>需要有一个链接的过程,每个程序只是有一个符号表,实际执行的函数没有直接打包进程序里面</li>
</ol>
<p>静态库的特点:</p>
<ol>
<li>代码装载速度快,执行快,需要打包进程序里,可能会比较大</li>
<li>多个程序使用的话,会被装载多次,浪费内存</li>
</ol>
<blockquote>
<ul>
<li>代码共用:很多程序都动态链接了这些 lib,但它们在内存和磁盘中中只有一份</li>
<li>易于维护:由于被依赖的 lib 是程序执行时才 link 的,所以这些 lib 很容易做更新,比如libSystem.dylib 是 libSystem.B.dylib 的替身,哪天想升级直接换成 libSystem.C.dylib 然后再替换替身就行了</li>
<li>减少可执行文件体积:相比静态链接,动态链接在编译时不需要打进去,所以可执行文件的体积要小很多</li>
</ul>
</blockquote>
<h2 id="mian函数之前都干了什么"><a href="#mian函数之前都干了什么" class="headerlink" title="mian函数之前都干了什么"></a>mian函数之前都干了什么</h2><ul>
<li>link framework <ul>
<li>CoreGrapics</li>
<li>UIKit</li>
<li>Foundation</li>
<li>CoreFoundation</li>
<li>libObjc (即objc和runtime)</li>
<li>libSystem (列几个熟知的:libdispatch(GCD), libsystem_c(c语言),libsystem_blocks(block), libcommonCrypto(加密))</li>
</ul>
</li>
</ul>
<h2 id="如何获得应用的加载时间"><a href="#如何获得应用的加载时间" class="headerlink" title="如何获得应用的加载时间"></a>如何获得应用的加载时间</h2><p>在工程的scheme中添加环境变量<strong>DYLD_PRINT_STATISTICS</strong>,设置value为1。App启动的时候就会有日志输出。</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">Total pre-main <span class="selector-tag">time</span>: <span class="number">74.37</span> milliseconds (<span class="number">100.0%</span>)</div><div class="line"> dylib loading <span class="selector-tag">time</span>: <span class="number">41.05</span> milliseconds (<span class="number">55.2%</span>)</div><div class="line"> rebase/binding <span class="selector-tag">time</span>: <span class="number">8.10</span> milliseconds (<span class="number">10.9%</span>)</div><div class="line"> ObjC setup <span class="selector-tag">time</span>: <span class="number">9.87</span> milliseconds (<span class="number">13.2%</span>)</div><div class="line"> initializer <span class="selector-tag">time</span>: <span class="number">15.23</span> milliseconds (<span class="number">20.4%</span>)</div><div class="line"> slowest intializers :</div><div class="line"> libSystem<span class="selector-class">.B</span><span class="selector-class">.dylib</span> : <span class="number">6.58</span> milliseconds (<span class="number">8.8%</span>)</div><div class="line"> libBacktraceRecording<span class="selector-class">.dylib</span> : <span class="number">6.27</span> milliseconds (<span class="number">8.4%</span>)</div></pre></td></tr></table></figure>
<h2 id="启动优化"><a href="#启动优化" class="headerlink" title="启动优化"></a>启动优化</h2><h4 id="对动态库加载的时间优化"><a href="#对动态库加载的时间优化" class="headerlink" title="对动态库加载的时间优化"></a>对动态库加载的时间优化</h4><p>每个App都会进行动态库的加载,系统级别的占了大多数,针对系统界别的动态库是经过系统高度优化的。开发者需要关心自己集成到App中的动态库,这也是最消耗加载时间的地方。Apple建议减少在App里开发者的动态库的集成或者尽可能把多个动态库合并成一个来导入,保证在6个之内。</p>
<h4 id="减少App的Objective-C分类,分类和唯一的Selector的个数"><a href="#减少App的Objective-C分类,分类和唯一的Selector的个数" class="headerlink" title="减少App的Objective-C分类,分类和唯一的Selector的个数"></a>减少App的Objective-C分类,分类和唯一的Selector的个数</h4><p>为了加快程序的整个动态链接, 在进行动态库的重定位和绑定(Rebase/binding)过程中减少指针修正的使用,加快程序机器码的生成.</p>
<h4 id="减少Objc运行初始化的时间"><a href="#减少Objc运行初始化的时间" class="headerlink" title="减少Objc运行初始化的时间"></a>减少Objc运行初始化的时间</h4><p>主要是类的注册,分类的注册,唯一选择器的存在,以及涉及子父类内存布局的Non Fragile ivars偏移的更新,都会影响Objective-C运行时初始化的时间消耗.</p>
<h4 id="使用initialize方法替换原先在-laod-方法中"><a href="#使用initialize方法替换原先在-laod-方法中" class="headerlink" title="使用initialize方法替换原先在 +laod 方法中"></a>使用initialize方法替换原先在 +laod 方法中</h4><p>用+initialize方法替换调用原先在OC的+load方法中执行初始代码工作,从而加快所有类文件的加载速度.</p>
<h2 id="最后演讲者对加载启动优化的整体概括了Session所要传达的内容"><a href="#最后演讲者对加载启动优化的整体概括了Session所要传达的内容" class="headerlink" title="最后演讲者对加载启动优化的整体概括了Session所要传达的内容:"></a>最后演讲者对加载启动优化的整体概括了Session所要传达的内容:</h2><ul>
<li>使用DYLD_PRINT_STATISTICS测试启动加载时间</li>
<li>减少自定义的动态库集成</li>
<li>精简原有的Objective-C类和代码</li>
<li>移除静态的初始化操作</li>
<li>使用更多的Swift代码</li>
</ul>
]]></content>
<summary type="html">
<blockquote>
<ol>
<li><a href="https://developer.apple.com/videos/play/wwdc2016/406/" target="_blank" rel="external">2016 WWDC session 406</
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
</entry>
<entry>
<title>iOS 10 隐私政策</title>
<link href="https://qmkcamel.github.io/2016/09/30/iOS%2010%20%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96/"/>
<id>https://qmkcamel.github.io/2016/09/30/iOS 10 隐私政策/</id>
<published>2016-09-29T16:00:00.000Z</published>
<updated>2017-04-07T03:15:32.000Z</updated>
<content type="html"><![CDATA[<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><!-- 相册 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSPhotoLibraryUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问相册<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 相机 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSCameraUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问相机<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 麦克风 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSMicrophoneUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问麦克风<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 位置 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSLocationUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问位置<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 在使用期间访问位置 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSLocationWhenInUseUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能在使用期间访问位置<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 始终访问位置 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSLocationAlwaysUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能始终访问位置<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 日历 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSCalendarsUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问日历<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 提醒事项 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSRemindersUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问提醒事项<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 运动与健身 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSMotionUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问运动与健身<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 健康更新 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSHealthUpdateUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问健康更新 <span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 健康分享 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSHealthShareUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问健康分享<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 蓝牙 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSBluetoothPeripheralUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问蓝牙<span class="tag"></<span class="name">string</span>></span> </div><div class="line"><span class="comment"><!-- 媒体资料库 --></span> </div><div class="line"><span class="tag"><<span class="name">key</span>></span>NSAppleMusicUsageDescription<span class="tag"></<span class="name">key</span>></span> </div><div class="line"><span class="tag"><<span class="name">string</span>></span>App需要您的同意,才能访问媒体资料库<span class="tag"></<span class="name">string</span>></span></div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div>
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
</entry>
<entry>
<title>+load 和 +initialize 的区别是什么?</title>
<link href="https://qmkcamel.github.io/2016/09/26/load%E5%92%8Cinitialize%E7%9A%84%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88/"/>
<id>https://qmkcamel.github.io/2016/09/26/load和initialize的区别是什么/</id>
<published>2016-09-25T16:00:00.000Z</published>
<updated>2017-03-22T06:59:35.000Z</updated>
<content type="html"><![CDATA[<h2 id="void-load"><a href="#void-load" class="headerlink" title="+(void)load"></a>+(void)load</h2><ul>
<li>程序启动的时候会调用</li>
<li>load 方法会在每一个类和分类被引入时仅调用一次,调用的顺序:父类优先于子类, 子类优先于分类(父类>子类>分类)</li>
<li><p>load 方法不会被类自动继承,如果一个类本身没有实现 load 方法,不管其各级超类是否实现,系统都不会调用</p>
<blockquote>
<p>凡是想通过load在类加载之前执行某些任务的,基本都做的不太对。其真正的用途是用来调试程序,比如看某个分类是否被正常加载,可以在 load 里面判断。(Effitive Objective-C)</p>
</blockquote>
</li>
</ul>
<h2 id="void-initialize"><a href="#void-initialize" class="headerlink" title="+(void)initialize"></a>+(void)initialize</h2><ul>
<li>在第一次使用这个类的时候运行期系统会调用这个方法,是“惰性调用”</li>
<li>运行期系统在执行这个方法的时候,是处于正常状态,而且是线程安全的,也就是说只有执行 initialize的线程可以操作类或者实例,其他线程需要先阻塞,等着 initialize 先执行完</li>
<li>initialize 方法遵循继承体系,如果某个类没有实现它,而超类实现了的话,就会执行超类的方法。比如下面的例子<blockquote>
<p><code>initialize</code>方法只应该来设置内部数据,不应该在其中调用别的方法,即使是本类自己的方法,也最好别调用。(Effective Objective-C)</p>
</blockquote>
</li>
</ul>
<figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#import <span class="meta-string"><Foundation/Foundation.h></span></span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">CamBaseClass</span> : <span class="title">NSObject</span></span></div><div class="line"><span class="keyword">@end</span> </div><div class="line"></div><div class="line"><span class="class"><span class="keyword">@implementation</span></span></div><div class="line">+ (<span class="keyword">void</span>)initialize {</div><div class="line"> <span class="built_in">NSLog</span>(<span class="string">@"%@ initialize"</span>,<span class="keyword">self</span>);</div><div class="line">}</div><div class="line"><span class="keyword">@end</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">CamSubClass</span> : <span class="title">CamBaseClass</span></span></div><div class="line"><span class="keyword">@end</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">@implementation</span></span></div><div class="line"><span class="keyword">@end</span></div><div class="line">首次使用 CamSubClass 初始化的时候控制台输出如下。</div><div class="line">CamBaseClass initialize</div><div class="line">CamSubClass initialize</div></pre></td></tr></table></figure>
<p>如果想避免上面的情况,只要自己指定的类执行,最佳实践如下</p>
<figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">+ (<span class="keyword">void</span>)initialize {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">self</span> == [CamBaseClass <span class="keyword">class</span>]) {</div><div class="line"> <span class="built_in">NSLog</span> (<span class="string">@"%@ initialize"</span>, <span class="keyword">self</span>);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="为什么两个方法的实现代码要精简?"><a href="#为什么两个方法的实现代码要精简?" class="headerlink" title="为什么两个方法的实现代码要精简?"></a>为什么两个方法的实现代码要精简?</h2><p>+(void)load 和 +(void)initialize 方法的实现要尽量精简。在里面设置一些状态,使本类能够正常运作就可以了,不要执行那种耗时太久或需要加锁的任务。</p>
<p><code>load</code>的原因如下</p>
<ul>
<li>无法确定<code>load</code>的顺序,如果依赖别的类的话,会出现别的类没有load完成的情况发生</li>
<li><code>load</code>的时候整个程序都会都会阻塞,如果复杂的话,会造成没有相应</li>
</ul>
<p><code>initialize</code>的原因如下</p>
<ul>
<li>不能确定初始化是在什么线程执行,如果是在UI线程上,耗时操作会引起挂起</li>
<li>无法控制类的初始化时机</li>
<li>如果很复杂的话,会直接或间接的用到别的类。如果所依赖的类正好依赖本类的某些数据,而本类还没有初始化。就会有错误出现。举个例子</li>
</ul>
<figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">static</span> <span class="built_in">NSString</span> *CamClassAInternalString;</div><div class="line"><span class="keyword">static</span> <span class="built_in">NSString</span> *CamClassBInternalString;</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">CamClassA</span> : <span class="title">NSObject</span></span></div><div class="line"></div><div class="line"><span class="keyword">@end</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">@implementation</span> <span class="title">CamClassA</span></span></div><div class="line"></div><div class="line">+ (<span class="keyword">void</span>)initialize {</div><div class="line"> debugLog(<span class="string">@"%@ initialize"</span>,<span class="keyword">self</span>);</div><div class="line"> CamClassAInternalString = <span class="string">@"在CamClassA的Initialize中完成"</span>;</div><div class="line"> debugLog(<span class="string">@" %@ "</span>,CamClassAInternalString);</div><div class="line"> debugLog(<span class="string">@" %@ "</span>,CamClassBInternalString);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">@end</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">CamClassB</span> : <span class="title">NSObject</span></span></div><div class="line"></div><div class="line"><span class="keyword">@end</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">@implementation</span> <span class="title">CamClassB</span></span></div><div class="line"></div><div class="line">+ (<span class="keyword">void</span>)initialize {</div><div class="line"> debugLog(<span class="string">@"%@ initialize"</span>,<span class="keyword">self</span>);</div><div class="line"> CamClassBInternalString = <span class="string">@"在CamClassB的initialize中完成"</span>;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">@end</span></div><div class="line"></div><div class="line">CamClassA *classA = [[CamClassA alloc] init];</div><div class="line">CamCalssB *classB = [[CamClassB alloc] init];</div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<h2 id="void-load"><a href="#void-load" class="headerlink" title="+(void)load"></a>+(void)load</h2><ul>
<li>程序启动的时候会调用</li>
<li>load 方法会在每一个
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
</entry>
<entry>
<title>MQTT入门第一篇</title>
<link href="https://qmkcamel.github.io/2016/09/19/MQTT%E5%85%A5%E9%97%A8%E7%AC%AC%E4%B8%80%E7%AF%87/"/>
<id>https://qmkcamel.github.io/2016/09/19/MQTT入门第一篇/</id>
<published>2016-09-18T16:00:00.000Z</published>
<updated>2017-04-07T03:03:54.000Z</updated>
<content type="html"><![CDATA[<h2 id="Message-Queuing-Telemetry-Transport"><a href="#Message-Queuing-Telemetry-Transport" class="headerlink" title="Message Queuing Telemetry Transport"></a>Message Queuing Telemetry Transport</h2><p>MQTT是基于二进制消息的发布/订阅编程模式的消息协议,主要解决的是机器与机器之间数据通信,物联网通信协议。之前web的request/response模式不再合适。</p>
<p>具有如下特点:</p>
<ul>
<li>即时传输的轻量级协议</li>
<li>专门设计用于低带宽或者高昂的网络费用</li>
<li>具备三种服务品质层级</li>
</ul>
<h2 id="由于规范简单,非常适用于低功耗和网络带宽有限的场景,如:"><a href="#由于规范简单,非常适用于低功耗和网络带宽有限的场景,如:" class="headerlink" title="由于规范简单,非常适用于低功耗和网络带宽有限的场景,如:"></a>由于规范简单,非常适用于低功耗和网络带宽有限的场景,如:</h2><ul>
<li>遥感数据</li>
<li>汽车</li>
<li>智能家居</li>
<li>智慧城市</li>
<li>医疗医护</li>
</ul>
<h2 id="由于物联网的环境是很特别的,所以遵循如下设计规则:"><a href="#由于物联网的环境是很特别的,所以遵循如下设计规则:" class="headerlink" title="由于物联网的环境是很特别的,所以遵循如下设计规则:"></a>由于物联网的环境是很特别的,所以遵循如下设计规则:</h2><ul>
<li>精简,不添加可有可无的功能</li>
<li>发布/订阅(Pub/Sub)模式,方便消息在传感器之间传递</li>
<li>允许用户动态创建主题,零成本运维</li>
<li>传输量降到最低以提高传输效率</li>
<li>把低带宽,高延迟,不稳定的网络因素考虑在内</li>
<li>支持连续的会话控制</li>
<li>理解客户端计算能力可能很低</li>
<li>提供服务质量管理</li>
<li>假设数据不可知,不强求数据的类型和格式,保持灵活性</li>
</ul>
<h2 id="发布-订阅模式"><a href="#发布-订阅模式" class="headerlink" title="发布/订阅模式"></a>发布/订阅模式</h2><ul>
<li>发布者和订阅者不需要了解彼此,只需要一个消息代理就好</li>
<li>发布者和订阅者不需要交互,发布者不会因为等订阅者确认而导致锁定</li>
<li>发布者和订阅者不需要同时在线,可以自由选择时间来消费消息</li>
</ul>
<h2 id="主题"><a href="#主题" class="headerlink" title="主题"></a>主题</h2><ul>
<li>MQTT通过主题对消息进行分类,本质上是UTF-8的字符串</li>
<li>不需要创建,直接使用,有一定的规则</li>
<li>可以用通配符订阅主题,但是不允许通配符广播</li>
</ul>
<h2 id="服务质量"><a href="#服务质量" class="headerlink" title="服务质量"></a>服务质量</h2><ol>
<li>尽力而为。消息发送者会想办法发消息,但出现以外不会重试</li>
<li>至少一次。消息接收着没有反馈收到,后者反馈丢失,消息发送者会再次发送消息,一定程度上会造成消息重复。</li>
<li><p>恰好一次。保证这种语义肯定会减少并发或者增加延时。丢失消息或者重复消息不可接受时才是最合适的。</p>
<blockquote>
<p>2是最理想的,但是肯定会对并发和延迟带来影响。1在处理日志的情况下完全可以。0是鸡肋,和UDP有点像。</p>
</blockquote>
</li>
</ol>
<h2 id="消息类型"><a href="#消息类型" class="headerlink" title="消息类型"></a>消息类型</h2><p>MQTT拥有14种不同的消息类型:</p>
<ul>
<li>CONNECT:客户端连接到MQTT代理</li>
<li>CONNACK:连接确认</li>
<li>PUBLISH:新发布消息</li>
<li>PUBACK:新发布消息确认,是QoS 1给PUBLISH消息的回复</li>
<li>PUBREC:QoS 2消息流的第一部分,表示消息发布已记录</li>
<li>PUBREL:QoS 2消息流的第二部分,表示消息发布已释放</li>
<li>PUBCOMP:QoS 2消息流的第三部分,表示消息发布完成</li>
<li>SUBSCRIBE:客户端订阅某个主题</li>
<li>SUBACK:对于SUBSCRIBE消息的确认</li>
<li>UNSUBSCRIBE:客户端终止订阅的消息</li>
<li>UNSUBACK:对于UNSUBSCRIBE消息的确认</li>
<li>PINGREQ:心跳</li>
<li>PINGRESP:确认心跳</li>
<li>DISCONNECT:客户端终止连接前优雅地通知MQTT代理</li>
</ul>
<h3 id="Ref"><a href="#Ref" class="headerlink" title="Ref"></a>Ref</h3><ol>
<li><a href="http://www.infoq.com/cn/news/2014/12/mqtt-ibm-iot" target="_blank" rel="external">物联网传输协议MQTT</a></li>
<li><a href="https://github.com/mcxiaoke/mqtt" target="_blank" rel="external">MQTT协议中文版</a></li>
<li><a href="http://dataguild.org/?p=6817" target="_blank" rel="external">MQTT入门篇</a></li>
</ol>
]]></content>
<summary type="html">
<h2 id="Message-Queuing-Telemetry-Transport"><a href="#Message-Queuing-Telemetry-Transport" class="headerlink" title="Message Queuing Teleme
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
</entry>
<entry>
<title>iOS中的深复制和浅复制解读</title>
<link href="https://qmkcamel.github.io/2016/09/10/iOS%E4%B8%AD%E7%9A%84%E6%B7%B1%E5%A4%8D%E5%88%B6%E5%92%8C%E6%B5%85%E5%A4%8D%E5%88%B6%E8%A7%A3%E8%AF%BB/"/>
<id>https://qmkcamel.github.io/2016/09/10/iOS中的深复制和浅复制解读/</id>
<published>2016-09-09T16:00:00.000Z</published>
<updated>2017-03-23T06:01:58.000Z</updated>
<content type="html"><![CDATA[<h2 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h2><ul>
<li><strong>浅复制</strong> : 并不拷贝对象,只是拷贝指向对象的指针。简单来说就是<code>指针拷贝</code>。</li>
<li><strong>深复制</strong> : 直接拷贝整个对象内存到另一块内存中。简单来说就是<code>内容拷贝</code>。</li>
</ul>
<h2 id="非集合对象"><a href="#非集合对象" class="headerlink" title="非集合对象"></a>非集合对象</h2><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)nonCollectionObjectCopy {</div><div class="line"> <span class="built_in">NSString</span> *string = <span class="string">@"string"</span>;</div><div class="line"> <span class="built_in">NSMutableString</span> *mutableString = [[<span class="built_in">NSMutableString</span> alloc] initWithString:<span class="string">@"mutableString"</span>];</div><div class="line"> </div><div class="line"> <span class="built_in">NSString</span> *stringCopy = [string <span class="keyword">copy</span>];</div><div class="line"> <span class="built_in">NSMutableString</span> *stringMutableCopy = [string mutableCopy];</div><div class="line"> </div><div class="line"> <span class="built_in">NSString</span> *mutableStringCopy = [mutableString <span class="keyword">copy</span>];</div><div class="line"> <span class="built_in">NSMutableString</span> *mutableStringMutableCopy = [mutableString mutableCopy];</div><div class="line">}</div></pre></td></tr></table></figure>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="regexp">//</span> (lldb) p string</div><div class="line"><span class="regexp">//</span> (__NSCFConstantString *) <span class="variable">$1</span> = <span class="number">0</span>x000000010aeeade0 @<span class="string">"string"</span></div><div class="line"><span class="regexp">//</span> (lldb) p mutableString</div><div class="line"><span class="regexp">//</span> (__NSCFString *) <span class="variable">$2</span> = <span class="number">0</span>x0000608000266380 @<span class="string">"mutableString"</span></div><div class="line"><span class="regexp">//</span> (lldb) p stringCopy</div><div class="line"><span class="regexp">//</span> (__NSCFConstantString *) <span class="variable">$3</span> = <span class="number">0</span>x000000010aeeade0 @<span class="string">"string"</span></div><div class="line"><span class="regexp">//</span> (lldb) p stringMutableCopy</div><div class="line"><span class="regexp">//</span> (__NSCFString *) <span class="variable">$4</span> = <span class="number">0</span>x00006080002673c0 @<span class="string">"string"</span></div><div class="line"><span class="regexp">//</span> (lldb) p mutableStringCopy</div><div class="line"><span class="regexp">//</span> (__NSCFString *) <span class="variable">$5</span> = <span class="number">0</span>x000060800023c8a0 @<span class="string">"mutableString"</span></div><div class="line"><span class="regexp">//</span> (lldb) p mutableStringMutableCopy</div><div class="line"><span class="regexp">//</span> (__NSCFString *) <span class="variable">$6</span> = <span class="number">0</span>x0000608000266300 @<span class="string">"mutableString"</span></div></pre></td></tr></table></figure>
<p>结论如下:</p>
<ul>
<li><code>[immutableObject copy]</code> // 浅复制</li>
<li><code>[immutableObject mutableCopy]</code> //深复制</li>
<li><code>[mutableObject copy]</code> //深复制</li>
<li><code>[mutableObject mutableCopy]</code> //深复制</li>
</ul>
<p>PS :<br><code>__NSCFConstantString</code>和 <code>__NSCFString</code>都是掩藏在NSString下的类。如果我们直接用语法糖来生成NSString的话,编译器会做一些优化,让静态字符都保存在一个段内。这是大部分编译器都会做的事情。</p>
<h2 id="集合对象"><a href="#集合对象" class="headerlink" title="集合对象"></a>集合对象</h2><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)collectionObjectCopy {</div><div class="line"> <span class="built_in">NSArray</span> *array = @[<span class="string">@"A"</span>,<span class="string">@"B"</span>];</div><div class="line"> <span class="built_in">NSMutableArray</span> *mutableArray = [[<span class="built_in">NSMutableArray</span> alloc] initWithArray:@[<span class="string">@"A"</span>,<span class="string">@"B"</span>]];</div><div class="line"> </div><div class="line"> <span class="built_in">NSArray</span> *arrayCopy = [array <span class="keyword">copy</span>];</div><div class="line"> <span class="built_in">NSArray</span> *arrayMutableCopy = [array mutableCopy];</div><div class="line"> </div><div class="line"> <span class="built_in">NSArray</span> *mutableArrayCopy = [mutableArray <span class="keyword">copy</span>];</div><div class="line"> <span class="built_in">NSArray</span> *mutableArrayMutableCopy = [mutableArray mutableCopy]; </div><div class="line">}</div></pre></td></tr></table></figure>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="regexp">//</span> (lldb) p array</div><div class="line"><span class="regexp">//</span> (__NSArrayI *) <span class="variable">$7</span> = <span class="number">0</span>x000060800023c340 @<span class="string">"2 elements"</span></div><div class="line"><span class="regexp">//</span> (lldb) p mutableArray</div><div class="line"><span class="regexp">//</span> (__NSArrayM *) <span class="variable">$8</span> = <span class="number">0</span>x000060800005d460 @<span class="string">"2 elements"</span></div><div class="line"><span class="regexp">//</span> (lldb) p arrayCopy</div><div class="line"><span class="regexp">//</span> (__NSArrayI *) <span class="variable">$9</span> = <span class="number">0</span>x000060800023c340 @<span class="string">"2 elements"</span></div><div class="line"><span class="regexp">//</span> (lldb) p arrayMutableCopy</div><div class="line"><span class="regexp">//</span> (__NSArrayM *) <span class="variable">$10</span> = <span class="number">0</span>x000060800005fce0 @<span class="string">"2 elements"</span></div><div class="line"><span class="regexp">//</span> (lldb) p mutableArrayCopy</div><div class="line"><span class="regexp">//</span> (__NSArrayI *) <span class="variable">$11</span> = <span class="number">0</span>x000060800023c120 @<span class="string">"2 elements"</span></div><div class="line"><span class="regexp">//</span> (lldb) p mutableArrayMutableCopy</div><div class="line"><span class="regexp">//</span> (__NSArrayM *) <span class="variable">$12</span> = <span class="number">0</span>x000060800005da30 @<span class="string">"2 elements"</span></div><div class="line"></div><div class="line"><span class="regexp">//</span> 集合中的内容还是指针拷贝</div><div class="line">(lldb) p array[<span class="number">0</span>]</div><div class="line">(__NSCFConstantString *) <span class="variable">$17</span> = <span class="number">0</span>x000000010aeeafa0 @<span class="string">"A"</span></div><div class="line">(lldb) p array[<span class="number">1</span>]</div><div class="line">(__NSCFConstantString *) <span class="variable">$18</span> = <span class="number">0</span>x000000010aeeafc0 @<span class="string">"B"</span></div><div class="line">(lldb) p arrayMutableCopy[<span class="number">0</span>]</div><div class="line">(__NSCFConstantString *) <span class="variable">$19</span> = <span class="number">0</span>x000000010aeeafa0 @<span class="string">"A"</span></div><div class="line">(lldb) p arrayMutableCopy[<span class="number">1</span>]</div><div class="line">(__NSCFConstantString *) <span class="variable">$20</span> = <span class="number">0</span>x000000010aeeafc0 @<span class="string">"B"</span></div><div class="line">(lldb)</div></pre></td></tr></table></figure>
<p>结论如下:</p>
<ul>
<li><code>[immutableObject copy]</code> // 浅复制</li>
<li><code>[immutableObject mutableCopy]</code> //单层深复制</li>
<li><code>[mutableObject copy]</code> //单层深复制</li>
<li><code>[mutableObject mutableCopy]</code> //单层深复制</li>
</ul>
<h2 id="集合对象的完全深复制"><a href="#集合对象的完全深复制" class="headerlink" title="集合对象的完全深复制"></a>集合对象的完全深复制</h2><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">- (<span class="keyword">void</span>)collectionObjectCompletelyCopy {</div><div class="line"> <span class="built_in">NSArray</span> *array = @[<span class="string">@"A"</span>,<span class="string">@"B"</span>];</div><div class="line"> <span class="built_in">NSMutableArray</span> *arrayCompletelyCopy = [[<span class="built_in">NSMutableArray</span> alloc] initWithArray:array copyItems:<span class="literal">YES</span>];</div><div class="line"> </div><div class="line"> <span class="built_in">NSDictionary</span> *dic = @{<span class="string">@"key"</span>:<span class="string">@"value"</span>};</div><div class="line"> <span class="built_in">NSMutableDictionary</span> *dicCompeletelyMutableCopy = [[<span class="built_in">NSMutableDictionary</span> alloc] initWithDictionary:dic copyItems:<span class="literal">YES</span>];</div><div class="line">}</div></pre></td></tr></table></figure>
<p>这样的话,collection对象的内容也是深复制</p>
<h2 id="如何实现使自定义的类支持拷贝"><a href="#如何实现使自定义的类支持拷贝" class="headerlink" title="如何实现使自定义的类支持拷贝"></a>如何实现使自定义的类支持拷贝</h2><p>声明该类遵从NSCopying(NSMutableCopying)协议,并实现其中的方法即可。</p>
<figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//以前开发程序的时候会把内存分为不同的“区”(zone),对象会创建在某个区中。</span></div><div class="line"><span class="comment">//现在每个程序只有一个默认的区(default zone)。</span></div><div class="line">- (<span class="keyword">id</span>)copyWithZone:(<span class="keyword">nullable</span> <span class="built_in">NSZone</span> *)zone;</div><div class="line">- (<span class="keyword">id</span>)mutableCopyWithZone:(<span class="keyword">nullable</span> <span class="built_in">NSZone</span> *)zone;</div></pre></td></tr></table></figure>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ol>
<li><a href="https://github.com/ChenYilong/iOSInterviewQuestions/blob/master/01%E3%80%8A%E6%8B%9B%E8%81%98%E4%B8%80%E4%B8%AA%E9%9D%A0%E8%B0%B1%E7%9A%84iOS%E3%80%8B%E9%9D%A2%E8%AF%95%E9%A2%98%E5%8F%82%E8%80%83%E7%AD%94%E6%A1%88/%E3%80%8A%E6%8B%9B%E8%81%98%E4%B8%80%E4%B8%AA%E9%9D%A0%E8%B0%B1%E7%9A%84iOS%E3%80%8B%E9%9D%A2%E8%AF%95%E9%A2%98%E5%8F%82%E8%80%83%E7%AD%94%E6%A1%88%EF%BC%88%E4%B8%8A%EF%BC%89.md#13-用property声明的nsstring或nsarraynsdictionary经常使用copy关键字为什么如果改用strong关键字可能造成什么问题" target="_blank" rel="external">招聘一个靠谱的iOS</a></li>
<li><a href="https://www.zybuluo.com/MicroCai/note/50592" target="_blank" rel="external">iOS集合的深复制和浅复制</a></li>
</ol>
]]></content>
<summary type="html">
<h2 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h2><ul>
<li><strong>浅复制</strong> : 并不拷贝对象,只是拷贝指向对象的指针。简单来说就是<code>指针拷贝</code
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
</entry>
<entry>
<title>iOS中属性的解读</title>
<link href="https://qmkcamel.github.io/2016/08/22/iOS%E4%B8%AD%E5%B1%9E%E6%80%A7%E7%9A%84%E8%A7%A3%E8%AF%BB/"/>
<id>https://qmkcamel.github.io/2016/08/22/iOS中属性的解读/</id>
<published>2016-08-21T16:00:00.000Z</published>
<updated>2017-05-16T12:37:05.000Z</updated>
<content type="html"><![CDATA[<h2 id="为什么要有属性?"><a href="#为什么要有属性?" class="headerlink" title="为什么要有属性?"></a>为什么要有属性?</h2><p>属性是由实例变量来实现的,但却提供了一个简洁的抽象机制。编译器一般会自动生成一套存取方法,用来访问给定类型中具体给定名称的变量。<br>简单的理解就是,属性是方便生成,操作实例变量的一个手段。property = ivar + getter + setter。</p>
<p>属性分为四大类 :</p>
<ul>
<li>原子性(atomic,nonatomic)</li>
<li>读写权限(readwrite,readonly)</li>
<li>内存管理语义(assign,strong,weak,unsafe_unretained,copy)</li>
<li>方法名(getter=name,setter=name)</li>
</ul>
<p>下面分别介绍其中值得注意的地方</p>
<h2 id="原子性"><a href="#原子性" class="headerlink" title="原子性"></a>原子性</h2><p><code>atomic</code>:原子的,会通过同步锁来保证其原子性,默认值,用原子性比较影响性能,所以一般我们都会用nonatomic。</p>
<h2 id="读写权限"><a href="#读写权限" class="headerlink" title="读写权限"></a>读写权限</h2><p><code>readwrite</code>:默认值。一般都不写,编译器会自动生成所修饰属性的getter和setter。<br><code>readonly</code>:编译器一般会只生成getter。如果我们希望一个属性对外只读,对内可读写,可以在.m的class-continuation分类(是一个匿名分类)中重写为readwrite。</p>
<h2 id="内存管理语义"><a href="#内存管理语义" class="headerlink" title="内存管理语义"></a>内存管理语义</h2><p>编译器在生成setter方法的时候,要根据这个语义生成不同的代码。不影响getter方法。<br><code>assign</code>: 设置方法只会执行针对“纯量类型”的简单复制操作,一般都来修饰非对象的类型。在MRC中也用来修饰对象,与现在ARC中的unsafe_unretained语义一样。<br><code>strong</code>: 拥有关系,setter的时候会先保留新值,释放旧值,然后再将新值设置上去。<br><code>weak</code>: 非拥有关系,setter的时候既不保留新值,也不释放旧值,在属性所指的对象遭到销毁的时候,属性值也会清空,变为nil。<br><code>unsafe_unretained</code>: 语义同assign差不多,但是适用于修饰对象类型。非拥有关系(unretained不保留),当所执行的对象遭到销毁的时候,属性值不会自动清空(unsafe)。<br><code>copy</code>: setter不保留新值,而是将其拷贝(copy)。一般NSString,NSArray和NSDictionary用copy比较多。这里来举例说下<br><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">strong</span>) <span class="built_in">NSString</span> *strongString;</div><div class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">copy</span> ) <span class="built_in">NSString</span> *copiedString;</div><div class="line"></div><div class="line"><span class="comment">//用copy来保证其封装性</span></div><div class="line"><span class="built_in">NSMutableString</span> *mutableString = [[<span class="built_in">NSMutableString</span> alloc] initWithString:<span class="string">@"hello world"</span>];</div><div class="line"><span class="keyword">self</span>.strongString = mutableString;</div><div class="line"><span class="keyword">self</span>.copiedString = mutableString;</div><div class="line"></div><div class="line">(lldb) p mutableString</div><div class="line">(__NSCFString *) $<span class="number">1</span> = <span class="number">0x000060000007c680</span> <span class="string">@"hello world"</span></div><div class="line">(lldb) p <span class="keyword">self</span>.strongString</div><div class="line">(__NSCFString *) $<span class="number">2</span> = <span class="number">0x000060000007c680</span> <span class="string">@"hello world"</span></div><div class="line">(lldb) p <span class="keyword">self</span>.copiedString</div><div class="line">(__NSCFString *) $<span class="number">3</span> = <span class="number">0x000060000003a920</span> <span class="string">@"hello world"</span></div><div class="line">(lldb) p [<span class="keyword">self</span>.strongString isMemberOfClass:[<span class="built_in">NSString</span> <span class="keyword">class</span>]]</div><div class="line">(<span class="built_in">BOOL</span>) $<span class="number">4</span> = <span class="literal">NO</span></div><div class="line">(lldb) p [<span class="keyword">self</span>.copiedString isMemberOfClass:[<span class="built_in">NSString</span> <span class="keyword">class</span>]]</div><div class="line">(<span class="built_in">BOOL</span>) $<span class="number">5</span> = <span class="literal">NO</span></div><div class="line">(lldb) p [<span class="keyword">self</span>.strongString isKindOfClass:[objc_getClass(<span class="string">"__NSCFString"</span>) <span class="keyword">class</span>]]</div><div class="line">(<span class="built_in">BOOL</span>) $<span class="number">8</span> = <span class="literal">YES</span></div><div class="line">(lldb) p <span class="string">@"hello"</span></div><div class="line">(<span class="built_in">NSTaggedPointerString</span> *) $<span class="number">6</span> = <span class="number">0xa00006f6c6c65685</span> <span class="string">@"hello"</span></div><div class="line"><span class="comment">//stongString的地址和mutableString的地址一样,copiedString地址是新的。</span></div><div class="line"><span class="comment">//有一点值得注意是__NSCFString,很明显NSString下面另有黑幕。随后会详细介绍。</span></div></pre></td></tr></table></figure></p>
<h2 id="方法名"><a href="#方法名" class="headerlink" title="方法名"></a>方法名</h2><p><code>getter=<name></code>: 指定“获取方法”的方法名。常用如下<br><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">@property</span>(<span class="keyword">nonatomic</span>, <span class="keyword">getter</span>=isOn) <span class="built_in">BOOL</span> on;</div></pre></td></tr></table></figure></p>
<p><code>setter=<name></code>: 指定“设置方法”的方法名。一般不怎么用。</p>
<h2 id="从-NSCFConstantString和-NSCFString-NSTaggedPointerString说起"><a href="#从-NSCFConstantString和-NSCFString-NSTaggedPointerString说起" class="headerlink" title="从__NSCFConstantString和__NSCFString,NSTaggedPointerString说起"></a>从<code>__NSCFConstantString</code>和<code>__NSCFString</code>,<code>NSTaggedPointerString</code>说起</h2><ul>
<li><code>__NSCFConstantString</code></li>
</ul>
<p><code>__NSCFConstantString</code>对象,就是字符串常量对象,存储在栈上。创建之后由系统来管理内存。相同内容的<code>__NSCFConstantString</code>对象地址相同。该对象的引用计数很大,为固定值不会变。当创建一个<code>__NSCFConstantString</code>对象时,会检测这个字符串内容是否存在,如果存在,则直接将地址赋值给变量,不存在的话,则创建新的地址,再赋值。只要字符串内容不变,就不会分配新的内存地址,这种优化可以节省内存,提高性能。</p>
<ul>
<li><code>__NSCFStrign</code></li>
</ul>
<p><code>__NSCFStrign</code>对象是NSString的一个子类,存储在栈上,不属于字符创常量对象。使用<code>[NSString stringWithFormat:]</code>和<code>NSMutableString</code>创建的字符串等都是这种对象。</p>
<ul>
<li><code>NSTaggedPointerString</code></li>
</ul>
<p>为什么要引入 Tagged Pointer ?<br>原有对象会造成内存浪费。假设我们存储NSNumber对象,其值是NSInteger。正常情况下,他所占用的内存是跟CPU的位数有关系的,在32位上是4个字节,在64位上是8个字节。指针的大写也跟CPU的位数有关系,在32位上4个字节,64位上是8个字节。如果没有 Tagged Pointer,像NSNumber和NSDate这些对象内存直接翻倍。</p>
<p>因此,苹果提出了Tagged Pointer,它是一个能够提升性能,节省内存的又去技术。我们都知道,程序使用了指针地址对齐的概念。指针地址对齐就是指分配在堆中的内存对象往往采用偶数倍或以2为指数倍的内存地址作为地址边界。</p>
<p>苹果将Tagged Pointer引入,给64位系统带来了内存的节省和运行效率的提高。Tagged Pointer通过在其最后一个bit位设置一个特殊标记,用于将数据直接保存在指针本身中。因为Tagged Pointer并不是真正的对象,我们在使用时需要注意不要直接访问其isa变量。</p>
<blockquote>
<p>我们也可以在WWDC2013的《Session 404 Advanced in Objective-C》视频中,看到苹果对于Tagged Pointer特点的介绍:</p>
<ul>
<li>Tagged Pointer专门用来存储小的对象,例如NSNumber和NSDate</li>
<li>Tagged Pointer指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要malloc和free。</li>
<li>在内存读取上有着3倍的效率,创建时比以前快106倍。</li>
</ul>
</blockquote>
]]></content>
<summary type="html">
<h2 id="为什么要有属性?"><a href="#为什么要有属性?" class="headerlink" title="为什么要有属性?"></a>为什么要有属性?</h2><p>属性是由实例变量来实现的,但却提供了一个简洁的抽象机制。编译器一般会自动生成一套存取方法,用
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
</entry>
<entry>
<title>软件设计的规则</title>
<link href="https://qmkcamel.github.io/2016/08/01/%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E7%9A%84%E5%8E%9F%E5%88%99/"/>
<id>https://qmkcamel.github.io/2016/08/01/软件设计的原则/</id>
<published>2016-07-31T16:00:00.000Z</published>
<updated>2017-03-10T16:12:22.000Z</updated>
<content type="html"><![CDATA[<blockquote>
<ol>
<li>软件的目的是帮助别人。</li>
<li>相比降低开发成本,更重要的是降低维护的成本。</li>
<li>变化定律:程序存在的时间越长,他的某个部分需要变化的可能性越大。</li>
<li>缺陷定律:程序出现缺陷的可能性,正比于你对他所做修改的程度。</li>
<li>简洁定律:软件任何一部分的维护难度,正比于该部分的简洁程度。</li>
<li>测试定律:你对软件行为的了解程度,等与你真正测试他的程度。<br>from <a href="https://book.douban.com/subject/20445258/" target="_blank" rel="external">简约之美</a></li>
</ol>
</blockquote>
<p>在发开经过一段时间之后,随着维护成本的不断提高,越来越感到下面两点的重要性。</p>
<ul>
<li>相比降低开发成本,降低维护成本更加重要。</li>
<li>维护成本正比于系统的复杂程度。</li>
</ul>
]]></content>
<summary type="html">
<blockquote>
<ol>
<li>软件的目的是帮助别人。</li>
<li>相比降低开发成本,更重要的是降低维护的成本。</li>
<li>变化定律:程序存在的时间越长,他的某个部分需要变化的可能性越大。</li>
<li>缺陷定律:程序出现缺陷的可能性,正比于你对他所
</summary>
<category term="软件工程" scheme="https://qmkcamel.github.io/tags/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B/"/>
<category term="瞎扯" scheme="https://qmkcamel.github.io/tags/%E7%9E%8E%E6%89%AF/"/>
</entry>
<entry>
<title>Joel Test</title>
<link href="https://qmkcamel.github.io/2016/07/28/Joel%20Test/"/>
<id>https://qmkcamel.github.io/2016/07/28/Joel Test/</id>
<published>2016-07-27T16:00:00.000Z</published>
<updated>2017-03-07T10:15:11.000Z</updated>
<content type="html"><![CDATA[<blockquote>
<ul>
<li>你们使用源代码控制吗?</li>
<li>你们每步都做构建吗?</li>
<li>你们每日都做构建吗?</li>
<li>你们有缺陷数据库吗?</li>
<li>你们会在写新代码之前修复缺陷吗?</li>
<li>你们有与当前工作吻合的进度安排吗?</li>
<li>你们有规约吗?</li>
<li>程序员工作环境安静吗?</li>
<li>你们采用了市面上最好的工具吗?</li>
<li>你们有测试人员吗?</li>
<li>你们会要求应聘者在面试时写代码吗?</li>
<li>你们做走廊可用性测试吗?</li>
</ul>
</blockquote>
<p>很早之前提出来的12个问题,现在看起来貌似很普通,但是能都做到的话还是很厉害的。</p>
<p>走廊性测试让我想到了一个问题,如果某些功能连开发者自己都一脸茫然的话,用户肯定更是丈二和尚摸不着头了。</p>
]]></content>
<summary type="html">
<blockquote>
<ul>
<li>你们使用源代码控制吗?</li>
<li>你们每步都做构建吗?</li>
<li>你们每日都做构建吗?</li>
<li>你们有缺陷数据库吗?</li>
<li>你们会在写新代码之前修复缺陷吗?</li>
<li>你们有与当前工作吻合的
</summary>
<category term="软件工程" scheme="https://qmkcamel.github.io/tags/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B/"/>
<category term="瞎扯" scheme="https://qmkcamel.github.io/tags/%E7%9E%8E%E6%89%AF/"/>
</entry>
<entry>
<title>App执行状态</title>
<link href="https://qmkcamel.github.io/2016/07/15/App%E6%89%A7%E8%A1%8C%E7%8A%B6%E6%80%81/"/>
<id>https://qmkcamel.github.io/2016/07/15/App执行状态/</id>
<published>2016-07-14T16:00:00.000Z</published>
<updated>2017-03-07T09:58:52.000Z</updated>
<content type="html"><![CDATA[<h2 id="iOS执行状态"><a href="#iOS执行状态" class="headerlink" title="iOS执行状态"></a>iOS执行状态</h2><ul>
<li>Not running<ul>
<li>The app has not been launched or was running but was terminated by the system.</li>
</ul>
</li>
<li>Inactive<ul>
<li>The app is running in the foreground but is currently not receiving events. (It may be executing other code though.) An app usually stays in this state only briefly as it transitions to a different state.</li>
</ul>
</li>
<li>Active<ul>
<li>The app is running in the foreground and is receiving events. This is the normal mode for foreground apps.</li>
</ul>
</li>
<li>Background<ul>
<li>The app is in the background and executing code. Most apps enter this state briefly on their way to being suspended. However, an app that requests extra execution time may remain in this state for a period of time. In addition, an app being launched directly into the background enters this state instead of the inactive state. For information about how to execute code while in the background, see Background Execution.</li>
</ul>
</li>
<li>Suspended<ul>
<li>The app is in the background but is not executing code. The system moves apps to this state automatically and does not notify them before doing so. While suspended, an app remains in memory but does not execute any code.<br>When a low-memory condition occurs, the system may purge suspended apps without notice to make more space for the foreground app.</li>
</ul>
</li>
</ul>
]]></content>
<summary type="html">
<h2 id="iOS执行状态"><a href="#iOS执行状态" class="headerlink" title="iOS执行状态"></a>iOS执行状态</h2><ul>
<li>Not running<ul>
<li>The app has not been lau
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
<category term="App" scheme="https://qmkcamel.github.io/tags/App/"/>
</entry>
<entry>
<title>Designated和Secondary(Convenience)初始化方法</title>
<link href="https://qmkcamel.github.io/2016/07/09/Designated%E5%92%8CSecondary(Convenience)%E5%88%9D%E5%A7%8B%E5%8C%96%E6%96%B9%E6%B3%95/"/>
<id>https://qmkcamel.github.io/2016/07/09/Designated和Secondary(Convenience)初始化方法/</id>
<published>2016-07-08T16:00:00.000Z</published>
<updated>2017-03-09T05:59:59.000Z</updated>
<content type="html"><![CDATA[<h2 id="两步创建"><a href="#两步创建" class="headerlink" title="两步创建"></a>两步创建</h2><p>如下所以,分配内存和初始化对象被分为两步来进行<br><code>[[NSObject alloc] init]</code></p>
<ul>
<li>alloc 创建对象,分配足够的内存,写入isa指针,初始化引用计数,重置所以实例变量</li>
<li>init 初始化对象,使对象处于可用的状态。为对象的实例变量赋予合理有用的值</li>
</ul>
<h2 id="designated"><a href="#designated" class="headerlink" title="designated"></a>designated</h2><ul>
<li>只有一个</li>
<li>提供所有的参数 </li>
</ul>
<h3 id="定义一个新类的时候如何做"><a href="#定义一个新类的时候如何做" class="headerlink" title="定义一个新类的时候如何做"></a>定义一个新类的时候如何做</h3><ul>
<li>不需要重载任何初始化函数</li>
<li>重载designated initializer</li>
<li>重新定义一个designated initializer</li>
</ul>
<h3 id="需要提供自己的初始化函数时需要怎么做"><a href="#需要提供自己的初始化函数时需要怎么做" class="headerlink" title="需要提供自己的初始化函数时需要怎么做"></a>需要提供自己的初始化函数时需要怎么做</h3><ul>
<li>定义自己的designated initializer,确保调用了直接超类的designated initializer</li>
<li>重载直接超类的designated initializer,调用你的新designated initializer</li>
<li>为新的designated initializer写文档</li>
</ul>
<h2 id="secondary"><a href="#secondary" class="headerlink" title="secondary"></a>secondary</h2><ul>
<li>一个或者多个</li>
<li>提供一个或者多个默认参数</li>
<li>需要调用designated方法</li>
</ul>
<h2 id="举个例子"><a href="#举个例子" class="headerlink" title="举个例子"></a>举个例子</h2><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">UIView</span> 的 designated initializer 有两个,分别是</div><div class="line">- (<span class="keyword">instancetype</span>)initWithFrame:(<span class="built_in">CGRect</span>)frame <span class="built_in">NS_DESIGNATED_INITIALIZER</span>;</div><div class="line">- (<span class="keyword">nullable</span> <span class="keyword">instancetype</span>)initWithCoder:(<span class="built_in">NSCoder</span> *)aDecoder <span class="built_in">NS_DESIGNATED_INITIALIZER</span>;</div><div class="line"></div><div class="line">我们有一个类就叫 <span class="built_in">MKSubView</span> : <span class="built_in">UIView</span> </div><div class="line">然后我们在.m 中如果这样来些初始化类的话,.h没有任何说明的话,就会有一些问题,没有重载直接超类的designated initializer </div><div class="line">- (instance)init {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">self</span> = [<span class="keyword">super</span> init]) {</div><div class="line"> <span class="comment">//something to do</span></div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">self</span>;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="number">1.</span> [[<span class="built_in">MKSubView</span> alloc] initWithFrame:frame]</div><div class="line"><span class="number">2.</span> [<span class="built_in">MKSubView</span> new]</div><div class="line"><span class="number">3.</span> [[<span class="built_in">MKSubView</span> alloc] init]</div><div class="line">如果我们用 <span class="number">1</span> 来初始化的话,不会被正确的初始化。</div><div class="line">只有这样 <span class="number">2</span> 或者 <span class="number">3</span> 才会正确执行初始化。</div><div class="line">但是不能保证所以人都认真看了代码,尤其是你做一个这样的类给别人用的时候。</div><div class="line"></div><div class="line">正确方法是直接重载直接父类的designated initializer</div><div class="line"> </div><div class="line">- (<span class="keyword">instancetype</span>)initWithFrame:(<span class="built_in">CGRect</span>)frame {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">self</span> = [<span class="keyword">super</span> initWithFrame:frame]) {</div><div class="line"> <span class="comment">//something to do </span></div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">self</span>;</div><div class="line">}</div><div class="line">这样的话调用 <span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span> 就都能保证正常初始化了</div></pre></td></tr></table></figure>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://github.com/oa414/objc-zen-book-cn#%E9%9D%A2%E5%90%91%E5%88%87%E9%9D%A2%E7%BC%96%E7%A8%8B" target="_blank" rel="external">https://github.com/oa414/objc-zen-book-cn#%E9%9D%A2%E5%90%91%E5%88%87%E9%9D%A2%E7%BC%96%E7%A8%8B</a></p>
]]></content>
<summary type="html">
<h2 id="两步创建"><a href="#两步创建" class="headerlink" title="两步创建"></a>两步创建</h2><p>如下所以,分配内存和初始化对象被分为两步来进行<br><code>[[NSObject alloc] init]</code
</summary>
<category term="iOS" scheme="https://qmkcamel.github.io/tags/iOS/"/>
</entry>
<entry>
<title>网络协议概览</title>
<link href="https://qmkcamel.github.io/2016/07/09/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E6%A6%82%E8%A7%88/"/>
<id>https://qmkcamel.github.io/2016/07/09/网络协议概览/</id>
<published>2016-07-08T16:00:00.000Z</published>
<updated>2017-03-14T14:12:15.000Z</updated>
<content type="html"><![CDATA[<h2 id="物理层"><a href="#物理层" class="headerlink" title="物理层"></a>物理层</h2><p>物理层(physical layer)指光纤,电缆或者电磁波等真实存在的媒介。</p>
<h3 id="0-1"><a href="#0-1" class="headerlink" title="0,1"></a>0,1</h3><p>针对特定的媒介,设备可以有相应的接口,用来接收物理信号。随后利用物理层的协议可以把物理信号转化为0/1序列。</p>
<h2 id="连接层"><a href="#连接层" class="headerlink" title="连接层"></a>连接层</h2><p>在连接层中把0/1序列分成帧(frame)。帧是一段有序的0,1序列。连接层规定了帧的格式,确定特殊的0/1序列为帧的起始和结束,帧中还包含送信地址和收信地址,还有能够探测错误的校验序列,当然最重要的肯定是payload和相应的类型。连接层不关心传输的数据内容,只是像一个信封一样把数据包裹起来。帧的收信地址只能是局域网里地址,连接层更像是一个社区的邮差,更远的需要依赖高层的协议。</p>
<h3 id="Ethernet(以太网)"><a href="#Ethernet(以太网)" class="headerlink" title="Ethernet(以太网)"></a>Ethernet(以太网)</h3><h3 id="Wifi"><a href="#Wifi" class="headerlink" title="Wifi"></a>Wifi</h3><h3 id="ARP"><a href="#ARP" class="headerlink" title="ARP"></a>ARP</h3><h2 id="网络层"><a href="#网络层" class="headerlink" title="网络层"></a>网络层</h2><p>网络层的目的就是为了让不同的“社区”之间通信。比如我们希望WiFi局域网上的一台计算机和以太网上的一台计算通信,那么就需要有能从物理层上在两个网络之间发送和接收0/1序列,并能理解多种帧格式的“中间人”。路由器就是为了这个而产生的“中间设备”。</p>
<h3 id="ICMP(介于网络层和传输层)"><a href="#ICMP(介于网络层和传输层)" class="headerlink" title="ICMP(介于网络层和传输层)"></a>ICMP(介于网络层和传输层)</h3><p>Internet Control Message Protocol</p>
<ul>
<li><p>回音(echo)<br>ping 命令</p>
</li>
<li><p>源头冷却(source quench)</p>
</li>
<li><p>目的地无法到达(destination unreachable)</p>
</li>
<li><p>超时(tiem exceeded)<br>traceroute 用这种类型</p>
</li>
<li><p>重新定向(redirect)</p>
</li>
</ul>
<h3 id="IPv4-IPv6"><a href="#IPv4-IPv6" class="headerlink" title="IPv4/IPv6"></a>IPv4/IPv6</h3><h2 id="传输层"><a href="#传输层" class="headerlink" title="传输层"></a>传输层</h2><h3 id="TCP"><a href="#TCP" class="headerlink" title="TCP"></a>TCP</h3><ul>
<li><p>滑动窗口</p>
<ul>
<li><p>累计ACK(而且会故意有一定的延迟)</p>
</li>
<li><p>流量控制</p>
</li>
<li><p>零窗口</p>
</li>
<li><p>白痴窗口综合症</p>
</li>
</ul>
</li>
<li><p>三次握手/四次挥手</p>
</li>
<li><p>重发</p>
<ul>
<li><p>超时重新发送</p>
</li>
<li><p>快速重新发送</p>
</li>
</ul>
</li>
<li><p>堵塞控制</p>
<ul>
<li><p>阻塞窗口</p>
<ul>
<li><p>慢启动</p>
</li>
<li><p>阻塞避免</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="UDP"><a href="#UDP" class="headerlink" title="UDP"></a>UDP</h3><ul>
<li>感觉像是实现了端口的IP</li>
</ul>
<h2 id="应用层"><a href="#应用层" class="headerlink" title="应用层"></a>应用层</h2><h3 id="DNS"><a href="#DNS" class="headerlink" title="DNS"></a>DNS</h3><p>基于UDP<br>Linux 查看DNS 服务地址 cat /etc/resolv.conf</p>
<ul>
<li><p>DNS劫持</p>
</li>
<li><p>DNS缓存</p>
</li>
<li><p>DNS查询</p>
</li>
<li><p>反向DNS</p>
</li>
</ul>
<h3 id="HTTP-HTTPS"><a href="#HTTP-HTTPS" class="headerlink" title="HTTP/HTTPS"></a>HTTP/HTTPS</h3><p>大多基与TCP 偶尔基于UDP </p>
<p>以前HTTP连接完成之后就会断开底层的TCP,每次重新建立连接都需要耗费时间。现在如果IP和端口一样的,会使用同一个TCP连接,但是HTTP仍是无状态的。</p>
<ul>
<li><p>格式</p>
<ul>
<li><p>起始行</p>
<ul>
<li><p>request</p>
<ul>
<li><p>资源路径</p>
</li>
<li><p>协议</p>
</li>
<li><p>Host</p>
</li>
</ul>
</li>
<li><p>response</p>
<ul>
<li><p>协议</p>
</li>
<li><p>状态码</p>
</li>
<li><p>状态码描述</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>头信息</p>
</li>
<li><p>主体</p>
</li>
</ul>
</li>
<li><p>默认80端口</p>
</li>
<li><p>发展历程</p>
<ul>
<li><p>0.9</p>
<ul>
<li><p>只有一个get</p>
</li>
<li><p>只能返回HTML格式的字符串</p>
</li>
</ul>
</li>
<li><p>1.0</p>
<ul>
<li><p>返回格式任意</p>
</li>
<li><p>引入POST/HEAD</p>
</li>
<li><p>增加了 HTTP Header</p>
</li>
<li><p>其他新增:状态码,多字符集支持,多部分发送,权限,缓存,内容编码</p>
</li>
<li><p>缺点<br>主要缺点:每个TCP连接只能发送一个请求,发送数据完毕,就关闭连接。三次握手成本高。<br>为了解决这个问题:部分浏览器在请求的header 里面用了非标准的Connection: keep-alive 告诉不要断开连接,服务器也返回同样,然后就可以复用了。</p>
</li>
</ul>
</li>
<li><p>1.1</p>
<ul>
<li><p>持久连接</p>
<ul>
<li><p>TCP连接默认不关闭</p>
</li>
<li><p>发现没活动可以主动关闭连接(规范做法:客户端最后一个请求发送 Connection:Close)</p>
</li>
<li><p>同一个域名,大多浏览器最大同时建立6个持久连接</p>
</li>
</ul>
</li>
<li><p>管道机制</p>
<ul>
<li><p>同一个TCP,客户端同时发送多个请求</p>
</li>
<li><p>以前:同一个TCP,发送A,收到回复,然后发B</p>
</li>
<li><p>现在:同一个TCP,可以同时发送A,B,但是服务器还是按照顺序来</p>
</li>
</ul>
</li>
<li><p>Content-Length字段</p>
<ul>
<li>区分数据包是属于哪一个回应的</li>
</ul>
</li>
<li><p>分块传输编码</p>
<ul>
<li>采用流模式取代缓存模式,Transfer-Encoding,表明回应有数量未定的数据块组成</li>
</ul>
</li>
<li><p>增加了的动词: PUT PATCH HEAD OPTION DELETE</p>
</li>
<li><p>缺点<br>允许TCP复用,同一个TCP里,所有数据还是按次序来的。可能会造成队头堵塞。<br>避免这个问题:1.减少请求次数 2.同时多开持久连接。<br>产生了很多网页优化技巧: </p>
<ol>
<li>合并脚本和样式表 2. 图片嵌入CSS 3. 域名分片</li>
</ol>
</li>
</ul>
</li>
<li><p>2.0</p>
<ul>
<li><p>SPDY(2.0的前身)</p>
</li>
<li><p>二进制协议</p>
</li>
<li><p>多工</p>
</li>
<li><p>数据流</p>
</li>
<li><p>头信息压缩</p>
</li>
<li><p>服务器推送</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>HTTPS证书分类<br><a href="http://www.ruanyifeng.com/blog/2016/08/migrate-from-http-to-https.html" target="_blank" rel="external">http://www.ruanyifeng.com/blog/2016/08/migrate-from-http-to-https.html</a></p>
<ul>
<li><p>认证级别</p>
<ul>
<li><p>域名认证<br>可以确认申请人拥有这个域名</p>
</li>
<li><p>公司认证<br>确认域名是哪一家公司,证书里有公司信息</p>
</li>
<li><p>扩展认证<br>最高级别认证,浏览器会显示公司名<br>比如payple</p>
</li>
</ul>
</li>
<li><p>覆盖范围</p>