web-dev-qa-db-fra.com

Comment écrire un bloc d'achèvement Objective-C

Je suis dans une situation où j'ai besoin d'appeler une méthode de classe à partir de mon contrôleur de vue, de le faire faire, mais d'exécuter certaines actions UNIQUEMENT APRÈS la fin de la méthode de classe.

(Je pense que j'ai besoin d'un bloc d'achèvement, mais veuillez me corriger si je me trompe.)

Voici la situation:

J'utilise Parse.com pour le back-end de mes applications. Lorsqu'un utilisateur ouvre un compte, il saisit son nom, sa société et d'autres informations dans une fenêtre contextuelle, puis clique sur soumettre. Le bouton d'envoi est lié à une méthode de classe (illustrée ci-dessous) qui prend leur objet PFUser et le nom de l'entreprise et crée des objets de base de données. Une fois la fonction terminée, la fenêtre contextuelle est fermée à l'aide d'un délégué.

Le problème est que j'ai besoin que la création de ces objets se produise dans un ordre spécifique car ils dépendent des autres objectId pour exister. Le problème est que la méthode déléguée pour fermer la fenêtre contextuelle est appelée immédiatement après avoir cliqué sur soumettre car c'est la suivante sur la pile.

Lorsque vous enregistrez un objet Parse, on appelle une méthode qui ressemble à ceci: (C'est le genre de ce que j'espère écrire et je pense que cela résoudrait mon problème)

[someParseObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
    // Code here runs AFTER the method completes.
    // This also happens on another thread which
    // I'd like to implement as well.
}];

Donc, ce dont j'ai besoin pour comprendre comment faire quelque chose comme ceci: (Tout ce qui a à voir avec le bloc est complètement faux, je suis sûr)

SignUpViewController.m

myUserOrg *userOrg = [myUserOrg object]; // myUserOrg = Custom PFObject Subclass

// My method that takes in a user object and a string, creates
// the database objects in order.
[userOrg registerNewUserOrgWithUser:(PFUser*) andCompanyName:(NSString*) companyName withBlock(somethingHere)block {

    if(error) {
        NSLog(@"Unable to create org!");
    } else {
        NSLog(@"Created Org!");
        [self.delegate dismissSignupView];
}

Veuillez me faire savoir si vous avez besoin d'informations supplémentaires ou de clarifications.

Merci d'avance!

--------- MODIFIER UN ----------

D'accord, donc plusieurs unités de temps importantes plus tard, c'est ce que j'ai trouvé. L'ensemble de l'implémentation pourrait être mieux simplifié et effectuer beaucoup moins d'appels API, mais cela fonctionnera. Plusieurs autres problèmes flagrants avec elle aussi, mais c'est une première étape.

Appel de méthode:

[testOrg registerNewUserOrgWithUser:currentUser
         creatingOrgContactWithName:@"MyBigHappy Corp."
                          withBlock:^(BOOL succeeded, NSError *error) {
                              if (error) {
                                  NSLog(@"Not working");
                              } else {
                                  NSLog(@"Working!");
                              }
                          }];

Implémentation de la méthode:

@implementation MYUserOrg

@dynamic orgContact;
@dynamic orgDisplayName;
@dynamic members;
@dynamic contacts;

+ (NSString *)parseClassName {
    return @"MYUserOrg";
}

dispatch_queue_t NewUserOrgRegistrationQueue;

-(void)registerNewUserOrgWithUser:(MYUser*)user
       creatingOrgContactWithName:(NSString*) orgContactName
                        withBlock:(MYBooleanResultBlock) block {

    NewUserOrgRegistrationQueue = dispatch_queue_create("com.myapp.initialOrgCreationQueue", NULL);

    dispatch_async(NewUserOrgRegistrationQueue, ^{

        NSMutableArray *errors = [[NSMutableArray alloc] init];

        // Initial org save to generate objectId
        NSError *orgSaveError = nil;
        [self save:&orgSaveError];

        if (orgSaveError) {
            [errors addObject:@"Initial Org save Failed"];
        }

        // Create and Relate Org Contact
        NSError *saveOrgContactError = nil;
        MYontact *orgContact = [MYContact object];
        [orgContact setContactType:MYContactTypeUserOrganization];
        [orgContact setDisplayName:orgContactName];
        [orgContact setParentOrg:self];
        [orgContact save:&saveOrgContactError];

        if (saveOrgContactError) {
            [errors addObject:@"Saving Org Contact Failed"];
        } else {
            // If Org contact saved, set it;
            [self setOrgContact:orgContact];
        }

        // Create AMD Relate User Contact
        NSError *saveUserContactError = nil;
        MYContact *userContact = [MYContact object];
        [userContact setFirstName:user.firstName];
        [userContact setLastName:user.lastName];
        [userContact setContactType:MYcontactTypeUser];
        [userContact setParentOrg:self];
        [userContact save:&saveUserContactError];

        if (saveUserContactError) {
            [errors addObject:@"Saving user contact failed"];
        }

        NSError *saveUserError = nil;
        [user setParentOrg:self];
        [user setUserContact:userContact];
        [user save:&saveUserError];

        if (saveUserError) {
            [errors addObject:@"Saving User failed"];
        }

        // Return if block succeeded and any errors.
        NSError *error = nil;
        BOOL succeeded;
        if (errors.count > 0) {

            NSDictionary *userInfo = @{@"error" : errors};
            errors = [NSError errorWithDomain:@"MyAppErrorDomain"
                                         code:1
                                     userInfo:userInfo];
            succeeded = NO;
        } else {
            succeeded = YES;
        }
        block(succeeded, error);
    });

}

@end
36
Andrew
78
CW0007007

J'ai écrit un ComplémentBlock pour une classe qui retournera les valeurs d'un dé après qu'il ait été secoué:

  1. Définissez typedef avec returnType (.h au dessus de @interface déclaration)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
    
  2. Définissez un @property pour le bloc (.h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
    
  3. Définissez une méthode avec finishBlock (.h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
    
  4. Insérer la méthode définie précédente dans .m fichier et commit finishBlock dans @property défini avant

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
    
  5. Pour déclencher completionBlock passez-lui un variableType prédéfini (N'oubliez pas de vérifier si le completionBlock existe)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }
    
32
Alex Cio

Concernant http://goshdarnblocksyntax.com/

En tant que variable locale :

returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};

En tant que propriété :

@property (nonatomic, copy) returnType (^blockName)(parameterTypes);

En tant que paramètre de méthode :

- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;

En tant qu'argument à un appel de méthode :

[someObject someMethodThatTakesABlock:^returnType (parameters) {...}];

En tant que type typedef :

typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters) {...};
12
carmen_munich

Vous définissez le bloc comme un type personnalisé:

typedef void (^ButtonCompletionBlock)(int buttonIndex);

Ensuite, utilisez-le comme argument pour une méthode:

+ (SomeButtonView*)buttonViewWithTitle:(NSString *)title 
                      cancelAction:(ButtonCompletionBlock)cancelBlock
                  completionAction:(ButtonCompletionBlock)completionBlock

Lorsque vous appelez cela dans le code, c'est comme n'importe quel autre bloc:

[SomeButtonView buttonViewWithTitle:@"Title"
                   cancelAction:^(int buttonIndex) {
                         NSLog(@"User cancelled");
               } 
                 completionAction:^(int buttonIndex) {
                         NSLog(@"User tapped index %i", buttonIndex);
               }];

Si le moment est venu de déclencher le bloc, il suffit d'appeler complétementBlock () (où complémentBlock est le nom de votre copie locale du bloc

11