iOS OC 学习手册IOS开发规范

iOS代码规范

2017-03-20  本文已影响226人  CoderHw

iOS代码规范

一、前言

本规范基于Google Objective-C Style Guide和百度Objective-C规范和实际开发情况,对其中的说明性语句及非ARC部分进行了删减。
每项规范前面的[强制]代表该规范需要强制执行,[建议]代表推荐执行但不强制。

本文章里面的代码格式大部分内容可以通过插件自动格式化,详见ClangFormat-Xcode插件使用。

二、缩进与格式

1、缩进符

2、每行的长度

3、逗号分隔项

4、左大括号位置

5、声明与定义

示例

- (void)doSomethingWithString:(NSString *)theString { 
    ...
} 

示例

- (void)doSomethingWith:(GTMFoo *)theFoo 
                   rect:(NSRect)theRect                
               interval:(float)theInterval { 
    ...
} 

示例

- (void)short:(GTMFoo *)theFoo 
      longKeyword:(NSRect)theRect     
evenLongerKeyword:(float)theInterval                 
            error:(NSError **)theError { 
     ...
} 

6、方法调用

示例

[myObject doFooWith:arg1 name:arg2 error:arg3]; 

或者每个参数一行,并按 : 对齐。

[myObject doFooWith:arg1               
           name:arg2              
          error:arg3]; 

不建议采用以下风格:

 [myObject doFooWith:arg1 name:arg2 //这行写了两个参数
               error:arg3];  
[myObject doFooWith:arg1                
                 name:arg2 error:arg3]; 

就像声明和定义一样,当第一个关键词比其他的短时,可以缩进之后的行至少4个空格,同样按 : 进行对齐:

[myObj short:arg1          
    longKeyword:arg2    
  evenLongerKeyword:arg3                
          error:arg4]; 

7、@public、@protected与@private

8、异常

@try {     
    foo(); 
} @catch (NSException *ex) {     
    bar(ex); 
} @finally {     
    baz(); 
}

9、协议

@interface MyProtocoledClass : NSObject <NSWindowDelegate> {    
    @private      id <MyFancyDelegate> delegate_; 
} 
(void)setDelegate:(id <MyFancyDelegate>)aDelegate; 
@end 

解释:这些适用于类的声明、实例变量和方法的声明。

10、Blocks

示例


//整个block放在一行的 
[operation setCompletionBlock:^{ [self onOperationDone]; }];

//多行时缩进四个空格,{要和block所在行的第一个字符对齐
[operation setCompletionBlock:^{

    [self.delegate newDataAvailable];
}]; 

//在C函数中使用block时遵循和Objective-C同样的对齐和缩进原则
dispatch_async(fileIOQueue_, ^{

    NSString *path = [self sessionFilePath];     
    if (path) {       // ...     
    } 
});

// 方法参数与block声明能放到一行时。注意比较^(SessionWindow *window) {和上面的^{。 
[[SessionService sharedService]  loadWindowWithCompletionBlock:^(SessionWindow *window) {
         
    if (window) {          
    [self windowDidLoad:window];        
    } else {           
        [self errorLoadingWindow];        
    }     
}]; 

//方法参数与block声明不能放到一行时。 
[[SessionService sharedService]     
    loadWindowWithCompletionBlock:^(SessionWindow *window) {  
           
        if (window) {              
        [self windowDidLoad:window];             
        } else {               
        [self errorLoadingWindow];             
        }         
    }];  

// 较长的Block可声明为变量。 
void (^largeBlock)(void) = ^{
     // ... 
}; 
[operationQueue_ addOperationWithBlock:largeBlock]; 

 // 一次调用中包含多个内联block。 
[myObject doSomethingWith:arg1
    firstBlock:^(Foo *a) { // ...
    }
    secondBlock:^(Bar *b){
            // ...
    }];

11、Container Literals

NSArray *array = @[ [foo description], @"Another String", [bar description] ];
NSDictionary *dict = @{ 
    NSForegroundColorAttributeName : [NSColor redColor] 
};
NSArray *array = @[     
    @"This",     
    @"is",    
    @"an",     
    @"array" 
]; 
NSDictionary *dictionary = @{
    NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
    NSForegroundColorAttributeName : fontColor
};

三、命名与规范

