2011-03-14 93 views

回答

37

的问题是,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... 
}

这样,你只传递一个“单一“的背景调用的参数,但该方法可以构建真正调用所需的多个参数(这将发生在同一个背景线上)。

+1

通过使用NSInvocation的类和可变参数列表中的一个可以写的时候一个非常优雅的通用包装类..也许下一次我需要写另一个包装我会试一试! – hariseldon78 2012-03-26 16:23:31

+0

@ hariseldon78 +1你激励我写这样的东西,看看我的答案。 – 2013-08-31 19:25:20

+1

这几天你应该真的使用dispatch_async(...)来做这样的事情,而不是-performSelectorInBackground:... – 2014-06-20 21:26:11

5

好了,我已经使用这个:

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

此:

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

这将泄漏一个'NSArray'。你应该使用'[NSArray arrayWithObjects:...]'而不是'[[NSArray alloc] initWithObjects:...]'。 – respectTheCode 2013-04-29 15:28:45

+0

感谢respectTheCode,我很懒,所以我总是使用autorelease。不管怎么说,多谢拉。 – 2013-04-29 19:46:33

+0

这似乎不工作,除非我正在执行的选择器正在期待一个数组。否则它的东西选择器中的第一个参数应该是数组。 – Will 2013-08-23 20:36:22

6

我只是发现了这个问题,并没有高兴与任何答案。在我看来,既没有充分利用现有的工具,也没有在数组和字典中传递任意信息,这通常令我感到担忧。

于是,我又写了一个小NSObject的类别,将与参数个数可变调用任意选择:

Category接头

@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]; 
} 
+0

这是解决问题最优雅的解决方案。 – 2013-11-16 15:42:55

0

与performSelectorInBackground你只能传递一个参数,所以使自定义对象的这个方法来保存数据,ITLL比暧昧字典或数组更加简洁。这样做的好处是,当包含多个返回属性时,您可以传递相同的对象。

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

确保清理对象做是为了防止内存泄漏