2011-12-30 6 views
13

Estoy tratando de encontrar una forma de que pueda precargar los datos en el núcleo de datos mientras usa un UIManagedDocument. Mi intento hasta ahora es hacer que el documento en una aplicación "Cargador" utilizando este código ..Precargue la base de datos de núcleo de datos en iOS 5 con 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]; 
    }]; 
} 

y luego copiar el archivo PersistentStore desde el directorio 'documentos' que se crea en el directorio del simulador a la sección de recursos en Xcode para la aplicación principal que usará la base de datos cargada.

Mi problema es que no puedo encontrar la manera de copiar el documento del paquete de la aplicación y usarlo como documento con éxito.

He intentado copiar el directorio de documentos tal como está del paquete de aplicaciones e intentar acceder a él como un documento que dio el error de que UIManagedDocument solo puede acceder a un paquete de archivos. He intentado crear otro documento nuevo en la aplicación principal y copiar el persistentStore del paquete sobre el que se creó en el documento con el mismo error. Y he intentado usar UIManagedDocument 's -(BOOL)loadFromContents:ofType:error: método .. Ni siquiera estoy seguro de que esto es lo que debería estar usando.

¿Alguien tiene una idea de cómo se hace normalmente? ¡Gracias!

Respuesta

9

No creo que deba perder el tiempo con los archivos y directorios usted mismo en iOS.

Sin embargo, puede abrir el documento directamente desde su paquete. Para eso, simplemente tiene que copiar todo el directorio de documentos que creó en su aplicación Loader en su paquete final. La estructura debería ser bastante simple, solo dos directorios con el archivo persistentStore dentro.

Después, cuando desee abrir su documento, debe ocuparse de dos cosas: necesita usar el directorio del paquete como el directorio base y debe agregar un / al final del nombre del "archivo" , por lo que UIManagedDocument sabe que el directorio es el documento. El código es el siguiente:

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

Tenga en cuenta que no puede de escritura a ese archivo, ya que no se permite la escritura dentro de su paquete de aplicaciones. Entonces, si desea tener un documento que se pueda escribir, debe copiar ese documento en la carpeta de documentos. Puede hacerlo fácilmente simplemente guardando doc a una ubicación diferente:

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

Una cosa más: Usted tiene que asegurarse de que la estructura de la carpeta se crea en su paquete de aplicación. La forma más fácil de hacerlo es arrastrar toda la carpeta a su proyecto y luego seleccionar "Crear referencias de carpeta para cualquier carpeta agregada". Para el "archivo" symbollist_en (que en realidad es un paquete/carpeta) debería verse así:
A folder reference in XCode
Si no lo hace, el "contenido" del documento residirá directamente en su paquete de aplicaciones, que no se puede abrir como UIManagedDocument, como descubrió.

4

La respuesta de Shezi ayudó mucho, pero como otros aquí: Preloaded Core Data Database in ios5 with UIManagedDocument y aquí: Pre load core data database coming up black with UIManagedDocument Tuve problemas.

En primer lugar, el comportamiento en el simulador es notablemente diferente del comportamiento en un dispositivo.Si instancia el UIManagedDocument utilizando initWithURL donde la URL apunta al paquete de la aplicación, recibirá una advertencia de que este es un directorio de solo lectura en la consola cuando se ejecuta en el dispositivo, pero tal advertencia no aparece en el simulador. El manejo de permisos parece ser bastante diferente y puede obtener resultados diferentes.

Los documentos sugieren que migratePersistentStore:toURL:options:withType:error: deben utilizarse en lugar de [doc saveToURL:newURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){}]

yo pasamos mucho tiempo tratando de conseguir que esto funcione, pero tenía un montón de problemas para conseguir un puntero al almacén persistente. A pesar de que mi aplicación funcionó bien para las operaciones de solo lectura después de seguir la solución de Shezi, el coordinador de la tienda persistente siguió dándome un puntero nulo para la tienda persistente. Esto sucedió cuando probé tanto – persistentStores (que devolvió una matriz vacía) como – persistentStoreForURL: Si alguien puede explicar por qué sucedió esto, estaría interesado. Lo molesto era que a veces funcionaría en el simulador, pero cuando probé en el dispositivo, falló.

Al final, cambié las cosas y copié la carpeta del paquete en el directorio de documentos primero, antes de crear una instancia del UIManagedDocument. Esto parece haber hecho el truco. Aquí está el código. Supone que su UIManagedDocument es una propiedad de la clase. Puse esto en el método viewWillAppear del controlador de vista inicial. Recuerde que debe abrir el documento si crea una instancia utilizando una URL que contiene una tienda persistente existente.

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) { 
    }]; 
} 

Por supuesto, lo anterior supone que ya ha generado la base de datos utilizando el simulador y copiado el directorio en el haz de aplicación exactamente de la manera descrita Shezi. Cualquier comentario o sugerencia sobre cómo mejorar el código es bienvenido. Todavía estoy aprendiendo aquí.

+0

Lo que estoy haciendo es crear el siguiente directorio (Documentos/AppDatabase/StoreContent) en el directorio de documentos y sólo afrontar el archivo en la carpeta PersistentStore StoreContent. Esto es trabajo para mí. ¿Crees que tendré algún problema? – tomidelucca

0

El método de shezi parece funcionar para mí, lo único que me gustaría añadir es "archivo" significa symbolist_en en este caso. Esto puede ser un poco confuso para los nuevos desarrolladores como yo (estaba poniendo persistentStore /).

+0

Gracias por señalar eso, he editado mi respuesta para reflejar esto. – shezi

0

La respuesta de Shezi ayudó mucho. Pero no funcionó como es. Solté el directorio del documento en xcode pero no se copió del paquete al directorio de Documentos. Luego me encontré con macbeb's question con respecto a la precarga. Probé su enfoque que involucraba solo incluir el archivo persistentStore en el paquete. Luego, crea el directorio de nombre de documento requerido en la carpeta de Documento y luego copia persistentStore a esa ruta.

Comprobar el código con el comentario "COPIA DE PAQUETE"

he utilizado clase estática para el manejo de documentos.

+(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); 
    } 
} 
Cuestiones relacionadas