wake-up-neo.com

So schreiben Sie einen Objective-C-Abschlussblock

Ich bin in einer Situation, in der eine Klassenmethode von meinem View-Controller aufgerufen werden muss, damit sie funktioniert, aber dann NUR einige Aktionen ausführt, nachdem die Klassenmethode abgeschlossen wurde.

(Ich denke, was ich brauche, ist ein Abschlussblock, aber bitte korrigieren Sie mich, wenn ich falsch liege.)

Hier ist die Situation:

Ich verwende Parse.com für mein Apps-Backend. Wenn sich ein Benutzer für ein Konto anmeldet, gibt er seinen Namen, seine Firma und einige andere Informationen in ein Popup ein und klickt dann auf Senden. Die Senden-Schaltfläche ist mit einer Klassenmethode (siehe unten) verknüpft, die das PFUser-Objekt und den Firmennamen verwendet und einige Datenbankobjekte erstellt. Nach Abschluss der Funktion wird das Popup mit einem Delegaten geschlossen.

Das Problem ist, dass die Erstellung dieser Objekte in einer bestimmten Reihenfolge erfolgen muss, da die Existenz der Objekt-IDs von der jeweiligen Objekt-ID abhängt. Das Problem ist, dass die Delegate-Methode zum Ausblenden des Popups sofort nach dem Klicken auf "Submit" aufgerufen wird, da dies die nächste auf dem Stapel ist.

Wenn man ein Parse-Objekt speichert, ruft man eine Methode auf, die ungefähr so ​​aussieht:

[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.
}];

Also, was ich brauche, um herauszufinden, wie man so etwas macht: (Alles, was mit dem Block zu tun hat, ist völlig falsch, da bin ich mir sicher)

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

Bitte lassen Sie mich wissen, wenn Sie zusätzliche Informationen oder Erläuterungen benötigen.

Danke im Voraus!

--------- EDIT ONE ----------

Okay, also einige große Zeiteinheiten später habe ich mir das ausgedacht. Die gesamte Implementierung könnte besser vereinfacht werden und viel weniger API-Aufrufe machen, wird aber daran arbeiten. Einige andere krasse Probleme damit sind aber ein erster Schritt.

Methodenaufruf:

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

Methodenimplementierung:

@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

Ich benutze das immer, wenn ich einen Block schreiben möchte:

http://fuckingblocksyntax.com

Oder die weniger profane Version:

http://goshdarnblocksyntax.com/

Für Swift:

https://web.archive.org/web/20180527074325/http://fuckingswiftblocksyntax.com:80/

78
CW0007007

Ich habe einen CompletionBlock für eine Klasse geschrieben, die nach dem Schütteln die Werte eines Würfels zurückgibt:

  1. Definiere typedef mit returnType (.h über @interface Erklärung)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
    
  2. Definiere ein @property für den Block (.h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
    
  3. Definiere eine Methode mit finishBlock (.h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
    
  4. Einfügen der zuvor definierten Methode in .m Datei und Commit von finishBlock zu @property zuvor definiert

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
    
  5. Um completionBlock auszulösen, übergeben Sie ihm einen vordefinierten Variablentyp. (Vergessen Sie nicht zu prüfen, ob completionBlock vorhanden ist.)

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

In Bezug auf http://goshdarnblocksyntax.com/

Als lokale Variable :

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

Als Eigenschaft :

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

Als Methodenparameter :

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

Als Argument für einen Methodenaufruf :

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

Als typedef :

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

Sie definieren den Block als benutzerdefinierten Typ:

typedef void (^ButtonCompletionBlock)(int buttonIndex);

Verwenden Sie es dann als Argument für eine Methode:

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

Wenn Sie dies im Code aufrufen, verhält es sich wie bei jedem anderen Block:

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

Wenn es Zeit ist, den Block auszulösen, rufen Sie einfach completionBlock () auf (wobei completionBlock der Name Ihrer lokalen Kopie des Blocks ist

11