iOS編碼規(guī)范

總體命名規(guī)則

  • 命名原則首先是要顧名思義。命名不要太隨意,描述性的命名是最好的健民。
  • 變量名抒巢、方法名遵守駝峰命名法,首字母小寫秉犹。
  • 類名蛉谜、協(xié)議名、枚舉類型遵守駝峰命名法凤优,首字母大寫悦陋,這些命名前面均需加前綴,推薦“JM“ + (功能簡稱)筑辨。
  • 常量名以k開頭,如kJMTest幸逆。
  • 宏所有字母均大寫棍辕,命名前面加前綴,推薦”JM“ + (功能簡稱)还绘。
  • 通知Notification的格式 推薦 類/頭文件名 + 進行狀態(tài)(Will | Did) + 通知名稱 + Notification
  • 協(xié)議名使用Delegate做后綴楚昭,DataSource使用DataSource做后綴。

頭文件

  • 聲明一個孤立的class或protocol 將聲明放入單獨的文件拍顷,
    使頭文件名與聲明的class/protocol相同抚太。

  • 聲明關聯(lián)的class或protocol 將關聯(lián)的聲明(class/category/protocol)放入同一個頭文件,頭文件名與主要的class/category/protocol相同。

變量

變量盡量以描述性的方式來命名尿贫。單個字符的變量命名應該盡量避免电媳,除了在for()循環(huán)。
星號表示變量是指針庆亡。例如匾乓, <font color=#FF69B4>NSString *text </font>既不是 <font color=#FF69B4>NSString* text</font> 也不是 <font color=#FF69B4>NSString * text</font>,除了一些特殊情況下常量又谋。

  1. 類成員變量

    類中所有成員變量以屬性的方式提供拼缝,不要使用其他類型的變量聲明。

    通過使用'back'屬性(_variable彰亥,變量名前面有下劃線)直接訪問實例變量應該盡量避免咧七,除了在初始化方法 <font color=#FF69B4>(init, initWithCoder:</font>, 等…), <font color=#FF69B4>dealloc</font> 方法和自定義的<font color=#FF69B4>setters</font>和<font color=#FF69B4>getters</font>任斋。如果要使用成員變量继阻,必須以下劃線'_'開頭,如 NSString *_name。局部變量不應該包含下劃線仁卷。

    應該:

    @interface Test : NSObject
    @property (nonatomic, strong) NSString *name;
    @end
    

    不應該:

    @interface Test : NSObject {
     NSString *_name;
        }
    
  2. 私有屬性應該聲明在類的.m中穴翩,只有需要外部使用的變量才聲明在.h中。

  3. 所有屬性特性應該顯式地列出來锦积,有助于新手閱讀代碼芒帕。屬性特性的順序應該是atomicity、storage丰介。

    應該:

    @property (nonatomic, strong) NSString *name;
    

    不應該:

    @property (nonatomic) NSString *testName;
    
  4. 屬性是指針類型的集合時背蟆,格式如下:
    @property (nonatomic, strong) NSArray <Item *>*array;

  5. 屬性是delegate時,聲明成weak哮幢,防止循環(huán)引用带膀,格式如下:
    @property(nonatomic, weak) id<UIScrollViewDelegate> delegate;

常量

常量應該使用static來聲明而不是使用#define,除非顯式地使用宏橙垢。

應該:

static NSString * const kJMAboutViewController = @"JMAboutViewController";
static CGFloat const kRowHeight = 50.0;

不應該:

#define kJMAboutViewController @"JMAboutViewController"
#define kRowHeight 2

布爾值

Objective-C使用的是BOOL值垛叨,對應的是YES和NO。true和false是bool類型柜某,Objective-C不要使用嗽元。

既然nil解析成NO,所以沒有必要在條件語句比較喂击。不要拿某樣東西直接與YES比較剂癌。

應該:

if (someObject) {
}
if (![anotherObject boolValue]) {
}

不應該:

if (someObject == nil) {}
if ([anotherObject boolValue] == NO) {}
if (isAwesome == YES) {} // Never do this.
if (isAwesome == true) {} // Never do this.

如果BOOL屬性的名字是一個形容詞,屬性就能忽略"is"前綴翰绊,但要指定get訪問器的慣用名稱佩谷。例如:
@property (assign, nonatomic, getter=isEditable) BOOL editable;

枚舉型

普通枚舉型

typedef NS_ENUM(NSInteger,JMTypeTest){
 kJMTypeA = 0, // 注釋
 kJMTypeB = 1, // 注釋
 kJMTypeC = 2, // 注釋
 kJMTypeD = 3  // 注釋
};

