前言:
最近一直在維護老的項目,遇到的問題也千奇百怪,需要修補的,需要優化的,需要特殊處理的,感覺總是那么的無語。也許這時候也應該感嘆一句:路漫漫其修遠兮,吾將上下而求索吧。
這篇文章就只是講講老項目中遇到的種種不敢茍同的代碼寫法,以及遇到一些問題時的處理方法。
1、關于按鈕事件的重復點擊問題
我們開發中大概都經歷過這樣的事情,我的一個<code>button</code>被重復的快速點擊,(我們開發者應該更清楚的知道這意味著什么)。那我們再深入的想一下(給這樣的事件安排一個特定的環境):例如當網絡較差的情況下,再例如當<code>button</code>的執行事件較為耗時時。這時就會出現很多的問題:有時是界面出現問題(當<code>button</code>執行事件中出現調節界面<code>frame</code>的時候);有時則會出現卡頓,更甚至會出現崩潰現象。對于這種問題,我們要提前考慮到,做好防范處理:即點擊按鈕事件時,添加防止重復點擊功能。
思路是:防止按鈕重復點擊
比較推薦的解決方法代碼:
<pre> - (void)btnClicked:(id)sender {
//在這里做按鈕的想做的事情。
}
- (void)buttonClicked:(id)sender {
//先將未到時間執行前的任務取消。
[[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(btnClicked:)object:sender];
[self performSelector:@selector(btnClicked:)withObject:sender afterDelay:0.2f];
}</pre>
原理是 :我們每次點擊按鈕時,先執行取消之前的按鈕點擊執行事件,然后再去執行一個延遲執行方法(方法中執行的是按鈕執行的事件)。
還有一種方法也是可以實現的:具體的看《iOS之防止用戶重復點擊Button(按鈕)問題 》
2、很多界面共用一個界面時:使用枚舉做類型判斷
老的項目中會出現很多這樣的現象:很多界面重復使用一個界面,這樣就自然而然的需要在不同的界面跳轉到復用的界面時去做判斷。而奇怪的地方在于:判斷的依據是<code>self.title</code>。那么就會出現這樣一種現象:在跳轉界面后會有一大段<code>if</code>去判斷字符串是否等于<code>self.title</code> 。
如果我們做一些改變:使用枚舉來做界面類型的判斷,使用<code>switch case</code>語句做判斷執行代碼。這樣會不會更優美,簡潔一些。
3、關于老項目中iOS10以上的情況下,導航欄中按鈕不顯示問題
如果你的<code>viewController</code>都繼承于基類,那么在基類中添加這樣一段代碼(這也是目前我發現的最省事的方法):
<pre>- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:NO];
[self.navigationController setNavigationBarHidden:NO animated:NO];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:YES animated:NO];
[self.navigationController setNavigationBarHidden:NO animated:NO];
}</pre>
4、事件方法要每個界面區分開
老項目中會有這種情況:在本界面 command點擊一個<code>button</code>執行事件方法或者手勢事件方法時,會莫名其妙的跳轉到另外一個界面。
我們在開發時最好給不同界面<code>button</code>的<code>clicked</code>事件命名是區分開來,例如:界面名 + <code>ButtonClicked</code>
5、對象為空現象
在開發中如果存在<code>image</code>為空,或者必須顯示的<code>String</code>為空現象,
記得在代碼中作判斷,圖片可以直接設置默認圖片,字符串也可以設置默認字符串
這一點可以學一下SDWebImage庫中對于網絡請求圖片不存在的處理方法:
<pre>//給一張默認圖片,先使用默認圖片,當圖片加載完成后再替換
[self.image1 sd_setImageWithURL:imagePath1 placeholderImage:[UIImage imageNamed:@"default"]];</pre>
例如:
<pre>
UIImage *image = [UIImage imageNamed:@"image"];
UIImage *defaultImage = [UIImage imageNamed:@"defaultImage"];
UIImageView *imageView = [[UIImageView alloc]initWithImage:image==nil ? image:defaultImage];
</pre>
字符串當然也是類似,其實看似有些費事甚至有的顯得多余的寫法,會使以后的維護變得更加的如意。
6、一個界面多網絡請求問題,而且需要多個請求都完成后,對界面有一些操作。
這是一個老的話題了,我之所以重新提及這個話題,原因是我從一些文章中發現了一個從來沒使用過的方法,這個下面會提到,現在就讓我們列舉出來比較常用的方法。就以一個界面兩個網絡請求為例 A和B
1、兩個請求互套)(也是最笨的方法)
具體是這樣的,我在A請求成功后,再請求B。當然如果請求多的話,這個肯定是作廢的。
2、使用GCD中的通知
<pre>
dispatch_group_t serviceGroup = dispatch_group_create();
// 開始第一個網絡請求
servicedispatch_group_enter(serviceGroup);
[self.configService startWithCompletion:^(ConfigResponse results, NSError error) {
//請求成功后的操作
configError = error;
dispatch_group_leave(serviceGroup);//完成后離開分組
}];
// 開始第二個請求
dispatch_group_enter(serviceGroup);
[self.preferenceService startWithCompletion:^(PreferenceResponse results, NSError error) {
//請求成功后的操作
preferenceError = error;
dispatch_group_leave(serviceGroup);//完成后離開分組
}];
dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
// Assess any errors
NSError *overallError = nil;
if (configError || preferenceError) {
// 判斷時候請求有失敗
overallError = configError ?: preferenceError;
}
// 最后完成后執行的block
completion(overallError);
});
</pre></code>
3、利用GCD中的信號量
在GCD中有三個函數是<code>semaphore</code>的操作,分別是:
<code>dispatch_semaphore_create</code> 創建一個semaphore
<code>dispatch_semaphore_signal</code> 發送一個信號
<code>dispatch_semaphore_wait</code> 等待信號
簡單的介紹一下這三個函數,第一個函數有一個整形的參數,我們可以理解為信號的總量,<code>dispatch_semaphore_signal</code>是發送一個信號,自然會讓信號總量加1,<code>dispatch_semaphore_wait</code>等待信號,當信號總量少于0的時候就會一直等待,否則就可以正常的執行,并讓信號總量-1,根據這樣的原理,我們便可以快速的創建一個并發控制來同步任務和有限資源訪問控制。
利用這樣的機制,當信號量達到我們網絡請求的數量時,請求結束。
4、這個也是我上面說的無意中看到的一個方法,僅拿出來作為參考
<pre>dispatch_async(concurrent_queue, ^{
NSLog(@"---并發任務1---");
});
dispatch_async(concurrent_queue, ^{
NSLog(@"---并發任務2---");
});
dispatch_barrier_async(concurrent_queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"---所有并發任務結束后回到主線程刷新---");
});
}); </pre></code>
以上就是關于一界面多請求的不同解決方案。
7、代碼規范問題
- 為什么這個普通的話題放到最后呢,大概是因為我覺得這個很重要的問題吧,畢竟技術水平不高,還是可以提升的。但代碼不規范的話,養成習慣后很難改的,我見過太多項目中使用【拼音命名、不注意駝峰命名法、define預處理指令滿天飛等等的代碼】這些出現在項目中就像時時刻刻在提醒你,看這樣的項目是一種煎熬。
- 其實代碼規范不僅僅是公司對開發者的要求,也是開發者對自己的一個要求。因為如果統一每個人的寫作規范,是一件耗時,耗材的事情。小一些的公司是做不來,中型的公司大多是不想做。而大型的公司總是花費近幾個月的時間去培養員工的代碼規范,這就是財大氣粗吧。而且開發者本身對于技術的提升、追求等,都無形中要求自己注意代碼規范問題。
- 對于這部分,建議看看《Effective Objective-C 2.0》這本書,其中起到的。