将数据插入FMDB会在设备上崩溃,这是将数据插入sqlite的大多数内存有效方式

时间:2012-07-22 23:27:27

标签: iphone fmdb

我有很多行需要插入数据库。我下载了大约50个.txt文件,这些文件是以我需要的信息分隔的标签。我解析数据并以相同的方法将其插入数据库。当我把它作为单独的方法时,我的27“iMac上的模拟器会因内存不足而崩溃。方法如下:

- (BOOL)insertDataWithFileName:(NSString *)fileName {
    NSLog(@"%s %@", __FUNCTION__, fileName);
    if (_db == nil) {
        return NO;
    }
    // Get the data from the file
    NSData *data = [[NSData alloc] initWithContentsOfFile:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:fileName]];
    NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    // Parse each line by newlines first
    NSArray *lines = [responseString componentsSeparatedByString:@"\n"];        

    NSString *ID = [[fileName componentsSeparatedByString:@"."] objectAtIndex:0];

    // Set up the database insert statement
    NSString *tableName = @"Hardcodedtablename"; // remove after prototype
    BOOL oldshouldcachestatements = _db.shouldCacheStatements;
    [_db setShouldCacheStatements:YES];
    [_db beginTransaction];
    NSString *insertQuery = [NSString stringWithFormat:@"INSERT INTO %@ values(null, ?, ?, ?, ?, ?, ?, ?);", tableName];
    BOOL success;

    // Parse each line by tabs
    for (NSString *line in lines) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSArray *fields = [line componentsSeparatedByString:@"\t"];

        // Need to check since some of the .txt files have an empty newline at the EOF.
        if ([fields count] == NUM_VARIANT_FIELDS) {
            NSNumber *loc = [NSNumber numberWithInteger:[[fields objectAtIndex:0] integerValue]];       
            NSString *carType = [fields objectAtIndex:1];
            NSString *model = [fields objectAtIndex:2];
            NSString *AA = [fields objectAtIndex:7];
            NSString *BB = [fields objectAtIndex:8];

            NSNumber *freq = [[fields objectAtIndex:11] isEqualToString:@""] ? [NSNumber numberWithDouble:-1.0] : [NSNumber numberWithDouble:[[fields objectAtIndex:11] doubleValue]];

            NSArray *argArray = [[NSArray alloc] initWithObjects:ID, loc, carType, model, AA, BB, freq, nil];

            success = [_db executeUpdate:insertQuery withArgumentsInArray:argArray];
            [argArray release];

        }
        [pool drain];
    }

    [_patientAnnotatedDatabase commit];
    [_patientAnnotatedDatabase setShouldCacheStatements:oldshouldcachestatements];

    return success;
}

从我的for循环可以看出,实际上我不需要在它被\ t分隔之后数组中的所有文件。我设置了一个自动释放池来减少for循环中的内存占用。最大的文件中有270,000行。这些文件大约有50个。因此,在设备上的2个文件之后,它会崩溃。但是没有错误消息。

我想知道我的选择在这一点上是什么。 iPad能否实际处理这么多数据?我可以对这种方法进行优化吗?

或者我是否必须在服务器端创建数据库并将数据库下载到设备?如果我确实将数据库从服务器下载到设备,那么FMDB是否支持将这些表从一个数据库转移到另一个数据库?当我在谷歌上搜索时,我无法找到类似的东西。谢谢!

2 个答案:

答案 0 :(得分:0)

这实际上取决于您使用的数据。如果您正在使用它进行搜索或出于某些目的而您真正需要所有这些内容,那么您基本上就是在使用这么多内存:

270,000 rows * 25 chars/row * 50 files * 1 byte/char = 321 Mb of RAM

我在猜测25个字符/行部分,但是当你使用超过100 Mb的内存时,你会占用大量内存。但是,iPad 有大约1GB的RAM供你使用,所以你似乎在可用内存量之内。 但是,因为你用来存储它的NSArrays和SQLite FMDB(以及其他NSObjects),当加到iPad上运行的其他进程时,带封装的数据可能超过1GB

所以,所有这些记忆都可能是你的问题。您可能最好将所有这些数据保存在可以处理它的Web服务器上,并通过所述服务器调用您想要的任何功能。它可能会更快,如果需要更新,它可以让您轻松调整数据。它还允许您的应用程序在没有足够RAM的iPhone等设备上使用。

如果大量数据是您的问题,那么您的解决方案就是上面的解决方案。但是,我仍然相信iPad能够处理300多Mb的RAM,所以你的问题可能在于代码。确保正确访问所有数据,尤其是在将数据与文件分离成数组时,因为最小的“越界”数组错误可能导致程序失败。

您是否也尝试在启用内存分析器的情况下运行代码。您可以通过按住“运行”圆形按钮在新Xcode中启用此应用程序,直到您可以选择“Profiler”选项。此应用程序将显示您的应用程序使用了多少内存,因此您可以确保它低于1GB。

答案 1 :(得分:0)

不幸的是,我在我的计划中设置了NSZombieEnabled来追踪早期的错误。关闭它,现在似乎没有崩溃。