可按位或

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

字面值

NSString, NSDictionary, NSArray, 和 NSNumber的字面值應該在創(chuàng)建這些類的不可變實例時被使用旁壮。請?zhí)貏e注意nil值不能傳入NSArray和NSDictionary字面值,因為這樣會導致crash谐檀。

應該:

NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingStreetNumber = @10018;

不應該:

NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingStreetNumber = [NSNumber numberWithInteger:10018];

操作符

一元操作符不帶空格抡谐,多元運算符要帶空格隔開。

  1. 逗號后面都要跟隨一個空格稚补。

    NSArray *array = @[1, 2, 3, 4];

  2. 二元操作符童叠,如+, -课幕, *厦坛, /,>乍惊, <杜秸, =, ==润绎, ->撬碟, <<, >>等莉撇。

    a + b = c;
    a > b;
    a == b;
    a << 2;
    Object -> c;
    
  3. 三元操作符 Non-boolean的變量與某東西比較呢蛤,加上括號()會提高可讀性。如果被比較的變量是boolean類型棍郎,那么就不需要括號其障。

    應該:

    NSInteger value = 5;
    result = (value != 0) ? x : y;
    
    BOOL isHorizontal = YES;
    result = isHorizontal ? x : y;
    

    不應該:

    result = a > b ? x = c > d ? c : d : y;
    result = a ?: b;
    

集合類型

  • 如果初始值太長,元素需要換行涂佃,使?四個空格來進行縮進,右括號 ] 或者 } 寫在新的?行,并且與調?語法糖那?代碼的第一個非空字符對齊励翼。
  • 構造字典時,字典的 Key 和 Value與中間的冒號都要留一個空格辜荠。
  • 需要使用類似”增刪改查”方法來對集合進行操作時汽抚,方法名前面加上“add”、“remove”伯病、“update”類似表明函數(shù)功能的關鍵字造烁。
NSArray *array = @[ 
    @"This",
    @"is",
    @"an", 
    @"array"
];

NSDictionary *dictionary = @{
    NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12], 
    NSForegroundColorAttributeName : fontColor 
};

系統(tǒng)保留字

  • 系統(tǒng)保留字如if/else、do/while午笛、try/catch 跟()和{}之間都要留一個空格膨蛮。
  • 將關鍵字與花括號放在一行。
  • switch語句每個分支都必須用大括號包起來季研。
  • switch使用枚舉型時,如果窮舉完所有情況誉察,不能有default分支与涡。其他情況,都必須有default分支。

應該

if (a == 1) {
    NSLog(@"test1");
} else if (b == 2) {
    NSLog(@"test2");
} else {
    NSLog(@"test3");
}
switch (condition) {
  case 1:
    // ...
    break;
  case 2: {
    // ...
    // Multi-line example using braces
  }
    break;
  case 3:
    // ...
    break;
  default: 
    // ...
    break;
}

不應該

if(a==1){
    NSLog(@"test1");
}else if(b==2){
    NSLog(@"test2");
}else{
    NSLog(@"test3");
}

if條件語句

  • 條件語句主體為了防止出錯應該使用大括號包圍驼卖,即使只有一行代碼氨肌。這些錯誤包括添加第二行代碼和期望它成為if語句,但是沒包含進大括號酌畜;還有怎囚,更危險的可能發(fā)生在if語句里面一行代碼被注釋了,然后下一行代碼不知不覺地成為if語句的一部分桥胞。

    應該:

    if (!error) {
        return success;
    }
    

    不應該:

    if (!error)
       return success;
    

    if (!error) return success;

  • 不要使用過多的分支恳守,善于使用return來提前返回錯誤情況,把最正確的情況放到最后返回贩虾。

    應該

    if (!user.UserName) {
        return NO;
    }
    if (!user.Password) {
        return NO;
    }
    if (!user.Email) {
        return NO;
    }
    return YES;
    

    不應該

    BOOL isValid = NO;
    if (user.UserName)  {
        if (user.Password) {
            if (user.Email) {
                isValid = YES;
            }
         }
    }
    return isValid;
    
  • 條件過多催烘,過長的時候應該換行。條件表達式如果很長缎罢,則需要將他們提取出來賦給一個BOOL值伊群,或者抽取出一個方法。

    應該

    if (condition1 && 
         condition2 && 
         condition3 && 
         condition4) {
        // Do something
    }
    
    BOOL finalCondition = condition1 && condition2 && condition3 && condition4
    if (finalCondition) {
       // Do something
    }
    
    if ([self canDelete]) {
       // Do something
    }
    
    - (BOOL)canDelete{
        BOOL finalCondition1 = condition1 && condition2;
        BOOL finalCondition2 =  condition3 && condition4;
        return condition1 && condition2;
    }
    

    不應該

    if (condition1 && condition2 && condition3 && condition4) {
        // Do something
    }
    
  • if條件語句是和常量比較時策精,多于3個舰始,使用switch/case實現(xiàn)。

