標籤:obj == 解析 val 三方 opacity number lsh 釋放
iOS 開發規範&建議
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 = 0,UIControlStateHighlighted = 1 << 0,UIControlStateDisabled = 1 << 1,} 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 *topicsM;
13.如果不是屬性,盡量不要點文法;使用點文法會讓代碼簡潔。但對於其他情況,都應該使用方括弧文法。
//建議NSInteger arrayCount = [self.array count];view.backgroundColor = [UIColor orangeColor];[UIApplication sharedApplication].delegate;
//不建議NSInteger arrayCount = self.array.count;[view setBackgroundColor:[UIColor orangeColor]];UIApplication.sharedApplication.delegate;
14.使用第三方架構,盡量不要更改內部檔案,而應該再次封裝,個性定製;
15.判斷if書寫方式
建議這樣寫- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{if (indexPath.row == 0) return 44;if (indexPath.row == 1) return 80;if (indexPath.row == 2) return 50;return 44;}
而不是
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{if (indexPath.row == 0) {return 44;}else if (indexPath.row == 1){return 80;}else if (indexPath.row == 2){return 50;}else{return 44;}}
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出一個控制器建議:
[UIApplication sharedApplication].keyWindow.rootViewController代替self.window.rootViewController,因為程式可能不止一個window,self.window可能不是主視窗;
18.建議:
用CGSizeZero 代替 CGSizeMake(0,0);CGRectZero代替CGRectMake(0, 0, 0, 0);CGPointZero代替CGPointMake(0, 0)
19.監聽鍵盤的通知建議:
UIKIT_EXTERN NSString *const UIKeyboardWillChangeFrameNotification而不是,下面代碼;因為鍵盤可能因為改變IME,切換成表情輸入,切換成英文,那麼frame可能會變高,變矮,不一定會發出下面這些通知,但是肯定會發上面的通知UIKIT_EXTERN?NSString *const UIKeyboardWillShowNotification;UIKIT_EXTERN?NSString *const UIKeyboardDidShowNotification;UIKIT_EXTERN?NSString *const UIKeyboardWillHideNotification;UIKIT_EXTERN?NSString *const UIKeyboardDidHideNotification;
20.發布通知的字串常量規範,建議模仿蘋果;如上鍵盤的通知的書寫,加上const 保證字串不可更改,以Notification結尾,一看就知道是通知;應盡量保證可讀性,不要怕句子太長;
NSString *const buttonDidClickNotification = @"buttonDidClickNotification";
21.如果除數為0,iOS8以下會直接報錯,(NaN—>Not a Number)iOS9不會,所以應該判斷,比如伺服器返回圖片的寬高,按比例縮放:
CGFloat contentH = textW * self.height / self.width;
22.如果聲明的屬性,只想使用的get方法,不使用set方法,並且不想讓外界更改這個屬性的值,那麼建議在括弧裡面加readonly;樣本:
@property(nonatomic,readonly,getter=isKeyWindow) BOOL keyWindow;
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 = 5;self.loginBtn.layer.masksToBounds = YES;
28.給分類擴充方法,建議加上首碼,比如第三方架構SDWebImage,這樣做跟系統的方法很容易區分開,減少了程式員之間的溝通成本,同理跟分類添加屬性(利用運行時),建議加首碼,以防止蘋果官方過一段時間添加了一模一樣的屬性名稱,比如給UITextField分類添加了placeholderColor這個屬性,萬一某天官方給placeholder擴充了這個命名一模一樣的屬性,那麼就不好了
29.凡是在storyboard或者xib中給某個控制項添加顏色,顏色對角線有分割線,表示可以設定透明度,如果給這個控制項設定透明度建議在這裡設定,而不是設定alpha,因為設定了alpha,那麼上面有文字也會隨著透明度變大,而變得不清楚;可以設定background -->other -->opacity
30.整形轉化成浮點型,不建議這麼寫 a / b * 1.0,這樣寫是錯誤寫法,樣本1 / 2 * 1.0;根據運演算法則,從左至右,0 * 1.0 == 0,而應該在前面寫1.0 * 1 / 2;建議直接強轉 (double)a/b;
31.抽取方法,或者寫工具類,能寫類方法,盡量寫成類方法,減少了建立對象的步驟,比如給UIView擴充分類載入xib,viewWithXib;
32.耗時操作應該放在子線程,避免卡主主線程,比如計算檔案大小,下載大檔案,清除緩衝;
33.聲明一個屬性,如果是對象,比如數組,不能以new單詞開始,否則直接報錯,因為new在OC中是產生一個對象的方法,有特殊含義;比如,
@property (nonatomic,strong) NSMutableArray *newTopicsM;注意:如果newtopicsM是一個單詞(區別於駝峰標誌),這樣寫不會報錯;如果是基礎資料型別 (Elementary Data Type)則不會報錯,比如@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.多線程同步問題造成的Crash
對於資料來源或model類一定要注意多線程同時訪問的情況, 可以用GCD的串列隊列來同步線程.
36.Observer的移除
現在的代碼裡面很多需要用到Observer, 根據被觀察對象的狀態來相應的Update UI或者執行某個操作. 註冊observer很簡單, 但是移除的時候就出問題了, 要麼是忘記移除observer了, 要麼是移除的時機不對. 如果某個被觀察對象已經被釋放了, observer還在, 那結果只能是crash了, 所以切記至少在dealloc裡面移除一下observer
37.NSArray, NSDictionary成員的判空保護
在addObject或insertObject到NSArray或者NSDictionary時最好加一下判空保護, 尤其是網路相關的邏輯, 如果網路返回為空白(jason解析出來為空白), 需要先判空再add到array裡面
38.commit代碼之前一定要保證沒有warning, 沒有記憶體泄露, 確保都OK之後再上傳代碼。上傳代碼之前Command + Shift + B靜態分析一下, 看看有沒有什麼issue即可
iOS開發規範&建議