天天看點

iOS中書寫代碼規範35條小建議:

1.精簡代碼, 傳回最後一句的值,這個方法有一個優點,所有的變量都在代碼塊中,也就是隻在代碼塊的區域中有效,這意味着可以減少對其他作用域的命名污染。但缺點是可讀性比較差

NSURL *url = ({ NSString *urlString = [NSString stringWithFormat:@"%@/%@", baseURLString, endpoint];
[NSURL URLWithString:urlString];
});
           

2.關于編譯器:關閉警告:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[myObj performSelector:mySelector withObject:name];
#pragma clang diagnostic pop
           

3.忽略沒用的變量

#pragma unused (foo)
明确定義錯誤和警告
#error Whoa, buddy, you need to check for zero here!
#warning Dude, don't compare floating point numbers like this!
           

4.避免循環引用

  • 如果【block内部】使用【外部聲明的強引用】通路【對象A】, 那麼【block内部】會自動産生一個【強引用】指向【對象A】
  • 如果【block内部】使用【外部聲明的弱引用】通路【對象A】, 那麼【block内部】會自動産生一個【弱引用】指向【對象A】
__weak typeof(self) weakSelf = self;
dispatch_block_t block = ^{
   [weakSelf doSomething]; // weakSelf != nil
// preemption, weakSelf turned nil
[weakSelf doSomethingElse]; // weakSelf == nil
};
最好這樣調用:
__weak typeof(self) weakSelf = self;
myObj.myBlock = ^{
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
     [strongSelf doSomething]; // strongSelf != nil
// preemption, strongSelf still not nil(搶占的時候,strongSelf 還是非 nil 的)
[strongSelf doSomethingElse]; // strongSelf != nil }
else { // Probably nothing... return;
}
};
           

5.宏要寫成大寫,至少要有大寫,全部小寫有時候書寫不提示參數;

6.建議書寫枚舉模仿蘋果——在列出枚舉内容的同時綁定了枚舉資料類型NSUInteger,這樣帶來的好處是增強的類型檢查和更好的代碼可讀性,示例:

// 不推薦寫法
typedef enum{
    UIControlStateNormal       = ,
    UIControlStateHighlighted  =  << ,
    UIControlStateDisabled     =  << ,
} UIControlState;
           
// 推薦寫法
typedef NS_OPTIONS(NSUInteger, UIControlState) {
    UIControlStateNormal       = 0,
    UIControlStateHighlighted  = 1 << 0,
    UIControlStateDisabled     = 1 << 1,
};
           

7.建議加載xib,xib名稱用NSStringFromClass(),避免書寫錯誤

// 推薦寫法
 [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([DXRecommendTagVCell class]) bundle:nil] forCellReuseIdentifier:ID];
           
// 不推薦寫法
 [self.tableView registerNib:[UINib nibWithNibName:@"DXRecommendTagVCell" bundle:nil] forCellReuseIdentifier:ID];
           

8.場景需求:在繼承中,凡是要求子類重寫父類的方法必須先調用父類的這個方法進行初始化操作;建議:父類的方法名後面加上NS_REQUIRES_SUPER; 子類重寫這個方法就會自動警告提示要調用這個super方法,示例代碼

// 注意:父類中的方法加`NS_REQUIRES_SUPER`,子類重寫才有警告提示
- (void)prepare NS_REQUIRES_SUPER;
           

9.建議書寫屬性名不要和系統一樣,避免發生莫名其妙的問題;特别注意的是label;屬性名不要寫成

textLabel

10.項目中添加plist類型檔案,不要命名為info.plist,以防止和系統自帶的檔案重名,發生莫名其妙的問題;

11.如果控制器已經加載過,就不用再次加載,優化性能

if (vc.isViewLoaded) return;
           

12.id類型屬性不能用點文法,調用get方法隻能用中括号調用,[id 方法名],利用iOS9新特性泛型就可以; 比如數組;

@property (nonatomic,strong) NSMutableArray<DXTopics *> *topicsM;
           

13.如果不是屬性,盡量不要點文法,一個老程式員的建議;

14.使用第三方架構,盡量不要更改内部檔案,而應該再次封裝,個性定制;

15.判斷if書寫方式

建議這樣寫

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == ) return ;
    if (indexPath.row == ) return ;
    if (indexPath.row == ) return ;
    return ;
}
           

而不是

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == ) {
        return ;
    }else if (indexPath.row == ){
        return ;
    }else if (indexPath.row == ){
        return ;
    }else{
        return ;
    }
}
           

16接手一個新項目,快速的調試,檢視某個子產品或者方法的作用,需要注釋掉一個方法,或者某個代碼塊,直接寫

return;

而不是全選,注釋掉;

比如:檢視這個方法

loadNewRecommendTags

作用

