【问题标题】:Objective C : class init with block ?目标 C:带块的类初始化?
【发布时间】:2012-10-09 09:46:45
【问题描述】:

是否有可能,比如说,在视图控制器的 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;
}

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

有什么不好的吗?会有保留周期吗?

【问题讨论】:

    标签: objective-c ios objective-c-blocks


    【解决方案1】:

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

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

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

    这正是块版本所做的(没有麻烦)。

    有什么不好的吗?会有保留周期吗?

    不,但出于架构原因,我会驳回您的提议:您要么破坏了类的封装,要么没有获得任何优势,而不是仅仅在初始化后执行块所做的事情。

    【讨论】:

    • 使用这样的属性确实比使用块更简单。
    【解决方案2】:

    问题是:

    1. 这种方式有什么好处?
    2. 您能否高效地管理此代码?

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

    【讨论】:

    • 这里的块在同一个线程中,不是吗?但我明白你的意思。谢谢。
    【解决方案3】:

    你可以定义你的

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

    我认为这应该可以正常工作。

    【讨论】:

      【解决方案4】:

      这是可能的,没有retain 问题。一切都将在同一个线程上同步调用。

      但是 不以简单的方式执行此操作有什么好处 - 在init 之后调用另一个方法,例如

      MyController* controller = [[[MyController alloc] init] autorelease];
      [self updateController:controller];
      
      代码是否已从 init 方法调用?

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

      【讨论】:

        【解决方案5】:

        我真的不知道你为什么会采取这种方法(除非你想引起 OOD 警察的注意)。 it's not a good idea.

        你的控制器可以定义一个函数或方法来返回一个实例,而不是按照它想要的方式初始化。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-11-10
          • 1970-01-01
          • 2013-02-01
          • 2021-12-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-23
          相关资源
          最近更新 更多