在撰写纯粹的Objective-C代码时,推荐使用驼峰命名法。

1、文件名

文件名应该反映其中包含的类实现的名称,按照项目中的约定且大小写相关。

2、Objective-C++

在一个源码文件中, Objective-C++ 遵循你实现的函数/方法的风格。
为了最小化在混合开发Cocoa/Objective-C和C++时由命名风格造成的冲突,遵循正在实现方法的风格。如果正在实现的方法是在@implementation 块中, 使用Objective-C的命名规范。如果正在实现的方法是在C++的class中,则采用C++的命名规范。

class CrossPlatformAPI {
  public:
    ... int DoSomethingPlatformSpecific(); // 每个平台的实现都不一样

  private:
    int an_instance_var_;
};

// 文件 mac_implementation.mm
#include "cross_platform_header.h" //

// 典型的Objective-C class, 使用Objective-C命名规范。
@interface MyDelegate :

    NSObject {
  @private
    int _instanceVar;
    CrossPlatformAPI *_backEndObject;
}
- (void)respondToSomething:(id)something;
@end

@implementation MyDelegate

- (void)respondToSomething:(id)something {

    //从Cocoa桥接到C++的后端
    _instanceVar = _backEndObject->DoSomethingPlatformSpecific();
    NSString *tempString = [NSString stringWithFormat:@"%d", _instanceVar];
    NSLog(@"%@", tempString);
}
@end

// C++ class平台相关的实现, 使用C++命名规范
int CrossPlatformAPI::DoSomethingPlatformSpecific() {

    NSString *temp_string = [NSString stringWithFormat:@"%d", an_instance_var_];
    NSLog(@"%@", temp_string);
    return [temp_string intValue];
}

3、类名

示例


@protocol AdvertisingViewDelegate <NSObject>

- (void)didSelectImageAtIndex:(NSInteger)index;

@end

@interface AdvertisingView : UIView

@property (weak, nonatomic) id <AdvertisingViewDelegate> delegate;

@end

4、Category名

比如我们要给NSString类加一个解析的功能,我们创建一个category,命名为GTMStringParsingAdditions,并且放在名为NSString+Parsing.h的文件中。

示例

//扩展一个framework类:
@interface NSString (GTMStringParsingAdditions)
- (NSString *)foobarString;
@end

//使方法和属性私有化
@interface FoobarViewController ()
@property(nonatomic, retain) NSView *dongleView;
- (void)performLayout;
@end

5、Objective-C 方法名

示例

- (id)getDelegate;  // 应避免的 
- (id)delegate;     // 推荐的

示例

