Objective-C編程規范

引言

一直以來都是在談如何開發, 如開發的小技巧小經驗

今天為什么突然說起編程規范來了呢?

因為在我看來, 編程規范是反映一個開發者或是一個開發團隊素質和成熟度的最重要標志!

注意這里的措辭很嚴厲哈, 我用了"最重要"

當我們看到各種文不表意的函數命名、剪不斷理還亂的文件和代碼結構、以及不符合Apple官方基本規范的風格時

我想說: 程序員的加班 -- 你懂得(開發者制造的問題往往比他們解決的問題要多)

如果讀者覺得有比編程規范更重要的事情, 可以來辯, 歡迎拍磚~

本文的代碼規范基于The official raywenderlich.com Objective-C style guide, 但不局限于此, 結合實際開發遇到的問題, 做了部分修訂和補充

背景

Apple官方的代碼規范, 供補充參考:

目錄

語言

使用美式英語

Preferred:

UIColor *myColor = [UIColor whiteColor];

Not Preferred:

UIColor *myColour = [UIColor whiteColor];

代碼組織

使用#pragma mark -對function/protocol/delegate進行分組

#pragma mark - Lifecycle

- (instancetype)init {}
- (void)dealloc {}
- (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)privateMethod {}

#pragma mark - Protocol

#pragma mark - UITextFieldDelegate
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate

#pragma mark - NSCopying

- (id)copyWithZone:(NSZone *)zone {}

#pragma mark - NSObject

- (NSString *)description {}

空格

條件表達式的括號 (如: if/else/switch/while), 左括號和表達式在同一行, 右括號另起一行

Preferred:

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

Not Preferred:

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

避免使用冒號對齊方式, 除非代碼過長需要換行, 但是不要讓block也同樣保持冒號對齊

Preferred:

// blocks are easily readable
[UIView animateWithDuration:1.0f animations:^{
  // something
} completion:^(BOOL finished) {
  // something
}];

Not Preferred:

// colon-aligning makes the block indentation hard to read
[UIView animateWithDuration:1.0
                 animations:^{
                     // something
                 }
                 completion:^(BOOL finished) {
                     // something
                 }];
  • 簽代理

Preferred:

@interface UIViewController : UIResponder <NSCoding, UIAppearanceContainer>
@property (nonatomic, assign) id<ChooseProvinceViewControllerdDelegate> delegate;

Not Preferred:

@interface UIViewController : UIResponder<NSCoding,UIAppearanceContainer>
@property (nonatomic, assign) id <ChooseProvinceViewControllerdDelegate> delegate;

注釋

  • 確實需要, 才加注釋

  • 注釋是用來解釋why, 而不是what

Preferred:

// alignment attributes must have a secondViewAttribute
// therefore we assume that is refering to superview
// eg make.left.equalTo(@10)
if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
    secondLayoutItem = self.firstViewAttribute.view.superview;
    secondLayoutAttribute = firstLayoutAttribute;
}

Not Preferred:

/**
 * show head image
 */
@property (nonatomic, strong) DDImageView *headView;

// im conversation done edit
- (void)imConversationDoneEdit;
  • 添加的注釋要保持更新或刪除

命名

  • 使用長且描述性強的命名方式

Preferred:

UIButton *settingsButton;

Not Preferred:

UIButton *setBut;
  • 在類名和常量名前加上3個字母的前綴(Core Data entity names去掉前綴)

需要統一整個工程的命名前綴, 因為OC里沒有namespace, 工程越龐大后果越嚴重

  • 常量的命名采用"駝峰"的命名方式

Preferred:

static NSTimeInterval const RWTTutorialViewControllerNavigationFadeAnimationDuration = 0.3f;

Not Preferred:

static NSTimeInterval const fadetime = 1.7f;

成員的命名采用首字母小寫的"駝峰"命名方式, 并且使用auto-synthesis方式聲明成員, 而不是@synthesize方式

Preferred:

@property (nonatomic, copy) NSString *descriptiveVariableName;

Not Preferred:

id varnm;

命名時注意存儲數據的數據結構發生改變的時候,會不會引起命名的改變。

Preferred:

@property (nonatomic, strong) NSArray *actionSheetItems;
@property(nullable, nonatomic, copy) NSArray<UIBarButtonItem *> *items;   

Not Preferred:

@property (nonatomic, strong) NSArray *actionSheetItemArray;

圖標資源命名

模塊名+功能名+[狀態],( [ ] : 表明可選)

圖標在Xcode里面的名稱需要與圖標的物理命名保持一致

Preferred:

