iOS調用reloadRowsAtIndexPaths Crash報異常NSInternalInconsistencyException

這裏寫圖片描述
關鍵信息:attempt to delete row 0 from section 0 which only contains 0 rows before the update

最近在處理刷新cell的時候有很小几率發送上面所報崩潰信息的問題,在網上找了一下信息包括騰訊bugly 分享的可能性,先貼出來看下:

解決方案
內部矛盾異常,斷言評估一個條件,如果條件爲 false ,調用當前線程的斷點句柄。每一個線程有它自已的斷點句柄,它是一個 NSAsserttionHandler 類的對象。當被調用時,斷言句柄打印一個錯誤信息,該條信息中包含了方法名、類名或函數名。然後,它就拋出一個 NSInternalInconsistencyException 異常。

NSInternalInconsistencyException,從它的字面意思來看的話,是不一致導致的,下面就一些例子

1. NSMutableDictionary的錯誤使用
比如把NSDictionary當做NSMutableDictionary來使用,從他們內部的機理來說,就會產生一些錯誤,NSMutableDictionary中有很多NSDictionary不支持的接口

[objc] view plain copy 在CODE上查看代碼片派生到我的代碼片
NSString *result = @"{\"username\”:\”aaa\”,\"phone\":\"15666666666\",\"bankcount\":\"98765432112345678\"}";    
NSData *data = [result dataUsingEncoding:NSUTF8StringEncoding];    
NSMutableDictionary *info = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];    
if (info) {    
    NSString *username = [Utils UrlDecode: info[@"username"]];    
    [info  setObject:username forKey:@"username"];    
}    

執行上述代碼後報錯:

[objc] view plain copy 在CODE上查看代碼片派生到我的代碼片
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'    

出錯原因在於:
[objc] view plain copy 在CODE上查看代碼片派生到我的代碼片
[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];  

返回的結果是immutable對象,不能直接對immutable進行賦值操作,否則會報錯。

修改後代碼:
[objc] view plain copy 在CODE上查看代碼片派生到我的代碼片
NSString *result = @"{\"username\”:\”aaa\”,\"phone\":\"15666666666\",\"bankcount\":\"98765432112345678\"}";    
NSData *data = [result dataUsingEncoding:NSUTF8StringEncoding];    
//----將immutable轉換爲mutable----    
NSDictionary *temp = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];    
NSMutableDictionary *info = [NSMutableDictionary dictionaryWithDictionary:temp];    
//----------------------    
if (info) {    
    NSString *username = [Utils UrlDecode:info[@"username"]];    
    [info  setObject:username forKey:@"username"];    
}    


2. 界面使用不當
[objc] view plain copy 在CODE上查看代碼片派生到我的代碼片
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',   
eason: 'Could not load NIB in bundle: 'NSBundle </var/mobile/Applications/74075F37-7B13-4D39-8686-050402501AE0/CanUSee.app> (loaded)' with name 'ViewController''  

其中一個原因是:AppDelegate.m的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions中使用xib文件初始化,但程序的入口是storyboard,didFinishLaunching不需要寫東西
self.viewController = [[ViewController alloc] initWithNibName: @"ViewController" bundle: nil];
工程裏面沒有ViewController.xib,初始化出錯。

3.Constant is not finite! That's illegal. constant:nan'
除數爲0時候崩潰

4. failed to obtain a cell from its dataSource
CellIdentifier I bet your cellForRowAtIndexPath is returning null.
應該避免cellForRowAtIndexPath 返回的cell爲空

5.對象爲nil,不存在
[MASViewConstraint setSecondViewAttribute:],nil調用約束方法導致崩潰

最終分析最符合情況的應該是3.4 這兩類。
在更新 TableView 的時候調用

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];

crash掉了,報異常attempt to delete row 0 from section 0 which only contains 0 rows before the update。

原因:
在調用reloadRowsAtIndexPaths時,依賴於tableView先前的狀態已有要更新的cell,它內部是先刪除該cell,再重新創建,所以當你在原先沒有該cell的狀態下調用reloadRowsAtIndexPaths,會報異常你正在嘗試不存在的cell。
簡言之,如果你要改變tableView的cell數量,就不要調用更新局部的cell方法。

解決辦法

1.使用reloadData
reloadData是完全重新加載,包括cell數量也會重新計算,不會依賴之前tableView的狀態。
2.使用beginUpdates和 endUpdates(未自驗證,驗證者可留言)
當你在將要更改cell數量的時候都要通知tableView更新(調用[tableView beginUpdates];)
添加時通知使用方法(void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
移除時通知使用方法 (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
當你已經更改cell數量的時候都要告訴tableView更新完畢(調用[tableView endUpdates];)

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