内存管理 - 如何最好地初始化标头中声明的实例

发布于 2024-09-26 08:23:39 字数 2306 浏览 7 评论 0原文

我读过一些关于此的文章,但仍有一件事我不清楚。我知道这可能是一个很棘手的问题,但实际上我已经进行了相当长的开发,但还没有完全掌握这个基本问题。我猜这是自学的症状。

您在标头中声明一个变量,如下所示:

@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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猥︴琐丶欲为 2024-10-03 08:23:40

分配一个对象时,其引用计数为 1。
设置具有“retain”属性的属性也会增加引用计数。

所以,这意味着这通常是不好的:

@property (nonatomic, retain) Object * variable;

...

self.variable = [[Object alloc] init];

因为变量现在的引用计数为 2。

当设置对象的成员变量时,只需执行以下操作:

variable = [[Object alloc] init];

您还应该意识到这有效,

        self.anArray = [NSMutableArray arrayWithCapacity:10];

因为“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:

@property (nonatomic, retain) Object * variable;

...

self.variable = [[Object alloc] init];

Because variable now has a reference count of 2.

When setting a object's member variable, just do this:

variable = [[Object alloc] init];

You should also realize that this works

        self.anArray = [NSMutableArray arrayWithCapacity:10];

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.

月下客 2024-10-03 08:23:40

分配内存的不是实例。您可以正确地假设在 Objective-C 中(至少在所有基于 Apple 的操作系统上),新初始化的类将所有 ivars 设置为 0(或 nil 或 NULL,视情况而定)。

您看到的问题是您正在使用该属性,而不是初始化中的 ivar。由于您将属性声明为retain,因此使用属性访问器设置它会自动保留它。

因此,当您初始化时,您要么必须取得所有权并直接设置 ivar,要么像您正在做的那样并使用属性访问器来设置属性,然后在 init 方法中放弃所有权(通过释放您拥有的对象或,就像您在第二个实例中所做的那样,使用方便的构造函数,这样您就永远不会拥有返回的实例)。

所以请记住,如果您曾经使用过属性访问器,即使在类本身内,您也将获得您在属性上设置的功能(例如,非原子、保留等)。每当您执行以下操作之一时,您就可以使用属性访问器:

// in these cases the property takes ownership through the
// retain keyword, so you must not take ownership yourself
self.anArray = something;
[self setAnArray:something];
[self setValue:something forKey:@"anArray"];

您将直接访问您的 ivar,如下所示:

anArray = something; // in this case you must take ownership

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:

// in these cases the property takes ownership through the
// retain keyword, so you must not take ownership yourself
self.anArray = something;
[self setAnArray:something];
[self setValue:something forKey:@"anArray"];

You would access your ivar directly like:

anArray = something; // in this case you must take ownership
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文