2011-03-14 60 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; 
} 

確保清理對象做是爲了防止內存泄漏