函數(shù)聲明

  • 方法名和參數(shù)盡量讀起來像是一句話咽袜。
  • 方法名不允許使用 get丸卷、 do 或does 做前綴,動詞本身的暗示就夠了酬蹋。
  • 如果方法是為了獲取對象的一個屬性值及老,直接用屬性名稱來命名方法,不要添加 get 或其他的動詞范抓。
  • and 和 with 不應該用于多個參數(shù)來說明骄恶。
  • 方法類型(-/+)和返回值之間要有一個空格。
  • 參數(shù)類型和指針符之間要留空格匕垫。
  • 參數(shù)類型和冒號之間不需要留空格僧鲁。
  • 參數(shù)類型和參數(shù)名之間不需要留空格。

應該

- (UIView *)initWithTitle:(NSString *)title backgroundColor:(UIColor *)color;

不應該

-(UIView *)initWithTitle:(NSString *)title withBackgroundColor: (UIColor*) color;

函數(shù)實現(xiàn)

  • { 和函數(shù)名可以在同一行象泵,也可以換行寞秃。但是一個類文件里面要保持統(tǒng)一風格。修改者要遵循創(chuàng)建者的風格偶惠。
  • 函數(shù)和函數(shù)之間空一行春寿。
  • 內部實現(xiàn)時,花括號的嵌套要注意對齊忽孽。也可以全部選中绑改,然后使用快捷鍵control+I谢床。
  • 每行建議不超過120個字符,函數(shù)名過長時厘线,使用冒號對齊的方式识腿。
  • 如果在不同的函數(shù)內部有相同的功能,應該把相同的功能抽取出來單獨作為另一個函數(shù)造壮。
  • 將函數(shù)內部比較復雜的邏輯提取出來作為單獨的函數(shù)渡讼。
  • 盡量避免空方法的產生。
- (void)popBack {
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure

.m文件整理

  • 如果有實例化函數(shù)應該放在最前面耳璧。
  • 如果是view或者viewController的.m文件成箫,應該按照loadView、viewDidLoad楞抡、viewWillApperar伟众、viewDidAppear、viewWillDisappear召廷、viewDidDisapper和dealloc的順序實現(xiàn)凳厢,并且這些生命周期相關的函數(shù)放在最前面。
  • 后面再跟viewWillLayoutSubviews和viewDidLayoutSubviews等這些布局相關的函數(shù)竞慢。
  • setter先紫、getter同類型方法放在一起,并用pragma mark - setter方法 或 pragma mark - getter方法進行標注筹煮。
  • 相同delegate和datasource的函數(shù)放在一起遮精,并用pragma mark - xxx標注。

init方法

Init方法應該遵循Apple生成代碼模板的命名規(guī)則败潦。返回類型應該使用instancetype而不是id本冲。

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

類構造方法

當類構造方法被使用時,它應該返回類型是instancetype而不是id劫扒。這樣確保編譯器正確地推斷結果類型檬洞。

@interface Airplane
+ (instancetype)airplaneWithType:(RWTAirplaneType)type;
@end

回調方法

函數(shù)調用的可知性,回調時被調用者要知道其調用者沟饥,方便信息的傳遞添怔,所以建議在回調方法第一個參數(shù)中加上調用者。除非只有一個名為sender的參數(shù)贤旷。

如:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)windowShouldClose:(id)sender;

CGRect函數(shù)

當訪問CGRect里的x, y, width, 或 height時广料,應該使用CGGeometry函數(shù)而不是直接通過結構體來訪問。引用Apple的CGGeometry:

應該:

CGRect frame = self.view.frame;

CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
CGRect frame = CGRectMake(0.0, 0.0, width, height);

不應該:

CGRect frame = self.view.frame;

CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;
CGRect frame = (CGRect){ .origin = CGPointZero, .size = frame.size };

單例模式

單例對象應該使用線程安全模式來創(chuàng)建共享實例幼驶。

+ (instancetype)sharedInstance {
  static id sharedInstance = nil;

  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    sharedInstance = [[self alloc] init];
  });

  return sharedInstance;
}

