iOS 代碼規範

概述

命名的好壞在開發中每每也不怎麼重視,畢竟差的命名也不會影響程序邏輯。可是很差的命名在大項目中帶來的隱形維護成本是至關高的,這些在項目開始時可能還很難察覺,然後來會陷入前仆後繼的維護困境中。咱們每每很是重視項目邏輯的複雜性,卻不能好好的把「簡單」的命名作好。其實,若是簡單的東西都作很差,那麼作出再複雜的東西那也是垃圾。html

命名規範

分類(類別)命名

與類命名相同,此外需添加要擴展的類名和「+」ios

舉例:NSString+URLEncodinggit

協議(委託)命名

與類命名相同,此外需添加「Delegate」後綴github

舉例:ReplyViewDelegateide

方法命名

首字母小寫,以後每一個單詞首字母都大寫函數

方法名使用動詞短語動畫

舉例:- (void)setupPostWithValue:(int)valueui

「要什麼」每每被胡亂命名爲get開頭的方法。首先get是一個動詞,因此它仍是「作什麼」或者說「作的是要什麼」。那麼get方法不要用於返回對象,但它可用於參數。編碼

- (XXItem *)getItemAtIndex:(NSUInteger)index                  //Bad!! 不規範的命名
- (XXItem *)itemAtIndex:(NSUInteger)index                     //Good, 命名清晰
- (void)getItem:(XXItem **)outItem atIndex:(NSUInteger)index  //比較符合規範,但第二種更好。

參數命名

首字母小寫,以後每一個單詞首字母都大寫atom

每一個參數前要加參數的名稱提示

舉例:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
- (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender

對象命名

採用修飾+類型的方式

舉例:

titleLabel    //表示標題的label,  是UILabel類型
confirmButton //表示確認的button, 是UIButton類型

圖片命名

使用英文,所有小寫 ,添加模塊名做爲前綴,避免衝突 。圖片應該與類文件同樣,按模塊分組放置

舉例:

Home(界面名稱)_(功能屬性簡寫+描述).png

如: home_btn_recommended.png 

或:

compose_mentionbutton_background@2x.png

compose_mentionbutton_background_highlighted@2x.png

分組命名

使用英文,首字母大寫,以後每一個單詞首字母都大寫

每一個分組使用模塊的名字

使用的開源庫統一放在「Library」分組下

使用的公共組件統一放在「Common」分組下

使用資源統一放在"Resource"分組下,包括文件、音頻、圖片、證書等

編碼規範 

編碼規範簡單來講就是爲了保證寫出來的代碼具有三個原則:可複用, 易維護, 可擴展. 這其實也是面向對象的基本原則. 可複用, 簡單來講就是不要寫重複的代碼, 有重複的部分要儘可能封裝起來重用。

判斷nil或者YES/NO

推薦:

if (someObject) { ... } 
if (!someObject) { ... }

不推薦:

if (someObject == YES) { ...} 
if (someObject != nil) { ...}

if (someObject == YES)容易誤寫成賦值語句

條件賦值

推薦:

result = object ? : [self createObject];

不推薦:

result = object ? object : [self createObject];

若是是存在就賦值自己, 簡潔。

BOOL賦值

推薦:

BOOL isAdult = age > 18;

不推薦:

BOOL isAdult;
if (age > 18)
{
    isAdult = YES;
}
else
{
    isAdult = NO;
}

拒絕死值

推薦:

if (car == Car.Nissan)
or
const int adultAge = 18; 
if (age > adultAge) { ... }

不推薦:

if (carName == "Nissan")
or
if (age > 18) { ... }

死值每次修改的時候容易被遺忘, 地方多了找起來就悲劇了. 並且定義成枚舉或者static可讓錯誤發生在編譯階段. 另外僅僅看到一個數字, 徹底不知道這個數字表明的意義. 納尼?

複雜的條件判斷

推薦:

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;
}

不推薦:

if (job.JobState == JobState.New
    || job.JobState == JobState.Submitted
    || job.JobState == JobState.Expired
    || (job.JobTitle && job.JobTitle.length))
{
    //....
}

清晰明瞭, 每一個函數DO ONE THING!

嵌套判斷

推薦:

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

不推薦:

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

一旦發現某個條件不符合, 當即返回, 條理更清晰。

全部的邏輯塊必須使用花括號包圍,即便條件體只需編寫一行代碼也必須使用花括號

推薦:

if (!error) {
    return success;
}

不推薦:

if (!error)
    return success;
...
if (!error) return success;

參數過多

推薦:

- (void)registerUser(User *user)
{
     // to do...    
}

不推薦:

- (void)registerUserName:(NSString *)userName
                password:(NSString *)password 
                   email:(NSString *)email
{
     // to do...
}

當發現實現某一功能須要傳遞的參數太多時, 就預示着你應該聚合成一個model類了...這樣代碼更整潔, 也不容易由於參數太多致使出錯。

點標記語法

屬性和冪等方法(屢次調用和一次調用返回的結果相同)使用點標記語法訪問,其餘的狀況使用方括號標記語法。

推薦:

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

