2013-02-21 9 views
1

Est-il possible de faire passer un bloc entièrement formé (un bloc avec tous ses paramètres inclus) dans une méthode pour ensuite exécuter ce bloc dans la méthode?Passer un bloc en paramètre

Au moment où je l'ai répété cette structure dans mon projet:

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

Cependant Idéalement, je voudrais faire abstraction du code ci-dessus clunk dehors dans une méthode similaire à:

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

} 

EDIT:

Le type de bloc ne serait pas connu à l'avance.

Ainsi, le chemin d'appel pourrait ressembler à ceci

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

    [self reportSuccessWithBlock:success(array)]; 

} 

Il y a quelques hypothèses dans le code ci-dessus (que je ne sais pas sont possibles):

  1. Les méthodes peuvent accepter bloc générique types
  2. Un bloc peut être passé avec tous ses paramètres présents mais sans exécuter réellement
+1

Quand vous dites « Le bloc lui-même peut contenir un certain nombre de différentes variables », voulez-vous dire le bloc peut accepter un nombre différent de paramètres? – trojanfoe

+0

@trojanfoe Ce que je veux dire, c'est que cette méthode devrait être capable d'accepter des blocs avec des signatures différentes, par ex. (void (^) (NSArray * tableau)) success ou (void (^) (dictionnaire NSDictionary *, valeur NSUInteger)) succès – williamb

+0

Ce sera un problème car vous devez fournir les paramètres aux blocs et si vous ne le faites pas savoir ce qu'ils seront, alors comment pouvez-vous faire cela? C'est peut-être possible, mais ça va être désordonné et ça ne sonne pas comme si ça en valait la peine. – trojanfoe

Répondre

2

Si vous avez deux blocs différents comme vous l'avez dit dans les commentaires, vous pouvez fusionner les deux comme suit. Cependant, ceci est assez hacky, et vous devrez vérifier la classe du object quand le bloc est appelé.

- (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 
    } 
} 

Par conséquent, lorsque le bloc est appelé, tout ce que vous devez faire est de vérifier la classe et faire tout avec les objets retournés:

- (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, je pense que l'idée d'utiliser NSArray paramètres travaillera, de sorte que vous pouvez donner à vos blocs la même signature:

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

et mettre en œuvre votre méthode comme:

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

Et puis, il suffit de s'assurer que le bon type d'argument est donné au bloc dans le bon ordre (cela semble banal, mais provoquera toutes sortes d'aggro si vous vous trompez).

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

et de l'appeler comme:

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

Votre réponse est très utile, au moins pour moi - lire environ 10 article sur le bloc d'utilisation en tant que paramètre de la méthode et toujours avoir une question - lire votre réponse - et pleinement sous-entendu. Merci beaucoup, surtout pour cette ligne: '[someClass reportSuccessWithBlock: block1 andArguments: @ [@ (1), @" Bonjour ", @ (cgpoint)]]' – gbk