内存管理 - 如何最好地初始化标头中声明的实例
我读过一些关于此的文章,但仍有一件事我不清楚。我知道这可能是一个很棘手的问题,但实际上我已经进行了相当长的开发,但还没有完全掌握这个基本问题。我猜这是自学的症状。
您在标头中声明一个变量,如下所示:
@interface SomeClass : NSObject {
NSMutableArray *anArray;
}
@property (nonatomic, retain) NSMutableArray *anArray;
end
然后在主文件中合成它并将其设置为初始值:
@implementation SomeClass
@synthesize anArray
- (SomeClass *)init{
if (self = [super init]) {
self.anArray = [[NSMutableArray alloc] initWithCapacity:10];
}
[return self];
并在类释放时释放它:
- (void)dealloc {
[anArray release];
[super dealloc];
}
现在,当我运行仪器时,该行
self.anArray = [[NSMutableArray alloc] initWithCapacity:10];
被识别为内存泄露。这是内存泄漏吗,因为当您在标头中定义变量 anArray 时,它会分配内存? (因为我认为它是一个空指针。)因此,当您想要初始化它并调用 [[NSMutableArray alloc] initWithCapacity:10] 时,您正在重新分配内存,并丢失指向原始分配的指针?
因此,我使用方便的类方法:
@implementation SomeClass
@synthesize anArray
- (SomeClass *)init{
if (self = [super init]) {
self.anArray = [NSMutableArray arrayWithCapacity:10];
}
[return self];
这不再被识别为仪器中的内存泄漏。由于这是一种方便的方法,anArray 是自动释放的。但是,如果我假设标头中的实例声明分配内存(这可以解释上一个问题),那么我还应该释放 anArray 吗?以这种方式设置初始值是否可以保留它?
之间的区别
NSMutableArray *anArray = [[NSMutableArray alloc] initWithCapacity:10];
我理解和
NSMutableArray *anArray = [NSMutableArray arrayWithCapactiy:10];
,但我不确定我理解的是当您在标头中声明 NSMutableArray *anArray 时,您应该使用两种方法中的哪一种以及为什么。无论您是否使用第二种方法,您仍然应该在调用 dealloc 时释放 anArray。
我可能会补充一点,我发现以下帖子/链接很有用:
I've read a few posts on this, but there's still one thing that's not clear for me. I know this might be rather a n00b question, but I've actually got rather far into development without quite grasping this fundamental issue. A symptom of being self taught I guess.
You declare a variable in your header, like so:
@interface SomeClass : NSObject {
NSMutableArray *anArray;
}
@property (nonatomic, retain) NSMutableArray *anArray;
end
And then in your main file you synthesise it and set it to an initial value:
@implementation SomeClass
@synthesize anArray
- (SomeClass *)init{
if (self = [super init]) {
self.anArray = [[NSMutableArray alloc] initWithCapacity:10];
}
[return self];
And release it when your Class deallocs:
- (void)dealloc {
[anArray release];
[super dealloc];
}
Now, when I run instruments, the line
self.anArray = [[NSMutableArray alloc] initWithCapacity:10];
is identified as a memory leak. Is it a memory leak because when you define the variable anArray in the header it allocates memory? (Because I thought it was a null pointer.) Therefore when you want to initialise it, and you call [[NSMutableArray alloc] initWithCapacity:10], you are reallocating the memory, and losing the pointer to the original allocation?
So instead, I use the convenience class method:
@implementation SomeClass
@synthesize anArray
- (SomeClass *)init{
if (self = [super init]) {
self.anArray = [NSMutableArray arrayWithCapacity:10];
}
[return self];
This is no longer identified as a memory leak in instruments. And since it's a convenience method, anArray is autoreleased. However, if I am to assume that the instance declaration in the header allocates memory, which would explain the previous issue, then should I still release anArray? Does setting the initial values in this way retain it perhaps?
I understand the difference between
NSMutableArray *anArray = [[NSMutableArray alloc] initWithCapacity:10];
and
NSMutableArray *anArray = [NSMutableArray arrayWithCapactiy:10];
but what I'm not sure I understand is when you've declared NSMutableArray *anArray in your header, which of the two approaches you should use and why. And whether or not if you use the second approach, you should still release anArray when you call dealloc.
I might add that I've found the following posts/links useful:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
分配一个对象时,其引用计数为 1。
设置具有“retain”属性的属性也会增加引用计数。
所以,这意味着这通常是不好的:
...
因为变量现在的引用计数为 2。
当设置对象的成员变量时,只需执行以下操作:
您还应该意识到这有效,
因为“arrayWithCapacity”(以及其他类似的因子方法) 自动释放它返回的对象,因此在设置该属性后,它的引用计数基本上为 1。
alloc'ing an object starts it off with a reference count of 1.
Setting a property that has the 'retain' attribute also increases the reference count.
So, that means this is usually bad:
...
Because variable now has a reference count of 2.
When setting a object's member variable, just do this:
You should also realize that this works
Because "arrayWithCapacity" (and other similar factor methods) autoreleases the object it returns, so after you set the property, it essentially has a reference count of 1.
分配内存的不是实例。您可以正确地假设在 Objective-C 中(至少在所有基于 Apple 的操作系统上),新初始化的类将所有 ivars 设置为 0(或 nil 或 NULL,视情况而定)。
您看到的问题是您正在使用该属性,而不是初始化中的 ivar。由于您将属性声明为retain,因此使用属性访问器设置它会自动保留它。
因此,当您初始化时,您要么必须取得所有权并直接设置 ivar,要么像您正在做的那样并使用属性访问器来设置属性,然后在 init 方法中放弃所有权(通过释放您拥有的对象或,就像您在第二个实例中所做的那样,使用方便的构造函数,这样您就永远不会拥有返回的实例)。
所以请记住,如果您曾经使用过属性访问器,即使在类本身内,您也将获得您在属性上设置的功能(例如,非原子、保留等)。每当您执行以下操作之一时,您就可以使用属性访问器:
您将直接访问您的 ivar,如下所示:
It's not the instance that allocates the memory. You're right to assume that in Objective-C (at least on all Apple-based operating systems), newly initialized classes have all their ivars set to 0 (or nil or NULL as appropriate).
The problem you're seeing is that you're using the property, not the ivar in your initialization. Since you declared your property as retain, using the property accessor to set it automatically retains it.
So, when you initialize you either have to take ownership and set the ivar directly, or do like you're doing and use the property accessor to set the property and then relinquish ownership in the init method (by either releasing an object you own or, as you did in your second instance, using the convenience constructor so that you never owned the returned instance).
So just remember, if you ever use the property accessors, even within the class itself, you will get the features you set on the property (e.g., nonatomic, retain, etc.). You use the property accessors whenever you do one of the following:
You would access your ivar directly like: