-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
1815 lines (1446 loc) · 137 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><![CDATA[Imrazor's Blog]]></title>
<link href="http://imrazor.github.io/atom.xml" rel="self"/>
<link href="http://imrazor.github.io/"/>
<updated>2016-08-18T22:52:40+08:00</updated>
<id>http://imrazor.github.io/</id>
<author>
<name><![CDATA[imrazor]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[程序员进阶之路]]></title>
<link href="http://imrazor.github.io/blog/2016/08/18/programmer-advanced/"/>
<updated>2016-08-18T22:41:50+08:00</updated>
<id>http://imrazor.github.io/blog/2016/08/18/programmer-advanced</id>
<content type="html"><![CDATA[<p>今天公司做了一次内部培训,讲师是陆其明,主题是程序员进阶之路。感觉讲的非常好,做个摘要留存一下</p>
<h2>程序员进阶的三个要素:</h2>
<h3>一、专业</h3>
<p><strong>没有救世主</strong>,不能指望别人,只能靠自己</p>
<p><strong>静得下心</strong>,静下心来沉淀、积累,大牛不是一年两年就练就的</p>
<p><strong>钻得进去</strong>,钻的深,才能了解真正的原理,而不是浮于表面</p>
<p><strong>如痴如醉</strong>,当设计或是完成一个功能时,全身心的投入</p>
<p><strong>系统、全面</strong>,当对某个系统足够了解时,你站的高度就会高,对系统的整体运作也会有全面的认识</p>
<p><strong>实战磨练</strong>,多多实践,实战岀真知,某种设计是不是有效,只有在使用的时候才知道</p>
<p><strong>总结、积累</strong>,善于总结积累,下次遇到类似问题就容易解决了,而且经常总结会慢慢提高</p>
<h3>二、分享</h3>
<p>勤加练习,如果你天天埋头写代码,连讨论、反思或者学习的时间都没有,你将得不到真正的进步。</p>
<blockquote><p>eg:你天天开车上下班,但是你永远也不会成为真正的车手</p></blockquote>
<p>要在磨练工艺宇思考如何提高工艺之间找到一个适当的平衡点</p>
<p>开放的心态,阅读编程相关的博客或书籍,学会读源代码</p>
<p>最好的学习方法就是边做边学</p>
<p>成为杰出的程序员跟写代码没太大关系,坚韧不拔的精神很重要,更重要的是要有良好的沟通技巧</p>
<p>想从优秀到卓越,必须培养起有效沟通的能力,与同事沟通,与老板沟通,与用户沟通,最终与全世界沟通</p>
<p>如何提高沟通能力?写博客是个好方法</p>
<h3>三、职业精神</h3>
<p>关注公司战略,达成公司目标,与公司共同成长</p>
<p>心态平和,内心有一份坚持,该做什么不该做什么,do the right thing</p>
<p>快乐工作,快乐不是因为拥有的多,而是计较的少</p>
<blockquote><p>eg:不要同事升职加薪,自己没有就不高兴</p></blockquote>
<p>软件开发者的工作不是写代码,而是解决问题,关键是解决问题的能力</p>
<h4>最后讲师还说了一些转型问题:</h4>
<p>从一线开发变为管理,实际并不是晋升,而是转型了</p>
<p>管理者的定义:管理者是通过别人来完成工作的人</p>
<p>成为优秀的管理者要做到两点:确保你的员工能够工作,关心它们(把他们当人看,而不是资源)
Keep them busy,make them happy</p>
<blockquote><p>eg:老师问我,你这两天参加管理课程,你认为你的部下能完成工作的多少,我:50%吧(因为我技术比他们好很多,所以平时核心功能或者难点都是我来完成),老师:你这样不是管理者,而是super doer</p></blockquote>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[组件化之路]]></title>
<link href="http://imrazor.github.io/blog/2016/04/21/componentization/"/>
<updated>2016-04-21T21:10:22+08:00</updated>
<id>http://imrazor.github.io/blog/2016/04/21/componentization</id>
<content type="html"><![CDATA[<h2>前言</h2>
<p>随着业务模块及模块间相互调用的需求越来越多,如果解决耦合及方便模块间调用就变的越来越重要,解决这些问题的一个途径便是组件化</p>
<p>比如我们现在有阅读、电影票、泡泡、秀场、电商等等,这些模块都有调起登录、分享、播放器的需求,一些还需要调起其他的模块。如果直接引用进行调起,<strong>那模块的独立测试将变得困难</strong>(需要把别的模块也加到自己的测试工程中,如果别的模块又饮用了其他,那么最后会把所有的模块都带进来),<strong>而且一旦模块接口发生变化,则所有使用的地方都要进行修改</strong></p>
<h3>中介者模式</h3>
<p>解决耦合的一个比较通用的方式便是使用Mediator,各个模块都耦合Mediator,这样模块间则不需要相互引用了,并且模块间调起都通过统一接口进行,降低了学习成本</p>
<h3>第一次组件化</h3>
<p>第一次组件化我们的主要目的是解决耦合,于是创建了一个叫engine的模块,所有的模块间交互都通过engine,比如调起登录类似这样:</p>
<pre><code>EngineObj *obj = [EngineObj engineObjWithModule:ModuleLogin type:LoginRegisterType andParams:@{@"info":@"请先注册"}];
EngineCallback *cb = [EngineCallback engineCallbackWithTarget:self action:@selector(registerDone:)];
EngineSend(obj, cb)
</code></pre>
<p>这样调起者就可以不用关系调起注册模块的细节,不论注册成功或失败,调用者都会通过registerDone:方法得到结果</p>
<p>而engine会对应模块维护一个协议,比如上面代码中,打开的module是ModuleLogin,那就路由到openLoginModule:方法,具体的调起逻辑由主工程的一个manager实现,这个manager对象在程序启动时注入到engine中,并且实现了engine中的模块协议</p>
<h3>第一次组件化的问题</h3>
<p>现在看来,第一次组件化是有很多问题的:</p>
<p>1、模块type需要在engine中维护,新增时需要修改engine的头文件(新增一种module type),新增调起协议。这样一来就违反了开闭原则,虽然修改不多,但还是需要去维护</p>
<p>2、在新增模块或模块接口变更时,主工程的manager需要去维护,耗费人力</p>
<p>3、想调起新增的模块必须新增调用代码</p>
<h3>第二次组件化</h3>
<p>第二次组件化主要解决了上一次的问题,并且模块的创建模块自己最清楚。所以这一次我们改成了<strong>注册制</strong></p>
<p>每个模块在对应的模块中进行注册,并实现一个协议,类似这样:</p>
<pre><code>+ (void)load
{
[Engine resigserID:@"2" withClass:[self Class]];
}
+ (void)launchWithObj(Obj *)obj
{
//模块内部进行创建;
}
</code></pre>
<p>而这个Obj类包含了3个参数:</p>
<pre><code>//服务器原始数据,包含了模块id,及模块所需参数
@property (nonatomic, strong) NSDictionary *serverParams;
//客户端提供的数据,比如新模块承载的ViewController
@property (nonatomic, strong) NSDictionary *clientParams;
//模块退出时的回调
@property (nonatomic, copy) EngineClose close;
</code></pre>
<p>调起代码:</p>
<pre><code>Obj *obj = [Obj objWithSP:sp andCP:cp closeBlock:close];
EngineOpen(obj);
</code></pre>
<h3>第二次组件化的优点</h3>
<p>对比第一次,这一次可以说遵循了开闭原则,新增模块engine无需维护;此外,新模块接入时主工程无序添加任何代码;调用方添加一次调用逻辑,即支持了所有模块(包括后续新增的模块)</p>
<h3>总结</h3>
<p>组件化需要服务器、各模块的支持。入口的统一也方便做一些统计,比如模块的启动次数,记录栈顶模块还可以在崩溃时知道是哪个模块是active状态,从而为崩溃统计提供更多的信息</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[2015总结]]></title>
<link href="http://imrazor.github.io/blog/2016/01/17/2015-review/"/>
<updated>2016-01-17T09:57:26+08:00</updated>
<id>http://imrazor.github.io/blog/2016/01/17/2015-review</id>
<content type="html"><![CDATA[<p>2015对我来说可谓是喜忧参半的一年,喜的是工作上有所进步,忧的得了一场不大不小的病。</p>
<h3>什么最重要</h3>
<p>其实这一年对我影响最大的,就是这不大不小的病,他可谓给了我重重的一巴掌,让我清醒过来,明白什么才是最重要的。</p>
<p>10年毕业至得病前,我一直觉得事业是最重要的。为了这个,努力和奋斗自然不能少,平日加班,周末做兼职项目可以完全概括我毕业后前两年的生活。连在创业公司时的领导也常跟我说:“睿哲啊,要按时吃饭,我现在的胃病就是年轻时太拼落下的”。现在回过头看,才对领导的话感同身受。</p>
<p>今年3月底,我们又开始了每年的惯例-封闭开发。本来是两人的工作量,最后因为同事的工作任务变更,全部由我一人承担。常年吃饭不规律,爱喝咖啡的习惯已经埋下病根,最后封闭开发的巨大压力及繁重工作让病彻底显现出来。封闭开发结束时,工作可以说是非常好的完成了,而我因为吞咽食物疼痛进了医院。</p>
<p>拿到病理报告后才知道病的严重性,如果不加控制,就会从现在的轻度往后发展,如果真到了重度,就再也治不好了。家人很担心,带我去看了中医,此后一直喝中药至今,连牙都喝黄了:)</p>
<p>我所有的年假及调休,全部用在了去医院看病上。老婆辞掉工作在家为我熬药、做早饭,因为担心和着急,她自己也生了一场病。而我也终于明白,最重要的不是事业、钱财,而是健康。没有了健康,其他一切都只能是浮云。</p>
<h3>工作</h3>
<p>这一年回头看看,工作完成了不少,平台化及模块解耦、数据处理的异步化、Card架构都在基线扮演着举足轻重的角色。领导和同事对我很好,也让我觉得这一年的汗水没有白出。</p>
<p>当App越来越大,接入的业务越来越多,平台化即是必然。业务模块之间不能有耦合,相互之间的消息传递就需要一个中间人来进行,业务模块耦合中间人,从而减少了依赖的对象。</p>
<p>异步化数据处理其实主要是多线程处理,而线程安全在实际开发中还是有难度的。锁的使用、资源释放的时机都至关重要,一个不小心,就会发生开发测试过程中没碰到,到了用户那却被放大N倍的问题。</p>
<p>Card是一种客户端的UI及事件处理都由数据决定的机制,客户端预先实现一些固定的模版及实现,再根据数据类型做特定的展示、事件响应以及数据统计。Card的好处是比较灵活,尤其适用于对运营要求比较灵活的情况。而未来,我们也想做到客户端实现一个解析器,或者将Card机制迁移至ReactNative,直接将新Card模版从服务器那边获取,进而做到不发版就能支持新的Card样式。</p>
<h3>生活</h3>
<p>这一年因为生病很少骑行,在家宅着就开始琢磨别的东西:将两辆滑板车改成了电动,轮毂电机的一辆,航模电机的一辆。买了一架成品无人机,组装了一架穿越机、一架航拍机,也算进入了航模坑。其实在2015年消费级无人机就有不少新秀出现了,2016年这个市场肯定会继续火爆,像电脑、手机一样,以后人手一架无人机也不是不可能。</p>
<p>这一年老婆也为我付出了很多,为让我的病尽快好起来,联系医生,早起做饭,辞职在家熬药,甚至包揽了一切家务。希望病尽快痊愈,让她早日脱离操劳和担心的状态。</p>
<h3>2016目标</h3>
<p>2016最大的目标就是让病彻底痊愈,加强锻炼,提高身体素质。此外,不断学习,提高技术能力也是一个开发的根本。</p>
<p>希望2016一切顺利。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[创建自己的VPN服务器]]></title>
<link href="http://imrazor.github.io/blog/2015/03/06/create-your-own-vpn-seearver/"/>
<updated>2015-03-06T23:42:40+08:00</updated>
<id>http://imrazor.github.io/blog/2015/03/06/create-your-own-vpn-seearver</id>
<content type="html"><![CDATA[<p>首先创建一个Amazon Web Services (AWS) ,新用户有一年的免费试用权,使用free对应的配置,每月可以使用15G流量和750小时,网上有对应申请AWS的教程</p>
<p>服务器使用的操作系统为ubuntu,使用ssh连接到EC2实例;</p>
<pre><code>ssh -i key_pair.pem ubuntu@ip
</code></pre>
<p>安装pptpd:</p>
<pre><code>sudo aptitude install pptpd
</code></pre>
<p>编辑pptp配置文件:</p>
<pre><code>sudo vim /etc/pptpd.conf
</code></pre>
<p>在最后一行加上:</p>
<pre><code>localip 192.168.240.1
remoteip 192.168.240.2-9
</code></pre>
<!-- more -->
<p>使用Google Public DNS:
sudo vim /etc/ppp/pptpd-options找到ms-dns对应的位置,去掉注释,并修改如下:</p>
<pre><code>ms-dns 8.8.8.8
ms-dns 8.8.4.4
</code></pre>
<p>配置访问VPN的用户名和密码,将USERNAME和PASSWORD替换为你自己希望的。可以重复添加,分配给不同的用户:</p>
<pre><code>echo "USERNAME pptpd PASSWORD *" | sudo tee -a /etc/ppp/chap-secrets
</code></pre>
<p>重启服务:</p>
<pre><code>sudo /etc/init.d/pptpd restart
</code></pre>
<p>编辑/etc/sysctl.conf配置数据转发:</p>
<pre><code>sudo vim /etc/sysctl.conf
</code></pre>
<p>将下面一行的注释去掉:</p>
<pre><code>net.ipv4.ip_forward=1
</code></pre>
<p>重新加载:</p>
<pre><code>sudo sysctl -p
</code></pre>
<p>加入网络地址转换:</p>
<pre><code>sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
</code></pre>
<p>确保服务器重启后服务可用:sudo vim /etc/rc.local,在exit 0上面加入:</p>
<pre><code>iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
</code></pre>
<p>在EC2控制台将实例的Security Groups中的规则中的inbound添加一条custom tcp rule,端口号为1723:</p>
<p><img src="http://imrazor.github.io/images/blog/20150306.png" alt="" /></p>
<p>之后就可以使用自己的vpn服务器进行科学上网了:)</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[使用cubieboard创建热点]]></title>
<link href="http://imrazor.github.io/blog/2015/01/14/use-cubieboard-as-an-ap/"/>
<updated>2015-01-14T22:58:50+08:00</updated>
<id>http://imrazor.github.io/blog/2015/01/14/use-cubieboard-as-an-ap</id>
<content type="html"><![CDATA[<p>最近看到有人折腾树莓派,自己也想倒腾点东西。树莓派性能较差,于是买了个国产的板子——cubieboard</p>
<p><img src="http://imrazor.github.io/images/blog/2015/A47474333AC5351B48B4C6624CF05362.png" alt="" /></p>
<p><strong>开始</strong></p>
<p>首先是装系统,我装的debian server(<a href="http://forum.cubietech.com/forum.php?mod=viewthread&tid=3350&extra=&page=1">下载地址</a>),双卡板系统通过Win32DikImager可以很方便的刷好</p>
<p>接下来要驱动无线网卡,我的usb无线网卡为edup-n8508gs,系统中自带8192cu驱动,是可以支持我的无线网卡的</p>
<!--more-->
<p><strong>安装hostapd</strong></p>
<p>apt-get的hostapd无法跑起来,各种错误,无线网卡还分芯片,我的无线网卡是Realtek芯片,只有特定的hostapd才能驱动</p>
<p>github上下载别人处理好的源码来编译和安装:</p>
<pre><code>wget https://github.com/jenssegers/RTL8188-hostapd/archive/v1.1.tar.gz
tar -zxvf v1.1.tar.gz
cd RTL8188-hostapd-1.1/hostapd
sudo make
sudo make install
</code></pre>
<p>最后hostapd.conf要类似这么配置:</p>
<pre><code>interface=wlan0
driver=rtl871xdrv
ssid=wifi
channel=1
wmm_enabled=0
wpa=1
wpa_passphrase=12345678
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
auth_algs=1
macaddr_acl=0
</code></pre>
<p>参数不一一说明了,文档中都有说明,这里密码设置为1-8。启动hostapd</p>
<pre><code>sudo /etc/init.d/hostapd start
</code></pre>
<p><strong>安装dnsmasq</strong></p>
<p>dnsmasp的作用是让你的设备连接ap热点后,可以自动获取ip地址,首先:</p>
<pre><code>sudo apt-get dnsmasp
</code></pre>
<p>之后修改dnsmasq的配置文件/etc/dnsmasq.conf:</p>
<pre><code>#Name:Default
#Type:DNSMASQ
interface=wlan0
dhcp-range=192.168.0.2,192.168.0.255,12h;
server=/www.google.com/8.8.8.8
</code></pre>
<p>配置好后,启动</p>
<pre><code>sudo /etc/init.d/dnsmasq start
</code></pre>
<p><strong>设置开机生效</strong></p>
<p>在/etc/rl.local中加入如下代码,这样即使重启cb2也能生效:</p>
<pre><code>ifconfig wlan0 192.168.0.1 netmask 255.255.255.0
ip addr add 192.168.0.1/24 dev wlan0
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
</code></pre>
<p>在/etc/sysctl.conf加入:</p>
<pre><code>net.ipv4.ip_forward = 1
</code></pre>
<p>重启设备,之后就能看到你的热点(名叫wifi)了,快连接你的热点吧</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[使用lldb和Hopper破解Reveal的试用限制]]></title>
<link href="http://imrazor.github.io/blog/2014/10/20/use-lldb-and-hopper-break-reveal/"/>
<updated>2014-10-20T23:23:53+08:00</updated>
<id>http://imrazor.github.io/blog/2014/10/20/use-lldb-and-hopper-break-reveal</id>
<content type="html"><![CDATA[<p>本文仅供学习和交流,如有侵权或不妥,请联系我删除</p>
<p>之前写了篇lldb联机调试的文章,恰好Reveal的试用到期了,于是拿来练练手。本文参考了<a href="http://www.yangch.info/?p=1230">“[原创]破解Reveal购买提示框”</a>,但是去掉了“Free trial has ended” :),并假设你已经了解了一些lldb的基本调试命令</p>
<p>首先用Hopper分析Reveal源程序,搜索关键字trial,首先发现了IBATrialModeReminderPresenter</p>
<p><img src="http://imrazor.github.io/images/blog/2014-10-20/controller_image.png" alt="" /></p>
<p>用lldb调试下,断点在图中内存地址中</p>
<pre><code>(lldb) target create "/Applications/Reveal.app"
Current executable set to '/Applications/Reveal.app' (x86_64).
(lldb) b -a 0000000100094180
Breakpoint 1: address = 0x0000000100094180
(lldb) r
Process 4255 launched: '/Applications/Reveal.app/Contents/MacOS/Reveal' (x86_64)
2014-10-20 19:40:37.548 Reveal[4255:d0b] Unknown class IBAViewHierarchyCanvasSharingMenu in Interface Builder file at path /Applications/ Reveal.app/Contents/Resources/en.lproj/MainMenu.nib.
2014-10-20 19:40:37.554 Reveal[4255:d0b] INFO: Log Level Enabled
2014-10-20 19:40:37.554 Reveal[4255:d0b] WARN: Log Level Enabled
2014-10-20 19:40:37.554 Reveal[4255:d0b] ERROR: Log Level Enabled
2014-10-20 19:40:37.574 Reveal[4255:d0b] INFO: Reveal Automatic Updates are enabled!
2014-10-20 19:40:37.862 Reveal[4255:d0b] [HockeySDK] WARNING: Detecting crashes is NOT enabled due to running the app with a debugger attached.
2014-10-20 19:40:37.863 Reveal[4255:d0b] INFO: Reveal Crash Reporting is enabled!
Process 4255 stopped
* thread #1: tid = 0x3abbf, 0x0000000100094180 Reveal`___lldb_unnamed_function3544$$Reveal, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100094180 Reveal`___lldb_unnamed_function3544$$Reveal
Reveal`___lldb_unnamed_function3544$$Reveal:
-> 0x100094180: pushq %rbp
0x100094181: movq %rsp, %rbp
0x100094184: leaq 0xa05c5(%rip), %rsi ; { /usr/lib/ libobjc.A.dylib`objc_msgSend_fixedup, "alloc" }
0x10009418b: callq *0xa05bf(%rip) ; { /usr/lib/ libobjc.A.dylib`objc_msgSend_fixedup, "alloc" }
</code></pre>
<!--more-->
<p>至此Reveal启动,并进入了断点,si和ni都是一步步调试,直接finish单步跳出,第一次的内存地址100095f96中没什么太有用的信息,但是所在的类是IBATrialModReminderPresenter中,说明我们很进了…</p>
<pre><code>(lldb) finish
Process 4255 stopped
* thread #1: tid = 0x3abbf, 0x0000000100095f96 Reveal`___lldb_unnamed_function3586$$Reveal + 94, queue = 'com.apple.main-thread', stop reason = step out
frame #0: 0x0000000100095f96 Reveal`___lldb_unnamed_function3586$$Reveal + 94
Reveal`___lldb_unnamed_function3586$$Reveal + 94:
-> 0x100095f96: movq %rbx, %r13
0x100095f99: movq %rax, %rdi
0x100095f9c: callq 0x1000a0596 ; symbol stub for: objc_retainAutoreleasedReturnValue
0x100095fa1: movq 0x67400(%rip), %r15 ; (void *)0x00007fff8f6d10d0: objc_release
(lldb) finish
Process 4255 stopped
* thread #1: tid = 0x3abbf, 0x000000010009614e Reveal`___lldb_unnamed_function3588$$Reveal + 66, queue = 'com.apple.main-thread', stop reason = step out
frame #0: 0x000000010009614e Reveal`___lldb_unnamed_function3588$$Reveal + 66
Reveal`___lldb_unnamed_function3588$$Reveal + 66:
-> 0x10009614e: movq %r14, %rdi
0x100096151: popq %rbx
0x100096152: popq %r14
0x100096154: popq %rbp
</code></pre>
<p>再次finish,查看内存地址10009614e,这次发现了关键方法@selector(shouldShowTrialModeSheet):</p>
<p><img src="http://imrazor.github.io/images/blog/2014-10-20/address.png" alt="" /></p>
<p>不得不感慨老外起的方法名实在是太好了…进入到shouldShowTrialModeSheet方法中,处理下代码,会看到是这样的:</p>
<p><img src="http://imrazor.github.io/images/blog/2014-10-20/code.png" alt="" /></p>
<p>看代码,应该是通过日期进行了各种判断,来检测用户的试用是否过期了,关键变量rax如果要是为true,那么就不会进第一个if中,而rbx的又是0x0,那到最后rax一定会是0x0,也就是NO了,这个函数返回NO,那么启动时,过期提示框必然不会显示了</p>
<p>于是问题的关键集中在rax的第一次赋值,rax = sub_10009403c();搜索此方法并处理,看到是这样的:</p>
<p><img src="http://imrazor.github.io/images/blog/2014-10-20/function.png" alt="" /></p>
<p>我的汇编水平可以说是战斗力不到5的渣渣,然是还是看出来cmp这行是判断var_8与0x0是不是相等,那么如果三目运算符是真,rbx必然是0xff,rax也必然是真了。看来,只需要将这行的0x0改成0x1即可</p>
<p>使用UltraEdit在16进制下打开源码,找到对应的位置,即内存地址94060这里,然后查看这行对应的16进制编码:</p>
<p><img src="http://imrazor.github.io/images/blog/2014-10-20/intruction.png" alt="" /></p>
<p>找到E8后面的00,改成01,保存后重启Reveal,过期提示就去掉了</p>
<p><img src="http://imrazor.github.io/images/blog/2014-10-20/success.png" alt="" /></p>
<p>因为我也是刚用lldb没多久,汇编又比较渣,如有错误,欢迎大家指正</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[使用lldb调试别人的程序]]></title>
<link href="http://imrazor.github.io/blog/2014/10/14/lldb-debug/"/>
<updated>2014-10-14T23:20:28+08:00</updated>
<id>http://imrazor.github.io/blog/2014/10/14/lldb-debug</id>
<content type="html"><![CDATA[<p>文章翻译自 <a href="http://www.iphonedevwiki.net/index.php/Debugserver">这里</a></p>
<p>这是一篇粗略的翻译文章,只翻译第二种方法</p>
<p>首先我们需要一台越狱的设备,并且安装好了ssh</p>
<p>debugserver是一个用来远程gdb或lld调试的程序,当一个设备被标记为开发设备,那么这个程序会被安装到/Developer/usr/bin/debugserver路径下</p>
<p>debugserver的调用方式为:</p>
<pre><code>debugserver [<options>] host:<port> [<prog-name> <arg1> <arg2> ...]
</code></pre>
<p>你可以在Xcode中找到debugserver,比如挂载/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/ DeviceSupport/7.0.3\ (11B508)/DeveloperDiskImage.dmg后,他的路径为:/Volumes/DeveloperDiskImage/usr/bin/debugserver</p>
<!--more-->
<p>想要用起来debugserver,必须要对他进行签名,我们可以创建一个这样的plist文件:</p>
<pre><code><?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/ PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.springboard.debugapplications</key> <true/>
<key>run-unsigned-code</key>
<true/>
<key>get-task-allow</key> <true/> <key>task_for_pid-allow</key> <true/>
</dict>
</plist>
</code></pre>
<p>然后这样签名:</p>
<pre><code>codesign -s - --entitlements entitlements.plist -f debugserver
</code></pre>
<p>签名后,将debugserver放回到设备的/Developer/usr/bin/debugserver路径下:</p>
<pre><code>scp debugserver [email protected]:/Developer/usr/bin/debugserver
</code></pre>
<p>之后ssh连接设备,在控制台输入:</p>
<pre><code>./debugserver *:1234 -a "YouTube"
</code></pre>
<p>当你看到如下输出时,签名后的debugserver就安装成功了:</p>
<pre><code>My-iPhone-5S:~ root# ./debugserver *:1234 -a "YouTube"
debugserver-300.2 for arm64.
Attaching to process YouTube...
Spawning general listening thread.
Spawning kqueue listening thread.
Listening to port 1234 for a connection from *...
</code></pre>
<p>远程进行lldb会比较慢,我们可以通过USB调试,USB调试需要用到iPhoneTunnel:</p>
<pre><code>wget http://cgit.sukimashita.com/usbmuxd.git/snapshot/usbmuxd-1.0.8.tar.bz2
tar xjfv usbmuxd-1.0.8.tar.bz2
cd usbmuxd-1.0.8/python-client/
python tcprelay.py -t 1234:1234
</code></pre>
<p>之后所有与localhost:1234的连接都会重定向到USB设备的1234端口:</p>
<pre><code>(lldb) process connect connect://localhost:1234
Process 2612 stopped
* thread #1: tid = 0x30d1e, 0x3ba51a84 libsystem_kernel.dylib`mach_msg_trap + 20, queue = 'com.apple.main-thread, stop reason = signal SIGSTOP
frame #0: 0x3ba51a84 libsystem_kernel.dylib`mach_msg_trap + 20
libsystem_kernel.dylib`mach_msg_trap + 20:
-> 0x3ba51a84: pop {r4, r5, r6, r8}
0x3ba51a88: bx lr
libsystem_kernel.dylib`mach_msg_overwrite_trap:
0x3ba51a8c: mov r12, sp
0x3ba51a90: push {r4, r5, r6, r8}
(lldb) po [[UIApplication sharedApplication] delegate]
<YTAppDelegate: 0x15e635a0>
</code></pre>
<p>此时为断点状态,在控制台输入c,即可继续</p>
<p>gdb和lldb的对照在 <a href="http://lldb.llvm.org/lldb-gdb.html">这里</a></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Hand Off初探]]></title>
<link href="http://imrazor.github.io/blog/2014/09/03/hand-off/"/>
<updated>2014-09-03T21:42:01+08:00</updated>
<id>http://imrazor.github.io/blog/2014/09/03/hand-off</id>
<content type="html"><![CDATA[<p>iOS8的一个新功能是hand off,这个功能可以允许用户在多端继续他的某个任务,比如iPhone上写笔记写了一半,到家后使用iPad,从锁屏或后台打开程序自动导航到记笔记界面,并且可以继续刚才的笔记内容写。</p>
<p><img src="http://imrazor.github.io/images/blog/hand_off.png" title="hand off" alt="Alt text" /></p>
<p>Hand off功能要求用户的几个设备有相同的iCloud账号,打开蓝牙。对于开发者,我们的应用必须是在同一个team ID下,程序拥有相同的iCloud container。</p>
<!--more-->
<p>Hand off中一个很重要的类就是NSUserActivity,通过这个类的对象,我们可以把A设备当前的活动传给B设备。</p>
<p>这个类有着非常简单易用的API,分别为创建、对流的支持、activity数据及activity的传送。下面的代码就创建了一个NSUserActivity:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'> <span class="n">self</span><span class="p">.</span><span class="n">activity</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSUserActivity</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithActivityType:</span><span class="s">@"io.github.volcan1987.test"</span><span class="p">];</span>
</span><span class='line'> <span class="n">self</span><span class="p">.</span><span class="n">activity</span><span class="p">.</span><span class="n">delegate</span> <span class="o">=</span> <span class="n">self</span><span class="p">;</span>
</span><span class='line'> <span class="n">self</span><span class="p">.</span><span class="n">activity</span><span class="p">.</span><span class="n">webpageURL</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSURL</span> <span class="nl">URLWithString:</span><span class="s">@"http://www.baidu.com"</span><span class="p">];</span>
</span><span class='line'> <span class="n">self</span><span class="p">.</span><span class="n">activity</span><span class="p">.</span><span class="n">userInfo</span> <span class="o">=</span> <span class="err">@</span><span class="p">{</span><span class="s">@"data"</span><span class="o">:</span><span class="n">textField</span><span class="p">.</span><span class="n">text</span><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<p>对象创建好后,让我们调用[self.activity becomeCurrent];的时候,如果另一个设备安装了响应此activity的App,那么另一台设备的锁屏下或是后台就会显示这个程序的图标,否则就会显示safari的图标(因为我们指定了webpageURL)</p>
<p>如果要让App响应对应的activity,需要在AppDelegate里实现如下方法:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="k">-</span> <span class="p">(</span><span class="kt">BOOL</span><span class="p">)</span><span class="nf">application:</span><span class="p">(</span><span class="n">UIApplication</span> <span class="o">*</span><span class="p">)</span><span class="nv">application</span>
</span><span class='line'><span class="nf">continueUserActivity:</span> <span class="p">(</span><span class="n">NSUserActivity</span> <span class="o">*</span><span class="p">)</span><span class="nv">userActivity</span>
</span><span class='line'> <span class="nf">restorationHandler:</span> <span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">))</span><span class="nv">restorationHandler</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'> <span class="kt">BOOL</span> <span class="n">handled</span> <span class="o">=</span> <span class="n">NO</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// Extract the payload</span>
</span><span class='line'> <span class="n">NSString</span> <span class="o">*</span><span class="n">type</span> <span class="o">=</span> <span class="p">[</span><span class="n">userActivity</span> <span class="n">activityType</span><span class="p">];</span>
</span><span class='line'> <span class="n">NSString</span> <span class="o">*</span><span class="n">title</span> <span class="o">=</span> <span class="p">[</span><span class="n">userActivity</span> <span class="n">title</span><span class="p">];</span>
</span><span class='line'> <span class="n">NSDictionary</span> <span class="o">*</span><span class="n">userInfo</span> <span class="o">=</span> <span class="p">[</span><span class="n">userActivity</span> <span class="n">userInfo</span><span class="p">];</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// Assume the app delegate has a text field to display the activity information</span>
</span><span class='line'> <span class="n">NSLog</span><span class="p">(</span><span class="s">@"User activity is of type %@, has title %@, and user info %@"</span><span class="p">,</span> <span class="n">type</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">userInfo</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="n">restorationHandler</span><span class="p">(</span><span class="err">@</span><span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">window</span><span class="p">.</span><span class="n">rootViewController</span><span class="p">]);</span>
</span><span class='line'>
</span><span class='line'> <span class="n">handled</span> <span class="o">=</span> <span class="n">YES</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="n">handled</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>其中restorationHandler参数中的对象应该实现restoreUserActivityState:这个方法来进行后续的动作,在这里,我的root view controller只是简单的将数据显示出来</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">restoreUserActivityState:</span><span class="p">(</span><span class="n">NSUserActivity</span> <span class="o">*</span><span class="p">)</span><span class="nv">activity</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'> <span class="n">self</span><span class="p">.</span><span class="n">field</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="n">activity</span><span class="p">.</span><span class="n">userInfo</span><span class="p">[</span><span class="s">@"data"</span><span class="p">];</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>到此,一次完整的activity交互就完成了。通过观察,数据的交互应该是通过蓝牙传输的。本文的demo可以在 <a href="https://github.com/volcan1987/HandOffDemo">这里</a> 找到</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[KMP模式匹配算法]]></title>
<link href="http://imrazor.github.io/blog/2014/07/02/kmp/"/>
<updated>2014-07-02T23:27:32+08:00</updated>
<id>http://imrazor.github.io/blog/2014/07/02/kmp</id>
<content type="html"><![CDATA[<p>在写程序时,我们常常会用到从一个字符串找出子串的位置。</p>
<p>比如,在某个句子快速找到某个你感兴趣的词:“csscsdn”中找到csdn</p>
<p>以下是查找算法,注意:下标为1代表第一个位置,以此类推,跟数组不同</p>
<p>一、朴素模式匹配
朴素模式匹配是从第一个字符开始,依次向后匹配,这里我们假设游标起始点为1</p>
<pre><code>c s s c s d n
| | ?
c s d n
</code></pre>
<p>当i(主串的游标) = 3,j(子串的游标) = 3时,字符出现了不等,于是i回到2,j回到1</p>
<pre><code>c s s c s d n
?
c s d n
</code></pre>
<!-- more -->
<p>直到</p>
<pre><code>c s s c s d n
| | | |
c s d n
</code></pre>
<p>朴素模式匹配最大的问题就是i值回溯,如果碰到当子串的前面都与主串匹配,只有最后一个字符不同,而这个子串又在主串的末尾时,j值会每次遍历整个字串,i值会每次回溯
000…共n个0…0001
0…共m个0…01
当出现上面的情况时,会发生最坏的情况,此时时间复杂度为O((n-m+1)*m)</p>
<p>二、KMP算法
后来有三位前辈(Knuth、Pratt和Morris)发布了一个大大避免重复遍历的算法,简称KMP算法
1、</p>
<pre><code>c s d c s d n
?
c s d n
</code></pre>
<p>2、</p>
<pre><code>c s d c s d n
?
c s d n
</code></pre>
<p>3、</p>
<pre><code>c s d c s d n
?
c s d n
</code></pre>
<p>可以看到,其实2和3步骤完全是没有必要的,因为在第一次比较时csd都是一样的,所以主串中的第一个s必然不等于字串的c,主串中的第一个d也必然不等于子串中的c</p>
<p>再看另一种情况
1、</p>
<pre><code>c s c s c s b n
?
c s c s d n
</code></pre>
<p>2、</p>
<pre><code>c s c s c s b n
?
c s c s d n
</code></pre>
<p>3、</p>
<pre><code>c s c s c s b n
|
c s c s d n
</code></pre>
<p>4、</p>
<pre><code>c s c s c s b n
| |
c s c s d n
</code></pre>
<p>5、</p>
<pre><code>c s c s c s b n
| | |
c s c s d n
</code></pre>
<p>6、</p>
<pre><code>c s c s c s b n
| | | | |
c s c s d n
</code></pre>
<p>7、</p>
<pre><code>c s c s c s b n
| | | | | ?
c s c s d n
</code></pre>
<p>可以看出,2、3、4步是没有必要的,2步没必要跟上面的情况一致,而3、4没必要,是因为子串在1中已经知道前4个字符都与主串是一样的了,既然即主串中第三和第四个位置上的字符与子串第三和第四个位置上的字符是一样的,而子串第三和第四个位置上的字符又与子串第一和第二个位置上的字符一样,那子串中第一和第二个位置上的字符必然与主串中第三和第四个位置上的字符一样,所以是不需要3、4步骤的</p>
<p>综上,我们可以总结出两点:1、主串中的i是不需要回溯的,子串中的j需要回溯;2、子串中的j回溯的位置,跟子串字符的重复有关系</p>
<p>接下来,我们需要找出子串字符的重复关系,通过上面c s c s c s b n与 c s c s d n的查找,我们可以看到,如果省略步骤3和4,当i = 5时,是与j = 3的字符来比较的,</p>
<p>我们把子串j值的变化用一个next数组来表示:
j: 1 2 3 4 5 6
T: c s c s d n
next: 0 1 1 2 3 1
下面来说说为什么这么表示,首先,next[1] = 0,是为了简化判断,这个我们稍后再说;然后看next[5] = 3,之所以等于3,是因为在j = 5不匹配时,我们无需让j回溯到1,只需要回溯到3即可,因为T[1] = T[3],T[2] = T[4],可以推出next[j] = max{k|1<k<j, 且’p->1…p->k-1 = ‘p->j-k+1…p->j-1’}(当此集合不为空的时候,这里->代表下标),实际上,k就是子串开头字符重复的个数加1</p>
<p>next数组的生成代码,注意:T[0]表示子串的长度:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="kt">void</span> <span class="nf">get_next</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">T</span><span class="p">,</span> <span class="kt">int</span> <span class="o">*</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="kt">int</span> <span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">;</span>
</span><span class='line'> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'> <span class="n">next</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'> <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o"><</span> <span class="n">T</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="n">j</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">T</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">T</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'> <span class="o">++</span><span class="n">i</span><span class="p">;</span>
</span><span class='line'> <span class="o">++</span><span class="n">j</span><span class="p">;</span>
</span><span class='line'> <span class="n">next</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'> <span class="n">j</span> <span class="o">=</span> <span class="n">next</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>有了next数组,KMP实现代码就出来了,注意:T[0]表示子串的长度,S[0]表示主串的长度:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="kt">int</span> <span class="nf">index_KMP</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">S</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">T</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pos</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">pos</span><span class="p">;</span>
</span><span class='line'> <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'> <span class="kt">int</span> <span class="n">next</span><span class="p">[</span><span class="mi">255</span><span class="p">];</span>
</span><span class='line'>
</span><span class='line'> <span class="n">get_next</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o"><=</span> <span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&&</span> <span class="n">j</span> <span class="o"><=</span> <span class="n">T</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="n">j</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">T</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'> <span class="o">++</span><span class="n">i</span><span class="p">;</span>
</span><span class='line'> <span class="o">++</span><span class="n">j</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'> <span class="n">j</span> <span class="o">=</span> <span class="n">next</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="n">j</span> <span class="o">></span> <span class="n">T</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span><span class='line'> <span class="k">return</span> <span class="n">i</span> <span class="o">-</span> <span class="n">T</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>现在我们看到next[1]为0可以简化判断j是否回溯到开头的代码,并且方便的实现从j=1开始向后匹配,这个算法还是有点问题,比如当子串为aaaab情况时,会有重复向前匹配的情况,因为此时next数组为01234,如果主串S[i] != T[4]时,j值依次回溯,可是前四个都是完全一样的字符,所以j值的回溯是没有必要的</p>
<p>也就是说,在满足上一篇next数组的条件下,当子串有字符重复时,它所对应的next数组中的值只需要与它第一次出现时的在next数组中记录的值一样即可,比如,对于一个子串’a’, ‘b’, ‘a’, ‘b’, ‘a’, ‘c’, ‘c’, ‘a’, ‘c’,改进后的next数组应该为010104102</p>
<p>新的next数组生成代码:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="kt">void</span> <span class="nf">get_nextval</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">T</span><span class="p">,</span> <span class="kt">int</span> <span class="o">*</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="kt">int</span> <span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">;</span>
</span><span class='line'> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'> <span class="n">next</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'> <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o"><</span> <span class="n">T</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="n">j</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">T</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">T</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'> <span class="o">++</span><span class="n">i</span><span class="p">;</span>
</span><span class='line'> <span class="o">++</span><span class="n">j</span><span class="p">;</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="n">T</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="n">T</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'> <span class="n">next</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'> <span class="n">next</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">next</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'> <span class="n">j</span> <span class="o">=</span> <span class="n">next</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>KMP代码只需把get_next(T, next);替换成get_nextval(T, next);</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[分析微信来优化自己的应用]]></title>
<link href="http://imrazor.github.io/blog/2014/06/17/optimize-app-by-analyze-weixin/"/>
<updated>2014-06-17T20:23:04+08:00</updated>
<id>http://imrazor.github.io/blog/2014/06/17/optimize-app-by-analyze-weixin</id>
<content type="html"><![CDATA[<p>文章内容仅供学习交流,如有不妥,请联系我删除:)</p>
<p>用到的工具:Reveal,Charles,Hopper,越狱设备</p>
<p>流畅的列表滑动可以很大的提升用户体验,尽量减少程序控制的透明色(GPU发现某层是不透明的,就不会计算它下面的层来显示了)和阴影都能提升UITableView滑动的流畅性。实时计算的圆角(CALayer的cornerRadius)也会加重GPU的运算,可是我们的程序经常会遇到需要用圆角的情况,所以如何高效的进行圆角显示就变得非常重要。</p>
<p>Stack Overflow上也有一些优化的方案,比如让设计师提供带圆角,内部是透明色的图片;或者直接在服务器生成圆角图片等等。第一种方案不”优雅”,并且依然有透明色,第二种方案太死板,并且需服务端的支持。</p>
<p>看到微信的聊天列表页也有头像是圆角,服务号头像是圆形,通讯录又没有圆角,而且滑动也很流畅,很好奇微信是如何实现的,于是打算使用工具分析一下。</p>
<!--more-->
<p>首先在越狱设备上安装微信,将Reveal的framework和dylib分别copy到越狱机的:/System/Library/Frameworks和:/Library/MobileSubstrate/DynamicLibrarie下,重启设备。之后可以看到微信的布局了</p>
<p><img src="http://imrazor.github.io/images/blog/2014-6-17/reveal.png" title="weixin_layout" alt="Alt text" /></p>
<p>通过Reveal我们看到微信头像是通过一个叫MainFrameHeadView展示的,那让我们看一下MainFrameHeadView大概是如何实现的,将微信的二进制文件拖到Hopper中,等待分析完成。</p>
<p>分析完成后,搜索MainFrameHeadView</p>
<p><img src="http://imrazor.github.io/images/blog/2014-6-17/hopper.png" title="weixin_xxview" alt="Alt text" /></p>
<p>在这个类的代码段中,发现关键字CHeadImageMgr的getRoundImage:size:conerSize:forSence:方法,看其方法名就大概猜到是其对图片进行了圆角处理、或者是获取经过圆角处理的图片了。继续搜索CHeadImageMgr</p>
<p><img src="http://imrazor.github.io/images/blog/2014-6-17/c_head_m.png" title="weixin_cheadm" alt="Alt text" /></p>
<p>看到此类基本就是对头像进行了各种各样的处理。通过Charles抓包,发现圆形头像实际是服务器生成好的</p>
<p><img src="http://imrazor.github.io/images/blog/2014-6-17/charles.png" title="weixin_circle" alt="Alt text" /></p>
<p>至此,我们大概知道,微信中对话列表的用户头像圆角是本地生成的。原始头像下载好后,很可能立刻进行图片处理,保留不带圆角和带圆角的头像并进行本地持久化。以后圆角头像如果再次用到,就先走内存缓存,内存没有检查本地,本地没有再从网络获取(类似SDWebImage,只不过多了一步下载完成后进行了图片处理)。</p>
<p>本地缓存的圆角图片,跟背景颜色相同的UILabel,再加上不复杂的UI逻辑,你的UITableView也能像微信的对话列表一样流畅。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Cocos2d中的box2d]]></title>
<link href="http://imrazor.github.io/blog/2014/05/07/box2d-of-cocos2d/"/>
<updated>2014-05-07T07:49:49+08:00</updated>
<id>http://imrazor.github.io/blog/2014/05/07/box2d-of-cocos2d</id>
<content type="html"><![CDATA[<p>一、准备工作<br />
引入box2d包,在需要使用box2d的文件中加入box2d的头文件;由于box2d是c++编写的,所以要把引入box2d的所有文件后缀名都改为.mm</p>
<p>二、box2d中的一些重要参数<br />
1、gravity,重力加速度,同现实世界中的g,向量<br />
2、shape,形状,形状是有大小的<br />
3、density,密度<br />
4、friction,摩擦力<br />
5、restitution,恢复,此参数用于碰撞,如果两个物体有不同的restitution,box2d总是选择比较大的restitution进行计算<br />
6、meter,距离单位,灵活定义你的meter,当对象为0.1至10meters的时候,box2d可以很好的处理它们,</p>
<p>三、box2d之hello world<br />
让我们先创建一个box2d项目。创建好之后运行,每当我们点击屏幕时,会落下一个小方块:</p>
<p><img src="http://imrazor.github.io/images/blog/1343575297_7773.png" title="helloworld" alt="Alt text" /></p>
<!--more-->
<p>我们来详细看下生成的代码:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>