Подтвердить что ты не робот

Как написать блок завершения Objective-C

Я нахожусь в ситуации, когда нужно вызвать метод класса из моего контроллера представления, заставить его сделать это, но затем выполнить некоторые действия ТОЛЬКО ПОСЛЕ того, как метод класса завершил.

(Я думаю, что мне нужен блок завершения, но, пожалуйста, поправьте меня, если я ошибаюсь.)

Вот ситуация:

Я использую Parse.com для своих приложений. Когда пользователь регистрируется в учетной записи, он вводит свое имя, компанию и некоторую другую информацию во всплывающем окне, а затем нажимает кнопку "Отправить". Кнопка отправки связана с методом класса (показанным ниже), который берет их объект PFUser и название компании и создает некоторые объекты базы данных. После завершения функции всплывающее окно закрывается с использованием делегата.

Проблема в том, что мне нужно, чтобы создание этих объектов происходило в определенном порядке, потому что они зависят друг от друга. Проблема в том, что метод делегата для закрытия всплывающего окна вызывается сразу после нажатия кнопки "Отправить", поскольку он следующий в стеке.

При сохранении объекта Parse вызывается метод, который выглядит примерно так: (Это то, что я надеюсь написать, и я думаю, что это решит мою проблему)

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

Итак, что мне нужно выяснить, как сделать что-то вроде следующего: (Я уверен, что все, что связано с блоком, совершенно неправильно)

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

Пожалуйста, дайте мне знать, если вам нужна дополнительная информация или разъяснения.

Заранее спасибо!

--------- РЕДАКТИРОВАТЬ ОДИН ----------

Итак, несколько значительных единиц времени спустя, это то, что я придумал. Вся реализация могла бы быть лучше упрощена и делать намного меньше вызовов API, но будет работать над этим. Несколько других вопиющих проблем с этим также, но это первый шаг.

Вызов метода:

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

Реализация метода:

@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
4b9b3361

Ответ 2

Я написал блок завершения для класса, который вернет значения кубиков после того, как они будут встряхиваться:

  • Определите typedef с объявлением returnType (.h выше @interface)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
    
  • Определите @property для блока (.h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
    
  • Определите метод с finishBlock (.h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
    
  • Вставить предыдущий определенный метод в файл .m и зафиксировать finishBlock до @property, определенный перед

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
    
  • Чтобы запустить completionBlock передать предопределенный переменный тип ему (Не забудьте проверить, существует ли completionBlock)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }
    

Ответ 3

Относительно http://goshdarnblocksyntax.com/

Как локальная переменная :

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

Как свойство :

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

Как параметр метода:

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

Как аргумент для вызова метода:

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

Как typedef:

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

Ответ 4

Вы определяете блок как настраиваемый тип:

typedef void (^ButtonCompletionBlock)(int buttonIndex);

Затем используйте его в качестве аргумента для метода:

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

При вызове этого кода он как и любой другой блок:

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

Если пришло время запуска блока, просто вызовите completeBlock() (где completeBlock - это имя вашей локальной копии блока