【问题标题】:Static methods and good design静态方法和良好的设计
【发布时间】:2013-01-26 22:12:31
【问题描述】:

我看到了一种让我很感兴趣的初始化视图控制器的方法。可能是我缺乏经验,但我觉得它非常有用,但是,我正在尝试看看是否有任何理由应该避免它,所以我知道我是否也应该采用它。

UIViewController* imageC = [UIViewController imageViewController];

其中imageViewController 是类别中的静态方法:

+(UIViewController*) imageViewController
{
    return [[UIViewController alloc] initWithNibName:@"ImageViewController" bundle:nil];
}

这是好的、可靠的设计吗?我想是的,但不确定。作为静态方法意味着它缺乏上下文,但不确定在这种情况下这是一个问题。 如果你使用这种方法,你长期会遇到什么问题?(如果有的话)

【问题讨论】:

  • 如果你想要一个方便的构造方法,让它成为你的派生视图控制器类的类方法,而不是 UIViewController。
  • @HotLicks 为什么?每次调用它都会返回一个不同的实例,多次调用应该可以吗?没看懂,能解释一下吗?
  • 首先,当子类上的方法也能正常工作时,创建一个类别是愚蠢的。其次,这样您就可以为您定义的每个 VC 类拥有一个同名的convenienceConstructor 方法——需要保留的名称更少。在添加了多个视图控制器之后,您会发现为什么您的方案很差。
  • 并且该方法应该返回一个值,该值是创建的对象的类,而不是 UIViewController。
  • @HotLicks 我不同意it's silly to make a category when a method on a subclass will work just as well。有时您不需要子类(尽管它也可以正常工作)。例如,您可以在UIColor 上有一个方便的构造函数,它返回一个自定义颜色,如[UIColor turquoise]。不需要在那里进行子类化。

标签: objective-c oop objective-c-category


【解决方案1】:

您的代码存在几个问题。首先,Objective C 中没有静态方法。有类方法,它们与实例方法一样动态调度。他们只是为此使用类对象。

这就引出了第二个问题:您的代码总是分配一个UIViewController 的实例,即使在子类上调用时也是如此。这不是 Objective-C 的预期行为。 [NSMutableArray array] 返回一个可变数组,即使 array 是在 NSArray 中定义的便利构造函数。

第三个问题是次要的:如果您声明您的方法返回instancetype,这对子类的用户将是有益的。这样,您所说的方法返回接收器类的实例,编译器可以进行静态类型检查。这个概念叫做related return type,最近才被clang引入。

这是一个更好的版本:

+ (instancetype)imageViewController
{
    return [[self alloc] initWithNibName:@"ImageViewController" bundle:nil];
}

【讨论】:

  • 我明白你的第一点。但是,我应该如何声明我的方法以返回 instancetype 对象?
  • 哇,不知道instancetype!太棒了!
  • @NikolaiRuhe 如果你 alloc 是更好的做法,最好将你的方法命名为 newImageViewController(即使在 ARC 中)并删除 instanceType 返回类型,因为它隐含在以 alloc 开头的类方法中或new.
  • @ValentinRadu 请解释为什么最好使用new 家族的方法。
  • @NikolaiRuhe 因为它就是这样做的,它返回一个 new 实例,不是吗?在 ARC 中不太重要,但仍然是很好的编码风格。最重要的是,如果你使用new作为前缀,相关的结果类型由Clang推导,因此不需要instancetype
【解决方案2】:
  UIViewController* imageC = [UIViewController imageViewController];

这被称为便利构造函数工厂方法,是完全合法和有用的。顺便说一句,它是一个类方法,而不是静态方法。

便利构造函数有两个主要特征:

  1. 它提供了一种更方便的语法来通过标准 alloc/init 实例化一个类;

  2. 它返回一个autorelease 对象,该对象将在当前作用域结束或当前自动释放池结束时被释放。

到目前为止,您可能已经在类文档中注意到,大多数 Cocoa 类都有一组以 +className 格式命名的类方法。这些特殊的类方法称为“便利构造函数”,用于创建临时对象。我所说的临时的意思是,便利构造函数返回的对象被假定为自动释放的 [...]。

(source)

编辑:关于便利构造函数机制的更多细节(以及一般关于返回引用)可以在Objective C ARC Reference, sec. 3.2.2 中找到。

【讨论】:

  • ARC 不会将方便的构造函数解释为返回弱指针。它正确地将返回的对象解释为正在自动释放。
  • ARC 怎么知道它是一个方便的构造函数而不是一个简单的静态方法?
  • @Nikolai Ruhe:虽然我理解你的观点,但我也认为这取决于你如何解释和描述事物。你可以用底层的保留/释放机制来解释 ARC,或者你可以用弱所有权和强所有权来描述 ARC,这在某种程度上更“高级”并且接近 ARC 哲学。顺便说一句,我并不是说一种方法比水獭更好,两种方法我都很好。无论如何,我稍微改变了我的措辞,所以可能不太容易被误解。
  • @Meda:这是 ARC 的默认设置,尽管您可以定义一个使用 ns_returns_retained 属性的便利构造函数(通常是 alloc, init, new, copy 等的情况......另请参阅我的编辑。
  • 你描述的方式是错误的。 weak 在 ARC 的上下文中具有精确的含义,但不是自动释放的含义。此外,对象不会在作用域结束时被释放,而是在周围的自动释放池结束时被释放。
猜你喜欢
  • 2013-09-11
  • 2016-10-06
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
  • 2011-02-19
  • 1970-01-01
相关资源
最近更新 更多