【问题标题】:Pre-load core data database in iOS 5 with UIManagedDocument使用 UIManagedDocument 在 iOS 5 中预加载核心数据数据库
【发布时间】:2012-01-30 19:37:37
【问题描述】:

我正在尝试想出一种方法,可以在使用UIManagedDocument 的同时将数据预加载到核心数据中。到目前为止,我的尝试是使用此代码在“加载器”应用程序中制作文档..

NSURL *url  = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
                                                      inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:@"Default Database"];
if(![[NSFileManager defaultManager] fileExistsAtPath:[self.document.fileURL path]]){
    [self.document saveToURL:self.document.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){
        if(success)[self loadDataIntoDocument];
    }];
}

然后将持久存储文件从模拟器目录中创建的“documents”目录复制到 Xcode 中的资源部分,用于将使用加载的数据库的主应用程序。

我的问题是我不知道如何从应用程序包中复制该文档并将其成功用作文档。

我尝试从应用程序包中按原样复制文档目录并尝试将其作为文档访问,这给出了UIManagedDocument 只能访问文件包的错误。 我已经尝试在主应用程序中创建另一个新文档,并将persistentStore从包中复制到在文档中创建的具有相同错误的文档上。 我已经尝试使用UIManagedDocument-(BOOL)loadFromContents:ofType:error: 方法.. 我什至不确定这是我应该使用的。

有没有人知道这通常是如何完成的?谢谢!

