码迷,mamicode.com
首页 > 其他好文 > 详细

让代码更帅一点

时间:2015-08-15 00:15:26      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:ios   objective-c   代码规范   

博主的私人博客

写代码最重要的是实现功能,但是除了实现功能之外,我们还应该想办法,让代码变得更规范,更漂亮
最近在读《禅与Objective-C编程艺术》《Effective Objective C 2.0:编写高质量iOS与OS X代码的52个有效方法》,这两本都讲解了代码规范方面的东西,结合自己平时的代码习惯,发现有很多地方自己做的还是不够好,代码写得不够帅,所以总结一下,让以后的代码更帅一点

条件语句

条件语句一定要使用括号,如果不使用括号,if后面的那行代码删除,之后的代码会成为if语句里面的代码
推荐:

if (!error) {
    return success;
}

括号

大括号的使用最好跟Apple保持一致,大括号在同一行开始,在新的一行结束,
如:

if (user.isHappy) {
    //Do something
}
else {
    //Do something else
}

nil和BOOL判断

最好直接使用!判断nil,或者BOOL值
推荐:

if (![someObject boolValue]) { ...
if (!someObject) { ...

避免嵌套if

不要嵌套 if 语句。使用多个 return 可以避免增加循环的复杂度,并提高代码的可读性。
推荐:

- (void)someMethod {
  if (![someOther boolValue]) {
      return;
  }

  //Do something important
}

不推荐:

- (void)someMethod {
  if ([someOther boolValue]) {
    //Do something important
  }
}

多用字面量语法

何为字面量语法

NSString *string = @"string";

NSNumber *intNumber = @88;
NSNumber *boolNumber = @YES;
NSNumber *floatNumber = @3.14;
int var = 3;
NSNumber *varNumber = @(var);

NSArray *list = @[@"itme1",@"item2",@"item3"];
NSLog(@"%@,%@,%@",list[0],list[1],list[2]);
NSDictionary *map = @{@"key1":@"value1",@"key2":@"value2"};
NSLog(@"%@,%@",map[@"key1"],map[@"key2"]);

这就是字面量语法,用非常简单直观的方法创建或者获取常用的对象(NSString,NSNumber,NSArray,NSDictionary),使用字面量语法简单方便直观

复杂的表达式

当有一个复杂的if语句时,可以把判断条件提取出来作为BOOL变量

BOOL nameContainsSwift  = [sessionName containsString:@"Swift"];
BOOL isCurrentYear      = [sessionDateCompontents year] == 2014;
BOOL isSwiftSession     = nameContainsSwift && isCurrentYear;

if (isSwiftSession) {
    // Do something very cool
}

用常量代替宏

推荐:

static NSString * const ZOCCacheControllerDidClearCacheNotification = @"ZOCCacheControllerDidClearCacheNotification";
static const NSTimeInterval animationDuration = 3.0;

不推荐:

#define ZOCCacheControllerDidClearCacheNotification @"ZOCCacheControllerDidClearCacheNotification"
#define animationDuration 3.0

原因:
1. 使用宏的过程中无法直接知道常量类型(是int呢?还是Stiring呢?),除非查看宏定义的地方
2. 宏可以更改,,如果2个地方使用同样的名字定义了2个不一样的宏,你使用的时候可能会使用错误,造成难以发现的bug。使用const定义的常量如果更改编译器就会报错

static

在常量的使用过程中分两种情况
1.常量需要对外暴露。不使用static,并在.h中用extern暴露出去

// .h
extern NSString *const ZOCCacheControllerDidClearCacheNotification;
// .m
NSString * const ZOCCacheControllerDidClearCacheNotification = @"ZOCCacheControllerDidClearCacheNotification";

2.常量只在本类中使用,不需要对外暴露,使用static.

static NSString * const ZOCCacheControllerDidClearCacheNotification = @"ZOCCacheControllerDidClearCacheNotification";

static定义的变量仅在当前的.m文件中可见,如果常量只在本类中使用,用static会避免影响到其他类,如果需要全局可见,就不能使用static

命名冲突

1)类名,全局变量和C函数(C函数类似于全局变量)命名时,使用三个字母作为前缀,避免命名跟第三方API或者苹果API名称冲突
项目里经常看到不使用前缀或者使用两个字母作为前缀的命名方式。
不使用前缀可能发生冲突不言而喻,那为什么不使用两个字母作为前缀呢?
因为Apple宣称其保留使用所有”两字母前缀”的权利,使用两字母作为前缀有跟未来的苹果API冲突的风险,所以保险起见,尽量使用三个字母作为iOS的命名前缀

2)类内部使用的私有方法,可以加个前缀,但不要使用单个下划线_作为前缀,因为这也是Apple预留的。可以使用双下划线__或者p_作为前缀

3)如果需要为无源码的类(包括第三方类和系统类)添加category,方法名称前最好带前缀,避免冲突

Designated Initializer

子类重新定义designated initializer时应遵循以下步骤:

  1. 定义designated initializer,并调用父类的designated initializer
  2. 重载父类的designated initializer,并调用新定义的designated initializer
  3. 为新的designated initializer写文档

在.h中,使用__attribute__((objc_designated_initializer))标明哪个是designated initializer。
如果因为某些原因,父类的designated initializer被弃用,比如designated initializer必须要有某个参数,父类的designated initializer无法传这个参数。用__attribute__((unavailable("Invoke the designated initializer")))表示弃用