- (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;          // 错误的

示例

- (id)initWithFrame:(CGRect)frameRect;  // 原有方法 
- (id)initWithFrame:(NSRect)frameRect
               mode:(int)aMode
          cellClass:(Class)factoryId
       numberOfRows:(int)rowsHigh
    numberOfColumns:(int)colsWide;     // 新方法

示例

// 推荐的
(int)runModalForDirectory:(NSString *)path file:(NSString *) name types:(NSArray *)fileTypes;   
//错误的      
(int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes;

6、变量名

6.1、普通变量名

int w;
int nerr;
int nCompConns;
tix = [[NSMutableArray alloc] init];
obj = [someObject object];
p = [network port];

建议使用如下的变量命名:

int numErrors;
int numCompletedConnections;
tickets = [[NSMutableArray alloc] init];
userInfo = [someObject object];
port = [network port];

6.2、类成员变量

6.3、常量

示例

const int kNumberOfFiles = 12;
NSString *const kUserKey = @"kUserKey";
enum EDisPlayTinge { 
    EDisplayTingeGreen = 1 E
    DisplayTingeBlue = 2 
};

6.4、静态变量

示例

static MyClass *sharedInstance = nil;
static MyClass *sMyClassInstance = nil;

7、图片命名

示例

「tabbar_btn_red_n.png」  //tabbar 导航栏,btn 按钮,n normal 状态

四、注释

1、文件注释

2、声明部分的注释

示例

/** 
  * <#Description#>
  * @param nibNameOrNil <#nibNameOrNil description#>
  * @param nibBundleOrNil <#nibBundleOrNil description#>
  * @return <#return value description#>
*/
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
@property(copy) NSString *host;   //network host

3、实现部分的注释

五、Cocoa 和 Objective-C 特性

1、重载指定构造函数

2、重载 NSObject 的方法

3、初始化

4、避免调用+ new

5、保持公共 API 简单

示例

#import "GTMFoo.h"
@interface GTMFoo (PrivateDelegateHandling)
- (NSString *)doSomethingWithDelegate;
// Declare private method
@end

@implementation GTMFoo (PrivateDelegateHandling)
- (NSString *)doSomethingWithDelegate {
    // Implement this method
}
@end

示例

@interface GTMFoo () { 
    ...
} 

6、#import与#include

-[强制] 使用#import来引用Objective-C/Objective-C++头文件,使用#include引用C/C++头文件。

7、使用根框架

示例

#import <Foundation/Foundation.h>     // good 
#import <Foundation/NSArray.h>        // avoid

8、在init和dealloc中避免使用存取方法

示例

- (instancetype)init {
    self = [super init];
    if (self) {
        _bar = [[NSMutableString alloc] init]; // good
    }
    return self;
}

- (void)dealloc {
    [_bar release];
    // good
    [super dealloc];
}

- (instancetype)init {
    self = [super init];
    if (self) {
        self.bar = [NSMutableString string];   // avoid
    }
    return self;
}

- (void)dealloc {
    self.bar = nil;   // avoid
    [super dealloc];
}

9、按照声明顺序销毁实例变量

10、setter中对NSString进行copy

示例

- (void)setFoo:(NSString *)aFoo {

    [_foo autorelease];
    _foo = [aFoo copy];
} 

11、避免抛出异常

12、BOOL的使用

示例

- (BOOL)isBold {
    return [self fontTraits] & NSFontBoldTrait;
}

- (BOOL)isValid {
    return [self stringValue];
}

- (BOOL)isBold {
    return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;
}

- (BOOL)isValid {
    return [self stringValue] != nil;
}

- (BOOL)isEnabled {
    return [self isValid] && [self isBold];
}

同样,不要直接比较 YES/NO 和 BOOL 变量。

BOOL great = [foo isGreat]; if (great == YES) {   // ...be great! } 
BOOL great = [foo isGreat]; if (great) {   // ...be great! } 

13、属性

示例

@interface MyClass : NSObject
@property(copy, nonatomic) NSString *name;
@end

@implementation MyClass
// No code required for auto-synthesis, else use: //
@synthesize name = _name;
@end

14、没有实例变量的接口

示例

@interface MyClass : NSObject // Does a lot of stuff 
- (void)fooBarBam; 
@end
 
@interface MyClass : NSObject { } // Does a lot of stuff 
- (void)fooBarBam; 
@end

15、自动synthesize实例变量

示例


@interface Foo : NSObject <Thingy>
// A guy walks into a bar.
@property(nonatomic, copy) NSString *bar;
@end

// Implementation file
@interface Foo ()
@property(nonatomic, retain) NSArray *baz;
@end

@implementation Foo
@synthesize widgetName = _widgetName;
@end

16、数据格式

-[强制]suggest:
NSDictionary *userDic =
@{@"login_phone": theApp.user.phone? theApp.user.phone : @"",
@"timestamp" : timestamp,
@"version" : kAppstore_Version,
@"encoding" : @"utf-8",
@"client_type": @"1",
@"app_code" : VKNetContext.app_ProCode,
@"push_id" : theApp.apnsToken ? theApp.apnsToken : @""};

avoid:
NSNumber *timestamp = [NSNumber numberWithInt:[[NSDate date] timeIntervalSince1970]];
NSDictionary *userDic = @{@"login_phone": theApp.user.phone? theApp.user.phone : @"",@"timestamp" : timestamp,@"version": kAppstore_Version,@"encoding" : @"utf-8",@"client_type": @"1",@"app_code" : VKNetContext.app_ProCode,@"push_id" : theApp.apnsToken ? theApp.apnsToken : @""};

六、性能调优

这里只列一些需要注意的点,具体原理参见iOS应用性能调优的25个建议和技巧

入门级(这是些你一定会经常用在你app开发中的建议)

中级(这些是你可能在一些相对复杂情况下可能用到的)

进阶级(这些建议只应该在你确信他们可以解决问题和得心应手的情况下采用)

上一篇 下一篇

猜你喜欢

热点阅读