【问题讨论】:

    标签: iphone objective-c core-data ios5


    【解决方案1】:

    我认为你不应该在 iOS 中自己弄乱文件和目录。

    但是,您可以直接从您的捆绑包中打开该文档。为此,您只需将在 Loader 应用程序中创建的整个文档目录复制到最终包中。结构应该比较简单,只有两个目录,里面有persistentStore文件。

    之后,当你想打开你的文档时,你需要注意两件事:你需要使用 bundle 目录作为基础目录,你需要在“文件”的末尾添加一个/名称,所以UIManagedDocument 知道目录就是文档。代码如下所示:

    NSURL* url = [[NSBundle mainBundle] bundleURL];
    url = [url URLByAppendingPathComponent:@"filename/"];
    UIManagedDocument* doc = [[UIManagedDocument alloc] initWithFileURL:url];
    

    请注意,您不能写入该文件,因为您不允许在应用程序包内写入。因此,如果您想要一个可写的文档,您需要将该文档复制到您的文档文件夹中。您只需将doc 保存到其他位置即可轻松做到这一点:

    [doc saveToURL:newURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){}]
    

    还有一件事:您必须确保在您的应用程序包中创建了文件夹结构。实现这一点的最简单方法是将整个文件夹拖到您的项目中,然后选择“为任何添加的文件夹创建文件夹引用”。对于“文件”symbollist_en(实际上是一个包/文件夹本身),它应该如下所示:

    如果您不这样做,文档的“内容”将直接驻留在您的 app bundle 中,正如您发现的那样,无法以 UIManagedDocument 的形式打开。

    【讨论】:

      【解决方案2】:

      Shezi 的回答帮助很大,但和这里的其他人一样:Preloaded Core Data Database in ios5 with UIManagedDocument 和这里:Pre load core data database coming up black with UIManagedDocument 我遇到了问题。

      首先,模拟器上的行为与设备上的行为明显不同。如果您使用initWithURL 实例化 UIManagedDocument,其中 URL 指向应用程序包,则在设备上运行时,您将收到一条警告,指出这是控制台中的只读目录,但模拟器上不会出现此类警告。权限处理似乎有很大不同,可以得到不同的结果。

      文档建议应该使用migratePersistentStore:toURL:options:withType:error: 而不是[doc saveToURL:newURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){}]

      我花了很长时间试图让它工作,但在获取指向持久存储的指针时遇到了很多麻烦。尽管我的应用程序在遵循 Shezi 的解决方案后可以正常进行只读操作,但持久存储协调器仍继续为我提供持久存储的空指针。当我尝试– persistentStores(返回一个空数组)和 – persistentStoreForURL:如果有人能解释为什么会这样,我会很感兴趣。烦人的是,有时候在模拟器上也能用,但是我在设备上测试的时候就失败了。

      最后,在实例化 UIManagedDocument 之前,我改变了一些东西并首先将 bundle 文件夹复制到文档目录中。这似乎成功了。这是代码。它假定您的 UIManagedDocument 是该类的属性。我把它放在初始视图控制器的 viewWillAppear 方法中。请记住,如果您使用包含现有持久存储的 URL 进行实例化,则需要打开文档。

      if (!self.yourUIManagedDocument) {
          NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
          NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"yourUIManagedDocument"];
          NSString *documentsFolderPath = [documentsDirectory stringByAppendingPathComponent:@"yourUIManagedDocument"];
      
          NSURL *documentsUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
          documentsUrl = [documentsUrl URLByAppendingPathComponent:@"yourUIManagedDocument"];
      
          if (![[NSFileManager defaultManager] fileExistsAtPath:documentsFolderPath]) {
              NSError *error = nil;
      
              if([[NSFileManager defaultManager] copyItemAtPath:bundlePath
                                                         toPath:documentsFolderPath
                                                          error:&error]) {
                  self.yourUIManagedDocument = [[UIManagedDocument alloc] initWithFileURL:documentsUrl];
                  [self.yourUIManagedDocument openWithCompletionHandler:^(BOOL success) {
                  }];
              } else {
                  NSLog(@"%@", error);
              }
          } else {
              self.yourUIManagedDocument = [[UIManagedDocument alloc] initWithFileURL:documentsUrl];
              [self.yourUIManagedDocument openWithCompletionHandler:^(BOOL success) {
              }];
          }
      } else if (self.yourUIManagedDocument.documentState == UIDocumentStateClosed) {
          //Document is closed. Need to open it
          [self.yourUIManagedDocument openWithCompletionHandler:^(BOOL success) {
          }];
      }
      

      当然,以上假设您已经使用模拟器生成了数据库,并按照 Shezi 描述的方式将目录复制到了 app bundle 中。欢迎任何有关如何改进代码的 cmets 或建议。我还在这儿学习。

      【讨论】:

      • 我正在做的是在文档目录中创建以下目录(Documents/AppDatabase/StoreContent),并且只处理 StoreContent 文件夹中的 persistentStore 文件。这对我有用。你觉得我会有什么问题吗?
      【解决方案3】:

      shezi 的方法似乎对我有用,我想添加的唯一内容是“文件”在这种情况下表示 symbolist_en。对于像我这样的新开发人员来说,这可能有点令人困惑(我放置的是 persistentStore/)。

      【讨论】:

      • 感谢您指出这一点,我已经编辑了答案以反映这一点。
      【解决方案4】:

      社子的回答帮了大忙。但它没有按原样工作。我在 xcode 中删除了文档目录,但它没有从捆绑包复制到 Documents 目录。然后我偶然发现了 macbeb 的 question 关于预加载。我尝试了他的方法,该方法只在包中包含了 persistentStore 文件。然后在 Document 的文件夹下创建所需的文档名称目录,然后将 persistentStore 复制到该路径。

      检查带有注释“COPY FROM BUNDLE”的代码

      我使用静态类来处理文档。

      +(DocumentHandler *) sharedDocumentHandler {
          static DocumentHandler *mySharedDocumentHandler = nil;
          static dispatch_once_t once;
          dispatch_once(&once, ^{
              mySharedDocumentHandler = [[self alloc] init];
          });
          return mySharedDocumentHandler;
      }
      
      - (id)init {
          self = [super init];
          if (self) {
              NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
              url = [url URLByAppendingPathComponent:@"YourDocumentName"];
              self.sharedDocument = [[MyUIManagedDocument alloc] initWithFileURL:url];
          }
          return self;
      }
      - (void)performWithDocument:(OnDocumentReady)onDocumentReady
      {
          void (^OnDocumentDidLoad)(BOOL) = ^(BOOL success) {
              if(success) {
                  onDocumentReady(self.sharedDocument);
              } else {
                  NSLog(@"Error occured while creating or opening the database");
              }
          };
      
          if (![[NSFileManager defaultManager] fileExistsAtPath:[self.sharedDocument.fileURL path]]) {
              NSError *error = nil;
      
              // COPY FROM BUNDLE
      
              NSFileManager *fileManager = [NSFileManager defaultManager];
      
              NSString *DB = [[self.sharedDocument.fileURL path] stringByAppendingPathComponent:@"StoreContent"];
      
              [fileManager createDirectoryAtPath:DB withIntermediateDirectories:YES attributes:nil error:&error];
      
              NSLog(@"create directory error: %@",error);
      
              DB = [DB stringByAppendingPathComponent:@"persistentStore"];
      
              NSString *shippedDB = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"persistentStore"];
      
              NSLog(@"%d",[fileManager fileExistsAtPath:shippedDB]);
      
              [fileManager copyItemAtPath:shippedDB toPath:DB error:&error];
      
              NSLog(@"Copy error %@",error);        
          }
      
          if (![[NSFileManager defaultManager] fileExistsAtPath:[self.sharedDocument.fileURL path]]) {
              //Create documents [This is required while creating database first time]
              [self.sharedDocument saveToURL:self.sharedDocument.fileURL
                      forSaveOperation:UIDocumentSaveForCreating
                     completionHandler:OnDocumentDidLoad];
          } else if (self.sharedDocument.documentState == UIDocumentStateClosed) {
              [self.sharedDocument openWithCompletionHandler:OnDocumentDidLoad];
          } else if (self.sharedDocument.documentState == UIDocumentStateNormal) {
              OnDocumentDidLoad(YES);
          }
      }  
      

      【讨论】:

        猜你喜欢
        • 2012-07-14
        • 2011-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-22
        • 1970-01-01
        • 2012-02-21
        • 1970-01-01
        相关资源
        最近更新 更多