Как я могу создать свои собственные методы, которые принимают блок в качестве аргумента и которые я могу вызвать позже?

Как я могу создать свои собственные методы, которые принимают блок в качестве аргумента и которые я могу вызвать позже?

Я пробовал следующие вещи.

#import <UIKit/UIKit.h>
typedef void (^viewCreator)(void);

@interface blocks2ViewController : UIViewController
{
}
-(void)createButtonUsingBlocks:(viewCreator *)block;

@end


- (void)viewDidLoad {
  [super viewDidLoad];
  [self createButtonUsingBlocks:^(NSString * name) {
        UIButton *dummyButton = [[UIButton alloc]initWithFrame:CGRectMake(50, 50, 200, 100)];
        dummyButton.backgroundColor = [UIColor greenColor];
        [self.view addSubview:dummyButton];
  }];
}

-(void)createButtonUsingBlocks:(viewCreator *)block
{
    //    Do something
    NSLog(@"inside creator");
}

Я также пытался передать переменную блока своему пользовательскому методу, но безуспешно. Почему так и как правильно это сделать?


Обновить

Это файл is.h:

 #import <UIKit/UIKit.h>

typedef void (^viewCreator)(void);

@interface blocks2ViewController : UIViewController
{

}
- (void)createButtonUsingBlocks:(viewCreator)block;
@end

А это файл .m:

#import "blocks2ViewController.h"

@implementation blocks2ViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
        [self createButtonUsingBlocks:^(NSString * name) {
        UIButton *dummyButton = [[UIButton alloc]initWithFrame:CGRectMake(50, 50, 200, 100)];
        dummyButton.backgroundColor = [UIColor greenColor];
        [self.view addSubview:dummyButton];
        [dummyButton release];
    }];
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

// ...

-(void)createButtonUsingBlocks:(viewCreator)block
{
//    viewCreator;
    NSLog(@"inside creator");
}
@end

person Ajay Pandey    schedule 09.09.2010    source источник
comment
Пожалуйста, добавьте обновления вместо изменения исходного вопроса и проверьте форматирование в предварительном просмотре перед публикацией.   -  person Georg Fritzsche    schedule 09.09.2010
comment
В обновлении все еще есть проблема с typedef - изменить typedef void (^viewCreator)(void); на typedef void (^viewCreator)(NSString*);   -  person Georg Fritzsche    schedule 09.09.2010


Ответы (2)


Во-первых, typedef отключается, если вы хотите, чтобы ваши блоки принимали строковый параметр:

typedef void (^viewCreator)(NSString*);

Во-вторых, тип блоков:

ReturnType (^)(ParameterTypes...)

и не

ReturnType (^*)(ParameterTypes...)

Таким образом, нет необходимости добавлять указатели на тип viewCreator:

- (void)createButtonUsingBlocks:(viewCreator)block;

В-третьих вам действительно нужно вызвать блок, если вы этого еще не сделали:

-(void)createButtonUsingBlocks:(viewCreator *)block {
    block(@"button name");
    // ...

Четвёртое и последнее: UIButton слишком долго сохраняется — вам следует release или autorelease:

UIButton *dummyButton = [[UIButton alloc] initWithFrame:...];
// ...    
[self.view addSubview:dummyButton];
[dummyButton release];

Объединяем все это вместе:

#import <UIKit/UIKit.h>
typedef void (^viewCreator)(NSString*);

@interface blocks2ViewController : UIViewController {}
-(void)createButtonUsingBlocks:(viewCreator)block;      
@end

@implementation blocks2ViewController
- (void)viewDidLoad {
    [super viewDidLoad];  
    [self createButtonUsingBlocks:^(NSString *name) {
        UIButton *dummyButton = 
            [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 200, 100)];
        dummyButton.backgroundColor = [UIColor greenColor];
        [self.view addSubview:dummyButton];
        [dummyButton release];
    }];
}

