0

サーバーに画像を保存しました。次に、画像を取得し、画像 URL を介して db1.sqlite ファイルに保存します。画像は URL のように db1.sqlite ファイルに保存されます。保存したURLから画像を表示する方法。imageURL パスを持つ product_image。

コード:

sqlite テーブル構造:

CREATE TABLE "product" ("id" INTEGER PRIMARY KEY  NOT NULL , "cat_id" INTEGER NOT NULL , "product_image" VARCHAR NOT NULL , "order_by" INTEGER NOT NULL )

コードを挿入:

const char *sqlInsert = [[NSString stringWithFormat:@"insert into product (id, cat_id,product_image,order_by) values ('%@','%@','%@','%@')", [tuser objectForKey:@"id"], [tuser objectForKey:@"cat_id"],[tuser objectForKey:@"product_image"],[tuser objectForKey:@"order_by"]] cStringUsingEncoding:NSUTF8StringEncoding];

NSLog(@"product insert %s", sqlInsert);

if(sqlite3_prepare_v2(database, sqlInsert, -1, &addStmt, NULL) != SQLITE_OK)
    NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(database));

if(SQLITE_DONE != sqlite3_step(addStmt))
    NSAssert1(0, @"Error while inserting data. '%s'", sqlite3_errmsg(database));

画像の取得:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//NSLog(@"docs dir is %@", documentsDirectory);

NSString *path = [documentsDirectory stringByAppendingPathComponent:@"db1.sqlite"];
//NSLog(@"filepath %@",path);

mArray = [[NSMutableArray alloc]init];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {

    const char *sql = "SELECT id,cat_id,product_image FROM product order by order_by";

    NSLog(@"sql is %s",sql);

    sqlite3_stmt *statement;
    //  int catID = 0;
    if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
        // We "step" through the results - once for each row.
        while (sqlite3_step(statement) == SQLITE_ROW) {

            int length = sqlite3_column_bytes(statement, 2);
            NSData *imageData = [NSData dataWithBytes:sqlite3_column_blob(statement, 2) length:length];

            UIImage *image = [UIImage imageWithData:imageData];

            [mArray addObject:image];

            [image release];
        }
    }
    sqlite3_finalize(statement);
}
else {
    sqlite3_close(database);
    NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
    // Additional error handling, as appropriate...
}
4

1 に答える 1

1

Chatting with you offline, I discovered that product_image is not a NSData. (I had mistakenly inferred from the presence of sqlite3_column_blob later, that you were trying to store binary data, which is not the case.) Apparently product_image is string that contains the URL. So store it as a string. And never use stringWithFormat in your SQL statements, but rather use the sqlite3_bind_xxx functions with ? placeholders, e.g.:

const char *sqlInsert = "insert into product (id, cat_id, product_image, order_by) values (?, ?, ?, ?)";

if (sqlite3_prepare_v2(database, sqlInsert, -1, &addStmt, NULL) != SQLITE_OK)
    NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(database));

if (sqlite3_bind_int(addStmt, 1, [[tuser objectForKey:@"id"] intValue]) != SQLITE_OK)
    NSAssert1(0, @"Error binding 1. '%s'", sqlite3_errmsg(database));

if (sqlite3_bind_int(addStmt, 2, [[tuser objectForKey:@"cat_id"] intValue]) != SQLITE_OK)
    NSAssert1(0, @"Error binding 2. '%s'", sqlite3_errmsg(database));

if (sqlite3_bind_text(addStmt, 3, [[tuser objectForKey:@"product_image"] UTF8String], -1, NULL) != SQLITE_OK)
    NSAssert1(0, @"Error binding 3. '%s'", sqlite3_errmsg(database));

if (sqlite3_bind_int(addStmt, 4, [[tuser objectForKey:@"order_by"] intValue]) != SQLITE_OK)
    NSAssert1(0, @"Error binding 4. '%s'", sqlite3_errmsg(database));

if (SQLITE_DONE != sqlite3_step(addStmt))
    NSAssert1(0, @"Error while inserting data. '%s'", sqlite3_errmsg(database));

// don't forget to finalize

sqlite3_finalize(addStmt);

If you do this, you have to change your code that retrieves the images, too. For example, you have:

while (sqlite3_step(statement) == SQLITE_ROW) {

    int length = sqlite3_column_bytes(statement, 2);
    NSData *imageData = [NSData dataWithBytes:sqlite3_column_blob(statement, 2) length:length];

    UIImage *image = [UIImage imageWithData:imageData];

    [mArray addObject:image];

    [image release];
}

A couple of thoughts:

  1. The [image release] is an over-release. The imageWithData returns an autorelease object, so you don't need/want to release it. This sort of error can be catastrophic, so I'd suggest you run your code through the static analyzer to help identify these sorts of bugs (by choosing "Analyze" from the "Product" menu, or pressing command+shift+B). You should have zero warnings generated by the static analyzer. The analyzer is an incredibly useful tool to identify programming errors, so avail yourself of this excellent tool.

  2. That prior point is moot, though, because you're not storing an actual image in NSData, but rather you're storing a URL in a string, so you should be using sqlite3_column_text, instead.

  3. Once you convert the const char * you get from sqlite3_column_text into a NSString, you then want to take that string and create a URL, e.g.:

    NSURL *url = [NSURL URLWithString:urlStringFromDatabase];
    
  4. You can then use that NSURL in conjunction with a UIImageView category like SDWebImage, to asynchronously retrieve the image (and do all of the appropriate cacheing, etc.).

    [imageView setImageWithURL:url
              placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
    
  5. And, at the risk of repeating myself, your image retrieval code checks whether the SQLite functions returned, for example SQLITE_OK, but if not, you're not showing the sqlite3_errmsg. Always look at this when debugging apps. It will save you literally hours in development/debugging.

于 2013-08-22T16:15:36.367 に答える