程序运行正常
我可以看到正在打开的数据库
当我向应用添加项目时,它在 UITableView
我有单元测试来测试每个操作:创建、更新、删除和计数。
这些都通过了
这是我的单元测试:
- (void)testToDoItemSQLite {
NSLog(@" ");
NSLog(@"*** Starting testToDoItemSQLite ***");
ToDoItemSvcSQLite *todoitemSvc = [[ToDoItemSvcSQLite alloc] init];
ToDoItem *todoitem = [[ToDoItem alloc] init];
todoitem.itemname = @"This was created by a unit test";
[todoitemSvc createToDoItem:todoitem];
NSMutableArray *todoitems = [todoitemSvc retrieveAllToDoItems];
NSLog(@"*** number of todoitems: %lu", (unsigned long)todoitems.count);
todoitem.itemname = @"This was created by a unit test";
[todoitemSvc updateToDoItem:todoitem];
[todoitemSvc deleteToDoItem:todoitem];
NSLog(@"*** Ending testToDoItemSQLite ***");
NSLog(@" ");
}
这是我的创建、检索、更新和删除代码
#import "ToDoItemSvcSQLite.h"
#import "sqlite3.h"
@implementation ToDoItemSvcSQLite
NSString *databasePath = nil;
sqlite3 *database = nil;
- (id)init {
if ((self = [super init])) {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:@"todoitem.sqlite3"];
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(@"database is open");
NSLog(@"database file path: %@", databasePath);
NSString *createSql = @"Create table if not exists todoitem (id integer primary key autoincrement, itemname varchar(200))";
char *errMsg;
if (sqlite3_exec(database, [createSql UTF8String], NULL, NULL, &errMsg) !=SQLITE_OK) {
NSLog(@"Failed to create table %s", errMsg);
}
}
else {
NSLog(@"*** Failed to open database!");
NSLog(@"*** SQL error: %s\n", sqlite3_errmsg(database));
}
}
return self;
}
- (ToDoItem *) createToDoItem:(ToDoItem *)todoitem {
sqlite3_stmt *statement;
NSString *insertSQL = [NSString stringWithFormat: @"INSERT INTO todoitem (itemname) VALUES (\"%@\")", todoitem.itemname];
if (sqlite3_prepare(database, [insertSQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
if (sqlite3_step(statement) == SQLITE_DONE) {
todoitem.itemID = sqlite3_last_insert_rowid(database);
NSLog(@"ToDoItem added");
}
else {
NSLog(@"*** ToDoItem NOT added");
NSLog(@"*** SQL error: %s\n", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
}
return todoitem;
}
- (NSMutableArray *) retrieveAllToDoItems {
NSMutableArray *todoitems = [NSMutableArray array];
NSString *selectSQL = [NSString stringWithFormat:@"SELECT * FROM todoitem ORDER BY itemname"];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [selectSQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
NSLog(@"*** ToDoItems retrieved");
while (sqlite3_step(statement) == SQLITE_ROW) {
int id = sqlite3_column_int(statement, 0);
char *itemnameChars = (char *)sqlite3_column_text(statement, 1);
ToDoItem *todoitem = [[ToDoItem alloc] init];
todoitem.itemID = id;
todoitem.itemname = [[NSString alloc] initWithUTF8String:itemnameChars];
[todoitems addObject:todoitem];
}
sqlite3_finalize(statement);
}
else {
NSLog(@"*** ToDoItems NOT retrieved");
NSLog(@"*** SQL error %s\n", sqlite3_errmsg(database));
}
return todoitems;
}
- (ToDoItem *) updateToDoItem:(ToDoItem *)todoitem {
NSString *updateSQL = [NSString stringWithFormat: @"UPDATE todoitem SET itemname=\"%@\" WHERE id = %li ", todoitem.itemname, (long)todoitem.itemID];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [updateSQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(@"*** ToDoItem updated");
}
else {
NSLog(@"ToDoItem NOT updated");
NSLog(@"*** SQL error: %s\n", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
}
return todoitem;
}
- (ToDoItem *) deleteToDoItem:(ToDoItem *)todoitem {
NSString *deleteSQL = [NSString stringWithFormat: @"DELETE FROM todoitem WHERE id = %i",(int) todoitem.itemID];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [deleteSQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(@"*** ToDoItem deleted");
}
else {
NSLog(@"*** ToDoItem NOT deleted");
NSLog(@"*** SQL error: %s\n", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
}
return todoitem;
}
- (void)dealloc {
sqlite3_close(database);
}
@end
这是执行所有操作的代码
添加项目
- (IBAction)addToDoItem:(id)sender {
[self.view endEditing:YES];
NSLog(@"saveToDoItem: Adding ToDoItem");
ToDoItem *todoitem = [[ToDoItem alloc] init];
todoitem.todoitem = _toDoItem.text;
[ToDoItemSvc createToDoItem:todoitem];
//clears text field on save
_toDoItem.text = @"";
[self.tableView reloadData];
NSLog(@"saveToDoItem: todoitem saved");
}
删除项目
- (IBAction)deleteToDoItem:(id)sender {
NSLog(@"Deleting ToDoItem");
[self.view endEditing:YES];
}
更新项目
- (IBAction)updateToDoItem:(id)sender {
NSLog(@"updatingToDoItem: Updating ToDoItem");
toDoItemObject.todoitem = toDoItem.text;
}
填充 UITableView
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"toDoItemCell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:simpleTableIdentifier];
}
ToDoItem *toDoItem = [[ToDoItemSvc retrieveAllToDoItems]
objectAtIndex:indexPath.row];
cell.textLabel.text = [toDoItem description];
return cell;
}
我想弄清楚为什么我的值返回 NULL
。
当我查看数据库时,我实际上没有看到表中的任何实体
这是否意味着它实际上没有更新?我对此有点困惑。
编辑
我手动更新了数据库。我注意到它没有被阅读。我什至替换了 xcode 显示它正在读取的数据库。还是什么都没有。
当它使用存档运行时,效果很好。显然不同的持久数据方式。
编辑
看起来持久化数据实际上是有效的,但由于某种原因 NULL
被插入到数据库中。我尝试编辑数据库以查看表是否会重新加载并获取编辑后的值。好像没有用
应用已加载 保存新项目后 查看项目时
最佳答案
todoitem.todoitem
和 todoitem.itemname
有什么区别?您可能正在使用 todoitem.itemname
而不是 todoitem.todoitem
:
- (IBAction)addToDoItem:(id)sender {
…
todoitem.itemname = _toDoItem.text;
[ToDoItemSvc createToDoItem:todoitem];
...
}
- (IBAction)updateToDoItem:(id)sender {
NSLog(@"updatingToDoItem: Updating ToDoItem");
toDoItemObject.itemname = toDoItem.text;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
ToDoItem *toDoItem = [[ToDoItemSvc retrieveAllToDoItems]
objectAtIndex:indexPath.row];
cell.textLabel.text = toDoItem.itemname;
return cell;
}
希望对您有所帮助!
编辑:
ViewController.m
- (IBAction)addToDoItem:(id)sender {
[self.view endEditing:YES];
NSLog(@"saveToDoItem: Adding ToDoItem");
ToDoItem *todoitem = [[ToDoItem alloc] init];
todoitem.itemname = _toDoItem.text; // I edited
[ToDoItemSvc createToDoItem:todoitem];
//clears text field on save
_toDoItem.text = @"";
[self.tableView reloadData];
NSLog(@"saveToDoItem: todoitem saved");
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"toDoItemCell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:simpleTableIdentifier];
}
ToDoItem *toDoItem = [[ToDoItemSvc retrieveAllToDoItems]
objectAtIndex:indexPath.row];
cell.textLabel.text = [toDoItem itemname]; // I edited
return cell;
}
SecondViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
toDoItem.text = toDoItemObject.itemname; // I edited
}
ToDoItemSvcSQLite.m
- (ToDoItem *) updateToDoItem:(ToDoItem *)todoitem {
NSString *updateSQL = [NSString stringWithFormat: @"UPDATE todoitem SET itemname=\"%@\" WHERE id = %i ", todoitem.itemname, todoitem.id]; // I edited
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [updateSQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(@"*** ToDoItem updated");
} else {
NSLog(@"ToDoItem NOT updated");
NSLog(@"*** SQL error: %s\n", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
}
return todoitem;
}
最后,不要在 ToDoItemSvcSQLite
中使用 init
,而应使用 initialize
:
// ToDoItemSvcSQLite.m
static sqlite3 *database = nil;
+ (void)initialize {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:@"todoitem"];
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(@"database is open");
NSLog(@"database file path: %@", databasePath);
NSString *createSql = @"Create table if not exists todoitem (id integer primary key autoincrement, itemname varchar(200))";
char *errMsg;
if (sqlite3_exec(database, [createSql UTF8String], NULL, NULL, &errMsg) !=SQLITE_OK) {
NSLog(@"Failed to create table %s", errMsg);
}
} else {
NSLog(@"*** Failed to open database!");
NSLog(@"*** SQL error: %s\n", sqlite3_errmsg(database));
}
}
并在 dealloc
中注释这一行:
- (void)dealloc {
// sqlite3_close(database);
}
再次编辑:
您似乎更改了标识符
:
你应该使用viewToDoItem
:
if ([segue.identifier isEqualToString:@"viewToDoItem"]) {
然后:
// SecondViewController.m
#import "ToDoItemSvcSQLite.h"
- (IBAction)updateToDoItem:(id)sender {
NSLog(@"updatingToDoItem: Updating ToDoItem");
toDoItemObject.itemname = toDoItem.text;
[[ToDoItemSvcSQLite new] updateToDoItem:toDoItemObject];
}
关于ios - 从 SQLite 数据库获取 UITableView 中的 NULL 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30650061/