Objective C:使用块初始化类?

5

是否可能在视图控制器的init方法中使用块作为完成处理程序,以便父视图控制器能够填写块中的细节,而无需为每个可能的属性创建自定义initWithNibName:andResourceBundle:andThis:andThat:?

// ... in the didSelectRowAtIndexPath method of the main view controller :
SubViewController *subviewController = [[SubViewController alloc] initWithNibName:nil bundle:nil completionHandler:^(SubViewController * vc) {
    vc.property1 = NO;
    vc.property2 = [NSArray array];
    vc.property3 = SomeEnumValue;
    vc.delegate = self;
}];
[self.navigationController pushViewController:subviewController animated:YES];
[subviewController release];

在SubViewController.m中:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completionHandler:(void (^)(id newObj))block {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        block(self);
    }
    return self;
}

替代

// ... in the didSelectRowAtIndexPath method of the main view controller :
SubViewController *subviewController = [[SubViewController alloc] initWithNibName:nil bundle:nil andProperty1:NO andProperty2:[NSArray array] andProperty3:SomeEnumValue andDelegate:self];
[self.navigationController pushViewController:subviewController animated:YES];
[subviewController release];

使用

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andProperty1:(BOOL)p1 andProperty2:(NSArray *)p2 andProperty3:(enum SomeEnum)p3 andDelegate:(id<MyDelegateProtocol>)myDelegate {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
       self.property1 = p1;
       self.property2 = p2;
       self.property3 = p3;
       self.delegate = myDelegate;
    }
    return self;
}

这样,我就可以在主控制器中随心所欲地做任何事情,而不是调用预定义的初始化方法(并且必须为每种可能的初始化编写一个方法)。

这样做有什么不好吗?会出现保留环问题吗?

5个回答

3

您认为使用块有哪些优势?初始化程序通常用于设置实例的私有状态。由于块是在其他地方实现的,因此无法从块中访问此私有状态。

如果只使用公共属性,为什么不在初始化之后设置它们?

SubViewController *vc = [[SubViewController alloc] initWithNibName:nil bundle:nil];
vc.property1 = NO;
vc.property2 = [NSArray array];
vc.property3 = SomeEnumValue;
vc.delegate = self;

这正是块版本所做的(无需麻烦)。

这是什么意思?会有保留周期吗?

不会,但出于架构原因,我会驳回您的建议:您要么打破类的封装,要么与初始化后直接执行块没有任何优势。


使用像这样的属性确实比使用代码块更简单。 - David Lacourt

2
问题如下:
  1. 这种方法有什么好处?
  2. 你能有效地管理这个代码吗?

请注意,随着程序的增长,将会添加新的调用级别,这将使您的代码难以阅读、维护、扩展或开发。还要考虑未来的子类化以及如何在将来调试此代码以查找某些不匹配的值。块可以使您的代码更快,但委托模式将使您的代码干净,并在一个线程中运行,这对于专业程序员来说是易于维护的真正价值。

这里的代码块在同一线程中,不是吗?但我明白你的意思。谢谢。 - David Lacourt

1

您可以定义您的

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completionHandler:(void (^)(id newObj))block;

UIViewController类别中的方法; 从那里调用initWithNib,然后在刚分配的self上执行完成块:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completionHandler:(void (^)(id newObj))block
{
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
        block(self);
    }
    return self;
}

我认为这应该可以很好地工作。


1

这是可能的,没有保留问题。所有内容将在同一线程上同步调用。

BUT What is the benefit of not doing this the simple way - calling another method after init, e.g.

MyController* controller = [[[MyController alloc] init] autorelease];
[self updateController:controller];
Does the code have be called from the init method?

一般来说,如果您想以不同的方式初始化对象,我建议创建单独的init...方法。

1

我真的不确定为什么你会采取这种方法(除非你想引起OOD警察的注意)。这不是一个好主意

您的控制器可以定义一个函数或方法,该函数或方法返回一个实例,并以其希望的方式进行初始化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接