onprogressupdate - onpreexecute method in android
iOS/Objective-C equivalente de AsyncTask de Android (4)
Estoy familiarizado con el uso de AsyncTask
en Android: crea una subclase, execute
call en una instancia de la subclase y onPostExecute
se onPostExecute
en el subproceso de la interfaz de usuario o en el subproceso principal. ¿Cuál es el equivalente en iOS?
Swift 3
En Android, cuando quería ejecutar una tarea en un hilo de fondo y luego actualizar la UI cuando terminaba, usaba AsyncTask
( example ). Ahora cuando estoy haciendo versiones de iOS de mis aplicaciones, utilizo Grand Central Dispatch (GCD) para hacer lo mismo. Así es como se hace con Swift:
DispatchQueue.global(qos: .background).async {
// code to be run on a background task
DispatchQueue.main.async {
// code to be run on the main thread after the background task is finished
}
}
Notas
Respuesta a la pregunta original:
Grand Central Dispatch (GCD) ofrece un mecanismo para realizar tareas en segundo plano, aunque funciona de una manera estructuralmente diferente que AsyncTask. Para realizar algo de manera asincrónica, solo necesita crear una cola (como un hilo) y luego pasar un bloque a dispatch_async()
para que se realice en segundo plano. Lo encuentro más ordenado que AsyncTask, ya que no hay subclases involucrados; es más o menos plug-and-play donde quiera que tenga código que le gustaría ejecutar en segundo plano. Un ejemplo:
dispatch_queue_t queue = dispatch_queue_create("com.yourdomain.yourappname", NULL);
dispatch_async(queue, ^{
//code to be executed in the background
});
Otros puntos:
1) Retrollamadas
Si desea realizar una tarea en segundo plano y actualizar la interfaz de usuario (o hacer algo en otro hilo) cuando la tarea en segundo plano está terminada, simplemente puede anidar las llamadas de despacho:
dispatch_queue_t queue = dispatch_queue_create("com.yourdomain.yourappname", NULL);
dispatch_async(queue, ^{
//code to be executed in the background
dispatch_async(dispatch_get_main_queue(), ^{
//code to be executed on the main thread when background task is finished
});
});
2) Colas globales
Al crear una cola, también puede usar la función dispatch_get_global_queue()
para obtener una cola de despacho global con una cierta prioridad (como DISPATCH_QUEUE_PRIORITY_HIGH
). Estas colas son accesibles universalmente y son útiles cuando desea asignar múltiples tareas al mismo hilo / cola. Tenga en cuenta que iOS administra la memoria por completo.
3) Memoria
A veces existe cierta confusión con respecto a la administración de memoria y las colas de envío porque tienen sus propias funciones dispatch_retain
/ dispatch_release
. Sin embargo, puede estar seguro de que ARC los trata como objetos Objective-C, por lo que no debe preocuparse por llamar a estas funciones. Al hacer referencia a la gran respuesta de Rob Mayoff con respecto a GCD y ARC, puede ver la documentación que describe la equivalencia de las colas de GCD con los objetos de Objective-C:
* By default, libSystem objects such as GCD and XPC objects are declared as
* Objective-C types when building with an Objective-C compiler. This allows
* them to participate in ARC, in RR management by the Blocks runtime and in
* leaks checking by the static analyzer, and enables them to be added to Cocoa
* collections.
*
* NOTE: this requires explicit cancellation of dispatch sources and xpc
* connections whose handler blocks capture the source/connection object,
* resp. ensuring that such captures do not form retain cycles (e.g. by
* declaring the source as __weak).
*
* To opt-out of this default behavior, add -DOS_OBJECT_USE_OBJC=0 to your
* compiler flags.
*
* This mode requires a platform with the modern Objective-C runtime, the
* Objective-C GC compiler option to be disabled, and at least a Mac OS X 10.8
* or iOS 6.0 deployment target.
4) Tareas / Bloques múltiples
Añadiré que GCD tiene una interfaz de agrupación que admite la sincronización de múltiples bloques asíncronos si una tarea no puede continuar hasta que se completen varias actividades asincrónicas. Jörn Eyrich y ɲeuroburɳ ofrecen una explicación generosa de este tema here . Si necesita esta funcionalidad, le recomiendo tomarse unos minutos para leer atentamente sus dos respuestas y comprender las diferencias entre ellas.
La documentation tiene una gran cantidad de información sobre el tema si así lo desea.
No hay clases para eso en iOS pero puedes simularlo usando colas. Puedes llamar:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Your code to execute in background...
});
para tareas asincrónicas y dentro de su código asíncrono llame a la próxima cola para hacer algo en la vista ...:
dispatch_async(dispatch_get_main_queue(), ^{
//Your code to execute on UIthread (main thread)
});
Luego, usando estas dos colas puede crear una clase asyncTask, agregue esta clase a su proyecto para implementarlas:
//
// AsyncTask.h
//
// Created by Mansour Boutarbouch Mhaimeur on 25/10/13.
//
#import <Foundation/Foundation.h>
@interface AsyncTask : NSObject
- (void) executeParameters: (NSArray *) params;
- (void) preExecute;
- (NSInteger) doInBackground: (NSArray *) parameters;
- (void) postExecute: (NSInteger) result;
@end
//
// AsyncTask.m
//
// Created by Mansour Boutarbouch Mhaimeur on 25/10/13.
//
#import "AsyncTask.h"
@implementation AsyncTask
- (void) executeParameters: (NSArray *) params{
[self preExecute];
__block NSInteger result;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
result = [self doInBackground:params];
dispatch_async(dispatch_get_main_queue(), ^{
[self postExecute:result];
});
});
}
- (void) preExecute{
//Method to override
//Run on main thread (UIThread)
}
- (NSInteger) doInBackground: (NSArray *) parameters{
//Method to override
//Run on async thread (Background)
return 0;
}
- (void) postExecute: (NSInteger) result{
//Method to override
//Run on main thread (UIThread)
}
@end
Este es un ejemplo que estoy usando en un proyecto:
#import "AsyncTask.h"
#import "Chat.h"
@interface SendChatTask : AsyncTask{
NSArray * chatsNotSent;
}
@end
#import "SendChatTask.h"
@implementation SendChatTask
- (void) preExecute{
//Method to override
}
- (NSInteger) doInBackground: (NSArray *) parameters{
//Method to override
NSString *sendChatsURL = [NSString stringWithFormat:@"%@%@%@",HOST, NAMESPACE,URL_SEND_CHAT];
chatsNotSent = [parameters objectAtIndex:0];
NSString *response;
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
//...
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[ChatJSONParser wrapChatArray: chatsNotSent] options:0 error:&error];
NSString *JSONString = [[NSString alloc] initWithBytes:[jsonData bytes] length:[jsonData length] encoding:NSUTF8StringEncoding];
[params setObject:JSONString forKey:@"chats"];
response = [HTTPClient executePOST:sendChatsURL parameters:params];
if([respuesta isEqualToString:@"true"]){
return 1;
}else{
return -1;
}
}
- (void) postExecute: (NSInteger) result{
//Method to override
if (result == 1) {
for (Chat *chat in chatsNotSent) {
chat.state = STATE_NOT_SENT;
[chat save];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate refreshChat];
}
} else {
}
}
@end
Y la siguiente llamada:
[[[SendChatTask alloc] init] executeParameters:[NSArray arrayWithObjects: chatsNotSent, nil]];
Puede agregar un método de actualización publishProgress()
y respectivo ... No lo uso por el momento porque llamo a mi tarea asincrónica en servicios en segundo plano.
Espero que sea útil.
si su orientación es la versión anterior de iOS (que iOS 4 para Grand Central Dispatch) puede usar los métodos NSObject performSelector
Ejecutar en el subproceso de fondo performSelectorInBackground:withObject:
Y ejecute en MainThread performSelectorOnMainThread:withObject:waitUntilDone:
Esto es un ejemplo:
[self performSelectorInBackground:@selector(executeInBackground) withObject:nil];
-(void) executeInBackground
{
NSLog(@"executeInBackground");
[self performSelectorOnMainThread:@selector(executeOnMainThread) withObject:nil waitUntilDone:NO];
}
-(void) executeOnMainThread
{
NSLog(@"executeOnMainThread");
}