检索在 sqlite 数据库中插入的所有行,并在包含标签的表视图单元格中显示为具有不同部分的子视图

Posted

技术标签:

【中文标题】检索在 sqlite 数据库中插入的所有行,并在包含标签的表视图单元格中显示为具有不同部分的子视图【英文标题】:Retrieve all rows inserted in sqlite database and display in table view cells containing labels as subviews with different sections 【发布时间】:2011-12-20 10:56:26 【问题描述】:

我是 Objective-c 和 sqlite 的新手。我已成功使用 sqlite 将数据插入到表中。我的项目包含 2 页

添加提醒页面:用户输入数据并点击保存的地方是右侧导航栏

查看提醒页面:这是用户在表格视图的单元格中查看已保存提醒的地方,

即第一个单元格的第一个提醒,第二个单元格的第二个提醒等等......

我使用以下代码使我的任务更容易指定部分的数量,这意味着保存的提醒数量等于查看提醒表中的部分数量

-(NSInteger)numberOfSectionsInTableView:(UITableView *)view
    
    numTableRecords = -1;
    sqlite3_stmt *statement;
    if (sqlite3_open([self.databasePath UTF8String], &remindersDB) == SQLITE_OK) 
    
        NSString *sqlStatement = [NSString stringWithFormat: @"select count(*) from reminders"];
        const char *sql = [sqlStatement cStringUsingEncoding:NSUTF8StringEncoding];
        if(sqlite3_prepare_v2(remindersDB, sql, -1, &statement, NULL) == SQLITE_OK) 
                  
            while(sqlite3_step(statement) == SQLITE_ROW) 
            
                numTableRecords = sqlite3_column_int(statement, 0);
            
        
        else 
        
            printf("could not prepare statement: %s\n", sqlite3_errmsg(remindersDB));
        
    

    else 
    
        NSLog(@"Error in Opening Database File");
    
    sqlite3_close(remindersDB);
    NSLog(@"Number of records = %d",numTableRecords);
    return numTableRecords; 


根据以下链接中给出的建议,与我的要求非常相似:

Populate the table view sections with rows of table in sqlite database in an order

我取了一个数组并将检索到的数据作为对象插入到数组中,如下所示:

-(void)viewWillAppear:(BOOL)animated


    //Retrieve the values of database
    const char *dbpath = [self.databasePath UTF8String];
    sqlite3_stmt *statement;
    if (sqlite3_open(dbpath, &remindersDB) == SQLITE_OK)
    
        NSString *querySQL = [NSString stringWithFormat:@"SELECT * FROM reminders"];
        NSLog(@"Data = %@",querySQL);

        const char *query_stmt = [querySQL UTF8String];

        if (sqlite3_prepare_v2(self.remindersDB ,query_stmt , -1, &statement, NULL) == SQLITE_OK)
        
            if (sqlite3_step(statement) == SQLITE_ROW)
            
                ID = [[[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)]autorelease];

                nameField = [[[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)]autorelease];                    

                eventField = [[[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 2)]autorelease];

                dateField = [[[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 3)]autorelease];
             

            sqlite3_finalize(statement);
        
        sqlite3_close(self.remindersDB);
    
    [array addObject:ID];
    [array addObject:nameField];
    [array addObject:eventField];
    [array addObject:dateField];
    [self.theTable reloadData];
    [super viewWillAppear:YES];

