Objective-C Coding Guide
版本: 1.1
修訂: iOS茄子快傳組
時(shí)間: 2017/08/28
總則: 英文單詞拼寫一定要正確、交流發(fā)音一定要準(zhǔn)確嚷闭、動(dòng)名詞使用一定要恰當(dāng)
命名
類方法名、對(duì)象方法名、成員屬性名、臨時(shí)變量名 要遵循 駝峰 規(guī)則集币。首字母小寫,其余單詞首字母大寫
類文件名單詞首字母全部大寫翠忠,注意添加項(xiàng)目前綴鞠苟。
類方法名、對(duì)象方法名秽之、成員屬性名当娱、臨時(shí)變量名單詞不可簡寫,要寫的有意義考榨。
正確:
- (void)resetBarAttribute:(UIColor *)normal highlight:(UIColor *)highlight font:(UIFont *)font
{
for (UIButton *bar in self.bars) {
[self setBar:bar :normal :highlight :font];
}
}
不建議:
- (void)resetBarAttribute:(UIColor *)normal :(UIColor *)highlight :(UIFont *)font
{
for (UIButton *bar in self.bars) {
[self setBar:bar :normal :highlight :font];
}
}
- 為了避免混淆造成不必要的問題跨细,自己聲明的臨時(shí)變量或者全局靜態(tài)變量,不應(yīng)該以
_
下劃線開頭河质,因?yàn)橄到y(tǒng)為成員屬性生成的成員變量是以_
下劃線開頭冀惭。更不應(yīng)該用系統(tǒng)自有的變量或方法來聲明一個(gè)變量 比如*new
注釋
- 注釋應(yīng)在代碼的上方或者右方震叙,不可在下方
項(xiàng)目結(jié)構(gòu)
工具類的命名要為 xxxTool 或者 xxxUtil,不建議 xxxHelper
類文件盡量放在指定的文件夾中散休,文件夾的名稱不建議使用復(fù)數(shù)媒楼,文件夾名稱不建議加項(xiàng)目前綴
為了避免文件雜亂,物理文件應(yīng)該保持和 Xcode 項(xiàng)目文件同步溃槐。Xcode 創(chuàng)建的任何組(group)都必須在文件系統(tǒng)有相應(yīng)的物理映射匣砖。為了更清晰科吭,代碼可按照類型進(jìn)行分組昏滴,也可按功能進(jìn)行分組。
代碼格式化
-
空格的添加
+
对人、-
谣殊、*
、/
牺弄、?:
類方法姻几、對(duì)象方法的調(diào)用
正確: [[NSObject alloc] init]; 不建議: [[NSObject alloc]init];
- 類方法、對(duì)象方法的聲明和調(diào)用
聲明: - (void)run; + (void)personWithAge:(NSUInteger)age; 調(diào)用: - (void)run { } + (void)personWithAge:(NSUInteger)age { }
(* 注意:類方法對(duì)象方法在.m中實(shí)現(xiàn)的時(shí)候不允許復(fù)制势告,要用
+
或-
直接提示出方法來寫蛇捌,以免出現(xiàn)方法實(shí)現(xiàn)末尾出現(xiàn);
分號(hào)的情況 *, 如下所示:)+ (void)personWithAge:(NSUInteger)age; { }
if
、for
咱台、while
络拌、try
、catch
等語句自占一行回溺,執(zhí)行語句不得緊跟其后春贸,并且條件和這些關(guān)鍵詞之后都有空格。_ (建議:不論執(zhí)行語句有多少都要加 “{ }”) _ 遗遵。這樣可以防止書寫和修改代碼時(shí)出現(xiàn)失誤萍恕。宏要全部大寫,并且要用必要的下劃線分隔開單詞车要;常量要用字母k開頭后面單詞首字母全部大寫
#define MAX_SIZE 30
static const NSUInteger kUsernameRow = 0;
一個(gè)方法應(yīng)該太多行允粤,暫定不要超過 100 行。如果其中的過程沒有提取為獨(dú)立方法的必要翼岁,則不必限制長度
代碼行最大長度宜控制在 80 個(gè)字符以內(nèi)类垫。代碼行不要過長,否則眼睛看不過來登澜,不過此規(guī)則可以視情況適當(dāng)放寬阔挠。
不要出現(xiàn)下面這樣:
/**用于獲取每個(gè)section應(yīng)當(dāng)返回的cell個(gè)數(shù)*/
-(NSInteger)getSectionCount:(NSDictionary*)dict
{
return (dict[kPhotos]==nil?0:[dict[kPhotos] count]+1)+(dict[kMusics]==nil?0:[dict[kMusics] count]+1)+(dict[kFiles]==nil?0:[dict[kFiles] count]+1)+(dict[kVideos]==nil?0:[dict[kVideos] count]+1)+(dict[kContacts]==nil?0:[dict[kContacts] count]+1)+(dict[kFloders]==nil?0:[dict[kFloders] count]+1);
}
- 空行的使用,要內(nèi)函數(shù)內(nèi)模塊來分脑蠕。適當(dāng)?shù)奶砑涌招泄汉常梢允谴a結(jié)構(gòu)更為清晰跪削,減少錯(cuò)誤。
代碼組織
- 可變數(shù)組迂求、可變字典等可變的類型的命名碾盐,一定要以 M 結(jié)尾
NSMutableArray *mediaItemsArrM = [NSMutableArray array];
字符串后 xxxStr/xxxStrM
集合后 xxxArray/xxxArrayM xxxArr/xxxArrM
字典后 xxxDict/xxxDictM
- 可變數(shù)組和可變字典只要元素類型確定,一定要寫上 泛型 指定類型揩局。如果元素類型是多態(tài)可變的可不寫
NSMutableArray<ASMediaItem *> *mediaItemsArrM = [NSMutableArray array];
可變數(shù)組毫玖、可變字典等可變的類型不可用于返回值和參數(shù),一定要做出及時(shí)的轉(zhuǎn)換后再使用
類方法和對(duì)方法聲明的時(shí)候凌盯,一定要指定參數(shù)或返回值是否可
nil
付枫,做到及時(shí)斷言處理
- (nonnull NSArray<NSArray<ASMediaItem *> *> *)selectMediaItemsArr;
- (void)saveWithMediaItemsArr:(nonnull NSArray<ASMediaItem *> *)mediaItemsArr;
不可使用魔鬼數(shù)字和魔鬼字母
對(duì)象在使用前注意判
nil
,特別是將對(duì)象添加到可變數(shù)組和可變字典的時(shí)候驰怎。還有一些方法參數(shù)沒有明確說不可為nil
阐滩,但依然會(huì)崩潰,比如:
[NSURL fileURLWithPath:nil];
[[NSFileManager defaultManager] createSymbolicLinkAtURL:nil withDestinationURL:nil error:nil];
[NSJSONSerialization dataWithJSONObject:nil options:0 error:nil];
- 修飾符的位置:為便于理解县忌,應(yīng)當(dāng)將修飾符
*
和&
緊靠變量或參數(shù)
@property (nonatomic, copy, readonly, nonnull) NSString *layerId;
CFStringRef FileBlockMD5HashCreateWithPath(NSString *filePath)
UpdateHash(&hashObject, fileHandle, startIndex, blockSize);
[[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self accessToTheMainFilePath] error:&error];
其他
-
枚舉類型的定義
-
NS_ENUM
枚舉項(xiàng)的值為NSInteger
掂榔,NS_OPTIONS
枚舉項(xiàng)的值為NSUInteger
。像下面這樣:
typedef NS_ENUM(NSInteger, IJKMPMoviePlaybackState) { IJKMPMoviePlaybackStateStopped = 0, IJKMPMoviePlaybackStatePlaying, IJKMPMoviePlaybackStatePaused, IJKMPMoviePlaybackStateInterrupted, IJKMPMoviePlaybackStateSeekingForward, IJKMPMoviePlaybackStateSeekingBackward };
typedef NS_OPTIONS(NSUInteger, UISwipeGestureRecognizerDirection) { UISwipeGestureRecognizerDirectionNone = 0, //值為0 UISwipeGestureRecognizerDirectionRight = 1 << 0, //值為2的0次方 UISwipeGestureRecognizerDirectionLeft = 1 << 1, //值為2的1次方 UISwipeGestureRecognizerDirectionUp = 1 << 2, //值為2的2次方 UISwipeGestureRecognizerDirectionDown = 1 << 3 //值為2的3次方};
-
NS_ENUM定義
通用枚舉症杏,NS_OPTIONS
定義位移枚舉
位移枚舉即是在你需要的地方可以同時(shí)存在多個(gè)枚舉值如這樣: UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc] init]; swipeGR.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight; //這里幾個(gè)枚舉項(xiàng)同時(shí)存在表示它的方向同時(shí)包含1.向下2.向左3.向右 而NS_ENUM定義的枚舉不能幾個(gè)枚舉項(xiàng)同時(shí)存在装获,只能選擇其中一項(xiàng),像這樣: NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init]; paragraph.baseWritingDirection = NSWritingDirectionNatural;
-
- 類方法新建對(duì)象
ASAdWrapper 類
+ (nonnull instancetype)wrapperWithLayerId:(nonnull NSString *)layerId fullAdId:(nonnull NSString *)fullAdId expiredDuration:(long long)expiredDuration;
ASAdInfo 類
+ (nonnull instancetype)infoWithLayerId:(nonnull NSString *)layerId fullAdId:(nullable NSString *)fullAdId;
- 對(duì)象方法新建對(duì)象
ASAdWrapper 類
- (instancetype)initWithLayerId:(NSString *)layerId fullAdId:(NSString *)fullAdId expiredDuration:(long long)expiredDuration AdObject:(NSObject *)adObj adKeyword:(NSString *)adKeyword;
ASAdInfo 類
+ (instancetype)initWithLayerId:(NSString *)layerId fullAdId:(NSString *)fullAdId;
-
代理方法的命名
用delegate做后綴
用optional修飾可以不實(shí)現(xiàn)的方法厉颤,用required修飾必須實(shí)現(xiàn)的方法
當(dāng)你的委托的方法過多, 可以拆分?jǐn)?shù)據(jù)部分和其他邏輯部分, 數(shù)據(jù)部分用dataSource做后綴
使用did和will通知Delegate已經(jīng)發(fā)生的變化或?qū)⒁l(fā)生的變化
類的實(shí)例必須為回調(diào)方法的參數(shù)之一
回調(diào)方法的參數(shù)只有類自己的情況穴豫,方法名要符合實(shí)際含義
回調(diào)方法存在兩個(gè)以上參數(shù)的情況,以類的名字開頭走芋,以表明此方法是屬于哪個(gè)類的
@protocol UITableViewDataSource
@required
//回調(diào)方法存在兩個(gè)以上參數(shù)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
@optional
//回調(diào)方法的參數(shù)只有類自己
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented
@end
@protocol UITableViewDelegate
@optional
//使用did和will通知Delegate
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
@end
- .h 文件的組織:系統(tǒng)頭文件放在前面绩郎,自定義的頭文件放在后面,接著是
@class
, 中間空行; 成員屬性寫在上方翁逞,方法寫在下方
#import <UIKit/UIKit.h>
#import "MemberVariable.h"
@class ASUserInfo;
@interface DateilViewController : UIViewController
{
//變量
NSString *_dataString;
}
//屬性
@property (nonatomic, strong) NSDictionary *supplyDateilDict;
@property (nonatomic, strong) NSMutableArray *supplyArray;
//方法
- (void)handleData;
- (void)createView;
@end
- .h 文件中引用要使用
@class
肋杖,在.m引用要使用#import "xxx.h"
,加快編譯速度
#import <Foundation/Foundation.h>
#import <uShareitSDK/AndyDictStore.h>
@class ASAdWrapper;
@class ASAdInfo;
@interface ASAdCache : NSObject
SingletonH(Cache);
- (void)pushToAdCacheWithAdWrappersArray:(nonnull NSArray<ASAdWrapper *> *)adWrappersArr;
- (nullable NSArray<ASAdWrapper *> *)popFromAdCacheWithAdInfo:(nonnull ASAdInfo *)adInfo;
- (nullable NSArray<ASAdWrapper *> *)popFromAdCacheWithAdInfo:(nonnull ASAdInfo *)adInfo supportUseMinCount:(BOOL)supportUseMinCount;
- (BOOL)hasAdCacheWithAdInfo:(nonnull ASAdInfo *)adInfo;
@end
新建一個(gè)對(duì)象不建議使用
new
挖函,太過暴力状植,要使用對(duì)應(yīng)的類方法和對(duì)象方法來新建對(duì)象。盡管很多時(shí)候能用new
代替alloc
init
方法怨喘,但這可能會(huì)導(dǎo)致調(diào)試內(nèi)存時(shí)出現(xiàn)不可預(yù)料的問題津畸。Cocoa的規(guī)范就是使用alloc
init
方法,使用new
會(huì)讓一些讀者困惑必怜。類方法肉拓、對(duì)象方法返回對(duì)象自身要使用
instancetype
而不是使用id
。這樣IDE會(huì)幫你檢查類型梳庆,及時(shí)顯示警告暖途,減少錯(cuò)誤卑惜。屬性特性:
weak
、strong
驻售、atomic
露久、nonatomic
、readonly
欺栗、
getter
毫痕、setter
、nonnull
迟几、nullable
@property (nonatomic, copy, readonly, nonnull) NSString *layerId;
@property (nonatomic, copy, readonly, nullable) NSString *fullAdId;
@property (nonatomic, copy, readonly, nonnull) NSString *style;
@property (nonatomic, copy, readonly, nullable) NSString *placementId;
@property (nonatomic, strong, nonnull) NSMutableSet<NSString *> *excludeKeywordsSetM;
@property (nonatomic, assign, readonly) NSUInteger adPullCount;
@property (nonatomic, assign, getter=isEditable) BOOL editable;
- 使用//TODO:說明 標(biāo)記一些未完成的或完成的不盡如人意的地方
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//TODO:增加初始化
return YES;
}
-
函數(shù)
一個(gè)函數(shù)只做一件事(單一原則),每個(gè)函數(shù)的職責(zé)都應(yīng)該劃分的很明確(就像類一樣)
對(duì)于有返回值的函數(shù)(方法)消请,每一個(gè)分支都必須有返回值
對(duì)輸入?yún)?shù)的正確性和有效性進(jìn)行檢查,參數(shù)錯(cuò)誤立即返回
如果在不同的函數(shù)內(nèi)部有相同的功能瘤旨,應(yīng)該把相同的功能抽取出來單獨(dú)作為另一個(gè)函數(shù)
將函數(shù)內(nèi)部比較復(fù)雜的邏輯提取出來作為單獨(dú)的函數(shù)梯啤。一個(gè)函數(shù)內(nèi)的不清晰(邏輯判斷比較多,行數(shù)較多)的那片代碼存哲,往往可以被提取出去,構(gòu)成一個(gè)新的函數(shù)七婴,然后在原來的地方調(diào)用它這樣你就可以使用有意義的函數(shù)名來代替注釋祟偷,增加程序的可讀性。
Category
擴(kuò)展不可覆蓋原有類的方法注意
block
循環(huán)強(qiáng)引用盡量不要用
KVO
, 要用NSNotification
或者delegate
代替