- (instancetype)initWithName:(NSString *)name __attribute__((objc_designated_initializer));
- (instancetype)init __attribute__((unavailable("Invoke -initWithName:")));

类的封装

在封装一个类的时候,下面几点需要注意:

  1. 外部不需要了解的属性和方法,尽量定义在.m中
  2. 不要轻易暴露属性的setter方法,多使用readonly
  3. 尽量使用不可变对象
  4. 不要暴露可变的collection,应该提供相应的方法替代

protocol

1)一般情况下protocol分为2类,delegate和dataSource

  1. delegate:委托别的类去干活的,需要放在delegate里面,一般没有返回值
  2. dataSource:去别的类获取数据的,放在dataSource里面,主要用于获取数据

2)delegate属性在ARC下,一定要用weak取代assign,避免隐患
3)对于option的protocol。在调用之前一定要用-respondsToSelector:判断这个方法是否实现了

属性

规范

从代码规范和漂亮的角度来说,属性最好这样写,这是apple的写法
推荐:

@property(nonatomic, readonly, copy) NSString *nibName; 

不推荐:

@property(nonatomic, readonly, copy) NSString* nibName; 
@property(nonatomic, readonly, copy)NSString *nibName; 
@property (nonatomic, readonly, copy) NSString *nibName; 
...
setter&getter

属性除了init和dealloc外,建议使用setter和getter方法。在init和dealloc中,建议直接使用ivar
使用setter和getter方法的好处:

  1. 遵守内存管理语义(strong,copy…)
  2. kvo通知会自动被执行
  3. 方便debug,打断点
  4. 方便重写getter或者setter

为什么不要在init和dealloc中使用setter和getter?
如果init中使用了setter,在子类的属性初始化之前,调用[super init]的时候就会调用setter方法。这时候如果重写了setter,并在setter中做了特殊的操作,这时候就可能会引起一些非常难发现的bug。所以为了避免隐患,在init或者dealloc中直接使用ivar

可变对象赋值

对可以用可变对象赋值的属性(如:NSString,NSArray,NSDictionary),属性的内存管理类型必须为copy。这是为了防止可变对象(NSMultableArray)给不可变对象(NSArray)赋值。导致不可变对象(NSArray)指针指向可变对象(NSMultableArray),在使用过程中可能会改变它的值,出现bug

点符号

当使用属性的时候尽量使用.符号,方法调用使用[]
例:

 view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;

Block

推荐这种block使用方法

__weak __typeof(self)weakSelf = self;
[self executeBlock:^(NSData *data, NSError *error) {
    __strong __typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        [strongSelf doSomethingWithData:data];
        [strongSelf doSomethingWithData:data];
    }
}];

在block外面用weak持有self,避免循环引用
在block里面用strong持有self,避免多线程中block执行到一半,self被释放为nil,而出现的隐患
其他的block问题,可以看以前写的这篇文章

可变集合

永远不要枚举可变集合

推荐:

NSArray *staticArray = [multableArray copy];
for (id item in staticArray) {
    ....
}

不推荐:

for (id item in multableArray) {
    ....
}

可变集合在枚举时如果发生改变,会引起crash。
永远不要枚举可变集合,不管你有多么确定这个集合不会改变。因为代码也许以后会被修改,也许有别的线程会改变这个集合,太多意外可能会发生,唯一能保证不会有意外的就是永远不要枚举可变集合

不要将可变集合暴露成公共属性

推荐:

// .h
@property(nonatomic, readonly) NSArray *staticArray;

// .m
@property(nonatomic, strong) NSMutableArray *mutableArray;

- (NSArray *)staticArray
{
    return [self.mutableArray copy];
}

不推荐①:

// .h
@property(nonatomic, readonly)NSMutableArray *mutableArray;

不推荐②:

// .h
@property(nonatomic, readonly) NSArray *staticArray;

// .m
@property(nonatomic, strong) NSMutableArray *mutableArray;

- (NSArray *)staticArray
{
    return self.mutableArray;
}

你永远不知道外面会怎么用这个mutableArray,假设外面正在枚举这个mutableArray,在其他线程mutableArray被改变了。嘭,Crash了,还不是毕现,又是加班的节奏了…

如果在外部需要改变这个Array里面的item,添加改变item的方法:

// .h
@property(nonatomic, readonly) NSArray *staticArray;

- (void)addItem:(id)item;
- (void)removeItem:(id)item;

//.m
@property(nonatomic, strong) NSMutableArray *mutableArray;

- (void)addItem:(id)item
{
    [self.mutableArray addObject:item];
}

- (void)removeItem:(id)item
{
    [self.mutableArray removeObject:item];
}

NSNotification

remove

notification一定要remove!
notification一定要remove!!
notification一定要remove!!!
重要的东西一定要说三遍,Notification不remove很容易crash,包括KVO,也一定要记得remove,否则会有crash在前方等着你…

多次注册

notification如果多次注册会导致一次post,方法多次被调用,所以注意注册通知的时候一定要看清楚,是否通知只注册了一次,建议在init中注册通知,dealloc中remove通知

Reference

《禅与Objective-C编程艺术》
Effective Objective C 2.0:编写高质量iOS与OS X代码的52个有效方法
How Not to Crash

版权声明:本文为博主原创文章,未经博主允许不得转载。

让代码更帅一点

标签:ios   objective-c   代码规范   

原文地址:http://blog.csdn.net/xbenlang/article/details/47670035

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!