常見的線上異常崩潰一

一.UITableView reloadData的崩潰:

[tableView reloadData]後當需要立即獲取tableview的cell、高度,或者需要滾動tableview,那麼直接在reloadData後執行代碼是會有問題的。(如 在項目中用到scrollToRowAtIndexPath,但程序一旦調用scrollToRowAtIndexPath就出錯,經分析是數據源和tableview中cell不同步的原因, 比如,dataArray中有3個元素,而tableview中只顯示了2個元素,當你scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:2 時當然就出錯了)

原因:

因爲[tableview reloaddata] 需要在當前方法在runloop中執行完後它再在runloop中執行,處理函數是在runloop中串行的排隊執行的。但是[tableview reloaddata]後面的代碼需要[tableview reloaddata]的計算結果,所以[tableview reloaddata]後面的代碼需要一個延遲執行。只有當前方法不再佔用runloop,[tableview reloaddata]纔可以在runloop中執行,而這時延遲執行的部分在runloop中早就排在了[tableview reloaddata]的前面執行完了。如果表中的數據非常大,在一個runloop週期沒執行完,這時需要tableview視圖數據的操作就會出問題了。

解決方法:(就是要等排隊,等tableview的刷新操作完成,再去做滾動等其他操作)

方法1:layoutIfNeeded會強制重繪並等待完成

[self.tableView reloadData];  

[self.tableView layoutIfNeeded];  

方法2:

reloadData會在主隊列執行,而dispatch_get_main_queue會等待機會,直到主隊列空閒才執行。

[self.collectionView reloadData];

dispatch_async(dispatch_get_main_queue(), ^{

// 刷新完成   

 [self.tableView setContentOffset:offset animated:NO];

    });

}

方法3:

- (void)reload

{

    [_tableView reloadData];

    [self performSelector:@selector(scrollToIndexPath:) withObject:[NSIndexPath indexPathForRow:rowIndex inSection:sectionIndexafterDelay:0.0];

}

- (void)scrollToIndexPath:(NSIndexPath *)path

{

    [_tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];

}

 

二.

UILocalNotification *localNoti = [[UILocalNotification alloc] init];

localNoti.alertTitle = @"通知"; 

 這個本地通知在iOS8.2以下系統會崩潰,因爲alertTitle是8.2纔有的屬性.這裏只要判斷一下系統版本就可以。

 

三.BOOL 若干陷阱

1.變量BOOL未初始化時,出現隨機值(但是當一個對象的屬性含有bool類型時,如果對象用init方法初始化,則它的bool屬性是nil)

如果你聲明瞭一個變量但是沒有爲它提供一個值,它就被認爲是“未初始化的”。C中一個未初始化的變量具有“未定義”值,通常是垃圾,包含最後一次寫入該地址時發生的任何事情。嚴格來說,“未定義”意味着你不應該使用該值。

這個變量是本地的,每次運行該方法時都會被重新創建,因此會得到一個新的實際值,但每次都是未定義值。

在ARC下,本地對象指針總是有一個默認值nil,但是類似BOOL的非對象類型的局部變量仍然被初始化爲垃圾,垃圾值就是未確定的值,即會出現隨機值。

解決:給變量賦默認值。

2.將普通整形轉換成 BOOL 時要小心。不要直接將 BOOL 值與 YES 進行比較。

Ojbective-C 中把 BOOL 定義成無符號字符型,這意味着 BOOL 類型的值遠不止 YES``(1)或 ``NO``(0)。不要直接把整形轉換成 ``BOOL。常見的錯誤包括將數組的大小、指針值及位運算的結果直接轉換成 BOOL ,取決於整型結果的最後一個字節,很可能會產生一個 NO 值。當轉換整形至 BOOL 時,使用三目操作符來返回 YES 或者 NO。(譯者注:讀者可以試一下任意的 256 的整數的轉換結果,如 256、512 …)

OC中用一個字節,即8位來表示BOOL值,也就是取一個數的低八位。那麼對於8960這個數,它明顯是非零數字,但是,但是!它的低八位都是零,所以它是NO。

列:

int a = 8960;

if (a) { ISLog(@"---1---"); }

 else { ISLog(@"---2---"); }

// 這種方式很坑的。注意底部數據的打印

if (a == YES) { ISLog(@"---3---"); }

else { ISLog(@"---4---"); }

 BOOL b = a;

 if (b) { ISLog(@"---5---"); }

else { ISLog(@"---6---"); }

 if (b == YES) { ISLog(@"---7---"); }

else { ISLog(@"---8---"); }

 2018-06-08 16:28:51.143529+0800 ISBaseDemo[27344:15315162] -[ISHomePageViewController buttonClick:] [Line 119] ---1---

2018-06-08 16:28:51.143617+0800 ISBaseDemo[27344:15315162] -[ISHomePageViewController buttonClick:] [Line 127] ---4---

2018-06-08 16:28:51.143632+0800 ISBaseDemo[27344:15315162] -[ISHomePageViewController buttonClick:] [Line 131] ---5---

2018-06-08 16:28:51.143643+0800 ISBaseDemo[27344:15315162] -[ISHomePageViewController buttonClick:] [Line 137] ---7---

你可以安全在 BOOL、_Bool 以及 bool 之間轉換(參見 C++ Std 4.7.4, 4.12 以及 C99 Std 6.3.1.2)。你不能安全在 BOOL 以及 Boolean 之間轉換,因此請把 Boolean 當作一個普通整形,就像之前討論的那樣。但 Objective-C 的方法標識符中,只使用 BOOL。

對 BOOL 使用邏輯運算符(&&,|| 和 !)是合法的,返回值也可以安全地轉換成 BOOL,不需要使用三目操作符。

錯誤的用法:

- (BOOL)isBold {

  return [self fontTraits] & NSFontBoldTrait;}

- (BOOL)isValid {

  return [self stringValue];}

正確的用法:

(BOOL)isBold {

 return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;

}

 - (BOOL)isValid {

return [self stringValue] != nil;

}

- (BOOL)isEnabled {

return [self isValid] && [self isBold];

}

同樣,不要直接比較 YES/NO 和 BOOL 變量。不僅僅因爲影響可讀性,更重要的是結果可能與你想的不同。

錯誤的用法:

BOOL great = [foo isGreat];

if (great == YES)

  // ...be great!

正確的用法:

BOOL great = [foo isGreat];

if (great)

  // ...be great!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章