ios - 应用程序崩溃 : Index out of bound at random places

标签 ios iphone debugging nsarray

我的应用程序在不同的地方崩溃,但错误与下面相同,只是索引有时会发生变化,知道为什么会发生这种情况,我也附上了我的屏幕截图:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds for empty array'
*** First throw call stack:
(0x20d4012 0x1e34e7e 0x20760b4 0x152ba 0xdc4067 0xdc42db 0x14fca 0x16aa7 0x239253f 0x23a4014 0x2393fd6 0x23a4014 0x239b8b7 0x2397405 0x2394768 0x207aaf5 0x2079f44 0x2079e1b 0x2ca87e3 0x2ca8668 0xd78ffc 0x2b8d 0x2ab5)
libc++abi.dylib: terminate called throwing an exception
(lldb) 

我尝试调试它以查明导致崩溃的确切位置或代码行,但没有成功。它只是随机崩溃

谢谢 enter image description here

编辑 1:

好的,这是代码:

获取后,我将它们保存为:

-(void)saveTweetsArray:(NSMutableArray *)array{
    NSString *dbPath = [DatabaseHelper databasePath];
    sqlite3_stmt *statement;
    if(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK) {
        NSString *insertSql = [NSString stringWithFormat:@"delete from %@ where ACCOUNTID='%@'",[DatabaseHelper TweetsTable],self.accountId];
        const char *insertStmt = [insertSql UTF8String];
        sqlite3_prepare_v2(db, insertStmt, -1, &statement, NULL);
        if(sqlite3_step(statement) == SQLITE_DONE){
            NSLog(@"old tweets removed");
        }
        else{
            NSLog(@" deletion failed");
            NSLog(@"%@", [NSString stringWithUTF8String:(char*)sqlite3_errmsg(db)]);
        }
        sqlite3_finalize(statement);
        for(int i=0;i<[array count];i++){
            NSMutableDictionary *dictionary = [array objectAtIndex:i];
            NSString *insertSql = [NSString stringWithFormat:@"insert into %@ (ID,TWEET_TEXT,USER_NAME,ACCOUNTID) values (?,?,?,?)",[DatabaseHelper TweetsTable]];
            const char *insertStmt = [insertSql UTF8String];
            sqlite3_prepare_v2(db, insertStmt, -1, &statement, NULL);
            sqlite3_bind_text(statement, 1, [[dictionary valueForKey:@"id"] UTF8String], -1, NULL);
            sqlite3_bind_text(statement, 2, [[dictionary valueForKey:@"text"] UTF8String], -1, NULL);
            sqlite3_bind_text(statement, 3, [[dictionary valueForKey:@"userName"] UTF8String], -1, NULL);
            sqlite3_bind_text(statement, 4, [self.accountId UTF8String], -1, NULL);
            if(sqlite3_step(statement) == SQLITE_DONE)
                NSLog(@"data saved");
            else{
                NSLog(@"save failed");
                NSLog(@"%@", [NSString stringWithUTF8String:(char*)sqlite3_errmsg(db)]);
            }
            sqlite3_finalize(statement);
        }
        sqlite3_close(db);
    }

这是我在获取新推文时获取并填充到表格 View 的位置:

-(NSMutableArray*)tweetsArray{
    NSMutableArray* tweetsArray=[[NSMutableArray alloc] init];
    NSString *dbPath = [DatabaseHelper databasePath];
    if(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK) {
        const NSString *sql_stmt;
        sql_stmt= [NSString stringWithFormat:@"select ID,TWEET_TEXT,USER_NAME from %@ where ACCOUNTID='%@' ",[DatabaseHelper TweetsTable],self.accountId];

            const char *sql_stmt1=[sql_stmt UTF8String];
            sqlite3_stmt *compiledStatement;
            if(sqlite3_prepare_v2(db, sql_stmt1, -1, &compiledStatement, NULL) == SQLITE_OK) {
                // Loop through the results and add them to the feeds array
                while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
                    // Read the data from the result row
                    NSMutableDictionary *dictionary=[[NSMutableDictionary alloc] init];
                    [dictionary setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)] forKey:@"id"];
                    [dictionary setValue:((char *)sqlite3_column_text(compiledStatement, 1))!=NULL?[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)]:@"" forKey:@"text"];
                    [dictionary setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)] forKey:@"userName"];
                    [textsArray addObject:dictionary];
                }
                sqlite3_finalize(compiledStatement);
            }
        }
    sqlite3_close(db);
    return textsArray;
}

