从 iOS 中的选择查询中填充数组

Posted

技术标签:

【中文标题】从 iOS 中的选择查询中填充数组【英文标题】:Populating array from select query in iOS 【发布时间】:2014-05-24 23:42:00 【问题描述】:

所以我是 ios 开发的新手,我的选择功能有问题。我做了一个函数,应该接受一个选择查询和表名,并返回一个结果数组,其中每个数组条目都是一个带有一行结果的字典。不知何故,我对列名的查询正在删除我的 columnNames 变量并返回疯狂的结果。我只是想找出一种简单的方法来存储、访问、操作查询结果

这是将结果转换为数组的函数:

-(NSMutableArray *)selectQuery:(NSString*)query
                     table:(NSString*)table

NSMutableArray *returnArray = [NSMutableArray new];

if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)

    NSMutableArray *columnNames;
    NSString *tableQuery = [NSString stringWithFormat:@"PRAGMA table_info('%@')", table];

    if (sqlite3_prepare_v2(database, [tableQuery UTF8String], -1, &statement, nil) == SQLITE_OK)
    
        while (sqlite3_step(statement) == SQLITE_ROW)
        
            [columnNames addObject:[NSString stringWithUTF8String:(const char*)sqlite3_column_text(statement, 1)]];
        
    
    else
    
        NSLog(@"Error preparing table query:");
        NSLog(tableQuery);
    

    if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) == SQLITE_OK)
    
        while(sqlite3_step(statement)==SQLITE_ROW)
        
            NSMutableDictionary *temp= [NSMutableDictionary new];

            for (int i = 0; i < [columnNames count]; i++)
            
                [temp setObject:[NSString stringWithUTF8String:(const char*)sqlite3_column_text(statement, i)] forKey:columnNames[i]];
            

            if (temp != nil)
            
                [returnArray addObject:temp];

                temp = nil;
            
        
        sqlite3_reset(statement);
        sqlite3_close(database);
    
    else
    
        NSLog(@"Error preparing select statement with query:");
        NSLog(query);
    

else

    NSLog(@"Could not open database");

return returnArray;

这是对它的调用

NSMutableArray *queryResults = [dbInstance selectQuery:[NSString stringWithFormat:@"SELECT gallons, mileage FROM fillups WHERE carId = \"%d\" ORDER BY date asc",
                                                   carId]
                                            table:@"fillups"];

【问题讨论】:

“不知何故,我对列名的查询正在删除我的 columnNames 变量并返回疯狂的结果”你的证据是什么? 实际上发生了什么?描述事实,而不是你已经形成的结论...... 顺便说一句,如果您不想这样做,则不必拨打pragma table_info 电话。有 SQLite 函数调用可从您的 select 语句中返回列名(例如,sqlite3_column_count 获取列数,sqlite3_column_name 获取列名)。这样,您将自动从 SQL 语句中检索列的名称,而不是从表定义中检索(并且您不必调用PRAGMA table_info)。 matt,这就是我从调试器跟踪它时实际发生的事情。这不是基于我形成的任意点的疯狂结论。希望对 cme​​ts 投反对票。 Rob,非常感谢您对此进行调查。你给我的所有信息真的很有帮助。生病马上改变它,让你知道它是如何工作的:) @bia.migueis 另外,您的所有列都是TEXT 值吗?如果没有,您可能希望在sqlite3_column_type 的基础上创建适当的对象类型。 【参考方案1】:

你永远不会实例化columnNames。因此,您尝试将列名添加到该数组将不会成功。为了解决这个问题,当你声明它时,你也想实例化可变数组对象:

NSMutableArray *columnNames = [NSMutableArray array];

与此问题无关,当您完成检索列名后,在准备第二个语句之前,不要忘记释放与第一个准备好的语句相关的内存:

sqlite3_finalize(statement);

最后,当您检索完第二个准备好的 SQL 语句后,您希望再次为第二个准备好的语句调用 sqlite3_reset,而不是调用 sqlite3_finalizesqlite3_reset 用于在语句中将新值绑定到? 占位符时重置语句,此处不适用,因此不需要sqlite3_reset。但是如果你不调用sqlite3_finalize,你就不会释放与准备好的语句相关的内存。


顺便说一句,如果您想动态检索列名和列类型(无需执行PRAGMA table_info),您可以执行以下操作:

int rc;

if ((rc = sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, NULL)) != SQLITE_OK) 
    NSLog(@"select failed %d: %s", rc, sqlite3_errmsg(database));


NSMutableArray *returnArray = [NSMutableArray array];
NSInteger columnCount = sqlite3_column_count(statement);

id value;

while ((rc = sqlite3_step(statement)) == SQLITE_ROW) 
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

    for (NSInteger i = 0; i < columnCount; i++) 
        NSString *columnName   = [NSString stringWithUTF8String:sqlite3_column_name(statement, i)];
        switch (sqlite3_column_type(statement, i)) 
            case SQLITE_NULL:
                value = [NSNull null];
                break;
            case SQLITE_TEXT:
                value = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, i)];
                break;
            case SQLITE_INTEGER:
                value = @(sqlite3_column_int64(statement, i));
                break;
            case SQLITE_FLOAT:
                value = @(sqlite3_column_double(statement, i));
                break;
            case SQLITE_BLOB:
            
                NSInteger length  = sqlite3_column_bytes(statement, i);
                const void *bytes = sqlite3_column_blob(statement, i);
                value = [NSData dataWithBytes:bytes length:length];
                break;
            
            default:
                NSLog(@"unknown column type");
                value = [NSNull null];
                break;
        
        dictionary[columnName] = value;
    

    [returnArray addObject:dictionary];


if (rc != SQLITE_DONE) 
    NSLog(@"error returning results %d %s", rc, sqlite3_errmsg(database));


sqlite3_finalize(statement);

【讨论】:

完美,这个答案和对 OP 的评论真的很有帮助。它就像我现在想要的那样工作。谢谢:) @bia.migueis 我已经用代码示例更新了我的答案,展示了如何在没有PRAGMA table_info 的情况下动态确定列名/类型。

以上是关于从 iOS 中的选择查询中填充数组的主要内容,如果未能解决你的问题,请参考以下文章

如何获取选择选项的值,并使用它来查询数组,以填充另一个输入

如何从 NSStrings 数组中填充选择器视图?然后我将如何访问所选择项目的价值?

如何在访问中使用 VB 从选择查询中填充组合框?

使用可变数组中的值填充选择器视图

Angular - 我正在尝试从数组对象值的下拉菜单中填充和选择

(Vue.js)如何使用数据中数值数组中的选项标记填充选择标记?