0

我将图像保存在数据库中,并使用 av capture session 来创建自定义相机。但是当我在数据库中保存越来越多的图像时,它会发出内存警告。

当我停止将图像保存到数据库时,应用程序工作正常,为什么会发生这种情况?它是由于数据库大小的增加而发生的吗?

当前代码:

-(void)insert
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"dbsqlite.sqlite"];

    if (sqlite3_open([path UTF8String], &database) == SQLITE_OK)
    {
        ////////\\

        for (jk=0; jk<[globalvalue count];jk++)
        {


            NSData *imgData = UIImagePNGRepresentation((UIImage *)[globalvalue objectAtIndex:jk]);




            const char *query = "insert into color(img) values (?)";

            sqlite3_stmt *searchStatement2;



            if (sqlite3_prepare_v2(database,query, -1, &searchStatement2, NULL) == SQLITE_OK)
            {
                sqlite3_bind_blob(searchStatement2,1, [imgData bytes], [imgData length], NULL);
                if (sqlite3_step(searchStatement2) == SQLITE_DONE)
                {
                    NSLog(@"saved");
                }

    //
    //          while (sqlite3_step(searchStatement2) == SQLITE_ROW)
    //          {
    //              NSString *name2 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(searchStatement2, 0)];
    //              NSString *category2 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(searchStatement2, 1)];
    //              NSLog(@"%@ is a %@ color", name, category);
    //
    //
    //            }
            }
            sqlite3_finalize(searchStatement2);
        }
    }

    [[[UIAlertView alloc]initWithTitle:@"alert" message:@"your query saved" delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles: nil] show];
    sqlite3_close(database);
}

- (void)makeDBCopyAsNeeded
{
    BOOL success;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"dbsqlite.sqlite"];
    success = [fileManager fileExistsAtPath:writableDBPath];
    if (success)
    {
        return;
    }
    NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"dbsqlite.sqlite"];

    success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
    if (!success)
    {
        NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
    }
}

-(void)readFromDatabase
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"dbsqlite.sqlite"];


    if (sqlite3_open([path UTF8String], &database) == SQLITE_OK)
    {
        const char *sqlStatement="select img,rowID from color";
        sqlite3_stmt *compiledStatement;

        if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL)==SQLITE_OK)
        {
            while (sqlite3_step(compiledStatement)==SQLITE_ROW)
            {

                NSData *data = [[NSData alloc] initWithBytes:sqlite3_column_blob(compiledStatement,0) length:sqlite3_column_bytes(compiledStatement,0)];
                if(data == nil)
                    NSLog(@"No image found.");
                else
                {
                    UIImage *personImage= [UIImage imageWithData:data];
                    NSString *rowid1=[NSString stringWithFormat:@"%d", sqlite3_column_int(compiledStatement,1)];
                    [rowid addObject:rowid1];
                    [arrImageFromDataBase addObject:personImage];

                    //                NSData *data       = [NSData dataWithBytes:sqlite3_column_blob(compiledStatement, 4) length:length];
                    NSLog(@"%@",personImage);
                }

            }
        }
        sqlite3_finalize(compiledStatement);
    }
    sqlite3_close(database);
    NSLog(@"contents of array%@",rowid);
}

这有点令人困惑......很抱歉给您带来不便,但真的需要帮助!

4

3 回答 3

1

正如其他人所写,将图像存储在数据库中并不是一个好主意。但这不是问题:-)

我看到你有一个 for 循环。同时插入多张图片时是否会出现警告?或者即使您“一张一张”地插入图像,它们也会发生?

在第一种情况下,请考虑:

UIImagePNGRepresentation在 for 循环里面。这个函数返回一个自动释放的 NSData。自动释放池仅在当前运行循环结束时被清除(例如,当程序停止等待用户的下一个操作时)。因此,该函数创建的所有 NSData 都会保持活动状态,直到运行循环结束。

出于这个原因,如果您一次插入 10 个图像,您将在内存中复制 10 个 NSData,这些 NSData 只会在计算结束时被清除。如果你插入 100 张图片,同样的故事。

使用 Instruments - Allocation 工具检查是否是这种情况(您会看到 NSData 占用的内存在循环期间增加,并在计算完成后立即减少)。如果为真,您可以解决创建特定自动释放池的问题。

这样,在每个循环中都会清除特定的自动释放池

for (jk=0; jk<[globalvalue count];jk++)
{
    @autoreleasepool {

        NSData *imgData = UIImagePNGRepresentation((UIImage *)[globalvalue objectAtIndex:jk]);




        const char *query = "insert into color(img) values (?)";

        sqlite3_stmt *searchStatement2;



        if (sqlite3_prepare_v2(database,query, -1, &searchStatement2, NULL) == SQLITE_OK)
        {
            sqlite3_bind_blob(searchStatement2,1, [imgData bytes], [imgData length], NULL);
            if (sqlite3_step(searchStatement2) == SQLITE_DONE)
            {
                NSLog(@"saved");
            }

            //
            //          while (sqlite3_step(searchStatement2) == SQLITE_ROW)
            //          {
            //              NSString *name2 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(searchStatement2, 0)];
            //              NSString *category2 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(searchStatement2, 1)];
            //              NSLog(@"%@ is a %@ color", name, category);
            //
            //
            //            }
        } sqlite3_finalize(searchStatement2);
    }

}
于 2013-07-05T07:08:10.310 回答
0

首先,您必须将图像保存到库中,您可以使用以下代码:

UIImageWriteToSavedPhotosAlbum(UIImage *image, id completionTarget, SEL completionSelector, void *contextInfo);

然后将库路径保存到您的 sql 数据库中。这将减少数据库中的大小。您还可以调整图像大小以显示在图像视图中,以减少内存使用量。

+ (UIImage*)imageWithImage:(UIImage*)image 
           scaledToSize:(CGSize)newSize;
{
   UIGraphicsBeginImageContext( newSize );
   [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
   UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   return newImage;
}
于 2013-07-05T07:47:22.073 回答
-1

很明显,如果您将越来越多的图像保存在数据库中,它会发出内存警告。因为它会创建图像的副本并将其保存在数据库中。

只需将图像保存在库中并将路径保存在数据库或 plist 中。

于 2013-07-05T06:50:45.843 回答