-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathatom.xml
More file actions
790 lines (550 loc) · 29.9 KB
/
Copy pathatom.xml
File metadata and controls
790 lines (550 loc) · 29.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[北武灵尊]]></title>
<link href="http://lingzuer.github.io/atom.xml" rel="self"/>
<link href="http://lingzuer.github.io/"/>
<updated>2015-02-13T10:19:22+08:00</updated>
<id>http://lingzuer.github.io/</id>
<author>
<name><![CDATA[lingzuer]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[易信年会]]></title>
<link href="http://lingzuer.github.io/blog/2015/02/06/yi-xin-nian-hui/"/>
<updated>2015-02-06T23:23:04+08:00</updated>
<id>http://lingzuer.github.io/blog/2015/02/06/yi-xin-nian-hui</id>
<content type="html"><![CDATA[<p>易信年会收获:</p>
<p>1、能不能再多做一点</p>
<p>2、三等奖净水器</p>
<p>不好的:</p>
<p>家里已经安装了净水器</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[ALAssetsLibrary选择图片优化]]></title>
<link href="http://lingzuer.github.io/blog/2015/02/05/alassetslibraryxuan-ze-tu-pian-you-hua/"/>
<updated>2015-02-05T14:17:52+08:00</updated>
<id>http://lingzuer.github.io/blog/2015/02/05/alassetslibraryxuan-ze-tu-pian-you-hua</id>
<content type="html"><![CDATA[<p>背景:</p>
<p>老板的手机iphone 6 plus有5000+张相片,每次选择相片的时候需要长时间的loading,不能忍受。</p>
<p>排查问题:</p>
<p>打log排查到最耗时的地方是枚举相片的时候,调用的方法是:</p>
<pre><code>- (void)enumerateAssetsUsingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock;
</code></pre>
<p>这个在1000张左右的时候还算OK,但是相片多的时候就耗时了。</p>
<p>然后分析了微信、Lofter、QQ和易信,大概时间是这样的:</p>
<p>环境:iphone6+,相片6000张</p>
<p>微信:1秒</p>
<p>Lofter:1秒</p>
<p>QQ:秒开(无loading)</p>
<p>易信:4秒</p>
<p>注意我说的是大概感受的时间。</p>
<p>这一对比就不淡定了,通过查资料,最后决定使用方案:</p>
<pre><code>- (void)enumerateAssetsAtIndexes:(NSIndexSet *)indexSet options:(NSEnumerationOptions)options usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock;
</code></pre>
<p>对,其实就是换了一个方法,哈哈,那思路就完全不一样了,之前是枚举出了所有的图片,保存到内存中,后面都使用这个数组,这样,开始的时候就比较耗时,后面使用的时候倒是很爽,之后呢,是通过IndexSet方法配合Table的cellForRow,产看那个加载那个,一张张加载,是不是很爽。</p>
<p>换了新方法后,我也把loading给拿掉了,表现能达到QQ。</p>
<p>然后问题来了,预览大图的时候怎么处理?预览大图还要排除掉视频,怎么保证顺序和currentIndex?</p>
<p>又拿QQ和微信做了分析,发现:</p>
<p>QQ点击相片的时候是[选中]操作,最下面的“预览”按钮是预览所有选中的相片。</p>
<p>微信点击相片是预览大图,在预览大图的时候可以选中该相片。</p>
<p>我个人觉得QQ是很合理,策划说微信的交互比较方便,那挑战就来了,在我们的速度达到QQ以后,交互还要达到微信。</p>
<p>难点:</p>
<p>1、点击其中一个相片预览大图,大图可以左右滑动查看所有相片。</p>
<p>2、预览大图左右滑动的时候需要把视频过滤掉。</p>
<p>分析:</p>
<p>1、在显示相片列表的时候已经枚举了这一屏所显示的20几张相片,点击其中任何一个相片,预览大图都没有问题,那么滑动的时候我们再动态枚举后面的相片,就OK了吧。</p>
<p>2、动态枚举后面的相片时,过滤掉视频,然后再排序,然后再定位当前相片在新的数组中的index就好了,这个地方牵扯出了一个新的难点:动态枚举出新的相片产生新的数组后,什么时候更新PageView呢?</p>
<p>解决新的难题:</p>
<p>滑动预览时,预加载到index==0(PageView只显示三个图片,会预加载提前一个图片)的时候,我们通过IndexSet预加载接下来的20(自己定义)张相片,然后过滤掉视频,并且从新排序,把新取到的数组先放着,等到用户不滑动的时候更新PageView,重新定位currentIndex值。</p>
<p>后续:</p>
<p>1、继续重构、优化;</p>
<p>2、提供Demo</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[AssetsLibrary自定义图片选择器]]></title>
<link href="http://lingzuer.github.io/blog/2015/02/02/assetslibraryzi-ding-yi-tu-pian-xuan-ze-qi/"/>
<updated>2015-02-02T22:55:30+08:00</updated>
<id>http://lingzuer.github.io/blog/2015/02/02/assetslibraryzi-ding-yi-tu-pian-xuan-ze-qi</id>
<content type="html"><![CDATA[<p>1、ALAssetsLibraryAccessor单例</p>
<p>ALAssetsLibraryAccessor.h</p>
<pre><code>#import <Foundation/Foundation.h>
@class ALAssetsLibrary;
@interface ALAssetsLibraryAccessor : NSObject {
ALAssetsLibrary *assetsLibrary_;
}
+ (ALAssetsLibraryAccessor *)sharedInstance;
- (ALAssetsLibrary *)assetsLibrary;
- (void)refreshAssetsLibrary;
@end
</code></pre>
<p>ALAssetsLibraryAccessor.m</p>
<pre><code>#import "ALAssetsLibraryAccessor.h"
#import <AssetsLibrary/AssetsLibrary.h>
@implementation ALAssetsLibraryAccessor
- (id)init {
self = [super init];
if (self) {
assetsLibrary_ = [[ALAssetsLibrary alloc] init];
}
return self;
}
+ (ALAssetsLibraryAccessor *)sharedInstance
{
static ALAssetsLibraryAccessor *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[ALAssetsLibraryAccessor alloc] init];
});
return sharedInstance;
}
- (ALAssetsLibrary *)assetsLibrary {
return assetsLibrary_;
}
- (void)refreshAssetsLibrary {
assetsLibrary_ = nil;
assetsLibrary_ = [[ALAssetsLibrary alloc] init];
}
@end
</code></pre>
<p>2、ALAssetHelper获取AlAsset图片</p>
<p>ALAssetHelper.h</p>
<pre><code>#import <Foundation/Foundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
@interface ALAssetHelper : NSObject
+ (UIImage *)getImage:(ALAsset *)asset original:(BOOL)original;
@end
</code></pre>
<p>ALAssetHelper.m</p>
<pre><code>#import "ALAssetHelper.h"
@implementation ALAssetHelper
+ (UIImage *)getImage:(ALAsset *)asset original:(BOOL)original
{
UIImage *image = nil;
CGImageRef ref = nil;
ALAssetRepresentation *rep = [asset defaultRepresentation];
if (original) {
// 获取ios剪裁后的图片
NSData *xmpData = rep.metadata[@"AdjustmentXMP"];
if (xmpData != nil) {
ref = [rep fullScreenImage];
image = [UIImage imageWithCGImage:ref];
} else {
ref = [rep fullResolutionImage];
image = [UIImage imageWithCGImage:ref
scale:[rep scale]
orientation:(UIImageOrientation)[rep orientation]];
}
} else {
ref = [rep fullScreenImage];
image = [UIImage imageWithCGImage:ref];
}
return image;
}
@end
</code></pre>
<p>3、枚举相册</p>
<pre><code>- (void)enumerateAssetsGroups {
self.assetGroups = [NSMutableArray arrayWithCapacity:0];
ALAssetsLibrary *library = [[ALAssetsLibraryAccessor sharedInstance] assetsLibrary];
// Load Albums into assetGroups
dispatch_async(dispatch_get_main_queue(), ^{
@autoreleasepool {
// Group enumerator Block
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop)
{
if (group) {
[self.assetGroups addObject:group];
} else {
// group is nil, so there are no more groups to enumerate
}
};
// Group Enumerator Failure Block
void (^assetGroupEnumberatorFailure)(NSError *) = ^(NSError *error) {
if (error.code == ALAssetsLibraryAccessUserDeniedError ||
error.code == ALAssetsLibraryAccessGloballyDeniedError) {
// Denied Error
}
};
// Enumerate Albums
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock:assetGroupEnumberatorFailure];
}
});
}
</code></pre>
<p>4、枚举相片</p>
<pre><code>- (void)enumerateAssets:(ALAssetsGroup *)assetGroup {
NSMutableArray *assets = [NSMutableArray arrayWithCapacity:0];
ALAssetsGroupEnumerationResultsBlock groupEnumeration = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result) {
[assets addObject:result];
} else {
//
}
};
[assetGroup enumerateAssetsUsingBlock:groupEnumeration];
}
</code></pre>
<p>枚举相片的三个方法:</p>
<pre><code>// These methods are used to retrieve the assets that match the filter.
// The caller can specify which results are returned using an NSIndexSet. The index set's count or lastIndex cannot exceed -numberOfAssets.
// 'enumerationBlock' is used to pass back results to the caller and provide the opportunity to stop the filter.
// When the enumeration is done, 'enumerationBlock' will be called with result set to nil and index set to NSNotFound.
// If the application has not been granted access to the data, 'enumerationBlock' will be called with result set to nil, index set to NSNotFound, and stop set to YES.
- (void)enumerateAssetsUsingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock;
- (void)enumerateAssetsWithOptions:(NSEnumerationOptions)options usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock;
- (void)enumerateAssetsAtIndexes:(NSIndexSet *)indexSet options:(NSEnumerationOptions)options usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock;
</code></pre>
<p>提问:</p>
<p>如何发送一个ALAsset对象的视频?</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[常用工具]]></title>
<link href="http://lingzuer.github.io/blog/2015/02/01/chang-yong-gong-ju/"/>
<updated>2015-02-01T22:41:28+08:00</updated>
<id>http://lingzuer.github.io/blog/2015/02/01/chang-yong-gong-ju</id>
<content type="html"><![CDATA[<p>1、Unused</p>
<p>网址:<a href="https://github.com/jeffhodnett/Unused">https://github.com/jeffhodnett/Unused</a></p>
<p>优点:找到相同图片可以预览</p>
<p>缺点:</p>
<p>①没有考虑@3x图片(作者好像不维护了);</p>
<p>②没有排除某个文件夹下面的图片不过滤,导致查找时间较长;</p>
<p>不过这两点都可以自己试着改掉。</p>
<p>使用感受:</p>
<p>需求做完,bug改完,后可以试着跑一下。用处不是很大,该功能下面这个工具也有。主要是以前没有看到过这种用Xcode开发Mac上使用的小工具,比较新奇,玩一下。</p>
<p>2、FauxPas</p>
<p>网址:<a href="http://fauxpasapp.com">http://fauxpasapp.com</a></p>
<p>102 rules: <a href="http://fauxpasapp.com/rules/">http://fauxpasapp.com/rules/</a></p>
<p>这个工具不多说了,直接看官网,是我目前发现比较好用的工具,一是可以帮助我找到项目中写的不好的代码,还有一些建议,二是可以通过这些建议对照想要的代码深入学习理解OC。</p>
<p>使用FauxPas后我的思考和困惑:</p>
<p>1、这样的优化意义大不大?</p>
<p>2、怎么才能让真个团队都提高这种写代码的素质?</p>
<p>3、可以有什么新的产出么?比如做一个Web的分析平台?</p>
<p>之前写的时候<a href="http://mouapp.com">Mou</a>奔溃了,只截了一张图片</p>
<p><img src="http://lingzuer.github.io/images/blog/used-tools.png" alt="How" /></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[XCTest测试属性变化]]></title>
<link href="http://lingzuer.github.io/blog/2015/01/31/xctestce-shi-shu-xing-bian-hua/"/>
<updated>2015-01-31T21:01:07+08:00</updated>
<id>http://lingzuer.github.io/blog/2015/01/31/xctestce-shi-shu-xing-bian-hua</id>
<content type="html"><![CDATA[<p>之前有一篇写XCTest异步测试,现在写一下对属性值变化的测试。比如设置某个属性的值,然后调用了某个方法后,值的变化是不是我们预期得到的。下面的代码是作者jtang写的,我修改了一句以适应ARC模式。</p>
<p>1、创建一个NSObject的扩展类(Category)</p>
<p>NSObject+Properties.h</p>
<pre><code>#import <Foundation/Foundation.h>
@interface NSObject (Properties)
// 仅可用于单元测试 ivarName是成员变量名字,不是属性名字
// 对于对象直接返回,如果是原始数据类型.返回NSValue
// 示例:
// NSValue *value = [self getIvarFromString_ONLY_USE_IN_UNIT_TEST:@"_test"];
// int x;
// [value getValue:&x];
- (id)getIvarFromString_ONLY_USE_IN_UNIT_TEST:(NSString *)ivarName;
@end
</code></pre>
<p>NSObject+Properties.m</p>
<pre><code>#import "NSObject+Properties.h"
#import <objc/runtime.h>
@implementation NSObject (Properties)
- (id)getIvarFromString_ONLY_USE_IN_UNIT_TEST:(NSString *)ivarName
{
Ivar ivar = class_getInstanceVariable(self.class, [ivarName UTF8String]);
// Ivar ivar = object_getInstanceVariable(self, [ivarName UTF8String], NULL);
if (ivar)
{
id ivarID = object_getIvar(self, ivar);
const char *typeEncoding = ivar_getTypeEncoding(ivar);
if (typeEncoding[0] == '@')
{
return ivarID;
}
else
{
return [NSValue valueWithBytes:&ivarID objCType:typeEncoding];
}
}
return nil;
}
@end
</code></pre>
<p>2、用法举例</p>
<p>ViewController.h</p>
<pre><code>#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
- (void)test;
@end
</code></pre>
<p>ViewController.m</p>
<pre><code>#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSString *userName;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_userName = @"abc";
}
- (void)test {
_userName = @"def";
}
@end
</code></pre>
<p>测试文件MyAppTests.m</p>
<pre><code>#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "ViewController.h"
#import "NSObject+Properties.h"
@interface MyAppTests : XCTestCase {
// add instance variables to the CalcTests class
ViewController *viewController;
}
@end
@implementation MyAppTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
viewController = [[ViewController alloc] init];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testUserName {
[viewController test];
NSString *userName = (NSString *)[viewController getIvarFromString_ONLY_USE_IN_UNIT_TEST:@"_userName"];
XCTAssertEqualObjects(userName, @"def", @"Sussess");
}
@end
</code></pre>
<p>3、测试UI变化</p>
<pre><code>#import "TestSettingPickerCell_UI.h"
#import "SettingPickerCell.h"
#import "NSObject+Properties.h"
@implementation TestSettingPickerCell_UI
{
SettingPickerCell *cell;
}
- (void)testsetCheckMarkYES
{
UIImageView *checkImageView = [cell getIvarFromString_ONLY_USE_IN_UNIT_TEST:@"_mCheckImageView"];
[cell setCheckMark:YES];
STAssertEquals(checkImageView.image, [UIImage imageNamed:@"selected_green.png"],@"");
}
- (void)testsetCheckMarNO
{
UIImageView *checkImageView = [cell getIvarFromString_ONLY_USE_IN_UNIT_TEST:@"_mCheckImageView"];
[cell setCheckMark:NO];
STAssertEquals(checkImageView.image, [UIImage imageNamed:@"CellUnchecked.png"],@"");
}
- (void)setUp
{
[super setUp];
cell = [[SettingPickerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
- (void)tearDown
{
[super tearDown];
}
@end
</code></pre>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[积累的脚本]]></title>
<link href="http://lingzuer.github.io/blog/2015/01/30/ji-lei-de-jiao-ben/"/>
<updated>2015-01-30T22:06:38+08:00</updated>
<id>http://lingzuer.github.io/blog/2015/01/30/ji-lei-de-jiao-ben</id>
<content type="html"><![CDATA[<p>自己常用的一些脚本,批量查找、替换、删除。</p>
<p>1、复制一个文件夹下的文件到另外一个文件夹下</p>
<pre><code>cp -ri bar/ foo/
</code></pre>
<p>2、删除文件夹下的文件</p>
<pre><code>rm -rf /images/image*
</code></pre>
<p>3、在文件中查找关键字并替换</p>
<pre><code>grep -rl "2013 - 浙ICP备" * | xargs sed -i -e 's/2013 - 浙ICP备/2013-2014 - 浙ICP备/g'
</code></pre>
<p>4、查找文件夹下的文件是否包含某个关键字</p>
<pre><code>find src/ -name *.html |xargs grep -rn "火影"
find classes/ -name '*.xib' -o -name '*.mm' -o -name '*.m' |xargs grep -rl "bg_picker_white_cell"
find src/ -name *.js |xargs grep -rn "__dirty__"
</code></pre>
<p>5、批量替换的脚本</p>
<pre><code>#!/bin/sh
#批量替换文案
oldString='<a target="_blank" href="http://yixin.im/contact.html">联系我们</a>'
newString='<a target="_blank" href="http://yixin.im/contact.html">联系我们</a> - <a target="_blank" href="http://yixin.im/contact.html">扫黄打非·净网2014</a>'
grep -rl $oldString *.html | xargs sed -i -e "s#$oldString#$newString#g"
</code></pre>
<p>6、删除example文件所有包含test的行</p>
<pre><code>sed '/test/d' example
</code></pre>
<p>7、删除文件夹下文件中还有console.log的行,并且删除Sublime Text产生的-e结尾的文件</p>
<pre><code>find html/ -name *.html -o -name *.js | xargs sed -i -e '/console.log/d'
find javascript/ -name *.html -o -name *.js | xargs sed -i -e '/console.log/d'
find src/ -name "*.html-e" -o -name "*.js-e" | xargs rm -f
</code></pre>
<p>这个脚本的产生是有个缘由的,一个有奖(大奖有iPhone6 plus)的活动页面,查看页面源代码的时候,虽然js代码经过了压缩并混淆,但是文件中的console.log中写的中文都显示出来了,要命的是,console.log中把每一个步骤及逻辑都写在里面了。幸亏是在公司内测的时候发现的问题。</p>
<p><img src="http://lingzuer.github.io/images/blog/console-log-1.jpg" alt="console log" /></p>
<p><img src="http://lingzuer.github.io/images/blog/console-log-2.jpg" alt="console log" /></p>
<p>然后我就想怎么把所有的console.log干掉,然后再压缩混淆,于是就有了这个脚本。但是问题来了,console.log在本地调试的时候还是有用的(Native+Web的方式,<a href="https://www.npmjs.com/package/weinre">weinre</a>调试方便一点),总不能先运行脚本删掉,然后等打包发布完了,再revert回来吧,于是就想,能不能在打包脚本里面加上去掉console.log的功能呢,正好看了一下公司的打包脚本是<a href="https://github.com/mishoo/UglifyJS2">Uglifyjs2</a>,继续上网查找资料的时候,发现Uglifyjs2有去掉console.log的配置项,drop_console: true,然后联系了NEJ作者genify,大牛百忙中加上了这个<a href="https://github.com/genify/toolkit/commit/39e6faaae26e2f6efc744bfd79278a00e65bd729">配置</a>,工程在这里<a href="https://github.com/genify/toolkit">https://github.com/genify/toolkit</a>,顺利打包。</p>
<p>8、find的时候排除某个文件夹</p>
<p>文件结构:</p>
<pre><code>Demo
| ——— First
| ——— One
| ——— index.html
| ——— Second
| ——— index.html
| ——— index.html
</code></pre>
<p>1)、在Demo文件夹下查找index.html,排除Second文件夹</p>
<pre><code>find . -path './Second' -prune -o -name '*.html' -print
</code></pre>
<p>2)、在Demo文件夹下查找index.html,排除One文件夹</p>
<pre><code>find . -path './First/One' -prune -o -name '*.html' -print
</code></pre>
<p>3)、-prune对前面求值,-print不能少</p>
<p>这个脚本有什么具体的使用呢?这是我后来看到<a href="https://github.com/jeffhodnett/Unused">Unused</a>的时候想到的,这个项目有个问题,一是没有处理@3x的图片,作者很久都没有更新过了,另外一个就是跑出来的结果中,有个文件夹下面是我不想让它去检索的,比如存放Emoji表情的文件夹,那我就想,能不能也提供个输入框,用来选择要过滤的某个文件夹呢,然后一番尝试,还真成功了,哈哈,起作用的主要代码如下:</p>
<pre><code>// Create a find task
NSTask *task = [[[NSTask alloc] init] autorelease];
[task setLaunchPath: @"/usr/bin/find"];
// Search for all png files
NSArray *argvals = nil;
if (filterDirectoryPath.length <= 0) {
argvals = [NSArray arrayWithObjects:directoryPath, @"-name", @"*.png", nil];
} else {
argvals = [NSArray arrayWithObjects:directoryPath,
@"-path", filterDirectoryPath, @"-prune", @"-o", @"-name", @"*.png", @"-print", nil];
}
[task setArguments: argvals];
</code></pre>
<p>这是过滤了一个文件夹,要是过滤好几个呢,那就是:</p>
<pre><code>find ./ \( -path './dir0*' -o -path './dir1*' \) -a -prune -o -name '*.png' -print
</code></pre>
<p>对这个开源项目改造了一下,试跑了一下易信的工程,运行时间大大减少,并且还找出了好几个没有用到的图片资源,减少了好几十个kb呢,也算是安慰了一下这颗折腾的心吧。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[XCTest单元测试]]></title>
<link href="http://lingzuer.github.io/blog/2015/01/29/xctestdan-yuan-ce-shi/"/>
<updated>2015-01-29T22:14:13+08:00</updated>
<id>http://lingzuer.github.io/blog/2015/01/29/xctestdan-yuan-ce-shi</id>
<content type="html"><![CDATA[<p>QA的同事说帮他们讲一下OC,我自己都是个搓鸟,还给别人讲,就当是玩笑拒绝了,那么多大牛都在,找我讲?后来又说让我讲,是认真的,那我想,反正他们也不会,忽悠一下他们还是OK的了,简单的写个Hello World还是不成问题的,于是就去讲了,讲到后来才明白他们想的最终需求是:单元测试。作为开发我从来没有了解过这一块,我说自己回去先写个Demo。于是上网各种搜索,还是有些收获的,昨天晚上到12:40,对UI和属性的测试有了点思路,完成一个简单的Demo,就当是单元测试的Hello World吧,今天上午又搞定了异步请求的单元测试,结合自己项目(方便写登录的请求)写了一个Demo,这也是列为今天todo list的第一个任务。现在记录一下。</p>
<p>1、新建一个测试的Target</p>
<p><img src="http://lingzuer.github.io/images/blog/test-target.png" alt="Test Target" /></p>
<p>2、设置Search Paths
保持和项目的Target设置一致,不然在引用文件的时候,可能会提示有些文件找不到,比如:LoginManager.h:10:9: fatal error: ‘biz/service/auth/auth_protocol.h’ file not found</p>
<p><img src="http://lingzuer.github.io/images/blog/search-paths.png" alt="Search Paths" /></p>
<p>3、新建Test Class</p>
<p>见图一。</p>
<p>4、引入需要的文件开始测试
比如要写一个登录的单元测试,那要引入LoginManager.h之类的文件吧,我大概写一下,有些是项目的代码,不知道写在博文里面好不好。</p>
<pre><code>#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "LoginManager.h"
#import "LoginCallBack.h"
@interface MyTests : XCTestCase {
XCTestExpectation *_expectation;
}
@end
@implementation MyTests
- (void)setUp {
[super setUp];
[self addListenEvents];
}
- (void)tearDown {
[self removeListenEvents];
[super tearDown];
}
#pragma mark - 通知
- (void)addListenEvents {
extern NSString *kYIXINNotificationLoginResult;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onGetLoginResult:) name:kYIXINNotificationLoginResult object:nil];
}
- (void)removeListenEvents {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Test Methods
- (void)testUserLogin {
_expectation = [self expectationWithDescription:@"Login request"];
NSString *username = @"userID";
NSString *password = @"111111";
[LoginManager sharedManager].currentLoginData.userName = username;
[LoginManager sharedManager].currentLoginData.userPassword = [XXUtil encytePassword:password];
[LoginManager sharedManager].currentLoginData.type = kAccountYid;
[[LoginManager sharedManager] beginLogin];
[self waitForExpectationsWithTimeout:5
handler:^(NSError *error) {
// handler is called on _either_ success or failure
if (error != nil) {
XCTFail(@"timeout error: %@", error);
}
}];
}
#pragma mark - LoginResultProtocol
- (void)onGetLoginResult:(NSNotification*)aNotification {
extern NSString *kLoginStepKey;
extern NSString *kLoginResultKey;
NSDictionary *data = aNotification.userInfo;
NSInteger step = [[data objectForKey:kLoginStepKey] intValue];
NSInteger errorCode = [[data objectForKey:kLoginResultKey] intValue];
if (step == kLoginStepLogin) {
[_expectation fulfill];
if (errorCode == kResSuccess) {
XCTAssert(YES, @"Pass");
} else {
XCTAssert(NO, @"No Pass");
}
} else {
NSLog(@ "login result: step is %@, code is %@",@(step), @(errorCode));
}
}
@end
</code></pre>
<p>5、异步测试要点</p>
<pre><code>_expectation = [self expectationWithDescription:@"Login request”];
[_expectation fulfill];
XCTAssert(YES, @"Pass");
</code></pre>
<p>6、其他</p>
<p>其他的异步测试比如Block、Delegate的方式也都如此(采用XCTestExpectation)。</p>
<p>7、参考资料</p>
<ul>
<li><a href="http://objccn.io/issue-15-2/">http://objccn.io/issue-15-2/</a></li>
<li><a href="http://www.objc.io/issue-15/xctest.html">http://www.objc.io/issue-15/xctest.html</a></li>
<li><a href="http://www.bignerdranch.com/blog/asynchronous-testing-with-xcode-6/">http://www.bignerdranch.com/blog/asynchronous-testing-with-xcode-6/</a></li>
<li><a href="http://blog.dadabeatnik.com/2014/07/13/asynchronous-unit-testing-in-xcode-6/">http://blog.dadabeatnik.com/2014/07/13/asynchronous-unit-testing-in-xcode-6/</a></li>
<li><a href="http://www.pumpmybicep.com/2014/08/22/objective-c-http-stubbing-libraries/">http://www.pumpmybicep.com/2014/08/22/objective-c-http-stubbing-libraries/</a></li>
<li><a href="http://iosunittesting.com/asynchronous-tests-using-xctestexpectation/">http://iosunittesting.com/asynchronous-tests-using-xctestexpectation/</a></li>
<li><a href="http://www.pumpmybicep.com/2014/08/20/asynchronous-unit-testing-with-xctest/">http://www.pumpmybicep.com/2014/08/20/asynchronous-unit-testing-with-xctest/</a></li>
<li><a href="http://nshipster.com/xctestcase/">http://nshipster.com/xctestcase/</a></li>
<li><a href="http://ocmock.org">http://ocmock.org</a></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Hello to Myself]]></title>
<link href="http://lingzuer.github.io/blog/2015/01/28/hello-to-myself/"/>
<updated>2015-01-28T15:17:17+08:00</updated>
<id>http://lingzuer.github.io/blog/2015/01/28/hello-to-myself</id>
<content type="html"><![CDATA[<p>Octopress听到它有些时间了,并且还配置好Run成功了,甚至有个Hello World的一个博文,我看了提交记录是Aug 14, 2013。从这之后就放着了,因为不知道写什么。再后来,看很多大牛写博客,然后就自己也想写,有个幼稚的想法是:大牛要写博客,写博客会成为大牛。</p>
<p>仔细想想写什么东西呢?写的东西给谁看呢?好累,现在想通了,我的博客定位就是自己记录一下自己学到的知识点,以前不知道的,现在知道了,记录下来,下次再想查的时候,方便一点儿,于是就下定决心想要写了。</p>
<p>这个时候已经换了一台电脑了,又要重新折腾Octopress,在一步一步配置的时候,出现问题了,没有Run成功,于是又放下了,第二天又尝试了一次,又没有成功,就又放下了,如此反复几次后,暗暗的下了一个决心:一定要Run起来,不然会对以后的修行有障碍(凡人修仙)。</p>
<p>花了一整天时间上网查找资料,功夫不负有心人,折腾到下午的时候,突然一个尝试了一个方法,结果成功了。心里特别开心,觉得只要下死功夫没有搞不定的。</p>
<p>环境搞好了,又陷入了脑海(脑子里的一片独特空间,这个地方不断有新想法冒出来)中,第一篇写点什么呢,写的不好怎么办呢?就又放了有一个月。</p>
<p>而后在反思自己为什么总有一些想法(养鱼、养花、打羽毛球,还有很多)冒出来,却都没有实施的时候,突然诊断出自己又一个到了晚期的心理病:拖延症,严重的拖延症。</p>
<p>症状表现是:总是在想,从来没有实施。自己的脑海里面有N个idea,每个idea都是那么的美好(老婆说很多都不切实际),当想实施的时候,发现有许许多多的条件不满足,即使做了,也达不到预期的美好效果,然后就放弃了,开始下一个胡思乱想。可能还有个原因就是,想做到最好,所以没有开始做。</p>
<p>这让我心里有些害怕,我从什么时候变成这样,或者一直是这样,一直没有发现么。</p>
<p>我想改变,哪怕是做一点很小的事情或者举动(比如一直在脑海里做俯卧撑,这个时候身体实施了一个俯卧撑动作),只要不是光想着的就行。</p>
<p>这样有了这一篇博文,我想写,我写了。</p>
]]></content>
</entry>
</feed>