不推薦:

[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;

枚舉

枚舉使用Objective-C方式來定義,枚舉命名是 類前綴+枚舉名,枚舉值要加枚舉名。

舉例:

typedef NS_ENUM(NSUInteger, HGMachineState) {
    HGMachineStateNone,
    HGMachineStateIdle,
    HGMachineStateRunning,
    HGMachineStatePaused
};

常量

常量應該類名稱+「駱峯式」單詞大寫。

推薦:

static const NSTimeInterval HGSignInViewControllerFadeOutAnimationDuration = 0.4;

不推薦:

static const NSTimeInterval fadeOutTime = 0.4;

常數是優於串聯字符串或數字的,容許多個地方使用經常使用變量,能夠迅速改變不須要查找和替換。常量應該聲明爲靜態常量而不使用宏定義,除非明確須要定義一個宏。

推薦:

static NSString * const ZOCCacheControllerDidClearCacheNotification = @"ZOCCacheControllerDidClearCacheNotification";
static const CGFloat ZOCImageThumbnailHeight = 50.0f;

不推薦:

#define CompanyName @"Apple Inc."
#define magicNumber 42

單例模式

使用GCD代替使用sharedInstance,每次調用+ (id)sharedInstance函數都會付出取鎖的代價。

推薦:

+ (instancetype)sharedInstance
{
   static id sharedInstance = nil;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
      sharedInstance = [[self alloc] init];
   });
   return sharedInstance;
}

不推薦:

+ (instancetype)sharedInstance
{
    static id sharedInstance;
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[MyClass alloc] init];
        }
    }
    return sharedInstance;
}

代理

定義一個協議是 類名+Delegate,並要使用weak 弱指針,協議使用可選@optional

@class ZOCSignUpViewController;

@protocol ZOCSignUpViewControllerDelegate <NSObject>
@required
- (void)signUpViewController:(ZOCSignUpViewController *)controller didProvideSignUpInfo:(NSDictionary *);
@optional
- (void)signUpViewControllerDidPressSignUpButton:(ZOCSignUpViewController *)controller;
@end


@interface ZOCSignUpViewController : UIViewController

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

@end

在發送委託代理方法以前,必定要先檢查該委託方法已經被實現(不然會崩潰)。

if ([self.delegate respondsToSelector:@selector(signUpViewControllerDidPressSignUpButton:)]) {
    [self.delegate signUpViewControllerDidPressSignUpButton:self];
}

動畫

推薦

[UIView animateWithDuration:1.0
                 animations:^{
                     // something
                 }
                 completion:^(BOOL finished) {
                     // something
                 }];

不推薦

[UIView animateWithDuration:1.0 animations:^{
    // something 
} completion:^(BOOL finished) {
    // something
}];

Pragma Mark

使用「#pargma mark - 」實現方法的分組。建議按下面幾點單獨分組:

1.功能分組

2.代理協議實現分組

3.重寫父類方法

- (void)dealloc { /* ... */ }
- (instancetype)init { /* ... */ }

#pragma mark - View Lifecycle

- (void)viewDidLoad { /* ... */ }
- (void)viewWillAppear:(BOOL)animated { /* ... */ }
- (void)didReceiveMemoryWarning { /* ... */ }

#pragma mark - Custom Accessors

- (void)setCustomProperty:(id)value { /* ... */ }
- (id)customProperty { /* ... */ }

#pragma mark - IBActions

- (IBAction)submitData:(id)sender { /* ... */ }

#pragma mark - Public

- (void)publicMethod { /* ... */ }

#pragma mark - Private

- (void)zoc_privateMethod { /* ... */ }

#pragma mark - UITableViewDataSource

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { /* ... */ }

#pragma mark - ZOCSuperclass

// ... overridden methods from ZOCSuperclass

#pragma mark - NSObject

- (NSString *)description { /* ... */ }

抽象方法定義

在Componens中有不少的抽象類,由於Objective-C沒有語法限定抽象類,因此咱們約定一下抽象類的註釋和聲明方法。
在類註釋中聲明該類爲抽象類,抽象方法必須爲公開方法,並添加#pragma標記註釋 
@interface TestClass : NSObject

#pragma mark - Abstract Method

//抽象方法
-(void)doWork;

@end

抽象類不容許被實例化,因此須要在init方法中添加判斷代碼

@implementation TestClass

- (id)init {
    if( [self class] == [TestClass class]) {
        @throw [NSException exceptionWithName:@"抽象類沒法實例化" reason:@"抽象類沒法實例化: TestClass" userInfo:nil];
    }
    else {
        self = [super init];
        if(self){
            
        }
        return self;
    }
}

#pragma mark - Abstract Method

- (void)doWork {
    @throw [NSException exceptionWithName:@"抽象方法沒有被實現" reason:@"抽象方法沒有被實現: doWork" userInfo:nil];
}

@end

 

參數連接:

https://github.com/objc-zen/objc-zen-book

http://www.cocoachina.com/ios/20151014/13678.html

http://www.cocoachina.com/ios/20151118/14242.html

相關文章
相關標籤/搜索