iOS开发规范

代码结构

#pragma mark - life cycle  生命周期

#pragma mark - notification  通知

#pragma mark - action  事件处理

#pragma mark - Delegate

#pragma mark - UI  界面搭建

#pragma mark - setter & getter

#pragma mark - other

命名规则

1.常规
  • 格式:驼峰式;
  • 见名知义;杜绝拼音;不过度缩写
2.方法命名
  • 禁止在方法名前加下划线“ _ ”;
  • 如方法返回某个属性,则直接以属性名作为方法名。无需在方法名前加"get";
  • 只有当方法间接的返回对象或数值,才有必要在方法名中使用"get",这种格式只适用于返回多个数据项的情况;如:
// 通过传入指针,来获得多个值
- (void)getLineDash:(float *)pattern count:(int*)count phase:(float *)phase;
// NSURLCache (NSURLSessionTaskAdditions)中声明的方法
- (void)getCachedResponseForDataTask:(NSURLSessionDataTask *)dataTask completionHandler:(void (^) (NSCachedURLResponse * __nullable cachedResponse))completionHandler;
  • 方法中的所有参数前都应加关键字,描述参数的意义;
  • 如果当前子类创建的方法比从父类继承来的方法更加具体明确。本身提供的方法更具有针对性。则不该重写类本身提供的方法。而是应该单独的提供一个方法,并在新的方法后面添加上必要的关键参数;
// UIView提供的方法
- (instancetype)initWithFrame:(CGRect)frame
// 更具针对性的方法
- (instancetype)initWithFrame:(CGRect)frame mode:(int)aMode cellClass:(Class)factory Id numberOfRows:(int)rows numberOfColumns:(int)cols;
  • 私有方法命名,可加前缀xx_。如xx_SaveUserData;
3.代理方法命名
  • 使用did或will、should情态动词
  • 以触发消息的对象名开头,省略类名前缀并且首字母小写
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
  • 除非delegate方法只有一个参数,即触发delegate方法调用的delegating对象,否则冒号是紧跟在类名后面的
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender;
4.Category命名
  • 避免category中的方法覆盖系统方法。
  • 可以使用前缀来区分系统方法和category方法。
  • 如果一个类比较复杂,建议使用category增加方法。
5.属性命名
/** 订单总价 */
@property (nonatomic, assign) CGFloat totalPrice;
6.类名
  • 应该由两部分组成,前缀+名称。
7.协议名
  • 有时protocol只是声明了一堆相关方法,并不关联类。这时protocol使用ing形式,以和class区分开来。如:NSLocking
  • 如果proctocol还关联了某个类。这时命名取决于关联的类,然后再后面再加上protocol或delegate用于显示的声明这是一份协议。 如:UITableViewDeleagte
8.通知命名
  • 必须是全局的常量形式
  • 使用“will”或者“did”这样的助动词,命名格式:

[相关类名] + [Did | Will] + [UniquePartOfName] + Notification

NSApplicationDidBecomeActiveNotification
NSTextViewDidChangeSelectionNotification
  • 在发送通知时要传递信息,请使用userInfo,而不是object。因为object通常是指发出通知的对象。
9.常量命名

对于int常量,使用枚举创建;对于float常量,用const修饰符创建。
const float viewWidth

如果一个整型常量和其他常量不相关,使用const来创建,否则,使用枚举类型表示一组相关的整型常量。

10.枚举定义
typedef NS_ENUM(NSUInteger,myKeyBoradType){
    KeyBoardTypeDefault = 0,
    KeyBoardTypeNumber,
    KeyBoardTypeEmail
}

编码规范

1. dealloc
  • dealloc 方法应该放在实现文件的最上面。
  • init 应该直接放在 dealloc 方法的下面。
  • 不要忘记在dealloc方法中移除通知和KVO。
  • init方法一样,禁止在dealloc方法中使用点语法访问属性。
2.Block

调用block时需要对block判空。
注意block潜在的引用循环。

UI 规范

1.如果想要获取window请使用[[UIApplication sharedApplication] keyWindow];
2.使用到UITableView,UICollectionView ,要在 dealloc方法里手动的把对应的 delegate, dataSouce 置为 nil。
3.获取视图的x、y、width、height,请使用CGRectGet方法:

CGRect frame = self.view.frame;

CGFloat x = CGRectGetMinX(frame);
CGFloat width = CGRectGetWidth(frame);

反对以下写法:

CGRect frame = self.view.frame;

CGFloat x = frame.origin.x;
CGFloat width = frame.size.width;

IO规范

尽量少用NSUserDefaultssynchronize方法会block住当前线程,直到所有的内容都写进磁盘。如果内容过多,重复调用会影响性能。
一些经常被使用的文件建议做好缓存,避免重复的IO操作。

集合规范

0.集合类使用泛型来指定对象的类型。

@property(nonatomic,copy) NSArray *array;
@property(nonatomic,strong) NSMutableDictionary *dictionary;

