一.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:sectionIndex] afterDelay: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!