这是我在格式化后放在 tableview 上的地方:

        -(void)formatTweetsAndPaintView{
           NSArray *tweets = [dictionary valueForKey:@"twitter"];

        //first save the old tweets to show while new are fetched
           NSMutableArray *tempTweets=[[NSMutableArray alloc] initWithArray:[baseController tweetsArray]];

        //then clear the old tweets then format and fill array
           [[baseController tweetsArray] removeAllObjects];

           if(tweets && tweets.count){
                   for(int i=0;i<[tweets count];i++){
                           NSMutableDictionary *tweetsDictionary = [[NSMutableDictionary alloc] init];
                           [tweetsDictionary setValue:[[tweets objectAtIndex:i] valueForKey:@"id_str"]    forKey:@"id"];
                           [tweetsDictionary setValue:[[tweets objectAtIndex:i] valueForKey:@"text"] forKey:@"text"];
                           [tweetsDictionary setValue:[[[tweets objectAtIndex:i] valueForKey:@"user"] valueForKey:@"name"] forKey:@"userName"];

                           [[baseController tweetsArray] addObject:tweetsDictionary];
                   }
             }

//include non duplicate tempTweet to tweetArray
    for(int i=0;i<[tempTweets count];i++){
                if(![[baseController tweetsArray] containsObject:[tempTweets objectAtIndex:i]])
                    [[baseController tweetsArray] addObject:[tempTweets objectAtIndex:i]];
            }

            if([dictionary valueForKey:@"twitter"])
                [baseController setDictionary:[dictionary valueForKey:@"twitter"]];

            [baseController reloadTableViewData];

//finally save the tweets
            [[TweetDB _instance] saveTweetsArray:[baseController tweetsArray]];
        }

最佳答案

如果你想在程序崩溃的地方停止你的程序,你需要添加一个异常断点。

转到 Breakpoint Navigator,单击加号按钮,然后选择 Add Exception Breakpoint...

enter image description here

在 XCode 5 中它会直接添加它,但在以前的版本中你需要选择:所有异常(exception)

这将在您的 NSArray 被越界访问的地方停止,然后您可以进行调试。

编辑:

程序停止后,您应该能够在 XCode 中看到它崩溃的那一行。如果您在 XCode 中没有看到该行,您可以在调试器中输入:

(lldb) BT

'bt' 将打印程序为到达那里所做的所有步骤,它会为您提供有关调用了哪些方法的信息。

如果这不能为您提供所需的信息,您可以尝试以下方式:

您的第二个选择是重复之前的步骤,但不要选择添加异常断点...您应该选择广告符号断点...

选择它后,将弹出一个窗口提示输入一些值。输入以下内容:

enter image description here

在崩溃之前它应该停止。此时您可以导航到 Debug Navigator 以查看步骤是什么,并找出位置:

enter image description here

如您所见,setPrivateProperty 是停止前最后一次调用方法。

如果 Debug Navigator 没有给您任何信息,您可以随时转到调试器并键入:

(lldb) BT

和以前一样,'bt' 将追溯所有步骤以更详细地到达目的地。

所有这些信息应该足以调试您的程序。如果您需要帮助来解释“bt”输出,那是另一个话题!

关于ios - 应用程序崩溃 : Index out of bound at random places,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20329061/

相关文章:

ios - 如果为其设置了 beginTime,CAEmitterLayer 不会添加基本动画

ios - 添加、重用和删除 NSLayoutAnchors

iphone - AVplayer 2-3 次后未在 ScrollView 中显示

ios - 如何更改 App store 上 iphone 应用程序的设备兼容性?

php - 如何打印 Magento 中的所有查询?

ios - 如何与多个 iOS View Controller 共享一个数组

iphone - 在 objective-c 中创建像类属性一样调用的常量? (例如 classA.KEY_FOR_ITEM1)

iphone - 努力使用界面生成器来设置我的应用程序布局

debugging - 如何调试 vim indentexpr 脚本?

debugging - Pycharm 3 调试中的代码片段模式总是返回 None