1.插入数组前,需判空。
2.多线程环境下访问可变集合对象,必要时应该加锁保护。
不可变集合(如NSArray)类默认是线程安全的,而可变集合类(如NSMutableArray)不是线程安全的。
3.多线程访问可变集合对象中的元素,应该先对其进行copy,然后访问不可变集合对象内的元素。
4.注意使用enumerateObjectsUsingBlock遍历集合对象中的对象时,关键字return的作用域是使当前的block返回,而非使当前的整个函数体返回。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSArray *array = [NSArray arrayWithObject:@"1"];
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        // excute some code...
        return;
    }];
    
    NSLog(@"fall through");// 依然会执行到这里
}

4.如使用NSMutableDictionary作为缓存,建议用NSCache代替。

分支语句规范

1.条件语句必须要加大括号{}

// 建议
if (!error) {
    return success;
}
// 不建议
if (!error)  return success;

2.判断条件多于3个必须用参数分割成多个有意义的bool变量。

3.永远不要直接和 YES 和 NO进行比较。因为 YES 被定义为 1,而 BOOL 可以多达 8 位。

// 建议
if (isAwesome)
if (![someObject boolValue])
// 禁止这样做
if ([someObject boolValue] == NO) { }
if (isAwesome == YES) { } 

4.不要把真正的逻辑写到大括号内。

// 不建议
- (void)someFuncWith:(NSString *)parameter {
    if (parameter) {
        [self doSomething];
    }
}

// 建议
- (void)someFuncWith:(NSString *)parameter {
    if (!parameter) {
        return;
    }

    [self doSomething];
}

5.使用switch...case...语句的时候,不要丢掉default:。除非switch枚举。
每个case都要添加break关键字。

懒加载

适合的场景:
一个对象的创建依赖于其他对象。
一个对象在整个app过程中,可能被使用,也可能不被使用。
一个对象的创建需要经过大量的计算,或者比较消耗性能。

  • 如果都不符合以上条件,请不要使用懒加载。

  • 懒加载中不应该有其他的不必要的逻辑性代码。如果有,请把那些逻辑性代码放到合适的地方。

多线程规范

0.禁止在子线程中进行UI操作。
1.禁止使用GCD的dispatch_get_current_queue()获取当前线程信息。
2.禁止dispatch_sync(dispatch_get_main_queue(), block);会死锁。
3.在主线程中禁止进行同步网络资源读取,使用NSURLSession进行异步获取。
4.对剪贴板的读取必须要放在异步线程处理。因为读取大量的内容,导致读取线程被长时间阻塞。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; 
   if (pasteboard.string.length > 0) {  //这个方法会阻塞线程
      NSString *text = [pasteboard.string copy];
      [pasteboard setValue:@"" forPasteboardType:UIPasteboardNameGeneral];
      if (text == nil || [text isEqualToString:@""]) {
          return ;
      }
      dispatch_async(dispatch_get_main_queue(), ^{
          [self processShareCode:text];
      });
   }
});

内存管理

1.请慎重使用单例,避免产生不必要的常驻内存。

2.除非你清除的知道自己在做什么,否则不建议将UIView对象加入到NSArray、NSDictionary、NSSet中。如有需要,可添加到NSMapTable 、 NSHashTable

前者相当于weak的NSMutableArray;后者相当于weak的NSMutableDictionary。需注意元素提前释放。

因为NSArray、NSDictionary、NSSet会对加入的对象做strong引用(即使你把加入的对象进行了weak)。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    WSObject *object = [WSObject new];

    NSHashTable *hashTable = [NSHashTable weakObjectsHashTable];
    [hashTable addObject:object];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"count = %ld",hashTable.count);
    });
}
// 打印结果:
// dealloc
// count = 1

延迟调用规范

方法performSelector:withObject:afterDelay:要在有Runloop的线程里调用,否则调用无法生效。

异步线程默认是没有runloop的,除非手动创建;而主线程是系统会自动创建Runloop的。

注释规范

【必须】如果方法、函数、类、属性等需要提供给外界或者他人使用,必须要加注释说明。
【必须】如果你的代码以SDK的形式提供给其他人使用,那么接口的注释是必须的。必须对暴露给外界的所有方法、属性、参数加以注释说明。
【建议】注释应该说明其作用以及注意事项(如果有)。
【建议】因为方法或属性本身就具有自我描述性,注释应该简明扼要,说明是什么和为什么即可。

类的设计规范

1.尽量减少继承,类的继承关系不要超过3层。可以考虑使用category、protocol来代替继承。

【建议】把一些稳定的、公共的变量或者方法抽取到父类中。子类尽量只维持父类所不具备的特性和功能。

【建议】.h文件中尽量不要声明成员变量。属性尽量声明为只读。

【建议】.h文件中只暴露出一些必要的类、公开的方法、只读属性;私有类、私有方法和私有属性以及成员变量,尽量写在.m文件中。

你可能感兴趣的:(iOS开发规范)