【问题标题】:Copying data to the Application Data folder on the iPhone将数据复制到 iPhone 上的 Application Data 文件夹
【发布时间】:2011-01-11 08:39:42
【问题描述】:

我正在(最终)将我的应用程序加载到 iPhone 设备上进行测试。到目前为止,我只在模拟器中测试了该应用程序。该应用程序以数据为中心并使用 SQLite 数据库。我已经创建了一个适当的 SQLite 数据库,其中包含我在模拟器中使用的示例数据。如何将此 .sqlite3 文件复制到实际的 iPhone?

使用模拟器很容易,因为我可以将 .sqlite3 文件复制到 ~/Library/Application Support/iPhone Simulator/User/Applications/{UUID}/Documents 文件夹中,但我无法弄清楚如何将它放到实际 iPhone 设备上的相同位置。在手机上从头开始重新创建数据库并不是一个真正的选择,因为我已经完成了在 Mac 上创建数据库的所有工作。

【问题讨论】:

    标签: iphone objective-c sqlite


    【解决方案1】:

    正如 Alex 所说,您必须将数据库文件作为资源添加到您的项目中。这将指示 Xcode 将您的数据库文件捆绑到您的 .app 中。但是,该文件是只读的,您可以将其复制到您的应用程序文档文件夹(在设备或模拟器上,同样的东西),它基本上可以写入。

    下面是我用于此类事情的代码。这段代码的好处是,每当您更改捆绑在 .app 中的“主”副本时,它都会自动刷新您的应用程序文档文件夹中的可写副本。使用“pathLocal”打开您的(可写)数据库...

    下面的函数在操作成功时返回YES(无论是否需要副本)。你可以随心所欲地改变它:)

    NSString *pathLocal, *pathBundle;
    
    // Automatically copy DB from .app bundle to device document folder if needed
    - (BOOL)automaticallyCopyDatabase {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
        NSString *documentsDir = [paths objectAtIndex:0];
        pathLocal = [documentsDir stringByAppendingPathComponent:@"mydb.sqlite"];
        pathBundle = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mydb.sqlite"];
    
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSDictionary *localAttr = [fileManager fileAttributesAtPath:pathLocal traverseLink:YES];
        BOOL needsCopy = NO;
        if (localAttr == nil) {
            needsCopy = YES;
        } else {
            NSDate *localDate;
            NSDate *appDBDate;
            if (localDate = [localAttr objectForKey:NSFileModificationDate]) {
                NSDictionary *appDBAttr = [fileManager fileAttributesAtPath:pathBundle traverseLink:YES];
                appDBDate = [appDBAttr objectForKey:NSFileModificationDate];
                needsCopy = [appDBDate compare:localDate] == NSOrderedDescending;
            } else {
                needsCopy = YES;
            }
        }
        if (needsCopy) {
            NSError *error;
            BOOL success;
            if (localAttr != nil) {
                success = [fileManager removeItemAtPath:pathLocal error:&error];
            }
            success = [fileManager copyItemAtPath:pathBundle toPath:pathLocal error:&error];
            return success;
        }
        return YES;
    }
    

    【讨论】:

    • 太棒了。感谢此代码 Zoran。它会让我的事情变得更容易一些(即很多):) 我特别喜欢当主副本更改时代码会刷新可写副本。
    【解决方案2】:

    为什么不将它添加到您的应用程序包中?在 Xcode 的项目窗口中右键单击 Resources 文件夹,然后选择 Add > Existing Files... 以添加您的 sqlite 数据库。

    然后您将从应用程序包中加载文件:

    NSString *databasePath = [[NSBundle mainBundle] pathForResource:@"mySQLiteDatabaseFile" ofType:@"sqlite3"];
    NSData *databaseData = [NSData dataWithContentsOfFile:databasePath];
    // ...
    

    【讨论】:

    • 谢谢亚历克斯。但是,如果它已包含在应用程序包中,我可以写回数据库吗?
    • 否,但您可以将这个“预初始化”的基本数据库从那里复制到可写的Documents 文件夹中。好处是这种方法还允许用户“重置”应用程序。
    【解决方案3】:

    在这里我是如何创建一个名为 DBManagement 的类 并在m文件中实现这些方法。也将此行放在@implementation行上方的实现文件中

    静态 sqlite3 *CHManagement = nil;

    -(NSString *) getDBPath
    {
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
     NSString *documentsDirectory = [paths objectAtIndex:0];
     NSString *MyDatabasePath = [documentsDirectory stringByAppendingString:@"/CHManagement.sqlite"];
      return MyDatabasePath;
    
     }
    
    -(void) checkDataBase
    {
    NSLog(@"CheckDatabase Called");
    NSFileManager *fileManager=[NSFileManager defaultManager];
    NSError *error=[[[NSError alloc]init] autorelease]; 
    NSString *dbPath = [self getDBPath];
    BOOL success=[fileManager fileExistsAtPath:dbPath];
    if(!success)
    {
     NSString *defaultDBPath=nil;
     defaultDBPath=[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:@"CHManagement.sqlite"];
     success=[fileManager copyItemAtPath:defaultDBPath  toPath:dbPath error:&error];
     if(!success)
     {
       NSAssert1(0,@"failed to create database with message '%@'.",[error localizedDescription]); 
      }
     }
     else
     {
     sqlite3 *MyDatabase;
     NSInteger VersionNumber=0;
     sqlite3_stmt *CompiledStatement=nil;
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
     NSString *documentsDirectory = [paths objectAtIndex:0];
     NSString *MyDatabasePath = [documentsDirectory stringByAppendingString:@"/CHManagement.sqlite"];
     if(sqlite3_open([MyDatabasePath UTF8String],&MyDatabase) == SQLITE_OK)
     {
      sqlite3_prepare_v2(MyDatabase, "select appVersionNo from VersionInfo", -1, &CompiledStatement, NULL);
      while(sqlite3_step(CompiledStatement) == SQLITE_ROW)
      {
       VersionNumber=sqlite3_column_int(CompiledStatement,0);
      }
      sqlite3_reset(CompiledStatement);
      sqlite3_finalize(CompiledStatement);
      sqlite3_close(MyDatabase);
     }
     if (VersionNumber!=1)
     {
      [self deleteDatabase];
      NSString *defaultDBPath=[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:@"CHManagement.sqlite"];
      success=[fileManager copyItemAtPath:defaultDBPath  toPath:dbPath error:&error];
      if(!success)
      {
       NSAssert1(0,@"failed to create database with message '%@'.",[error localizedDescription]); 
       }
      }
     }
     }
    
    - (void)deleteDatabase
    {
    NSLog(@"Delete Database Called");
    NSError **error=nil;
    NSFileManager *FileManager = [NSFileManager defaultManager];
    NSString *databasepath = [self getDBPath];
      BOOL success = [FileManager fileExistsAtPath:databasepath];
    if(success) {
    [FileManager removeItemAtPath:databasepath error:error];
    }
     }
    

    通过这些方法,您可以轻松地将数据库加载到应用程序的 iphone 文件夹中。 对不起格式。而 appVersionNo 是表中的一个字段,称为 versionInfo,默认值为 1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-30
      • 2010-12-01
      相关资源
      最近更新 更多