¿Cómo puedo llamar a un método con múltiples params como a continuación con performSelectorInBackground?performSelectorInBackground con múltiples parametros
método de la muestra:
-(void) reloadPage:(NSInteger)pageIndex firstCase:(BOOL)firstCase;
¿Cómo puedo llamar a un método con múltiples params como a continuación con performSelectorInBackground?performSelectorInBackground con múltiples parametros
método de la muestra:
-(void) reloadPage:(NSInteger)pageIndex firstCase:(BOOL)firstCase;
El problema es que performSelectorInBackground:withObject:
toma sólo un argumento objeto. Una forma de superar esta limitación es pasar un diccionario (o matriz) de argumentos a un método de "contenedor" que deconstruye los argumentos y llama a su método actual:
- (void)callingMethod {
NSDictionary * args = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInteger:pageIndex], @"pageIndex",
[NSNumber numberWithBool:firstCase], @"firstCase",
nil];
[self performSelectorInBackground:@selector(reloadPageWrapper:)
withObject:args];
}
- (void)reloadPageWrapper:(NSDictionary *)args {
[self reloadPage:[[args objectForKey:@"pageIndex"] integerValue]
firstCase:[[args objectForKey:@"firstCase"] boolValue]];
}
- (void)reloadPage:(NSInteger)pageIndex firstCase:(BOOL)firstCase {
// Your code here...
}
De esta manera sólo estás pasando un " único "argumento para la llamada de fondo, pero ese método puede construir los múltiples argumentos que necesita para la llamada real (que tendrá lugar en el mismo hilo de fondo).
Bueno, he utilizado este:
[self performSelectorInBackground:@selector(reloadPage:)
withObject:[NSArray arrayWithObjects:pageIndex,firstCase,nil] ];
para esto:
- (void) reloadPage: (NSArray *) args {
NSString *pageIndex = [args objectAtIndex:0];
NSString *firstCase = [args objectAtIndex:1];
}
Esto tendrá un 'NSArray'. Debería usar '[NSArray arrayWithObjects: ...]' en lugar de '[[NSArray alloc] initWithObjects: ...]'. – respectTheCode
Gracias respetoTheCode, soy flojo, así que siempre uso autorelease.Gracias de todos modos. –
Esto no parece funcionar a menos que el selector que estoy realizando esté esperando una matriz. De lo contrario, el primer parámetro en el selector debería ser la matriz. – Will
Acabo de encontrar esta pregunta y no estaba contento con cualquiera de las respuestas. En mi opinión, ni hacer un buen uso de las herramientas disponibles, y pasar información arbitraria en matrices y diccionarios generalmente me preocupa.
Así que fui y escribí una pequeña NSObject
categoría que invocará un selector arbitraria con un número variable de argumentos:
Cabecera de Categoría
@interface NSObject (NxAdditions)
-(void)performSelectorInBackground:(SEL)selector withObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION;
@end
Categoría Implementación
@implementation NSObject (NxAdditions)
-(void)performSelectorInBackground:(SEL)selector withObjects:(id)object, ...
{
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
// Setup the invocation
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = selector;
// Associate the arguments
va_list objects;
va_start(objects, object);
unsigned int objectCounter = 2;
for (id obj = object; obj != nil; obj = va_arg(objects, id))
{
[invocation setArgument:&obj atIndex:objectCounter++];
}
va_end(objects);
// Make sure to invoke on a background queue
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithInvocation:invocation];
NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init];
[backgroundQueue addOperation:operation];
}
@end
Uso
-(void)backgroundMethodWithAString:(NSString *)someString array:(NSArray *)array andDictionary:(NSDictionary *)dict
{
NSLog(@"String: %@", someString);
NSLog(@"Array: %@", array);
NSLog(@"Dict: %@", dict);
}
-(void)someOtherMethod
{
NSString *str = @"Hello world";
NSArray *arr = @[@(1337), @(42)];
NSDictionary *dict = @{@"site" : @"Stack Overflow",
@"url" : [NSURL URLWithString:@"http://stackoverflow.com"]};
[self performSelectorInBackground:@selector(backgroundMethodWithAString:array:andDictionary:)
withObjects:str, arr, dict, nil];
}
Esta es la solución más elegante al problema. –
con performSelectorInBackground sólo se puede pasar un argumento, así que un objeto personalizado para este método para almacenar los datos, itll ser más conciso que un diccionario ambigua o matriz. El beneficio de esto es que puede pasar el mismo objeto cuando está hecho y contiene varias propiedades de devolución.
#import <Foundation/Foundation.h>
@interface ObjectToPassToMethod : NSObject
@property (nonatomic, strong) NSString *inputValue1;
@property (nonatomic, strong) NSArray *inputArray;
@property (nonatomic) NSInteger returnValue1;
@property (nonatomic) NSInteger returnValue2;
@end
y pasar ese objeto a su método:
ObjectToPassToMethod *obj = [[ObjectToPassToMethod alloc] init];
obj.inputArray = @[];
obj.inputValue1 = @"value";
[self performSelectorInBackground:@selector(backgroundMethod:) withObject:obj];
-(void)backgroundMethod:(ObjectToPassToMethod*)obj
{
obj.returnValue1 = 3;
obj.returnValue2 = 90;
}
asegúrese de limpiar el objeto cuando se hace para evitar pérdidas de memoria
Mediante el uso de la lista de clase NSInvocation y argumentos variables se podría escribir una clase de envoltura genérica muy elegante ... ¡Tal vez la próxima vez que necesite escribir otro envoltorio lo pruebe! – hariseldon78
@ hariseldon78 +1 me inspiró para escribir tal cosa, mira mi respuesta. –
En estos días realmente debería usar dispatch_async (...) para hacer algo como esto, en lugar de -performSelectorInBackground: ... –