綜合出現NSScanner: nil string argument libc++abi.dylib: terminat錯誤的解決方案


在開發中出現了這個錯誤,斷點查找很久,沒找到問題所在的代碼,google下,發現了下面這幾點會產生這個錯誤:

  1. 首先,顧名思義,錯誤原因是我們在調用某個方法的時候,傳入了一個空字符串(注意區別於字符串內容為空)作為方法參數。
  2. 對某一個空數組使用objectAtIndex方法。不會報數組越界的錯,而是NSScanner: nil string argument。

經過檢查,我代碼中如果字符串賦值,我一般都對nil做了一定處理,用@""代替,也未有數組越界,但是還是報這樣的錯誤。

現在的信息點是libc++abi.dylib,這個庫到底是做什么的?從后綴看,是一個動態庫,那么會不會是因為發生了一些動態錯誤?而按經驗來看,一般的動態錯誤基本是因為動態類型錯誤引起,在object-c語言中,會發生動態類型錯誤的可能基本存在於不可變類型與可變類型之間的轉換,那么我們的查錯范圍將優先限制在不可變類型與可變類型轉換上,是否我們對一個不可變類型進行了修改操作?當然,編譯器沒有那么傻,如果直接對一個不可變類型進行修改操作,是會直接報錯的,那么就剩下另一種可能,程序將一個不可變類型賦值給可變類型,然后對可變類型進行了修改操作,這樣可以通過靜態檢查,但是動態運行的時候,就會發生類型錯誤。基於以上分析,我們可以跟蹤斷點,會發現程序在對mutable對象進行add、set等操作時掛掉,而這個對象實際上賦值的是一個不可變對象。常見的情況是把一個NSArray對象賦值給一個NSMutableArray對象,然后進行了delete、add等修改操作,或者把一個NSDictionary對象賦值給一個NSMutableDictionary對象,然后進行了set等操作。

這是從http://www.itnose.net/detail/6196671.html里面得來的方案,經過排查,代碼表面上也未有這樣的錯誤。

然后找到最后崩潰處的斷點代碼如下:

NSDictionary *orderDict = [notification userInfo];
    
    self.selectedOrderDict = orderDict;
    
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.selectedRow inSection:0];
        [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:@[indexPath], nil] withRowAnimation:UITableViewRowAnimationNone];

 靈機一動,其實是實在不知道怎么改了,於是改成了下面的代碼,然后編譯,運行,既然可以了。。。。。。

NSDictionary *orderDict = [notification userInfo];
    
    self.selectedOrderDict = orderDict;
    
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.selectedRow inSection:0];
    NSMutableArray *tmpArray = [NSMutableArray array];
    [tmpArray addObject:indexPath];
    [self.tableView reloadRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationNone];

 不解,既然這樣就可以了,可是從代碼層次、邏輯層次來說,這兩種寫法應該是一樣的,難道是這個借口需要的是可變的數組?於是打開里面的接口,發現是這樣的:

- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);

 當時我的心情是崩潰的,尼瑪,那啥意思,於是有了下面的測試:

    NSDictionary *orderDict = [notification userInfo];
    
    self.selectedOrderDict = orderDict;
    
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.selectedRow inSection:0];
//    NSMutableArray *tmpArray = [NSMutableArray array];
//    [tmpArray addObject:indexPath];
//    [self.tableView reloadRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationNone];
    
    NSArray *tmpArray = @[indexPath];
    [self.tableView reloadRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationNone];

 這樣也是不崩潰的......

好吧,到這,還是沒發現錯誤原因,然后回去仔細看看面前的代碼,發現

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.selectedRow inSection:0];
        [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:@[indexPath], nil] withRowAnimation:UITableViewRowAnimationNone];

 indexPath本身就是個對象了,而我還用NSValues包裝它,放進去,肯定不能解析而崩潰啊......


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM