在Objective-C中动态创建对象

时间:2011-12-06 21:24:08

标签: ios objective-c

我想要批评我用来创建对象的以下方法:

在界面文件中:

MyClass * _anObject;
...
@property (retain, nonatomic) MyClass * anObject;

在实施文件中:

@property anObject = _anObject
到目前为止,这么简单。现在让我们覆盖默认的getter:

(MyClass *) anObject {
    if(_anObject == nil) {
        self.anObject = [[MyClass alloc] init];
        [_anObject dowWhateverInitAction];
    }
    return _anObject;
}

修改 我最初的问题是关于仅创建对象(而不是整个生命周期),但我添加了以下内容,以便它不会通过任何人:

- (void) dealloc {
   self.anObject = nil;
}

/修改

练习的要点是在getter中使用setter。我已经将它用于所有类型的对象(ViewController,无数其他类型等)。我得到的好处是:

  • 仅在需要时创建对象。它使应用程序非常快 (例如,应用程序中有6-7个视图,只有一个在中创建 开头)。
  • 我不必担心在使用之前创建一个对象......它会自动发生。
  • 我不必担心第一次需要对象的位置......我只能访问该对象,就好像它已经存在一样,如果不存在,它就会被创建为新的。

问题:

  • 是否恰好是既定模式?
  • 你觉得这样做有什么缺点吗?

5 个答案:

答案 0 :(得分:3)

此模式通常用作延迟加载技术,只有在首次请求时才会创建对象。

如果懒惰创建的对象需要大量的计算来创建,并且在时间紧迫的情况下被请求(这种情况下,使用这种技术没有意义),这种方法可能有一个缺点)。但是,如果对象快速创建,我会说这是一个合理的事情。

答案 1 :(得分:2)

你的实现唯一的错误(假设你还没有使用ARC)就是你有内存泄漏 - 使用setter意味着你的MyClass实例被过度保留。您应该在初始化后释放或自动释放_anObject,或直接分配其值而不是调用setter。

除此之外,这是完全正常的,当MyClass是一个不一定需要的对象并且可以轻松地重新创建时,它是一个很好的模式:你对内存警告的响应可以包括{{1释放实例的内存。

答案 2 :(得分:2)

它看起来像一个不错的lazy initialization。从哲学上讲,人们可以争辩说,缺点是吸气剂有副作用。但副作用在外面是不可见的,它是一种既定的模式。

答案 3 :(得分:2)

懒惰实例化是一种已建立的模式,Apple在其(可怕的)核心数据模板中使用它。

主要缺点是它过于复杂并且通常是不必要的。我已经失去了我已经看过的次数,在父对象初始化时简单地实例化对象会更有意义。

如果一个简单的解决方案同样好,那么请使用更简单的解决方案。是否有特殊原因导致在初始化父对象时无法实例化这些对象?也许子对象占用了大量内存,很少被访问?是否需要花费大量时间来创建对象,并且在应用程序的时间敏感部分初始化父对象?然后随意使用延迟实例化。但在大多数情况下,你应该更喜欢更简单的方法。

它也不是线程安全的。

关于你的优势:

  

仅在需要时创建对象。它使应用程序非常快(例如,在应用程序中有6-7个视图,只有一个在开始时创建)。

您是指视图还是视图控制器?你的陈述对于观点并没有多大意义。我通常不会发现自己需要在实例变量/属性中存储视图控制器,当我需要切换到它们并将它们推送到导航堆栈时,我将它们实例化,然后在我完成时弹出它们。

您是否尝试过不使用此模式的应用?关于性能的猜想经常是错误的。

  

我不必担心在使用之前创建一个对象......它会自动发生。

不,现在你不得不担心写一个特殊的吸气剂。这比简单的实例化更复杂,更容易出错。它还使您的应用程序逻辑和性能更难以理解和推理。

  

我不必担心第一次需要对象的位置......我只能访问该对象,就好像它已经存在一样,如果不存在,它就会被创建为新的。

在父对象初始化期间实例化它时,您不必担心这一点。

答案 4 :(得分:0)

是的,这是既定模式。我经常使用像这样的惰性实例化作为使用一堆设置代码来混淆-init-viewDidLoad的替代方法。如果由于-init中发生的事情导致该对象最终被创建,我会将值分配给实例变量而不是使用合成的setter。