现在在 (UITableViewCell)-cell for row at index path 我拿了 4 个标签并将它们添加为子视图并将 [array objectAtIndex:indexPath.row] 分配给 label.text,即:

 - (UITableViewCell *)tableView:(UITableView *)view cellForRowAtIndexPath:(NSIndexPath *)indexPath


    //NSString *CellId = [NSString stringWithFormat:@"S%1dR%1d",indexPath.section,indexPath.row];

    UITableViewCell *cell = (UITableViewCell *)[view dequeueReusableCellWithIdentifier:nil];

    if (cell == nil)
    
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil] autorelease];
        view.backgroundColor = [UIColor clearColor];
        cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:@"reminderbutton.png"]];

        label1 = [[[UILabel alloc]initWithFrame:CGRectMake(26, 3, 30, 40)]autorelease];
        label1.backgroundColor = [UIColor clearColor];
        label1.textColor = [UIColor whiteColor];

        label2 = [[[UILabel alloc]initWithFrame:CGRectMake(45, 3, 100, 40)]autorelease];
        label2.backgroundColor = [UIColor clearColor];
        label2.textColor = [UIColor whiteColor];

        label3 = [[[UILabel alloc]initWithFrame:CGRectMake(119, 3, 100, 40)]autorelease];
        label3.backgroundColor = [UIColor clearColor];
        label3.textColor = [UIColor whiteColor];

        label4 = [[[UILabel alloc]initWithFrame:CGRectMake(198, 3, 120, 40)]autorelease];
        label4.backgroundColor = [UIColor clearColor];
        label4.textColor = [UIColor whiteColor];

    
 label1.text = [array objectAtIndex:indexPath.row];
    label2.text = [array objectAtIndex:indexPath.row];
    label3.text = [array objectAtIndex:indexPath.row];
    label4.text = [array objectAtIndex:indexPath.row];

    [cell addSubview:label1];
    [cell addSubview:label2];
    [cell addSubview:label3];
    [cell addSubview:label4];

    return cell;

单元格上没有显示任何内容,请帮我解决这个问题。为此苦苦挣扎,因为我是 Objective-c 的新手,如果有人提出详细的解释和解决方案,我会很高兴。对不起对于这个问题是否听起来很愚蠢

提前谢谢大家:)

【问题讨论】:

如您所说,您刚刚开始objective-c开发:您直接使用SQLite的原因是什么?如果您要构建的是一个简单的提醒应用程序,那么还有很多其他选项需要考虑——当您还不确定要处理钉子时,不要直接拿起锤子! 不管我的第一条评论是什么:不要在控制器中做模型的东西。如果您在视图控制器中构建 SQL 语句,那么这是一个严重的信号,即“UR Doin It wr0ng!”。有一个单独的类来处理这些东西。 @danyowdee 哦,实际上我刚刚完成了objective-c的培训。我们被分配了项目,我已经使用了核心数据,但甚至我的数据都没有被保存。这就是我担心的原因关于保存我的数据的sqlite,可以检索但无法正确显示,无论如何感谢您的建议:) 【参考方案1】:

我明白你现在想做什么。

我建议创建一个类来保存每个提醒的数据,然后你可以拥有一个提醒数据的数组。

所以我会在您的项目中添加一个新类,将其命名为 Reminder,然后为您的每个字段添加一个属性。

你的提醒类如下:

提醒.h

#import <Foundation/Foundation.h>

@interface Reminder : NSObject

@property (nonatomic, copy) NSString *reminderId; 
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *event;
@property (nonatomic, copy) NSString *date;

@end

而您的reminder.m 文件将是:

#import "Reminder.h"

@implementation Reminder
@synthesize reminderId, name, event, date;

-(void)dealloc


    self.reminderId = nil;
    self.name = nil;
    self.event = nil;
    self.date = nil;


@end

所以这个类将简单地保存每个提醒的数据。

然后在显示提醒列表的视图控制器中,您需要添加一个数组属性来保存提醒对象。

因此,将以下属性添加到显示提醒列表的 ViewController 中。

@property (nonatomic, retain) NSMutableArray *reminders;

确保您还在视图控制器 .m 文件中进行了综合,为此,请在视图控制器 .m 文件的 @implementation 行下添加这行代码:

@synthesize reminders;

还记得在你的 dealloc 方法中将提醒属性设置为 nil 以确保正确的内存清理:

self.reminders = nil;

我们将使用我们在视图控制器中创建的 Reminder 类,因此您还需要导入您的类,因此在视图控制器的 .m 文件中,在文件顶部附近添加一个导入语句,如下所示:

#import "Reminder.h"

现在您的视图控制器已设置好,可以使用我们创建的提醒类了。

然后您需要在视图控制器中添加一个方法,该方法将用于从数据库加载数据并填充提醒对象和提醒数组。

向视图控制器添加一个新方法,将其命名为 loadReminders

此方法的实现将是:

