【问题标题】:How am I mismanaging my iPhone's memory?我对 iPhone 的内存管理不善怎么办?
【发布时间】:2009-09-01 08:15:32
【问题描述】:

此代码有效:

猴子.h

@interface monkey : NSObject {
NSNumber *monkeyRanch;
}
@property (nonatomic, retain) NSNumber *monkeyRanch;
-(id) gatherTheMonkeys:(int)howmany;

猴子.m

@synthesize monkeyRanch;
-(id) gatherTheMonkeys:(int)howmany{
NSNumber *temp=[[NSNumber alloc] initWithInt:howmany];
monkeyRanch = temp;
[temp release];
return [monkeyRanch autorelease];
}

appDelegate.m

theMonkeys = [[monkey alloc] gatherTheMonkeys:3];
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];

..和 theMonkeys 在 dealloc 中释放。仪器没有泄漏。 但是,如果我尝试使用NSMutable 数组而不是NSNumber

猴子.h

@interface monkey : NSObject {
    NSMutableArray *monkeyRanch;
}
@property (nonatomic, retain) NSMutableArray *monkeyRanch;
-(id) initTheMonkeys:(int)howmany;

猴子.m @synthesize monkeyRanch;

-(id) initTheMonkeys:(int)howmany{
monkeyRanch=[[NSMutableArray alloc] init];
NSNumber *imp =[[NSNumber alloc] initWithInteger:howmany];
[monkeyRanch addObject:imp];
[imp release];
return [monkeyRanch autorelease];
}

appDelegate

theMonkeys = [[monkey alloc] initTheMonkeys:3];
[theMonkeys retain];

这会在应用程序开始时导致(对象“猴子”)泄漏。

我尝试将initTheMonkeys 更改为以下内容:

NSMutableArray *temp=[[NSMutableArray alloc] init];
monkeyRanch=temp;
[temp release];
NSNumber *imp =[[NSNumber alloc] initWithInteger:howmany];
[monkeyRanch addObject:imp];
[imp release];
return [monkeyRanch autorelease];

monkeyRanch 的保留计数在释放 temp 时变为零,应用程序愉快地崩溃了。

我做错了什么,我该如何解决?

【问题讨论】:

  • 猴子牧场是什么鬼?那应该是“monkeyWrench”吗? :)

标签: iphone cocoa-touch memory-management


【解决方案1】:

您的记忆问题归结为所有权问题。当一个类有一个实例变量(如monkeyRanch)时,你通常会在该类的初始化器中创建一个实例,然后在dealloc 中释放它,如下所示:

@interface Monkey : NSObject {
    NSMutableArray * monkeyRanch;
}
@end

@implementation Monkey
- (id)init {
    if ((self = [super init]) == nil) { return nil; }
    monkeyRanch = [[NSMutableArray alloc] initWithCapacity:0];
    return self;
}
- (void)dealloc {
    [monkeyRanch release];
}
@end

在这种情况下,Monkey 类拥有 monkeyRanch 成员。

在函数调用中,您必须确保release 任何您initretaincopy本地 对象。看起来你的这部分是正确的,但我还是会展示一个简单的例子:

- (void)someFunction {
    NSNumber * myNumber = [[NSNumber alloc] init];
    ...
    [myNumber release];
}

接下来要了解的是,简单地设置成员变量和设置属性值之间存在巨大的区别。也就是说:

NSMutableArray * temp = [[NSMutableArray alloc] initWithCapacity:0];
monkeyRanch = temp;
[temp release]; // it's gone!

与以下内容相同:

NSMutableArray * temp = [[NSMutableArray alloc] initWithCapacity:0];
self.monkeyRanch = temp; // now owned by self
[temp release];

在第一种情况下,您只需将指针 (monkeyRanch) 设置为等于另一个指针 (temp)。该值不会被保留或复制。

在第二种情况下,您实际上是在设置属性。这意味着,假设属性设置为保留,则数组现在归您的类对象所有。

附注:

您也可能在设计方面走错了路。在我看来,猴子牧场是里面有很多猴子的地方。如果这是真的,那么您的 Monkey 对象真的不应该拥有 MonkeyRanch。相反,我会选择这样的东西:

Monkey.h

@class MonkeyRanch;

@interface Monkey : NSObject {
    MonkeyRanch * ranch;
}
@property (nonatomic, assign) MonkeyRanch * ranch;
@end

Monkey.m

@implementation Monkey
@synthesize ranch;
@end

MonkeyRanch.h

#import "Monkey.h"

@interface MonkeyRanch : NSObject {
    NSMutableArray * monkeys;
}
@property (nonatomic, retain) NSMutableArray * monkeys;
- (id)initWithNumberOfMonkeys:(int)howMany;
- (void)dealloc;
@end

MonkeyRanch.m

@implementation MonkeyRanch

@synthesize monkeys;

- (id)initWithNumberOfMonkeys:(int)howMany {
    if ((self = [super init]) == nil) { return nil; }

    monkeys = [[NSMutableArray alloc] initWithCapacity:howMany];
    for (int index = 0; index < howMany; index++) {
        Monkey * newMonkey = [[Monkey alloc] init];
        [newMonkey setRanch:self];
        [monkeys addObject:newMonkey];
        [newMonkey release];
    }

    return self;
}

- (void)dealloc {
    [monkeys release];
}

@end

用法:

#import "MonkeyRanch.h"

MonkeyRanch * theRanch = [[MonkeyRanch alloc] initWithNumberOfMonkeys:3];

...

[theRanch release];

【讨论】:

  • 谢谢詹姆斯!我错过了属性值和成员变量设置的差异。而且我一直想返回属性而不是类对象本身。如果我猜对了,我现在可以像 theRanch.monkeys 那样访问我的类属性(猴子数组)了吗? (我试图做的事情有什么解决方案吗?)
  • 是的,您可以通过theRanch.monkeys 访问阵列。你现在明白了 :) 但老实说,我不太确定你想要做什么。也许您应该发布另一个 SO 问题,如“您将如何为此类数据构建一个类?”
【解决方案2】:

确实,你错过了这个:

theMonkeys = [[monkey alloc] initTheMonkeys:3];
[theMonkeys retain];

当你“初始化”某些东西时,你最终会得到一个隐含的“保留”(保留计数为 1)。有你的泄漏;你正在初始化它保留它。

【讨论】:

  • 如果删除了保留,返回的自动释放对象会将猴子拖到 0 保留计数和程序... :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-10
  • 2011-10-10
  • 2010-10-28
相关资源
最近更新 更多