2013-02-21 93 views
1

是否可以將完全形成的塊(包含其所有參數的塊)傳遞給方法,然後在該方法中執行該塊?將塊作爲參數傳遞

目前,我有這樣的結構在我的項目重複:

if (//block exists) 
     { 
      if (self.returnOnMainThread) 
      { 
       dispatch_async(dispatch_get_main_queue(),^
           { 
            //call block here 
           }); 
      } 
      else 
      { 
       //call block here 
      } 
     } 

不過最好我喜歡想抽象上面的代碼悶響伸到類似的方法:

- (void) reportSuccessWithBlock:(GenericBlockType)block{ 
     if (block) 
     { 
      if (self.returnOnMainThread) 
      { 
       dispatch_async(dispatch_get_main_queue(),^
           { 
            block; 
           }); 
      } 
      else 
      { 
       block; 
      } 
     } 

} 

編輯:

塊的類型不會事先知道。

所以呼叫路徑可能看起來像這樣

- (void) someMethod:(void (^)(NSArray *array))success 
{ 
//Some code here setting up the array to be passed back 

    [self reportSuccessWithBlock:success(array)]; 

} 

有在上面的代碼中的一些假設(我不知道是可能的):

  1. 方法可以接受普通塊類型
  2. 可以傳遞所有參數但不實際執行的塊
+1

當你說「塊本身可以包含許多不同的變量」,你的意思是塊可以接受的參數不同數目? – trojanfoe 2013-02-21 15:16:59

+0

@trojanfoe我的意思是這種方法應該能夠接受具有不同簽名的塊,例如(void(^)(NSArray * array))成功或(無效(^)(NSDictionary *字典,NSUInteger值))成功 – williamb 2013-02-21 15:21:16

+0

這將是一個問題,因爲你需要提供參數的塊,如果你不知道他們會是什麼,那麼你怎麼能做到這一點?這可能是可能的,但會變得混亂,聽起來不值得付出努力。 – trojanfoe 2013-02-21 15:22:37

回答

2

如果您有兩個不同的塊,如您在評論中所做的那樣,則可以按如下所示合併兩個塊。但是,這很不方便,當調用塊時,您需要檢查object的類。

- (void) reportSuccessWithBlock:(void (^) (id object, NSUInteger value)) block { 

    if (!block) 
     return; 

    if (self.returnOnMainThread) { 
     dispatch_async(dispatch_get_main_queue(), block((id)someObject, value)); // return 0 instead if there is no value 
    } 

    else { 
     block((id) someObject, value)); // return 0 instead if there is no value 
    } 
} 

因此,當塊被調用,所有你需要做的是檢查類,做任何與返回的對象:

- (void) someMethod { 

    [self reportSuccessWithBlock:^(id object, NSUInteger value) { 

     if ([object isKindOfClass:[NSArray class]]) { 

      // returned an NSArray and `value` is 0 (unset) 

     } 

     else if ([object isKindOfClass:[NSDictionary class]]) { 

      // returned an NSDictionary and the `value` is not 0 (unset) 

     } 

     else { 

      // something has gone wrong somewhere! 

     } 

    }]; 

} 
1

OK,我想用NSArray參數的想法將工作,所以你可以給你塊相同的簽名:

typedef void ^(MYBLOCK)(NSArray *args); 

和實現你的方法爲:

- (void)reportSuccessWithBlock:(GenericBlockType)block 
        andArguments:(NSArray *)args 
{ 
    if (block != nil) 
    { 
     if (self.returnOnMainThread) 
     { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       block(args); 
      }); 
     } 
     else 
     { 
      block(args); 
     } 
    } 
} 

然後這只是確保正確類型的參數以正確的順序給予塊的情況(聽起來微不足道,但如果你弄錯了會引起各種各樣的仇恨)。

MYBLOCK block1 = ^(NSArray *args) { 
    // I accept NSNumber, NSString, NSValue 
    NSAssert(args.count == 3, @"Invalid argument count"); 
    NSNumber *arg1 = args[0]; 
    NSString *arg2 = args[1]; 
    NSValue *arg3 = args[2]; 

    // Do my thing 
}; 

,把它想:

[someClass reportSuccessWithBlock:block1 
        andArguments:@[ @(1), @"Hello", @(cgpoint) ]]; 
+0

您的回答非常有用,至少對我來說 - 閱讀大約10篇關於使用塊作爲方法參數的文章,並且仍然有一些問題 - 請閱讀您的答案 - 並充分發揮它的作用。 '非常感謝,特別是對於這一行:'[someClass reportSuccessWithBlock:block1 andArguments:@ [@(1),@「Hello」,@(cgpoint)]];' – gbk 2014-08-01 21:20:16