2010-07-13 9 views
15

Estoy intentando configurar mi aplicación para que en el primer inicio, una serie de archivos ubicados en la carpeta "Populator" en el paquete principal se copien en el directorio de documentos.iPhone (iOS): copiar archivos del paquete principal a la carpeta de documentos provoca crash

Mi aplicación actual es la siguiente:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 

    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
    NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Populator"]; 
    NSString *folderPath = [documentsDirectory stringByAppendingPathComponent:@"Files"]; 
    NSLog(@"Source Path: %@\n Documents Path: %@ \n Folder Path: %@", sourcePath, documentsDirectory, folderPath); 

    NSError *error; 

    [[NSFileManager defaultManager] copyItemAtPath:sourcePath 
             toPath:folderPath 
             error:&error]; 

    NSLog(@"Error description-%@ \n", [error localizedDescription]); 
    NSLog(@"Error reason-%@", [error localizedFailureReason]); 
    .... 
    return YES; 
} 

Sin embargo, esto se bloquea la primera vez que se ejecuta con los siguientes mensajes de la consola (pero los archivos se copian). La próxima vez que se abra la aplicación, no se bloqueará.

2010-07-13 15:14:26.418 AppName[5201:207] Source Path: /Users/jack/Library/Application Support/iPhone Simulator/3.2/Applications/1076C1FA-60B0-4AC7-8CD4-74F81472DAE6/AppName.app/Populator 
Documents Path: /Users/jack/Library/Application Support/iPhone Simulator/3.2/Applications/1076C1FA-60B0-4AC7-8CD4-74F81472DAE6/Documents 
Folder Path: /Users/jack/Library/Application Support/iPhone Simulator/3.2/Applications/1076C1FA-60B0-4AC7-8CD4-74F81472DAE6/Documents/Files 
2010-07-13 15:14:26.466 AppName[5201:207] *** +[AppNameAppDelegate localizedDescription]: unrecognized selector sent to class 0xa79c 
2010-07-13 15:14:26.475 AppName[5201:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[AppNameAppDelegate localizedDescription]: unrecognized selector sent to class 0xa79c' 
2010-07-13 15:14:26.495 AppName[5201:207] Stack: (
    40911435, 
    2569270537, 
    41183227, 
    40645910, 
    40642578, 
    9142, 
    2815466, 
    2819475, 
    2844680, 
    2826401, 
    2858055, 
    49271164, 
    40452156, 
    40448072, 
    2817668, 
    2850273, 
    8776, 
    8630 
) 

¿Alguien tiene alguna sugerencia en cuanto a lo que va mal? Ya tengo un código configurado para implementar la funcionalidad "solo en el primer inicio", pero no lo he incluido aquí para mayor claridad.

Gracias

Respuesta

4

No sé mucho acerca de la programación iPhone o C objetivo, pero por curiosidad, ¿cuál es el error en ese caso, si la operación de copia efectivamente su objetivo? ¿Podrían ser las líneas de registro las que se bloquean si no hubo ningún error?

[edit] Además, ¿puedes copiar todo el contenido de un subdirectorio como ese? (De nuevo, no estoy familiarizado con la API de iOS, solo estoy identificando posibles fuentes de error según lo que sé de otros lenguajes/API)

5

Acabo de leer mi código y encontré el problema. Como señala Sean Edwards arriba, no hay error si tiene éxito, de ahí el colapso.

Aquí está mi nuevo código para los interesados:

if([[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:folderPath error:&error]){ 
    NSLog(@"File successfully copied"); 
} else { 
    NSLog(@"Error description-%@ \n", [error localizedDescription]); 
    NSLog(@"Error reason-%@", [error localizedFailureReason]); 
} 
+0

Por alguna razón 'localizedDescription' no fue informativo para dejarme saber que el archivo ya existe (y no veo cómo está localizado, me está dando el inglés). Tuve que usar '[descripción del error]' (aún en inglés). – huggie

15
NSError *error; 

Usted está declarando una variable local sin inicializarla. Por lo tanto, estará lleno de basura.

[[NSFileManager defaultManager] copyItemAtPath:sourcePath 
             toPath:folderPath 
             error:&error]; 

Si no se produce ningún error en esta línea, el estado de la basura error seguiría siendo.

NSLog(@"Error description-%@ \n", [error localizedDescription]); 

Ahora envía un mensaje a una ubicación aleatoria no inicializada. Esta es la fuente del choque.


Para evitar esto, inicializar error-nil.

NSError* error = nil; 
//    ^^^^^ 

O imprimir el error sólo cuando -copyItemAtPath:… no devuelve nada (en el que el error se rellena correctamente).

if (![[NSFileManager defaultManager] copyItemAtPath:sourcePath ...]) { 
    NSLog(...); 
} 
+1

Esto está mal. Las API de Apple no prometen dejar intactos los parámetros de error en caso de que no haya ningún error, podría ser basura. Como han mencionado otros carteles, la forma correcta es ignorar el parámetro de error si se devuelve el éxito. –

+0

Kenny, si ocurre un error, el error apuntará al objeto de error recientemente asignado. Este es un parámetro de salida. La dirección (!) Al puntero se le da al método. El error no debe ser inicializado. Ver el manejo de errores en la documentación de Apple. – MacMark

2

Se registrará un error antes de saber que hay un error

poner el código en un bloque if

if(error) 
{ 
NSLog(@"Error description-%@ \n", [error localizedDescription]); 
NSLog(@"Error reason-%@", [error localizedFailureReason]); 
} 

para describir su problema con más detalle: el puntero de error apunta a DONDEQUIERA y ese objeto no reconoce ese mensaje.Por lo tanto se obtiene una excepción

1

Como práctica general de programación, siempre es mejor para inicializar las variables con un valor por defecto:

NSError *error = nil; 

En Objective-C, que es válida para enviar un mensaje a nil. Entonces, en su caso, la variable de error no causaría un bloqueo si se inicializara al nil.

Para obtener más información sobre la verificación de la sección Sending Messages to nil tema en https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html

4

debe comprobar si el archivo ya existe! Luego copia

+ (BOOL) getFileExistence: (NSString *) filename 
{ 
    BOOL IsFileExists = NO; 

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDir = [documentPaths objectAtIndex:0]; 
    NSString *favsFilePath = [documentsDir stringByAppendingPathComponent:filename]; 

    NSFileManager *fileManager = [NSFileManager defaultManager]; 

    // Check if the database has already been created in the users filesystem 
    if ([fileManager fileExistsAtPath:favsFilePath]) 
    { 
     IsFileExists = YES; 
    } 
    return IsFileExists; 
} 

+ (NSString *)dataFilePath:(NSString *)filename { 

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *docDirectory = [paths objectAtIndex:0]; 
    return [docDirectory stringByAppendingPathComponent:filename]; 
} 

- (void)copyFileToLocal:(NSString *)filename 
{ 

    if (![AppDelegate getFileExistence:filename]) 
    { 
     NSError *error; 
     NSString *file = [[NSBundle mainBundle] pathForResource:filename ofType:nil]; 

     if (file) 
     { 
      if([[NSFileManager defaultManager] copyItemAtPath:file toPath:[AppDelegate dataFilePath:filename] error:&error]){ 
       NSLog(@"File successfully copied"); 
      } else { 

       [[[UIAlertView alloc]initWithTitle:NSLocalizedString(@"error", nil) message: NSLocalizedString(@"failedcopydb", nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", nil) otherButtonTitles:nil] show]; 
       NSLog(@"Error description-%@ \n", [error localizedDescription]); 
       NSLog(@"Error reason-%@", [error localizedFailureReason]); 
      } 
      file = nil; 
     } 
    } 
} 

NSLocalizedString son cadenas de localización de la aplicación.

Cuestiones relacionadas