- (void)loadNewRecommendTags
{
    return;

    [SVProgressHUD show];
    // 取消之前的任務
    [self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
    NSMutableDictionary *params = [NSMutableDictionary dictionary];

    params[@"a"] = @"tag_recommend";
    params[@"c"] = @"topic";
    params[@"action"] = @"sub";
    [self.manager GET:DXCommonUrlPath parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {

        self.recommendTag = [DXRecommendTag mj_objectArrayWithKeyValuesArray:responseObject];
        [self.tableView reloadData];
        [SVProgressHUD dismiss];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        DXLog(@"%@",error);
        [SVProgressHUD dismiss];
    }];
}
           

17.在一個自定義的View中,或者自定義cell中,modal出一個控制器建議:

代替

self.window.rootViewController,因為程式可能不止一個window,self.window可能不是主視窗;
           

18.建議:用CGSizeZero 代替 CGSizeMake(0,0);

CGRectZero代替CGRectMake(0, 0, 0, 0);

CGPointZero代替CGPointMake(0, 0)

19.監聽鍵盤的通知建議:

而不是,下面代碼;因為鍵盤可能因為改變輸入法,切換成表情輸入,切換成英文,那麼frame可能會變高,變矮,不一定會發出下面這些通知,但是肯定會發上面的通知

UIKIT_EXTERN NSString *const UIKeyboardWillShowNotification;
UIKIT_EXTERN NSString *const UIKeyboardDidShowNotification;
UIKIT_EXTERN NSString *const UIKeyboardWillHideNotification;
UIKIT_EXTERN NSString *const UIKeyboardDidHideNotification;
           

20.釋出通知的字元串常量規範,建議模仿蘋果;如上鍵盤的通知的書寫,加上const 保證字元串不可更改,以Notification結尾,一看就知道是通知;應盡量保證可讀性,不要怕句子太長;

21.如果除數為0,iOS8以下會直接報錯,(NaN—>Not a Number)iOS9不會,是以應該判斷,比如伺服器傳回圖檔的寬高,按比例縮放,CGFloat contentH = textW * self.height / self.width;

22.如果聲明的屬性,隻想使用的get方法,不使用set方法,并且不想讓外界更改這個屬性的值,那麼建議在括号裡面加readonly;示例:

23.如果屬性是BOOL類型,建議在括号中重寫get方法名稱,以提高可讀性,示例代碼如上;

24.從系統相冊中取照片之前,應該判斷系統相冊是否可用,如果從相機中拍照擷取,要判斷相機是否可用

// 判斷相冊是否可以打開
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) return;

//  判斷相機是否可以打開
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) return;
           

25.在導航控制中,或它的子控制器,設定導航欄的标題應該用self.navigationItem.title = @“标題”而不建議self.title = @“标題”;

26.給cell設定分割線,建議用setFrame:通過設定它高度,設定分割線,而不推薦用給cell底部添加一個高度的UIView,這樣做增加了一個控件,從性能上來講,不如用setFrame設定高度

27.大量操作圖層會可能造成應用很卡,給使用者體驗差,是以盡量不要操作圖層;比如設定按鈕圓角,比如給button設定圓角;

self.loginBtn.layer.cornerRadius = ;
self.loginBtn.layer.masksToBounds = YES;
           

28.給分類擴充方法,建議加上字首,比如第三方架構

SDWebImage

,這樣做跟系統的方法很容易區分開,減少了程式員之間的溝通成本,同理跟分類添加屬性(利用運作時),建議加字首,以防止蘋果官方過一段時間添加了一模一樣的屬性名,比如給UITextField分類添加了placeholderColor這個屬性,萬一某天官方給placeholder擴充了這個命名一模一樣的屬性,那麼就不好了

29.凡是在storyboard或者xib中給某個控件添加顔色,顔色對角線有分割線,表示可以設定透明度,如果給這個控件設定透明度建議在這裡設定,而不是設定alpha,因為設定了alpha,那麼上面有文字也會随着透明度變大,而變得不清楚;可以設定background -->other -->opacity

30.整形轉化成浮點型,不建議這麼寫 a / b 1.0,這樣寫是錯誤寫法,示例1.5 / 2 1.0;根據運算法則,從作到右,0 1.0 == 0,而應該在前面寫1.0 1.5 /2;建議直接強轉;(double)a/b;

31.抽取方法,或者寫工具類,能寫類方法,盡量寫成類方法,減少了建立對象的步驟,比如給UIView擴充分類加載xib,viewWithXib;

32.耗時操作應該放在子線程,避免卡主主線程,比如計算檔案大小,下載下傳大檔案,清除緩存;

33.聲明一個屬性,如果是對象,比如數組,不能以new單詞開始,否則直接報錯,因為new在OC中是生成一個對象的方法,有特殊含義;比如,

@property (nonatomic,strong) NSMutableArray<DXTopics *> *newTopicsM;
           

注意:如果newtopicsM是一個單詞(差別于駝峰标志),這樣寫不會報錯;如果是基本資料類型則不會報錯,比如

@property (nonatomic,assign) int newNumber;
           

但是如果一定要寫new單詞開頭的屬性,那麼聲明屬性的時候,重寫getter方法名稱隻不過使用getter方法的時候注意下

34.在自定義方法中,

and

這個詞的用法應該保留。它不應該用于多個參數來說明,就像initWithWidth:height以下這個例子:

- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;
而不應該
- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height;
           

35.建議POST請求參數字典的寫法,這樣比較裝逼~

// NSDictionaryOfVariableBindings這個宏生成一個字典,這個宏可以生成一個變量名到變量值映射的Dictionary,比如:
NSNumber * packId=@();
NSNumber *userId=@();
NSNumber *proxyType=@();
NSDictionary *param=NSDictionaryOfVariableBindings(packId,userId,proxyType);