addressbook_isvnetwork // 指代沒有狀態的圖標名

addressbook_call_normal 
addressbook_call_highlight  // 指代有多種狀態的圖標名

conference_member_delete_normal
conference_member_delete_highlight  // 指代功能名較長且有多種狀態的圖標名

下劃線

使用self.方式來訪問對象的成員(參考點語法), 從視覺上就可以區分出哪些是本對象成員

注意:

  • 在初始化方法(init, initWithCoder:等), dealloc以及setters/getters方法中中必須使用保留的_variableName

  • 局部變量不要用下劃線開頭! 因為下劃線開頭的命名方式是Apple保留的命名方式

方法

  • 方法類型(-/+)的后面有個空格

  • 每一個參數都要有描述

注意:

  • 不要在多個參數的描述中添加"and", 例如下面的initWithWidth:height:方法

Preferred:

- (void)setExampleText:(NSString *)text image:(UIImage *)image;
- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;
- (id)viewWithTag:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;

Not Preferred:

-(void)setT:(NSString *)text i:(UIImage *)image;
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
- (id)taggedView:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height;
- (instancetype)initWith:(int)width and:(int)height;  // Never do this.

變量

變量命名要可讀性強, 避免用單個單詞的命名方式, 除了在for()循環里

指針的星號和變量名連在一起, 例如: NSString *text, 而不是NSString* text, NSString * text

避免直接使用_viriableName方式訪問對象的成員, 除了在初始化方法(init, initWithCoder:等), dealloc方法以及setters/getters方法中點語法

了解更多關于在初始化和dealloc中使用accessor方法, 請參考這里.

Preferred:

@interface RWTTutorial : NSObject

@property (nonatomic, copy) NSString *tutorialName;
@property (nonatomic, copy) NSArray<UIBarButtonItem *> *items;

@end 

Not Preferred:

@interface RWTTutorial : NSObject {
  NSString *tutorialName;
}

如果變量是一個度量的話(如按時間長度或者字節數),那么最好把名字帶上它的單位

Preferred:

NSString *durationOfSeconds;

Not Preferred:

NSString *duration;

屬性

屬性要按照先atomicity后storage的順序, 這是為了和Apple的Interface Builder生成的代碼保持一致.不用對齊,根據功能用空格實現分組

Preferred:

@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nullable, readonly, nonatomic, copy) NSString *tutorialName;

Not Preferred:

@property (weak, nonatomic) IBOutlet UIView *containerView;
@property (nonatomic) NSString *tutorialName;

注意:

  • 控件的storage屬性通常設置為weak, 而非strong

如果成員引用的對象是可變對象, 那么需要使用copy而非strong

Why?

因為即使成員的類型是NSString, 但實際傳入的如果是NSMutableString的對象

該對象在你不知情的情況下, 仍然會被修改

Preferred:

@property (nonatomic, copy) NSString *tutorialName;

Not Preferred:

@property (nonatomic, strong) NSString *tutorialName;

點語法

點語法實際是對accessor方法的封裝

了解更多點語法, 請參考這里

訪問和操作對象成員, 推薦使用點語法; Bracket notation is preferred in all other instances.

Preferred:

NSInteger arrayCount = [self.array count];
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;

Not Preferred:

NSInteger arrayCount = self.array.count;
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;

Object Literals

使用Object Literals(@)方式來快速創建NSString, NSDictionary, NSArray, NSNumber實例

注意:

  • 如果傳給NSArray, NSDictionary的值是nil會導致crash

Preferred:

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

Not Preferred:

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];
  • 容器類型最好標明存儲數據的類型

Preferred:

@property (nonatomic, readonly, nullable) NSArray<NSIndexPath *> *indexPathsForVisibleRows;