-(void)loadReminders


    // setup the reminders array
    self.reminders = nil;
    self.reminders = [[[NSMutableArray alloc] init] autorelease];

    //Retrieve the values of database
    const char *dbpath = [self.databasePath UTF8String];
    sqlite3_stmt *statement;
    if (sqlite3_open(dbpath, &remindersDB) == SQLITE_OK)
    
        NSString *querySQL = [NSString stringWithFormat:@"SELECT * FROM reminders"];
        NSLog(@"Data = %@",querySQL);

        const char *query_stmt = [querySQL UTF8String];

        if (sqlite3_prepare_v2(self.remindersDB ,query_stmt , -1, &statement, NULL) == SQLITE_OK)
        
            while (sqlite3_step(statement) == SQLITE_ROW)
            
                Reminder *loadedReminder = [[Reminder alloc] init];

                loadedReminder.reminderId = [[[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)]autorelease];

                loadedReminder.name = [[[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)]autorelease];                    

                loadedReminder.event = [[[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 2)]autorelease];

                loadedReminder.date = [[[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 3)]autorelease];

                [self.reminders addObject:loadedReminder];
                [loadedReminder release];
             

            sqlite3_finalize(statement);
        
        sqlite3_close(self.remindersDB);
    



所以这个方法所做的是从数据库中加载行,并为数据库中的每一行创建一个新的 Reminder 对象,使用该行中的数据设置属性,然后将此提醒对象添加到提醒数组。

请注意我对您的原始代码所做的更改:

while (sqlite3_step(statement) == SQLITE_ROW)

while 语句将循环并从数据库中获取每一行。

只要您想刷新数据列表,您就可以调用这个新方法 (loadReminders),因此,在您当前正在重新加载表格的代码中的任何地方,在重新加载表格之前调用这个方法,这将确保您的数组提醒已设置好,以便在重新加载时使用表。因此,在您上面的示例中,我会将您的 viewWillAppear 方法替换为:

-(void)viewWillAppear:(BOOL)animated

    [self loadReminders];
    [self.theTable reloadData];

现在所有数据都已设置好并可以使用了。并且使用提醒对象应该使 tableView 中的代码更易于阅读。

因此,要将您的数据放入表中,请将您当前的 tableview 方法替换为以下内容。

-(NSInteger)numberOfSectionsInTableView:(UITableView *)view

     return [self.reminders count];

这将告诉表格为提醒数组中的每个提醒创建一个部分。

现在根据您的描述(和链接),您正在做的是在每个部分中创建 1 个单元格。所以添加下面的方法来告诉 tableView 我们想要每个部分 1 行

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    return 1;

现在对于 cellForRowAtIndexPath,将您当前的方法替换为以下内容:

- (UITableViewCell *)tableView:(UITableView *)view cellForRowAtIndexPath:(NSIndexPath *)indexPath


    Reminder *reminderToDisplay;
    reminderToDisplay = [self.reminders objectAtIndex:indexPath.section];

    // Now create the cell to display the reminder data:

    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil] autorelease];
    view.backgroundColor = [UIColor clearColor];
    cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:@"reminderbutton.png"]];

    label1 = [[[UILabel alloc]initWithFrame:CGRectMake(26, 3, 30, 40)]autorelease];
    label1.backgroundColor = [UIColor clearColor];
    label1.textColor = [UIColor whiteColor];

    label2 = [[[UILabel alloc]initWithFrame:CGRectMake(45, 3, 100, 40)]autorelease];
    label2.backgroundColor = [UIColor clearColor];
    label2.textColor = [UIColor whiteColor];

    label3 = [[[UILabel alloc]initWithFrame:CGRectMake(119, 3, 100, 40)]autorelease];
    label3.backgroundColor = [UIColor clearColor];
    label3.textColor = [UIColor whiteColor];

    label4 = [[[UILabel alloc]initWithFrame:CGRectMake(198, 3, 120, 40)]autorelease];
    label4.backgroundColor = [UIColor clearColor];
    label4.textColor = [UIColor whiteColor];


    // Now set the labels using our reminder object
    label1.text = reminderToDisplay.reminderId;
    label2.text = reminderToDisplay.name;
    label3.text = reminderToDisplay.event;
    label4.text = reminderToDisplay.date;


    // now add the labels to the cell
    cell.contentView = [[UIView alloc] init] autorelease]
    [cell.contentView addSubview:label1];
    [cell.contentView addSubview:label2];
    [cell.contentView addSubview:label3];
    [cell.contentView addSubview:label4];

    return cell;


