2010-03-13 8 views
7

Uno de los marcos de informes de fallos que he encontrado lo hace así: si existen informes de fallos en la carpeta ~/Library/Logs/CrashReporter para la aplicación, se determina que se produjo un bloqueo antes. Luego permite al usuario enviar al desarrollador el registro de bloqueo. Y finalmente, borra esos registros.Cómo determinar, al iniciar, si la aplicación se bloqueó la última vez que se cerró?

Es esta eliminación lo que me molesta. No es aceptable para mi Quizás el usuario quiera mirar esos registros más tarde. Es simplemente grosero para el usuario simplemente eliminar sus registros de fallos.

Así que estoy buscando una mejor manera de determinar el colapso.

Realmente no funciona para almacenar los últimos registros de fallos de lectura en los valores predeterminados del usuario o los datos del usuario, porque eso significaría que si el usuario elimina los datos y los valores predeterminados (que tiene derecho a hacer cuando él o ella desea), y luego lanza la aplicación, se detectará como bloqueada la última vez que se cerró. Entonces esto no funciona.

¿Alguna idea?

Respuesta

2

Escribe en un archivo cada vez que salgas. Lea ese archivo cada vez que abra el programa. Escriba un número entero específico en el archivo cada vez que salga el programa y que se lea cada vez que se inicie el programa.

Por ejemplo, si se escribe un 0 en un archivo que puede significar que no se bloquea. Cualquier otra cosa significa un bloqueo.

+1

Hmm? ¿Y dónde escribiría este archivo? ¿Estás seguro de que se envía la aplicación WillQuit o los métodos de notificación antes de que * se bloquee *? Y aunque lo hiciera, ¿alguno de estos métodos de QQue realmente tiene un parámetro que dice que la aplicación se está bloqueando o no se está bloqueando? – Enchilada

+1

Oooh, creo que te entiendo. Quiere decir simplemente poner un SuccessfulQuit en los valores predeterminados del usuario, que siempre se establece en 1 al salir exitosamente, es 0 de manera predeterminada, y se establece en -1 una vez que la aplicación termina de iniciarse. Y luego, si en realidad es -1 cuando lo lanzo, significa que debí haber fallado. ¿Algo como eso? – Enchilada

+0

Sí, y leer/escribir el archivo en una ubicación depende de usted. –

0

Esta es una publicación anterior, pero estaba buscando una buena forma de hacerlo y no me encontré con ninguna.

Tal vez esto ayude a alguien en una situación similar ..

que estoy haciendo esto en Windows, pero tal vez también es posible en OSX/Linux a través de los mutex pthread nombrados, aunque no sé la política de cómo se manejan dichos mutexes si se termina una aplicación, que es fundamental para esta técnica.

El problema de usar una sola bandera es que no funciona en la situación en la que puede haber múltiples instancias de la aplicación:

  • App 1 ejecuta. Establece el indicador 'no se ha apagado correctamente'.
  • Aplicación 2 carreras. Ve que no se ha cerrado porque la bandera está configurada y cree que hubo un bloqueo cuando no la había.

Esto es un poco difícil de conseguir alrededor y probablemente hay varias formas de hacer esto, pero este método parece funcionar bien hasta ahora (en Windows, por lo menos):

Crea un mutex llamado global con una GUID/UUID recién generado como nombre.
El GUID es diferente para cada instancia de la aplicación, por lo que cada uno tendrá un único mutex con nombre. El GUID se escribe en un archivo que contiene una lista de GUID. Si la aplicación se cierra correctamente, se elimina el GUID del archivo y se cierra el mutex. Si la aplicación falla o finaliza, el GUID no se elimina del archivo PERO el mutex es destruido por el SO sin que la aplicación tenga que hacerlo.

Al iniciar la aplicación, puede ejecutar los GUID en la lista y llamar a OpenMutex y mutexes que no existen (GetLastError devuelve ERROR_FILE_NOT_FOUND).Cualquier exclusión mutua no existente indica que se produjo un bloqueo/terminación. Todos los GUID que tienen esta propiedad se pueden eliminar de la lista en este momento.

Una cosa adicional que puede hacer es eliminar GUID incorrectos de la lista cuando se apaga correctamente. esto se pone alrededor de la siguiente situación:

  • Aplicación 1 comienza
  • App 2 comienza
  • ! 1 accidentes
  • App 2 está cerrado correctamente
  • Aplicación 3 se ha iniciado.

Cuando se inicia la aplicación 3, no se debe publicar que hubo un bloqueo, porque el último apagado fue correcto.

