performSelectorInBackground с несколькими парами
Как я могу вызвать метод с несколькими парами, как показано ниже, с performSelectorInBackground?
Примерный Метод:
-(void) reloadPage:(NSInteger)pageIndex firstCase:(BOOL)firstCase;
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; }
Обязательно очистите объект, когда это будет сделано, чтобы предотвратить утечку памяти