对于iOS编程而言,我是一个完全新手,而且核心数据更少。对我来说这是非常不直观的,因为我真正使用MATLAB进行编程,我猜这更像是一种“脚本”语言。
无论如何,我的问题是我不知道为我的应用程序创建数据库需要做些什么。所以我读了一下,并认为我必须创建我的东西的SQL数据库,然后导入它。简而言之,我创建了一个SQLite数据库,我想使用我已经完成的工作将内容导入我的CoreData数据库。
我尝试导出到逗号分隔的文件和xml文件并阅读它们,但我不喜欢它,这似乎是我不应该做的额外步骤。
因此,我将SQLite数据库导入我的资源并添加了sqlite框架。
我有我的核心数据模型设置,它正在后台正确设置模型的SQLite数据库。
当我运行我的程序向我的实体添加对象时,它似乎工作,我甚至可以在之后获取结果。但是,当我检查Core Data Database SQLite文件时,没有保存任何记录。
它如何才能获取结果但不能将它们保存到数据库中?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//load in the path for resources
NSString *paths = [[NSBundle mainBundle] resourcePath];
NSString *databaseName = @"histology.sqlite";
NSString *databasePath = [paths stringByAppendingPathComponent:databaseName];
[self createDatabase:databasePath ];
NSError *error;
if ([[self managedObjectContext] save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
// Test listing all CELLS from the store
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityMO = [NSEntityDescription entityForName:@"CELL"
inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entityMO];
NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
for (CELL *cellName in fetchedObjects) {
//NSLog(@"cellName: %@", cellName);
}
-(void) createDatabase:databasePath {
NSLog(@"The createDatabase function was entered.");
NSLog(@"The databasePath is %@ ",[databasePath description]);
// Setup the database object
sqlite3 *histoDatabase;
// Open the database from filessytem
if(sqlite3_open([databasePath UTF8String], &histoDatabase) == SQLITE_OK) {
NSLog(@"The database was opened");
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "SELECT * FROM CELL";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(histoDatabase, sqlStatement, -1, &compiledStatement, NULL) != SQLITE_OK) {
NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(histoDatabase));
}
if(sqlite3_prepare_v2(histoDatabase, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to cell MO array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
CELL *cellMO = [NSEntityDescription insertNewObjectForEntityForName:@"CELL" inManagedObjectContext:[self managedObjectContext]];
if (sqlite3_column_type(compiledStatement, 0) != SQLITE_NULL) {
cellMO.cellName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
} else {
cellMO.cellName = @"undefined";
}
if (sqlite3_column_type(compiledStatement, 1) != SQLITE_NULL) {
cellMO.cellDescription = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
} else {
cellMO.cellDescription = @"undefined";
}
NSLog(@"The contents of NSString *cellName = %@",[cellMO.cellName description]);
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(histoDatabase);
}
我觉得它与打开/关闭两个数据库的时间有关?
附件我有一些SQL调试输出到终端
2012-05-28 16:03:39.556 MedPix[34751:fb03] The createDatabase function was entered.
2012-05-28 16:03:39.557 MedPix[34751:fb03] The databasePath is /Users/jack/Library/Application Support/iPhone Simulator/5.1/Applications/A6B2A79D-BA93-4E24-9291-5B7948A3CDF4/MedPix.app/histology.sqlite
2012-05-28 16:03:39.559 MedPix[34751:fb03] The database was opened
2012-05-28 16:03:39.560 MedPix[34751:fb03] The database was prepared
2012-05-28 16:03:39.575 MedPix[34751:fb03] CoreData: annotation: Connecting to sqlite database file at "/Users/jack/Library/Application Support/iPhone Simulator/5.1/Applications/A6B2A79D-BA93-4E24-9291-5B7948A3CDF4/Documents/MedPix.sqlite"
2012-05-28 16:03:39.576 MedPix[34751:fb03] CoreData: annotation: creating schema.
2012-05-28 16:03:39.577 MedPix[34751:fb03] CoreData: sql: pragma page_size=4096
2012-05-28 16:03:39.578 MedPix[34751:fb03] CoreData: sql: pragma auto_vacuum=2
2012-05-28 16:03:39.630 MedPix[34751:fb03] CoreData: sql: BEGIN EXCLUSIVE
2012-05-28 16:03:39.631 MedPix[34751:fb03] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA'
2012-05-28 16:03:39.632 MedPix[34751:fb03] CoreData: sql: CREATE TABLE ZCELL ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZCELLDESCRIPTION VARCHAR, ZCELLNAME VARCHAR )
...
2012-05-28 16:03:39.669 MedPix[34751:fb03] CoreData: annotation: Creating primary key table.
2012-05-28 16:03:39.671 MedPix[34751:fb03] CoreData: sql: CREATE TABLE Z_PRIMARYKEY (Z_ENT INTEGER PRIMARY KEY, Z_NAME VARCHAR, Z_SUPER INTEGER, Z_MAX INTEGER)
2012-05-28 16:03:39.672 MedPix[34751:fb03] CoreData: sql: INSERT INTO Z_PRIMARYKEY(Z_ENT, Z_NAME, Z_SUPER, Z_MAX) VALUES(1, 'CELL', 0, 0)
...
2012-05-28 16:03:39.701 MedPix[34751:fb03] CoreData: sql: CREATE TABLE Z_METADATA (Z_VERSION INTEGER PRIMARY KEY, Z_UUID VARCHAR(255), Z_PLIST BLOB)
2012-05-28 16:03:39.702 MedPix[34751:fb03] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA'
2012-05-28 16:03:39.703 MedPix[34751:fb03] CoreData: sql: DELETE FROM Z_METADATA WHERE Z_VERSION = ?
2012-05-28 16:03:39.704 MedPix[34751:fb03] CoreData: sql: INSERT INTO Z_METADATA (Z_VERSION, Z_UUID, Z_PLIST) VALUES (?, ?, ?)
2012-05-28 16:03:39.705 MedPix[34751:fb03] CoreData: sql: COMMIT
2012-05-28 16:03:39.710 MedPix[34751:fb03] CoreData: sql: pragma cache_size=200
2012-05-28 16:03:39.711 MedPix[34751:fb03] CoreData: sql: SELECT Z_VERSION, Z_UUID, Z_PLIST FROM Z_METADATA
2012-05-28 16:03:39.712 MedPix[34751:fb03] The contents of NSString *cellName = Beta Cell
2012-05-28 16:03:39.712 MedPix[34751:fb03] The contents of NSString *cellName = Gastric Chief Cell
...
2012-05-28 16:03:39.714 MedPix[34751:fb03] The database was prepared
2012-05-28 16:03:39.764 MedPix[34751:fb03] The createDatabase function has finished. Now fetching.
2012-05-28 16:03:39.765 MedPix[34751:fb03] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZCELLDESCRIPTION, t0.ZCELLNAME FROM ZCELL t0
2012-05-28 16:03:39.766 MedPix[34751:fb03] CoreData: annotation: sql connection fetch time: 0.0008s
2012-05-28 16:03:39.767 MedPix[34751:fb03] CoreData: annotation: total fetch execution time: 0.0016s for 0 rows.
2012-05-28 16:03:39.768 MedPix[34751:fb03] cellName: <CELL: 0x6bbc120> (entity: CELL; id: 0x6bbc160 <x-coredata:///CELL/t57D10DDD-74E2-474F-97EE-E3BD0FF684DA34> ; data: {
cellDescription = "S cells are cells which release secretin, found in the jejunum and duodenum. They are stimulated by a drop in pH to 4 or below in the small intestine's lumen. The released secretin will increase the s";
cellName = "S Cell";
organs = (
);
specimens = (
);
systems = (
);
tissues = (
);
})
...
切片缩短为缩写。但请注意,获取结果包含信息,但它表示总获取执行是“0”行?怎么可能?任何帮助将不胜感激,特别是详细的解释。 :)谢谢。
答案 0 :(得分:2)
有几件事。
首先,根据您导入的数据库的大小,您可能希望从主线程中导入。否则,如果您在applicationDidFinishLaunching:方法中需要很长时间,系统将终止您的应用程序。您可以按如下方式执行此操作:
// If in applicationDidFinishLaunching, we need to first schedule on the main queue
// We do this to be one of the first things scheduled once the main queue starts running
dispatch_async(dispatch_get_main_queue(), ^{
// now get off the main queue
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
[self createDatabase:databasePath];
// Now put the results back on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
NSError *error;
if ([[self managedObjectContext] save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
// Test listing all CELLS from the store
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityMO = [NSEntityDescription entityForName:@"CELL"
inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entityMO];
NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
for (CELL *cellName in fetchedObjects) {
//NSLog(@"cellName: %@", cellName);
}
});
});
});
我会检查导入是否已完成,如果没有,则使用Grand Central Dispatch从主线程中获取导入工作。
其次,正如gerry3在他的回答中提到的那样,您需要将save:消息发送到您的托管对象上下文。使用iOS5的父和子上下文将允许您通过子上下文在后台轻松导入,然后将这些更改推送到主父上下文。查看WWDC 2011核心数据会话和堆栈溢出,以获得良好的概述。
在您上面的代码的上下文中,您将执行以下所有操作:
// create a child context with a concurrent queue type.
NSManagedObjectContext *childManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
// Set the parentContext. Now whenever we save changes to the child context
// They will be pushed up to the parentContext and we can choose to save or throw them
// away
childManagedObjectContext.parentContext=self.managedObjectContext;
// Loop through the results and add them to cell MO array
NSInteger rowNumber=0;
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
CELL *cellMO = [NSEntityDescription insertNewObjectForEntityForName:@"CELL" inManagedObjectContext:[self managedObjectContext]];
if (sqlite3_column_type(compiledStatement, 0) != SQLITE_NULL) {
cellMO.cellName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
} else {
cellMO.cellName = @"undefined";
}
if (sqlite3_column_type(compiledStatement, 1) != SQLITE_NULL) {
cellMO.cellDescription = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
} else {
cellMO.cellDescription = @"undefined";
}
NSLog(@"The contents of NSString *cellName = %@",[cellMO.cellName description]);
// Save our records periodically. Choose a good number of iterations on this.
// depends on your particular situation.
if (rowNumber%100==0){
NSError *mocError=nil;
// Save the changes on the child context
// This will push the changes up to the parent context.
[childManagedObjectContext performBlock:^{
[self.managedObjectContext save: &mocError];
if (mocError){
NSLog(@"mocError on rowNumber: %d, error: %@",rowNumber, error);
}
// Now save the changes on the parent context
[self.managedObjectContext performBlock:^{
NSError *parentMocError=nil;
[self.managedObjectContext save: &parentMocError];
if (parentMocError){
NSLog(@"parentMocError on rowNumber: %d, error: %@",rowNumber, parentMocError);
}
}];
}];
}
rowNumber=rowNumber+1;
}
// Pickup and stragglers
[childManagedObjectContext performBlock:^{
[self.managedObjectContext save: &mocError];
if (mocError){
NSLog(@"mocError on rowNumber: %d, error: %@",rowNumber, error);
}
// Now save the changes on the parent context
[self.managedObjectContext performBlock:^{
NSError *parentMocError=nil;
[self.managedObjectContext save: &parentMocError];
if (parentMocError){
NSLog(@"parentMocError on rowNumber: %d, error: %@",rowNumber, parentMocError);
}
}];
}];
祝你好运!
添
答案 1 :(得分:0)
插入所有新对象后,您需要再次save:
managedObjectContext
。
如果要插入大量新对象,可能需要在整个过程中定期保存。