También implementé un tipo de spinlock para obtener acceso al archivo que contiene los GUID que continuarán después de un período de tiempo de espera y no agregue el guid de la aplicación al archivo. En tales casos, probablemente sea mejor dejar que la aplicación se ejecute de todos modos y perder la detección de bloqueo, en lugar de no ejecutar la aplicación en absoluto.

Otras advertencias son aferrarse al bloqueo de archivos al consultar y actualizar el archivo para evitar condiciones de carrera. En Windows, esto evita el uso de stl filestreams, ya que tendrá que truncar el archivo después de leerlo mientras mantiene el acceso exclusivo al archivo.

1

Lo resuelto de esta manera (el registro se debe acceder para cada lanzamiento de aplicaciones sin embargo):

@implementation ICNRegistry 

/** 
* @public 
* @date edited 2014-04-28 
*/ 
+ (ICNRegistry*) registry { 

    static ICNRegistry* registrySingleton = nil; 

    @synchronized(self) { 

     if (!registrySingleton) { 

      registrySingleton = [[ICNRegistry alloc] initPrivate]; 
     } 

     return registrySingleton; 
    } 
} 

#pragma mark - 
#pragma mark Initialization 

/** 
* @private 
* @date edited 2014-05-09 
*/ 
- (id) initPrivate { 

    self = [super init]; 

    if (self) { 

     _appQuitSuccessfulIndicatorFilePath = 
     [[self cacheRootForClass:[self class]] stringByAppendingPathComponent: 
     @"didQuitSuccessfullyIndicator"]; 
      // (implementation of cacheRootForClass not included) 

     // Set _lastAppQuitWasSuccessful: 
     [self readPreviousAppSuccessStatusAndStartMonitoringCurrentLaunchQuit]; 

     // Start monitoring app quit: 
     [[NSNotificationCenter defaultCenter] addObserver:self selector: 
     @selector(registerAppWillQuitSuccessfully) name: 
     UIApplicationWillTerminateNotification object:nil]; 
    } 

    return self; 
} 

#pragma mark - 
#pragma mark Monitoring App Quits 

/** 
* @private 
* Checks if a file exists at a specific location. If the file exists, then 
* last app quit was successful and lastAppQuitWasSuccessful will be set to YES. 
* Otherwise, if the file does not exist, lastAppQuitWasSuccessful will be set 
* to NO. 
* 
* @discussion 
* When app quits in a normal way, a file will be created on app termination, that 
* way indicating successful quit. If the app quits unexpectedly, then the file 
* will not be written and thus the quit will be indicated as not being successful. 
* 
* @since 2014-05-09 
* @date edited 2014-05-09 
*/ 
- (void) readPreviousAppSuccessStatusAndStartMonitoringCurrentLaunchQuit { 

    NSFileManager* fm = [NSFileManager defaultManager]; 

    self.lastAppQuitWasSuccessful = NO; 

    if ([fm fileExistsAtPath:self.appQuitSuccessfulIndicatorFilePath]) { 

     self.lastAppQuitWasSuccessful = YES; 

     NSError* error; 
     [fm removeItemAtPath:self.appQuitSuccessfulIndicatorFilePath error:&error]; 

     if (error) { 

      ICN_WARN(@"failed to delete 'app quit successful' indicator file at " 
        @"path %@; %@", self.appQuitSuccessfulIndicatorFilePath, 
        error.localizedDescription); 
     } 
    } 
} 

/** 
* @private 
* @since 2014-05-09 
* @date edited 2014-05-09 
*/ 
- (void) registerAppWillQuitSuccessfully { 

    NSFileManager* fm = [NSFileManager defaultManager]; 

    // Create file path if not present: 
    NSError* error; 
    NSString* dir = [self.appQuitSuccessfulIndicatorFilePath 
        stringByDeletingLastPathComponent]; 
    [fm createDirectoryAtPath:dir withIntermediateDirectories:YES 
        attributes:nil error:&error]; 

    if (error) { 

     ICN_WARN(@"failed to create dir %@; %@", dir, error.localizedDescription); 
     return; 
    } 

    [fm createFileAtPath:self.appQuitSuccessfulIndicatorFilePath 
       contents:nil attributes:nil]; 
} 

#pragma mark - 

@end 

Entonces, por ejemplo, en mi aplicación delegado hago algo como esto:

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

    // If app did quit unexpectedly (due to crash, reset, etc) last time it was 
    // used, then clear all cache to avoid inconsistencies 
    if (![[ICNRegistry registry] lastAppQuitWasSuccessful]) { 

     [ICNUIViewImageCache clearCache]; 
    } 
} 

Debe tenerse en cuenta que con esta solución, la PRIMERA vez que se inicia la aplicación se detectará como si hubiera fallado antes. Si esto es un problema, entonces el indicador de archivo podría crearse la primera vez que se inicie la aplicación.

Cuestiones relacionadas