iOS inicia hilo de fondo

117

Tengo un pequeño sqlitedb en mi dispositivo iOS. Cuando un usuario presiona un botón, obtengo los datos de sqlite y se los muestro al usuario.

Esta parte de búsqueda la quiero hacer en un hilo de fondo (para no bloquear el hilo principal de la interfaz de usuario). Hago esto así -

[self performSelectorInBackground:@selector(getResultSetFromDB:) withObject:docids];

Después de la búsqueda y un poco de procesamiento, necesito actualizar la interfaz de usuario. Pero dado que (como buena práctica) no deberíamos realizar la actualización de la interfaz de usuario desde subprocesos en segundo plano. Llamo selectora mainthread así -

[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];

Pero mi aplicación falla en el primer paso. es decir, iniciar un hilo de fondo. ¿No es esta una forma de iniciar subprocesos en segundo plano en iOS?

ACTUALIZACIÓN 1: Después de [self performSelectorInBackground....obtener este stacktrace, no hay información en absoluto -

ingrese la descripción de la imagen aquí

ACTUALIZACIÓN 2: Incluso lo intenté, comenzando un hilo de fondo como ese, [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];pero aún obtengo el mismo seguimiento de pila.

Solo para aclarar, cuando realizo esta operación en el hilo principal, todo funciona sin problemas ...

ACTUALIZACIÓN 3 Este es el método que estoy tratando de ejecutar desde el fondo

- (void)getResultSetFromDB:(NSMutableArray *)toProceessDocids
{
    SpotMain *mirror = [[SpotMain alloc] init];
    NSMutableArray *filteredDocids = toProceessDocids;

    if(![gMediaBucket isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForMediaBucketWithDocID:filteredDocids mBucket:gMediaBucket numRes:-1];
    if(![gMediaType isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForMediaType:filteredDocids mediaType:gMediaType numRes:-1];
    if(![gPlatform isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForPlatformID:filteredDocids platformId:@"1" numRes:-1];

    self.resultSet = [mirror FetchObjectFromDocid:filteredDocids];
    [filteredDocids release];
    [mirror release];

    [self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];
    return;
}
Srikar Appalaraju
fuente
¿Qué registro de errores / fallas obtienes?
jtbandes
Por favor, vea mis actualizaciones ...
Srikar Appalaraju
¿Puede mostrar el método al que está llamando en segundo plano? Y asegúrese de que el objeto docidsse conserve.
Rog
sí, lo docidsson retain. Lo he puesto .hcomo@property (nonatomic, retain) NSMutableArray *docids;
Srikar Appalaraju
No prefija los métodos con get; eso debería serresultSetFromDB:
bbum

Respuestas:

270

Si utiliza performSelectorInBackground:withObject:para generar un nuevo hilo, entonces el selector realizado es responsable de configurar el grupo de liberación automática del nuevo hilo, el ciclo de ejecución y otros detalles de configuración - consulte "Uso de NSObject para generar un hilo" en la Guía de programación de subprocesos de Apple .

Sin embargo, probablemente sería mejor usar Grand Central Dispatch :

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self getResultSetFromDB:docids];
});

GCD es una tecnología más nueva y es más eficiente en términos de sobrecarga de memoria y líneas de código.


Se actualizó con un toque de sombrero a Chris Nolet , quien sugirió un cambio que simplifica el código anterior y se mantiene al día con los últimos ejemplos de código GCD de Apple.

Scott Forbes
fuente
¡frio! no sabía esto. ¿Esto se aplica [NSThread detachNewThreadSelector:@selector....también a?
Srikar Appalaraju
Si. Según los documentos de Apple, llamar performSelectorInBackground:withObject:"es lo mismo que si llamaras al detachNewThreadSelector:toTarget:withObject:método de NSThreadcon el objeto actual, el selector y el objeto de parámetro como parámetros".
Scott Forbes
¿Hay alguna diferencia entre (unsigned long)NULLy 0en este asunto?
Sti
4
@Sti de Apple Dev Docs : Nota: El segundo argumento de la función dispatch_get_global_queue está reservado para una futura expansión. Por ahora, siempre debe pasar 0 para este argumento.
Jawad Al Shaikh,
¿Debería usar performSelectorOnMainThread para actualizar la IU con los resultados de la operación o hay una forma más consistente de actualizar la IU con GCD?
Ilya Denisov
9

Bueno, eso es bastante fácil en realidad con GCD. Un flujo de trabajo típico sería algo como esto:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_async(queue, ^{
        // Perform async operation
        // Call your method/function here
        // Example:
        // NSString *result = [anObject calculateSomething];
                dispatch_sync(dispatch_get_main_queue(), ^{
                    // Update UI
                    // Example:
                    // self.myLabel.text = result;
                });
    });

Para obtener más información sobre GCD, puede consultar la documentación de Apple aquí.

Pawan Ahire
fuente
4

Habilite NSZombieEnabled para saber qué objeto se libera y luego se accede. Luego verifique si getResultSetFromDB:tiene algo que ver con eso. También verifique si docidstiene algo adentro y si está retenido.

De esta forma, puede estar seguro de que no hay ningún problema.

Nicolas S
fuente
Copie la línea que utilizó que se ejecuta sin problemas en el hilo principal.
Nicolas S
Utilizo esto desde el hilo principal y al menos golpea ese método en lugar de estrellarse abruptamente[self getResultSetFromDB:docids];
Srikar Appalaraju
¿Has habilitado lo que te dije?
Nicolas S
Ponga un punto de interrupción en esta línea: SpotMain * mirror = [[SpotMain alloc] init]; y dime si está golpeado y, si es así, qué línea se bloquea. Habilite a los zombis para que podamos obtener un registro de errores claro.
Nicolas S
sí, he habilitado zombies. Recibo esto - `2011-08-14 12: 49: 42.697 FLO [16211: 707] *** - [FMResultSet release]: mensaje enviado a la instancia desasignada 0x2bff80 2011-08-14 12: 49: 42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool (): Objeto 0x2c0cc0 de la clase __NSCFData liberado automáticamente sin un grupo en su lugar - solo se filtra . Also when I try to call this method from background thread I do not reach SpotMain * espejo ... `, Se bloquea poco después de ingresar al hilo de fondo ...
Srikar Appalaraju
2

La biblioteca sqlite predeterminada que viene con iOS no se compila con la macro SQLITE_THREADSAFE en. Esta podría ser una razón por la que su código falla.

Mugunth
fuente
2

Respuesta rápida 2.x:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
Crashalot
fuente