performSelectorInBackground с несколькими парами


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

Примерный Метод:

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

4 ответа:

Проблема в том, что 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...
}

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

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

Итак, я пошел и написал небольшую категорию 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];
}

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

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

Для этого:

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

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

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