刘小汶

路漫漫其修远兮,吾将上下而求索。

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  79 随笔 :: 0 文章 :: 1 评论 :: 44364 阅读
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
## 命名规范
1.iOS命名原则
* 可读性高、可复用、易维护、可扩展
* 防止命名冲突(通过加前缀来保证)
* 每个模块都要加上自己的前缀, 前缀在编程接口中非常重要, 可以区分软件的功能范畴并防止不同文件或者类之间命名发生冲突, 比如相册模块(PhotoGallery)的代码都以PG作为前缀: PGAlbumViewController, PGDataManager.
* 可扩展则是要求写代码时要考虑后面的扩展需求, 这个属于架构层面的东东, 利用对应的设计模式来保证
 
2.iOS常量命令
 
1)对于常量的命名最好在前面加上字母k作为标记. 如:
```
static const NSTimeInterval kAnimationDuration = 0.3;
```
 
2)定义作为NSDictionary或者Notification等的Key值字符串时加上const关键字, 以防止被修改. 如:
```
NSString *const UIApplicationDidEnterBackgroundNotification
```
 
3)若常量作用域超出编译单元(实现文件), 需要在类外可见时, 使用extern关键字, 并加上该类名作为前缀. 如
```
extern NSString *const PGThumbnailSize
```
 
<!--more-->
 
3.iOS枚举命令
 
枚举类型命名要加相关类名前缀并且枚举值命名要加枚举类型前缀.
```
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
```
 
4.iOS变量和对象命名
 
1)给一个对象命名时建议采用修饰+类型的方式
```
titleLabel    //表示标题的label,  是UILabel类型
confirmButton //表示确认的button, 是UIButton类型
```
 
2)对于BOOL类型, 应加上is前缀
```
- (BOOL)isEqualToString:(NSString *)aString
```
 
3)如果某方法返回非属性的 BOOL 值, 那么应根据其功能, 选用 has 或 is 当前缀, 如
```
- (BOOL)hasPrefix:(NSString *)aString
```
 
4)如果某个命名已经很明确了, 为了简洁可以省去类型名. 比如scores, 很明显是个array了, 就不必命名成scoreArray了
 
5.iOS命名常规错误
```
UserFollowerTableViewController    // 不推荐
UserFollowerListController         // OK
UserLikedTagListController         // 不推荐
TagUserLikedListController         // OK,把显示的对象放在第一位
```
 
6.iOS通知命名
 
这里学习iOS的命名方法:
```
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
NSColorPanelColorDidChangeNotification
```
 
7.类名、局部变量、类成员命名
 
* 类名采用大驼峰(UpperCamelCase)
* 类成员、方法小驼峰(lowerCamelCase)
* 局部变量大小写首选小驼峰,也可使用小写下划线的形式(snake_case)
* C函数的命名用大驼峰
 
8.命名规范--函数命名
 
* 1)如果方法表示让对象执行一个动作,使用动词打头来命名,注意不要使用do,does这种多余的关键字,动词本身的暗示就足够了;动词打头的方法表示让对象执行一个动作
```
- (void)invokeWithTarget:(id)target;
- (void)selectTabViewItem:(NSTabViewItem *)tabViewItem;
```
 
* 2)如果方法是为了获取对象的一个属性值,直接用属性名称来命名这个方法,注意不要添加get或者其他的动词前缀
 
正确,使用属性名来命名方法
```
- (NSSize)cellSize;
```
 
错误,添加了多余的动词前缀
```
- (NSSize)calcCellSize;
- (NSSize)getCellSize;
```
* 3)对于有多个参数的方法,务必在每一个参数前都添加关键词,关键词应当清晰说明参数的作用
 
正确,保证每个参数都有关键词修饰
```
- (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag;
```
 
错误,遗漏关键词
```
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
```
 
正确
```
- (id)viewWithTag:(NSInteger)aTag;
```
 
错误,关键词的作用不清晰
```
- (id)taggedView:(int)aTag;
```
 
* 4)不要用and来连接两个参数,通常and用来表示方法执行了两个相对独立的操作(从设计上来说,这时候应该拆分成两个独立的方法):
 
错误,不要使用"and"来连接参数
```
- (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes;
```
 
正确,使用"and"来表示两个相对独立的操作
```
- (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;
```
 
9.命名规范--分组命名
* 使用英文,首字母大写,之后每个单词首字母都大写
* 每个分组使用模块的名字
* 使用的开源库统一放在“Library”分组下
* 使用的公共组件统一放在“Common”分组下
* 视图控制器及AppDelegate统一放在“Controllers”分组下
 
10.命名规范--图片命名
* 使用英文,首字母大写,之后每个单词首字母都大写
* 添加模块名作为前缀,避免冲突
* 图片应该与类文件一样,按模块分组放置
* 只要文件名叫做Icon.png,就会自动被当做是应用程序的图标
* 一个应用程序可以准备多种规格的图标,详情可以查看苹果官方文档,ios7 doc set/user expreience/guides/app icons on iPad and iphone
* 一个app在启动过程中会全屏显示叫做Default.png的图片
 
11.命名规范--特殊类命名
* 如果是视图控制器的子类应添加后缀“ViewController”或者“Controller”
* 如果是视图的子类应添加后缀“View”
* 如果是按钮的子类应添加后缀“Button”
 
命名规范--补充命名
 
常量(预定义,局部常量等)使用小写k开头的驼峰法
举例:kInvalidHandle , kWritePerm
 
枚举类型命名首字母大写,之后每个单词首字母都大写,最后加“s”
枚举变量使用枚举类型去掉“s”作为前缀,每个单词首字母大写,中间不允许加下划线
举例:
typedef enum UIControlEvents{
UIControlEventTouchDown,
UIControlEventTouchUpInside
}UIControlEvents;
 
## 编码规范
1.编码规范--判断nil或者YES/NO
```
if (someObject) { ... }
if (!someObject) { ... }
```
 
2.编码规范--条件赋值
 
如果是存在就赋值本身, 那就可以这样简写
```
result = object ? : [self createObject];
```
 
3.编码规范--初始化方法
 
初始化的时候,直接赋值的好处是:
 
第一个好处还是简洁
 
第二个好处是可以防止初始化进去nil值造成crash
```
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve"];
 
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal"};
 
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @10018;
```
 
4.编码规范--定义属性
 
1)建议定义属性的时候把所有的参数写全, 尤其是如果想定义成只读的(防止外面修改)那一定要加上readonly, 这也是代码安全性的一个习惯.
 
2)如果是内部使用的属性, 那么就定义成私有的属性(定义到.m的class extension里面)
对于拥有Mutable子类型的对象(e.g. NSString, NSArray, NSDictionary)一定要定义成copy属性. Why? 示例: NSArray的array = NSMutableArray的mArray; 如果mArray在某个地方改变了, 那array也会跟着改变. So, make sense?
 
3)尽量不要暴露mutable类型的对象在public interface, 建议在.h定义一个Inmutable类型的属性, 然后在.m的get函数里面返回一个内部定义的mutable变量. Why? For security as well!
 
@property (nonatomic, readwrite, copy) NSString *name;
 
5.编码规范--BOOL赋值
```
BOOL isAdult = age > 18;
```
 
6.编码规范--拒绝死值
 
1)死值每次修改的时候容易被遗忘, 地方多了找起来就悲剧了. 而且定义成枚举或者static可以让错误发生在编译阶段. 另外仅仅看到一个数字, 完全不知道这个数字代表的意义. 纳尼?
```
if (car == Car.Nissan)
or
const int adultAge = 18; if (age > adultAge) { ... }
```
 
7.编码规范--复杂的条件判断
 
清晰明了, 每个函数只做一件事!
```
if ([self canDeleteJob:job]) { ... }
 
- (BOOL)canDeleteJob:(Job *)job
{
BOOL invalidJobState = job.JobState == JobState.New
|| job.JobState == JobState.Submitted
|| job.JobState == JobState.Expired;
BOOL invalidJob = job.JobTitle && job.JobTitle.length;
 
return invalidJobState || invalidJob;
}
```
 
8.编码规范--嵌套判断
 
一旦发现某个条件不符合, 立即返回, 条理更清晰
```
if (!user.UserName) return NO;
if (!user.Password) return NO;
if (!user.Email) return NO;
return YES;
```
 
9.编码规范--参数过多
 
当发现实现某一功能需要传递的参数太多时, 就预示着你应该聚合成一个model类了...这样代码更整洁, 也不容易因为参数太多导致出错
```
user里面有userName、password、email
- (void)registerUser(User *user)
{
// to do...
}
```
 
10.编码规范--把方法进行分类
 
1)使用#pragma mark –来分类方法
 
#pragma mark – Life Cycle//代表生命周期方法
 
#pragma mark - Events//代表事件
 
#pragma mark – Private Methods//代表私有方法
 
#pragma mark - UITextFieldDelegate//代理
 
#pragma mark - UITableViewDataSource//数据源
 
#pragma mark - UITableViewDelegate//代理
 
#pragma mark - Custom Delegates//自定义代理
 
#pragma mark – Getters and Setters//getter和setter方法
 
11.编码规范--注释符号
```
 
/***************************************************************************
*                                文件引用
***************************************************************************/
 
/***************************************************************************
*                                 宏定义
***************************************************************************/
 
/***************************************************************************
*                                 常量
***************************************************************************/
 
/***************************************************************************
*                                类型定义
***************************************************************************/
 
/***************************************************************************
*                                全局变量
***************************************************************************/
 
/***************************************************************************
*                                 原型
***************************************************************************/
 
/ ***************************************************************************
*                                类特性
***************************************************************************/
 
/ ***************************************************************************
*                                类的实现
***************************************************************************/
 
```
 
* 块代码注释符号
1)块注释风格1
```
/////////////////////////////////////
// @name UIButton控件生成相关API
/////////////////////////////////////
```
 
2)块注释风格2
```
//
// 块功能说明
//
```
 
3)块注释风格3
```
/*
* 块功能说明
*/
```
 
* 使用#program mark -  注释内容
 
>#program mark 是每个ios程序员都必须会用的技巧,通过#program mark 把代码分为个个部分,良好的注释是好代码的开始
 
* 注释原则
>代码中尽量少注释,让代码能自我描述。不过当需要注释的时候,能需要清除的解释某个代码块的含义和作用。注释应当保持最新,如果不必要请删除。
 
* #pragma clang 使用
 
1)取消xcode编译器内对于启用方法的警告
```
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// CODE:这段中出现使用所有的弃用方法都不会产生告警
#pragma clang diagnostic pop
```
 
2)取消对未使用变量的警告,使用方法和上面相同,必须成对出现#pragma clang
```
//方法1:
diagnostic ---
#pragma clang diagnostic ignored "-Wunused-variable"
//方法2:
#pragma unused (foo)
```
 
3)忽略内存泄露告警
```
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[someController performSelector: NSSelectorFromString(@"someMethod")]
#pragma clang diagnostic pop
```
 
* 手动产生一条警告
```
#warning :手动产生一条告警
```
 
* 手动产生一条错误
```
#error : 手动产生一条错误
```
 
12.编码规范--花括号空格
```
- (void)methodName:(NSString *)string {
↑空格                              ↑空格,推荐花括号在一行
if () {
空格↑  ↑空格,花括号不要另起一行
}
else {
要换行↑ ↑空格,花括号不要另起一行
}
}
```
 
13.编码规范--编码注意
* 单个文件方法数不应超过30个
* 不要按类别排序(如把IBAction放在一块),应按任务把相关的组合在一起
* 禁止出现超过两层循环的代码,用函数或block替代
 
14.编码规范--编码例子
* 糟糕
```
- (Task *)creatTaskWithPath:(NSString *)path {
Task *aTask;
if ([path isURL]) {
if ([fileManager isWritableFileAtPath:path]) {
if (![taskManager hasTaskWithPath:path]) {
aTask = [[Task alloc] initWithPath:path];
}
else {
return nil;
}
}
else {
return nil;
}
}
else {
return nil;
}
return aTask;
}
```
 
*建议
```
- (Task *)creatTaskWithPath:(NSString *)path {
if (![path isURL]) {
return nil;
}
 
if (![fileManager isWritableFileAtPath:path]) {
return nil;
}
 
if ([taskManager hasTaskWithPath:path]) {
return nil;
}
 
Task *aTask = [[Task alloc] initWithPath:path];
return aTask;
}
```
 
15.编码规范--编码注释适当使用
 
* 尽量让代码可以自表述,而不是依赖注释。
* 注释应该表达那些代码没有表达以及无法表达的东西。
* 如果一段注释被用于解释一些本应该由这段代码自己表达的东西,我们就应该将这段注释看成一个改变代码结构或编码惯例直至代码可以自我表达的信号。
* 我们重命名那些糟糕的方法和类名,而不是去修补。我们选择将长函数中的一些代码段抽取出来形成一些小函数,这些小函数的名字可以表述原代码段的意图,而不是对这些代码段进行注释。
* 尽可能的通过代码进行表达。你通过代码所能表达的和你想要表达的所有事情之间的差额将为注释提供了一个合理的候选使用场合。对那些代码无法表达的东西进行注释,而不要仅简单地注释那些代码没有表达的东西。
* 方法内部禁止使用块注释。除非要临时注释大段代码,一般情况总应使用行注释。
 
16.编码规范--参数分行
 
* 正确使用:如果第一段名称过短,后续名称可以以Tab的长度(4个空格)为单位进行缩进
```
- (void)short:(GTMFoo *)theFoo
longKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval
error:(NSError **)theError {
...
}
```
 
* 错误使用:要么写在一行,要么全部分行
```
[myObject doFooWith:arg1 name:arg2
error:arg3];
[myObject doFooWith:arg1
name:arg2 error:arg3];
```
 
17.编码规范--冒号两边
* 正确,在语法糖的"[]"或者"{}"两端留有空格
```
NSArray *array = @[ [foo description], @"Another String", [bar description] ];
NSDictionary *dict = @{ NSForegroundColorAttributeName : [NSColor redColor] };
```
 
* 构造字典时,字典的Key和Value与中间的冒号:都要留有一个空格
* 正确,冒号':'前后留有一个空格
```
NSDictionary *option1 = @{
NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
NSForegroundColorAttributeName : fontColor
};
```
 
* 正确,按照Value来对齐
```
NSDictionary *option2 = @{
NSFontAttributeName :            [NSFont fontWithName:@"Arial" size:12],
NSForegroundColorAttributeName : fontColor
};
```
 
* 错误,冒号前应该有一个空格
```
NSDictionary *wrong = @{
AKey:       @"b",
BLongerKey: @"c",
};
```
 
* 错误,每一个元素要么单独成为一行,要么全部写在一行内
```
NSDictionary *alsoWrong= @{ AKey : @"a",
BLongerKey : @"b" };
```
 
* 错误,在冒号前只能有一个空格,冒号后才可以考虑按照Value对齐
```
NSDictionary *stillWrong = @{
AKey       : @"b",
BLongerKey : @"c",
};
```
 
18.编码规范--程序布局
 
1)程序布局目的:程序布局的目的是显示出程序良好的逻辑结构,提高程序的准确性、连续性、可读性、可维护性。更重要的是,统一的程序布局和编程风格,有助于提高整个项目的开发质量,提高开发效率,降低开发成本。同时,对于普通程序员来说,养成良好的编程习惯有助于提高自己的编程水平,提高编程效率。因此,统一的、良好的程序布局和编程风格不仅仅是个人主观美学上的或是形式上的问题,而且会涉及到产品质量,涉及到个人编程能力的提高,必须引起大家重视。
 
2)布局中的空格:每个方法或者功能块之间为了结构清晰,应当有且只有一行空格,如下示例
```
@interface SomeClass:NSObject
 
@property (noatomic, strong) UIView *aView
 
-(void)someMethod;
 
@end
 
@implementation SomeClass
 
- (void)setAView:(NSInteger )aview {
 
}
 
-(void)someMethod {
 
}
@end
```
 
3)布局中的Private Methods块:正常情况下ViewController里面不应该写
不是delegate方法的,不是event response方法的,不是life cycle方法的,就是private method了。对的,正常情况下ViewController里面一般是不会存在private methods的,这个private methods一般是用于日期换算、图片裁剪啥的这种小功能。这种小功能要么把它写成一个category,要么把他做成一个模块,哪怕这个模块只有一个函数也行。
 
ViewController基本上是大部分业务的载体,本身代码已经相当复杂,所以跟业务关联不大的东西能不放在ViewController里面就不要放。另外一点,这个private method的功能这时候只是你用得到,但是将来说不定别的地方也会用到,一开始就独立出来,有利于将来的代码复用。
 
4)布局中的初始化方法放哪里?
 
属性初始化放哪最好?建议在Getter中初始化
 
我看到很多APP,甚至我公司的项目,很多开发工程师,初始化属性的位置比较随意,有单独添加一个初始化方法类似setupView的,有在init初始化的,各种情况都有,我其实挺崩溃的,首先初始化方式不一致,其次这样做非常可能破坏了每个方法功能的单一性(每个方法只做一件事)。我比较习惯一个对象的"私有"属性写在extension里面,然后这些属性的初始化全部放在getter里面做,在init和dealloc之外,是不会出现任何类似_property这样的写法的。就是这样:
 
```
@interface CustomObject()
 
@property (nonatomic, strong) UILabel *label;
 
@end
 
@implementation
 
#pragma mark - getters and setters
 
- (UILabel *)label {
if (_label == nil) {
_label = [[UILabel alloc] init];
_label.text = @"1234";
_label.font = [UIFont systemFontOfSize:12];
... ...
}
return _label;
}
@end
#pragma mark - life cycle
 
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.label];
}
 
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.label.frame = CGRectMake(1, 2, 3, 4);
}
```
 
5)布局中的Getters and Setters放在最底部
 
一个view可能会有非常多的view和其他属性,如果getters and setters放在前面,就会导致在implementation代码顶部有大量的初始化代码,这就导致主要的逻辑代码挪到后面去了,其他人阅读代码是不太方便的。
 
19.编码规范--表达式
 
* if语句
 
> 表达式大括号和其他大括号(if/else/switch/while 等.)总是在同一行语句打开但在新行中关闭。如果没有else 并且括号内只有一行语句,可以和if语句同行,并且不需要括号。
```
if (user.isHappy) {
//Do something
} else {
//Do something else
}
if (somethingIsBad) return something;
```
 
* Switch语句
> 大括号在case语句中并不是必须的,除非编译器强制要求。当一个case语句包含多行代码时,大括号应该加上。
```
switch (condition) {
case 1:
// ...
break;
case 2: {
// ...
// Multi-line example using braces
break;
}
case 3:
// ...
break;
default:
// ...
break;
}
```
>当在switch使用枚举类型时,'default'是不需要的
```
RWTLeftMenuTopItemType menuType = RWTLeftMenuTopItemMain;
switch (menuType) {
case RWTLeftMenuTopItemMain:
// ...
break;
case RWTLeftMenuTopItemShows:
// ...
break;
case RWTLeftMenuTopItemSchedule:
// ...
break;
}
```
 
#### 参考链接
http://www.jianshu.com/p/414bb5a53139

  

posted on   williamliuwen  阅读(208)  评论(0编辑  收藏  举报
编辑推荐:
· 为什么构造函数需要尽可能的简单
· 探秘 MySQL 索引底层原理,解锁数据库优化的关键密码(下)
· 大模型 Token 究竟是啥:图解大模型Token
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· 继承的思维:从思维模式到架构设计的深度解析
阅读排行:
· 基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
· 由 MCP 官方推出的 C# SDK,使 .NET 应用程序、服务和库能够快速实现与 MCP 客户端
· 电商平台中订单未支付过期如何实现自动关单?
· 上周热点回顾(3.31-4.6)
· X86-64位简易系统开发 - 从BIOS阶段开始
点击右上角即可分享
微信分享提示