【原則1-1】首先是爲人編寫程序,其次纔是計算機。 說明:這是軟件開發的基本要點,軟件的生命週期貫穿產品的開發、測試、生產、用戶使用、版本升級和後期維護等長期過程,只有易讀、易維護的軟件代碼才具備生命力。 【原則1-2】保持代碼的簡明清晰,避免過度的編程技巧。 說明:簡單是最美。保持代碼的簡單化是軟件工程化的基本要求。不要過度追求技巧,不然會下降程序的可讀性。 【原則1-3】編程時首先達到正確性,其次考慮效率。 說明:編程首先考慮的是知足正確性、健壯性、可維護性、可移植性等質量因素,最後才考慮程序的效率和資源佔用。 【原則1-4】編寫代碼時要考慮到代碼的可測試性。 說明:不能夠測試的代碼是沒法保障質量的,開發人員要牢記這一點來設計、編碼。實現設計功能的同時,要提供能夠測試、驗證的方法。 【原則1-5】函數(方法)是爲一特定功能而編寫,不是萬能工具箱。 說明:方法是一個處理單元,是有特定功能的,因此應該很好地規劃方法,不能是全部東西都放在一個方法裏實現
程序佈局的目的是顯示出程序良好的邏輯結構,提升程序的準確性、連續性、可讀性、可維護性。更重要的是,統一的程序佈局和編程風格,有助於提升整個項目的開發質量,提升開發效率,下降開發成本。同時,對於普通程序員來講,養成良好的編程習慣有助於提升本身的編程水平,提升編程效率。所以,統一的、良好的程序佈局和編程風格不只僅是我的主觀美學上的或是形式上的問題,並且會涉及到產品質量,涉及到我的編程能力的提升,必須引發你們重視。html
【規則2-1-1】遵循統一的佈局順序來書寫頭文件。java
說明:如下內容若是某些節不須要,能夠忽略。可是其它節要保持該次序。 程序員
頭文件佈局:編程
文件頭
#import (依次爲標準庫頭文件、非標準庫頭文件) 全局宏 常量定義 全局數據類型 類定義
正例:app
/***************************************************************************函數
* 文件引用工具
***************************************************************************/ 佈局
/***************************************************************************測試
* 類引用編碼
***************************************************************************/
/***************************************************************************
* 宏定義
***************************************************************************/
/***************************************************************************
* 常量
***************************************************************************/
/***************************************************************************
* 類型定義
***************************************************************************/
/ ***************************************************************************
* 類定義
***************************************************************************/
【規則2-1-2】遵循統一的佈局順序來書寫實現文件。
說明:如下內容若是某些節不須要,能夠忽略。可是其它節要保持該次序。
實現文件佈局:
文件頭(參見「註釋」一節) #import (依次爲標準庫頭文件、非標準庫頭文件) 文件內部使用的宏 常量定義 文件內部使用的數據類型 全局變量 本地變量(即靜態全局變量) 類的實現
正例:
/***************************************************************************
* 文件引用
***************************************************************************/
/***************************************************************************
* 宏定義
***************************************************************************/
/***************************************************************************
* 常量
***************************************************************************/
/***************************************************************************
* 類型定義
***************************************************************************/
/***************************************************************************
* 全局變量
***************************************************************************/
/***************************************************************************
* 原型
***************************************************************************/
/ ***************************************************************************
* 類特性
***************************************************************************/
@implementation ClassName
/ ***************************************************************************
* 類的實現
***************************************************************************/
使用#pragma mark –來分類方法
#pragma mark – Getters and Setters #pragma mark – Life Cycle #pragma mark - Events #pragma mark – Private Methods #pragma mark - UITextFieldDelegate #pragma mark - UITableViewDataSource #pragma mark - UITableViewDelegate #pragma mark - Custom Delegates
每一個方法或者功能塊之間爲告終構清晰,應當有且只有一行空格。
#interface SomeClass:NSObject @property (noatomic, strong) UIView *aView -(void)someMethod; @end @implementation SomeClass - (void)setAView:(NSInteger )aview { } -(void)someMethod { } @end
不是delegate方法的,不是event response方法的,不是life cycle方法的,就是private method了。對的,正常狀況下ViewController裏面通常是不會存在private methods的,這個private methods通常是用於日期換算、圖片裁剪啥的這種小功能。這種小功能要麼把它寫成一個category,要麼把他作成一個模塊,哪怕這個模塊只有一個函數也行。
ViewController基本上是大部分業務的載體,自己代碼已經至關複雜,因此跟業務關聯不大的東西能不放在ViewController裏面就不要放。另一點,這個private method的功能這時候只是你用獲得,可是未來說不定別的地方也會用到,一開始就獨立出來,有利於未來的代碼複用。
我看到不少APP,甚至我公司的項目,不少開發工程師,初始化屬性的位置比較隨意,有單獨添加一個初始化方法相似setupView的,有在init初始化的,各類狀況都有,我其實挺崩潰的,首先初始化方式不一直,其次也這樣作很是有可能破壞了每一個方法功能的單一性(每一個方法只作一件事)。我比較習慣一個對象的"私有"屬性寫在extension裏面,而後這些屬性的初始化所有放在getter裏面作,在init和dealloc以外,是不會出現任何相似_property這樣的寫法的。就是這樣:
@interface CustomObject() @property (nonatomic, strong) UILabel *label; @end @implementation #pragma mark - getters and setters - (UILabel *)label { if (_label == nil) { _label = [[UILabel alloc] init]; _label.text = @"1234"; _label.font = [UIFont systemFontOfSize:12]; ... ... } return _label; } @end
#pragma mark - life cycle - (void)viewDidLoad { [super viewDidLoad]; [self.view addSubview:self.label]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.label.frame = CGRectMake(1, 2, 3, 4); }
唐巧說他喜歡的作法是用_property這種,而後關於_property的初始化經過[self setupProperty]這種作法去作。從剛纔上面的代碼來看,就是要在viewDidLoad裏面多調用一個setup方法而已,而後我推薦的方法就是不用多調一個setup方法,直接走getter。
嗯,怎麼說呢,其實兩種作法都能完成需求。可是從另外一個角度看,蘋果之因此選擇讓[self getProperty]和self.property能夠互相通用,這種作法已經很明顯地表達了蘋果的傾向:但願每一個property都是經過getter方法來得到。
早在2003年,Allen Holub就發了篇文章《Why getter and setter methods are evil》,自此以後,業界就對此產生了各類爭議,雖然是從Java開始說的,可是發展到後面各類語言也參與了進來。而後雖然如今關於這個問題討論得少了,可是依舊屬於沒有定論的狀態。setter的狀況比較複雜,也不是我這一節的重點,我這邊仍是主要說getter。咱們從objc的設計來看,蘋果的設計者更加傾向於getter is not evil。
認爲getter is evil的緣由有很是之多,或大或小,隨着爭論的進行,你們慢慢就聚焦到這樣的一個緣由:Getter和Setter提供了一個能讓外部修改對象內部數據的方式,這是evil的,正常狀況下,一個對象本身私有的變量應該是隻有本身關心。
而後咱們回到iOS領域來,objc也一樣面臨了這樣的問題,甚至更加嚴重:objc並無像Java那麼嚴格的私有概念。但在實際工做中,咱們不太會去操做頭文件裏面沒有的變量,這是從規範上就被禁止的。
認爲getter is not evil的緣由也能夠聚焦到一個:高度的封裝性。getter事實上是工廠方法,有了getter以後,業務邏輯能夠更加專一於調用,而沒必要擔憂當前變量是否可用。咱們能夠想一下,假設一個ViewController有20個subview要加入view中,這20個subview的初始化代碼是確定逃不掉的,放在哪裏比較好?放在哪裏都比放在addsubview的地方好,我我的認爲最好的地方仍是放在getter裏面,結合單例模式以後,代碼會很是整齊,生產的地方和使用的地方獲得了很好的區分。
因此放到iOS來講,我仍是以爲使用getter會比較好,由於evil的地方在iOS這邊基本都避免了,not evil的地方都能享受到,仍是不錯的。
表達式大括號和其餘大括號(if/else/switch/while 等.)老是在同一行語句打開但在新行中關閉。若是沒有else 而且括號內只有一行語句,能夠和if語句同行,而且不須要括號。
if (user.isHappy) { //Do something } else { //Do something else } if (somethingIsBad) return something;
大括號在case語句中並非必須的,除非編譯器強制要求。當一個case語句包含多行代碼時,大括號應該加上。
switch (condition) { case 1: // ... break; case 2: { // ... // Multi-line example using braces break; } case 3: // ... break; default: // ... break; }
當在switch使用枚舉類型時,'default'是不須要的。例如:
RWTLeftMenuTopItemType menuType = RWTLeftMenuTopItemMain; switch (menuType) { case RWTLeftMenuTopItemMain: // ... break; case RWTLeftMenuTopItemShows: // ... break; case RWTLeftMenuTopItemSchedule: // ... break; }
代碼中儘可能少註釋,讓代碼能自我描述。不過當須要註釋的時候,能須要清除的解釋某個代碼塊的含義和做用。註釋應當保持最新,若是沒必要要請刪除。
不要在viewDidLoad裏面初始化你的view而後再add,這樣代碼就很難看。在viewDidload裏面只作addSubview的事情,而後在viewWillAppear裏面作佈局的事情最後在viewDidAppear裏面作Notification的監聽之類的事情。至於屬性的初始化,則交給getter去作。
#pragma mark - life cycle - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; [self.view addSubview:self.firstTableView]; [self.view addSubview:self.secondTableView]; [self.view addSubview:self.firstFilterLabel]; [self.view addSubview:self.secondFilterLabel]; [self.view addSubview:self.cleanButton]; [self.view addSubview:self.originImageView]; [self.view addSubview:self.processedImageView]; [self.view addSubview:self.activityIndicator]; [self.view addSubview:self.takeImageButton]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; CGFloat width = (self.view.width - 30) / 2.0f; self.originImageView.size = CGSizeMake(width, width); [self.originImageView topInContainer:70 shouldResize:NO]; [self.originImageView leftInContainer:10 shouldResize:NO];
self.processedImageView.size = CGSizeMake(width, width); [self.processedImageView right:10 FromView:self.originImageView]; [self.processedImageView topEqualToView:self.originImageView]; CGFloat labelWidth = self.view.width - 100; self.firstFilterLabel.size = CGSizeMake(labelWidth, 20); [self.firstFilterLabel leftInContainer:10 shouldResize:NO]; [self.firstFilterLabel top:10 FromView:self.originImageView]; ... ... }
這樣即使在屬性很是多的狀況下,仍是可以保持代碼整齊,view的初始化都交給getter去作了。總之就是儘可能不要出現如下的狀況:
- (void)viewDidLoad { [super viewDidLoad]; self.textLabel = [[UILabel alloc] init]; self.textLabel.textColor = [UIColor blackColor]; self.textLabel ... ... self.textLabel ... ... self.textLabel ... ... [self.view addSubview:self.textLabel]; }