Block

  • 較短的Block可以寫在一行內艾杏。
  • 如果block過于龐大,應該使用typedef單獨聲明成一個變量來使用盅藻。
    typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);
  • 如果分行顯示的話糜颠,block的右括號應該和調用block那行代碼的第一個非空字符對齊汹族。
  • block內的代碼注意縮進對齊。
  • ^ 和左括號 ( 或者 { 之間沒有空格其兴,參數(shù)列表的右括號 ) 和 {之間有一個空格。
__weak typeof(manager)wManager = manager;
    
[manager POST:url parameters:reqDic progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [wManager invalidateSessionCancelingTasks:false];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [wManager invalidateSessionCancelingTasks:false];
    }];
    

圖片資源命名

圖片資源命名方式夸政,以 模塊 + 功能 為組織形式元旬,如果相同功能有多個,比如表情守问,則再加編號匀归。

如:

tabbar_item_1.png
tabbar_item_2.png

maitoutiao_topicon_1.png
maitoutiao_topicon_2.png

注釋

  • 使用 // 注釋時,后面要加一個空格耗帕,如果注釋+被注釋文本過長穆端,使用/*xxx*/。
  • 對函數(shù)注釋時仿便,將光標移到函數(shù)行体啰,使用option+command+/快捷鍵來生成注釋。
  • 對delegate和dataSource實現(xiàn)時嗽仪,在第一個函數(shù)前面#pragma mark - xxx來進行標注荒勇。

警告??

盡量減少??的產生,能修改的要及時修改闻坚。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末沽翔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子窿凤,更是在濱河造成了極大的恐慌仅偎,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雳殊,死亡現(xiàn)場離奇詭異橘沥,居然都是意外死亡,警方通過查閱死者的電腦和手機相种,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門威恼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寝并,你說我怎么就攤上這事箫措。” “怎么了衬潦?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵斤蔓,是天一觀的道長。 經常有香客問我镀岛,道長弦牡,這世上最難降的妖魔是什么友驮? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮驾锰,結果婚禮上卸留,老公的妹妹穿的比我還像新娘。我一直安慰自己椭豫,他們只是感情好耻瑟,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赏酥,像睡著了一般喳整。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上裸扶,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天框都,我揣著相機與錄音,去河邊找鬼呵晨。 笑死魏保,一個胖子當著我的面吹牛,可吹牛的內容都是我干的何荚。 我是一名探鬼主播囱淋,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼餐塘!你這毒婦竟也來了妥衣?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤戒傻,失蹤者是張志新(化名)和其女友劉穎税手,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體需纳,經...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡芦倒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡献起,死狀恐怖,靈堂內的尸體忽然破棺而出器钟,到底是詐尸還是另有隱情,我是刑警寧澤妙蔗,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布傲霸,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏昙啄。R本人自食惡果不足惜穆役,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梳凛。 院中可真熱鬧耿币,春花似錦、人聲如沸伶跷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叭莫。三九已至,卻和暖如春烁试,著一層夾襖步出監(jiān)牢的瞬間雇初,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工减响, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留靖诗,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓支示,卻偏偏與公主長得像刊橘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子颂鸿,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容

  • 摘要 為了規(guī)范看準iOS編碼而作促绵。主要包含編碼格式和命名規(guī)范兩大章節(jié)。 在寫之前對下面所用的有些詞匯進行一些約定:...
    叫我公爵大人閱讀 276評論 0 1
  • Object-C 開發(fā)代碼規(guī)范概要Object-C是一門面向對象的動態(tài)編程語言嘴纺,主要用于編寫IOS和MAC應用程序...
    克魯?shù)吕?/span>閱讀 534評論 0 1
  • 在開發(fā)過程中败晴,我們不僅要去看別人的代碼,也要讓別人看我們的代碼栽渴。每個人的Objective-C編碼風格都不一樣尖坤,這...
    叫我GuanRen閱讀 176評論 0 1
  • 面試被問到公司編碼規(guī)范問題,感覺有很多東西闲擦,但是不知道該怎么說出來慢味,今天突然找到 李明杰 老師的一份編碼規(guī)范。重新...
    Dombo_Y閱讀 967評論 1 2
  • ——書法班老師布置的作業(yè)(臨褚遂良) ——某同學的作業(yè)(是不是形神兼?zhèn)涓兄纾浚?我在味古方室書法培訓機構里已經進過四次...
    金垛愚叟閱讀 352評論 0 0