- (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView ;
  • 在數組和字典中, 使用索引和關鍵字來獲取數據

Preferred:

NSString *name = names[1];
NSString *product = [productManagers valueForKey:@"kate"]

Not Preferred:

NSString *name = [names objectAtIndex:1];
NSString *product = [productManagers objectForKey:@"@kate"]

常量

使用static而非#define來聲明常量; unless explicitly being used as a macro

用const修飾時,const右邊的總是不能被修改.聲明時不用對齊,根據功能用空格實現分組

Preferred:

static NSString * const RWTAboutViewControllerCompanyName = @"RayWenderlich.com";

static CGFloat const RWTImageThumbnailHeight = 50.0f;

Not Preferred:

#define CompanyName @"RayWenderlich.com"

#define thumbnailHeight 2.0f
  • 宏定義

使用大寫字母,用_分割單詞,宏定義中如果包含表達式或變量,表達式和變量必須用小括號括起來

不到萬不得已不推薦使用宏定義像數字常量,通知的參數一般不推薦使用宏定義,推薦使用static const 的形式

Preferred:

#define SCREEN_RECT ([UIScreen mainScreen].bounds)

#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
  • 浮點數

使用浮點數在數值的后面加上f,用來區別double類型

Preferred:

static NSTimeInterval const RWTTutorialViewControllerNavigationFadeAnimationDuration = 0.3f;

Not Preferred:

static NSTimeInterval const RWTTutorialViewControllerNavigationFadeAnimationDuration = 0.3;

枚舉

使用NS_ENUM()聲明枚舉, 因為它具有更強的類型檢查機制

For Example:

typedef NS_ENUM(NSInteger, RWTLeftMenuTopItemType) {
  RWTLeftMenuTopItemMain,
  RWTLeftMenuTopItemShows,
  RWTLeftMenuTopItemSchedule
};

當然你還是可以顯式地設置枚舉的值

typedef NS_ENUM(NSInteger, RWTGlobalConstants) {
  RWTPinSizeMin = 1,
  RWTPinSizeMax = 5,
  RWTPinCountMin = 100,
  RWTPinCountMax = 500,
};

不要使用老式的枚舉定義方式, 除非編寫CoreFoundation C的代碼

Not Preferred:

enum GlobalConstants {
  kMaxPinSize = 5,
  kMaxPinCount = 500,
};

Case表達式

Case表達式通常不需要加括號

Case內容有if判斷句, for循環和局部變量時, 需要加上括號 (左括號的右邊, break放在括號外). break與下一個case之間有空行.

switch (condition) {
  case 1:  {
     for () {
        // ...
     }
  }
     break;
  
  case 2: {
    if {
    //
    }
  }
    break;
  
  case 3:
    // ...
    break;
  
  default: 
    // ...
     break;
  }

多個Case表達式執行相同的邏輯, 使用fall-through方式(即刪除表達式里的break)

此時, 需要加上注釋說明注釋

switch (condition) {
  case 1:
    // ** fall-through! **
  case 2:
    // code executed for values 1 and 2
    break;
    
  default: 
    // ...
    break;
}

私有成員

私有屬性要在類的實現中聲明: 放在class extension(即匿名category)中

For Example:

@interface RWTDetailViewController ()

@property (nonatomic, strong) GADBannerView *googleAdView;
@property (nonatomic, strong) ADBannerView *iAdView;
@property (nonatomic, strong) UIWebView *adXWebView;

@end

布爾

Objective-C使用YESNO, 而truefalse只用在CoreFoundation, C或C++代碼里

Since nil resolves to NO it is unnecessary to compare it in conditions. Never compare something directly to YES, because YES is defined to 1 and a BOOL can be up to 8 bits.

This allows for more consistency across files and greater visual clarity.

Preferred:

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

Not Preferred:

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

如果BOOL類型的屬性是一個形容詞, 那么可以去掉"is"前綴, 但get accessor中仍然需要保留前綴

@property (assign, getter=editable) BOOL editable;

例子來自Cocoa Naming Guidelines.

條件語句

條件語句要加上括號, 即使是一行語句, 否則會存在隱患: even more dangerous defect

Preferred:

if (!error) {
  return success;
}

Not Preferred:

if (!error)
  return success;

or

if (!error) return success;

三元運算符

如果可以使代碼變得簡潔和高效, 那么可以考慮使用三元運算符?:, 否則還是用if表達式

通常, 給變量賦值時, 可以考慮使用三元運算符?:

Preferred:

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

BOOL isHorizontal = YES;
result = isHorizontal ? x : y;

Not Preferred:

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

初始化方法

初始化方法要和Apple模板保持一致

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

返回值類型是'instancetype'而不是'id'

關于instancetype, 請參考類構造方法

類構造方法

類構造方法返回值類型是'instancetype'而不是'id', 這樣可以幫忙編譯器推導出返回值得類型

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

了解更多關于instancetype: NSHipster.com.

CGRect函數

要獲取CGRectx, y, width, height, 不要直接訪問結構體的成員, 而應該使用CGGeometry functions

Apple官方對于CGGeometry的解釋:

All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.

Preferred:

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.0f, 0.0f, width, height);

Not Preferred:

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

Golden Path

如果把需要執行的邏輯比作"golden"或"happy" path

那么在判斷條件不滿足時, 直接return退出方法, 而不是判斷條件滿足時, 執行該Golden Path

Preferred:

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

Not Preferred:

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