-(void)createButtonUsingBlocks:(viewCreator)block {
    block(@"my button name");
}
@end
person Georg Fritzsche    schedule 09.09.2010
comment
@Ajay: Смотрите редактирование, вы действительно где-то вызываете блок? - person Georg Fritzsche; 09.09.2010
comment
Потрясающий ответ. Одно дополнительное примечание; если ваша цель состоит в том, чтобы сохранить блок и вызвать его позже, вам нужно copy блок. Блоки начинаются в стеке, и очень плохие вещи произойдут, если вызвать блок, который не был скопирован после уничтожения объявляющего кадра стека. - person bbum; 09.09.2010
comment
ОК, теперь, когда я прокомментировал оператор typedef и поскольку я использую блок как встроенную функцию (на самом деле я вызываю createButtonUsingBlocks:, который, в свою очередь, принимает этот блок в качестве аргумента), так что мне не нужно копировать, верно? Но все же кажется, что некоторые ошибка... Было бы неплохо, если бы вы могли просто опубликовать несколько строк, в которых пользовательский метод принимает блок в качестве аргумента и использовать его позже. Это сделает картину более четкой. - person Ajay Pandey; 09.09.2010
comment
@Ajay: Какая ошибка? И что вы имеете в виду под словом «позже»? Просто передать блок методу и вызвать его там? С кодом, структурированным как в вашем вопросе, если вы вызываете блок в -createButtonUsingBlocks:, проблем не возникает. Кстати, у Майка Эша был хороший пост на основные блоки. - person Georg Fritzsche; 09.09.2010
comment
это очень маленький код, и он дает ошибку в тех строках, где я объявил -createButtonUsingBlocks: и где я определил -createButtonUsingBlocks: я уверен, что это синтаксическая ошибка, поэтому я хотел, чтобы вы отправили несколько строк, чтобы я знал, где я не прав ..Ошибка читает ожидаемое ')' перед 'viewCreator' - person Ajay Pandey; 09.09.2010
comment
#import ‹UIKit/UIKit.h› @interface blocks2ViewController : UIViewController { } - (void)createButtonUsingBlocks:(viewCreator)block; @end извините за глупую ошибку.. - person Ajay Pandey; 09.09.2010
comment
@Ajay: теперь вам не хватает typedef void (^viewCreator)(NSString*); перед объявлением интерфейса. - person Georg Fritzsche; 09.09.2010
comment
но ты сказал, что это выключено, когда мой блок принимает любой параметр - person Ajay Pandey; 09.09.2010
comment
в частности, если аргументом является NSString - person Ajay Pandey; 09.09.2010
comment
@Ajay: Когда он был выключен, я имел в виду, что typedef был неправильным и его нужно изменить, а не удалять. Смотрите редактирование. - person Georg Fritzsche; 09.09.2010
comment
и после написания typedef в моем viewDidLoad появляется ошибка, говорящая об ошибке: несовместимые типы указателей блоков, инициализирующие «void (^) (struct NSString *)», ожидаемый «viewCreator». Мой viewDidLoad выглядит так - person Ajay Pandey; 09.09.2010
comment
- (void) viewDidLoad { [super viewDidLoad]; [self createButtonUsingBlocks: ^ (NSString * name) { UIButton *dummyButton = [[UIButton alloc] initWithFrame: CGRectMake (50, 50, 200, 100)]; dummyButton.backgroundColor = [зеленый цвет пользовательского интерфейса]; [self.view addSubview:dummyButton]; [отпустить фиктивную кнопку]; } ]; } - person Ajay Pandey; 09.09.2010
comment
@Ajay: Сравните свою версию с тем, что я добавил выше. Если это не поможет, добавьте свой текущий код в вопрос или в PasteBin или что-то подобное. - person Georg Fritzsche; 09.09.2010
comment
извините, Джордж, теперь это работает, но я не мог знать причину. Почему это не работает, когда я объявляю это в файле .h ... Должен ли я использовать это как способ использования методов, принимающих блок или что? - person Ajay Pandey; 09.09.2010
comment
Большое спасибо, Джордж. Это был лучший способ научиться создавать собственные методы с помощью блоков. Спасибо за все. - person Ajay Pandey; 09.09.2010
comment
@bbum: да, ты должен его скопировать, но тебе также нужно знать, когда его выпустить - person user102008; 21.06.2011

Вы также можете сделать это без предварительного определения метода:

@interface blocks2ViewController : UIViewController
-(void)createButtonUsingBlocks:(void (^)(NSString *name))block;
@end

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createButtonUsingBlocks:^(NSString * name) {
        UIButton *dummyButton = [[UIButton alloc]initWithFrame:CGRectMake(50, 50, 200, 100)];
        dummyButton.backgroundColor = [UIColor greenColor];
        [self.view addSubview:dummyButton];
    }];
}

-(void)createButtonUsingBlocks:(void (^)(NSString *name))block
{
    block(@"My Name Here");
}
person Gujamin    schedule 11.01.2012