Objective-C/iPhone开发中的延迟实例化

27

快速提问... 我知道在 Objective-C 中所有属性都会初始化为 nil,当发送消息给 nil 时什么也不会发生,因此你必须在向新创建的属性发送消息之前使用 [[Class alloc] init]; 进行初始化。然而,如果我不向这个属性发送消息,或者如果我使用 self.property = something 设置属性,那么需要进行 alloc init 吗?另外,UI 属性是否也会初始化为 nil,例如从 storyboard 拖出来的 UILabel 属性?这些是否需要进行 alloc init?

谢谢所有回答的人。


1
+1 非常好的问题。给尚未分配/初始化属性发送消息是OjbC初学者经常犯的错误。 - Philip007
4个回答

41

Stunner很好地解释了无需为已创建的对象分配内存。

但是,如果需要创建一个不存在的对象呢?一种非常常见的模式是懒加载。

所以,您想要一个NSMutableArray属性。您可以在使用它之前的某个方法中进行alloc init,但这样就必须担心“那个方法是否在我需要数组之前被调用?”或“我会不小心再次调用它并重新初始化它吗?”

因此,在属性的getter中执行它是一个可靠的方法。每次访问属性时都会调用它。

.h
@property (nonatomic, strong) NSMutableArray* myArray;

.m
@synthesize myArray = _myArray;

- (NSMutableArray*)myArray
{
    if (!_myArray) {
        _myArray = [[NSMutableArray alloc] initWithCapacity:2];
    }
    return _myArray;
}
每次访问该属性时,它会检查“myArray”是否存在。如果不存在,则创建它;如果存在,则直接返回已有的内容。
此设计模式的额外优点是在需要资源之前不会创建它们,而不是一次性全部创建,比如在视图控制器加载或应用启动时,这可能需要花费几秒钟,具体取决于要求。

4
回答不错,但我不同意在getter中实例化ivar,因为这会使查询对象是否存在变得不可行。相反,我建议您在setter中进行实例化,因为您确定要设置的该ivar不存在时,您希望它存在,以便可以将其设置为一个值。因此,在调用setter时,您永远不会希望它不存在,而在调用getter时,情况并非总是如此。 - Stunner
如果我能这么晚加入……如果属性具有“copy”属性,您是否需要在setter中添加它,因为它已经获得了要使用的副本? - ScottyB

4
实际上,当你执行 self.myProperty = [[Class alloc] init] 时,你并没有初始化你的属性。相反,你正在初始化一个对象,并告诉你的属性(实际上是一个指针)指向它。因此,如果你已经有了一个分配和初始化的对象,你就不需要再次分配/初始化,可以直接使用 self.myProperty = object
UI属性并不会起始为nil,这是因为当你在界面构建器中添加元素时,视图拥有你添加的元素,并自动为你初始化这些对象。这意味着如果你创建了IBOutlets并将它们连接到某些属性,你就不必进行alloc/init操作。
希望这对你有所帮助。

1

我没有使用Storyboards的经验,但我知道当您通过xib文件创建对象时,当您告诉视图控制器使用xib文件时,所有对象都会被正确实例化。因此,您无需担心在代码中分配/初始化这些对象。

关于使用self.property = <something>,这取决于something是什么。如果something是任何类型的现有对象,则无需对该对象进行alloc init,因为self.property = ...语法调用属性的setter方法,该方法将适当地保留、复制、分配等新值到属性中。

现有对象可以是alloc/init的对象,也可以是从方便方法(例如NSString的stringWithFormat:)获得的自动释放对象。

正如Kaan Dedeoglu指出的那样,self.property = ...语法指向(并保留)内存中的ivar,如果尚未实例化该对象,则由您来初始化它。


0

不需要在init方法中使用[[Class alloc]init来初始化属性。

然而,我建议您在init方法中明确将它们设置为Nil以增加清晰度。


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