錯誤處理

通過方法的返回值而不是返回的error引用, 來做錯誤處理的判斷條件

Preferred:

NSError *error;
if (![self trySomethingWithError:&error]) {
  // Handle Error
}

Not Preferred:

NSError *error;
[self trySomethingWithError:&error];
if (error) {
  // Handle Error
}

單例

單例對象的實例化必須要確保線程安全

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

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

  return sharedInstance;
}

否則可能會出現這樣的問題possible and sometimes prolific crashes.

換行

頭文件中的方法, 使用冒號對齊的方式

Preferred:

 - (void)setViewWithHeadImageUrl:(NSString *)headImageUrl 
                            name:(NSString *)name 
                     phoneNumber:(NSString *)phoneNumber;

Not Preferred:

- (void)setViewWithHeadImageUrl:(NSString *)headImageUrl name:(NSString *)name phoneNumber:(NSString *)phoneNumber;

實現文件或方法調用時, 不用冒號對齊

Preferred:

[[MSDBHelper sharedInstance] updateCallRecordsWithNumber:number isPersonalContact:YES oldName:oldContact.displayName toNewName:@""];

Not Preferred:

[[MSDBHelper sharedInstance] updateCallRecordsWithNumber:number
                                       isPersonalContact:YES
                                                 oldName:oldContact.displayName
                                               toNewName:@""];

如果語句過長, 需要考慮代碼的分解和優化

Preferred:

NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[ctpManager connectToHost:kHostNameCloudPhoneNoport onPort:kCTPPort userInfo:userInfo;
[userInfo setObject:[AccountLoginModel sharedInstance].userInfo.mobilephone forKey:CTP_AUTHUSER_USER_NAME, nil];
    

Not Preferred:

 [ctpManager connectToHost:kHostNameCloudPhoneNoport onPort:kCTPPort userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[AccountLoginModel sharedInstance].userInfo.mobilephone, CTP_AUTHUSER_USER_NAME, nil];

頭文件

  • 自定義頭文件放在系統頭文件的前面

  • 按功能分開,加空格以示區分

  • 按字母表排序

Preferred:

#import "DailModel"

#import "DialView.h"

#import "DialViewController.h"

#import <QYCTPManager/CTPManager.h>

Not Preferred:

#import <QYCTPManager/CTPManager.h>
#import "DialView.h"
#import "DailModel"
#import "DialViewController.h"
  • 不要引入無關的頭文件

  • 盡量使用向前聲明取代引入,這樣不僅可以縮減編譯時間,而且還能降低彼此依賴程度

版權聲明

Preferred:

//  MSDetailRecordsViewController.m
//  CloudPhone
//
//  Created by chenguang (guochenguang@qiyoukeji.com) on 15-12-6.
//  Copyright (c) 2015年 QIYOU Ltd. All rights reserved.
//

Not Preferred:

//  MSDetailRecordsViewController.m
//  chenguang
//
//  Created by chenguang on 15-12-6.
//  Copyright (c) 2015年 CloudPhone. All rights reserved.
//

Xcode Project

  • Xcode Group要和文件系統里的文件夾關聯起來

  • 代碼不僅要按照類型分組, 也要按照功能和特性進行分組

  • 如果可以的話, 打開Build Settings里的"Treat Warnings as Errors"選項

  • 并且盡可能多的打開additional warnings

如果需要忽略特定的warning, 請參考Clang's pragma feature.

其他Objective-C編程規范

更多文章, 請支持我的個人博客

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,327評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,996評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,316評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,406評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,128評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,524評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,576評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,759評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,310評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,065評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,249評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,821評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,479評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,909評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,140評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,984評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,228評論 2 375

推薦閱讀更多精彩內容

  • 命名規范 1.【強制】 代碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束。 反例: _nam...
    666真666閱讀 785評論 2 4
  • 本文記錄一下Objective-C編程規范以及一些建議,可能后續會有些修改和補充,至于初衷是最近接手的項目中代碼"...
    SuperMario_Nil閱讀 1,818評論 2 13
  • 方法聲明和定義 -或者+和返回類型之間須使用一個空格,括號要同行并有一個空格 方法應該像這樣: 如果函數名字太長,...
    Dayon閱讀 242評論 0 1
  • 從其他地方整理了一些編碼規范的資料,分享給大家。YoY 1.語言(Language) 需要使用US English...
    大臉貓121閱讀 444評論 0 2
  • Introduction 這個style guide規范描述了我們iOS開發團隊喜歡的Objectiv-C編程習慣...
    小山Sam閱讀 666評論 0 4