那么在这个方法中发生了什么,首先我们从提醒数组中获取当前部分的提醒:

Reminder *reminderToDisplay;
reminderToDisplay = [self.reminders objectAtIndex:indexPath.section];

接下来的几行应该很熟悉,我们正在创建单元格和标签。然后我们使用提醒对象来设置标签文本。

您现有的解决方案不起作用的原因是因为您使用的是 indexPath.Row,并且因为您为每个提醒使用一个部分,所以 indexPath.Row 将始终为 0,因为您在每个部分中只有 1 行。

我知道这是一篇很长的帖子,但希望能帮助您了解正在发生的事情。如有任何问题,请告诉我

【讨论】:

感谢您的回答,实施后会回复您 克雷格梅隆...很高兴完美!非常感谢您的回答....非常感谢...再见 TC :) 其实我参加了一个模型类,但正如你提到的,我试图在 indexPath.row 而不是 indexPath.section 检索数据,再次感谢大家的关心和关心,再见 TC : )【参考方案2】:

你真的应该创建一个自定义 UITableViewCell。

但为了快速解决问题,您可以将底部 [cell addSubview] 行替换为以下内容

cell.contentView = [[UIView alloc] init] autorelease]
[cell.contentView addSubview:label1];
[cell.contentView addSubview:label2];
[cell.contentView addSubview:label3];
[cell.contentView addSubview:label4];

【讨论】:

还值得注意的是,使用上面的代码,如果 deQueued 单元格为 nill,您将创建标签并将它们添加到单元格中。然后设置标签文本。但是,如果单元格被取消排队,即单元格不是 nil,则不会创建标签,并且您的 label1.text、label2.text 行将不起作用,因为 label1 没有引用任何内容。如果您仍想使用此方法而不是自定义单元格,我建议您不要使用 dequeuReusableCellWithIdentifier 并且每次都创建一个新单元格。 Craig Mellon 是的,我按照你的建议做了,我确实尝试了 2 种方法:添加 cell.contentView,然后下一个方法是删除出队可重用单元格标识符,并创建单元格但没有显示任何内容在单元格中,您能否通过编辑我发布的代码来放置答案,我将非常感谢您提前感谢 :) 我认为这可能是您的数据数组的问题。只是一个测试以确保您的单元格被正确添加尝试手动设置标签文本而不使用您的数据数组。这将使您能够确定问题出在您的数据还是单元格上。尝试替换 label1.text = [array objectAtIndex:indexPath.row]; with label1.text = @"测试标签"; 是的,它显示得更多了,我使用 4 个标签来显示每个单元格中的数据,这些数据是根据已保存提醒的数量添加的,这意味着如果 4 个提醒以这种方式保存 4 个单元格。 . 我能够在所有单元格上显示第一个提醒,我不知道我在哪里做错了,一些专家建议我拿一个数组,放置检索到的数据,然后简单地 [数组计数] 秒数在单元格中索引路径处的行:[array objectAtIndex:indexPath.row] 请帮帮我,我做错了什么: Craig Mellon 请查看此链接以获得更清晰的信息***.com/questions/8475446/…

以上是关于检索在 sqlite 数据库中插入的所有行,并在包含标签的表视图单元格中显示为具有不同部分的子视图的主要内容,如果未能解决你的问题,请参考以下文章

在 Hibernate 中,如何自动检索父 id 并在子插入中将其用作外键?

我有从 sqlite 检索数据并在 BaseAdapter 中显示数据的 android 应用程序 .. 最好的方法是啥?

从 sqlite3 检索图像并在 Kivy 图像小部件中显示 - ValueError

如何使用本机 sqlite 库而不是 QSql 从 sqlite 插入和检索 QString

SQLite3代码动态插入要删除的行数据的列值

将数据正确插入到 sqlite 数据库中