ВыполнитьSelectorInBackground с несколькими параметрами

Как я могу вызвать метод с несколькими параметрами, как показано ниже, с помощью функции performSelectorInBackground?

Пример метода:

-(void) reloadPage:(NSInteger)pageIndex firstCase:(BOOL)firstCase;

Ответы

Ответ 1

Проблема заключается в том, что performSelectorInBackground:withObject: принимает только один аргумент объекта. Один из способов обойти это ограничение - передать словарь (или массив) аргументов методу "обертку", который деконструирует аргументы и вызывает ваш фактический метод:

- (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...
}

Таким образом, вы передаете только один аргумент для вызова backgrounding, но этот метод может построить несколько аргументов, необходимых для реального вызова (который будет иметь место в том же фоновом потоке).

Ответ 2

Я только что нашел этот вопрос и не был доволен ни одним из ответов. По-моему, ни один из них не пользуется доступными инструментами, и, как правило, меня беспокоит передача произвольной информации в массивах и словарях.

Итак, я пошел и написал небольшую категорию NSObject, которая будет вызывать произвольный селектор с переменным числом аргументов:

Заголовок категории

@interface NSObject (NxAdditions)

-(void)performSelectorInBackground:(SEL)selector withObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION;

@end

Реализация категории

@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

Использование

-(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];
}

Ответ 3

Ну, я использовал это:

[self performSelectorInBackground:@selector(reloadPage:)
                       withObject:[NSArray arrayWithObjects:pageIndex,firstCase,nil] ];

для этого:

- (void) reloadPage: (NSArray *) args {
    NSString *pageIndex = [args objectAtIndex:0];    
    NSString *firstCase = [args objectAtIndex:1];    
}

Ответ 4

с помощью функции performSelectorInBackground вы можете передать только один аргумент, поэтому сделайте специальный объект для этого метода для хранения ваших данных, он будет более кратким, чем двусмысленный словарь или массив. Преимущество этого заключается в том, что вы можете передать один и тот же объект по завершении, содержащему несколько возвращаемых свойств.

#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

и передать этот объект вашему методу:

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;
}

Обязательно очистите объект, когда это сделано, чтобы предотвратить утечку памяти.