2011-12-06 136 views
1

我想下面的方法我用它来创建对象的批判:创建对象

在接口文件:

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

/EDIT

的工作的主要一点是,设置器吸气剂的内部使用。我已经将它用于所有类型的对象(ViewController,其他类型等)。我得到的优点是:

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

问题:

  • 是否恰好是一个既定的模式?
  • 你看到这样做的缺点吗?
+2

很常见的模式,通常称为延迟初始化。 – omz

+1

你打开ARC吗?如果你不这样做,那么就有内存泄漏。在用'self.anObject'语法将实例变量赋值给''[MyClass alloc] init]'后,你需要释放你创建的对象。你在做什么是大多数情况下推荐的模式。 –

+0

我个人不喜欢带副作用的吸气剂。是的,懒加载是常见的,但我完全不会使用它遍布我的应用程序,但只能用于包含许多子视图的视图(已由UIViewController完成)。 – Till

回答

0

是的这是一个确定的模式。我经常使用这样的懒惰实例来代替-init-viewDidLoad与一堆设置代码混淆。如果由于-init中发生的事件而导致该对象最终被创建,我会将该值赋给实例变量,而不是使用合成的setter。

3

这种模式通常用作延迟加载技术,只有在第一次请求时才创建对象。

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

+0

延迟加载通常不会在时间紧急的情况下完成,在时间紧张的情况下,您希望*预加载*和*缓存*,而不是延迟。延迟加载通常用于其他情况,即当某些事情需要一段时间才能加载但并非总是需要时。 – dreamlax

+1

是的,这是我的观点,你不会在时间紧急的情况下使用这种技术。我会编辑我的答案,以便更清楚一点。 – Stuart

2

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

除此之外,这是非常好的,当MyClass是一个不一定需要马上需要并且可以很容易重新创建的对象时,这是一个很好的模式:您对内存警告的响应可以包括self.anObject = nil到释放实例的内存。

2

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

2

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

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

如果一个简单的解决方案是一样好,请使用更简单的解决方案。当父对象被初始化时,为什么不能实例化这些对象是否有特殊的原因?也许这个子对象占用大量内存,而且很少被访问?是否需要大量的时间来创建对象,并且在应用程序的时间敏感部分中初始化父对象?然后随意使用懒惰的实例。但大多数情况下,您应该更喜欢更简单的方法。

它也不是线程安全的。

关于你的优点:

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

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

您是否尝试过不使用此模式的应用程序?关于表现的猜想常常是错误的。

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

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

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

在父对象的初始化过程中实例化它时,您不必担心。

+0

+1完全同意每一点。 – Till

+1

线程安全/原子性可以像使用任何其他手动执行的getter一样简单地通过'@ synthesis'实现。另外,懒加载并不真的太复杂,我根本没有发现它太复杂。即使只看5行代码,也不难看出发生了什么。一个简单的'/ /只有当使用'注释作为提示不会造成任何伤害,如果你认为它会使它更容易理解。 – dreamlax

+1

并非所有这些都是非常主观的,而且是一种风格和偏好的问题?我个人认为它完全像Jim一样行事,但我理解你的观点@dreamlax。 – Till