1

假设我有一个类似的界面:

@interface it:NSObject
{
  NSString* string;
}
@end

@implement it
-(id)init
{
  if(self = [super init]){
    self.string = [[NSString alloc]init];
  }
}

-(void)dealloc
{
   [self.string release];
   [super release];
}
@end

如果我在另一个文件中使用这个类,我称之为:

it ait = [[it allow] init];
NSString* anotherString = [[NSString alloc] init];
ait.string = anotherString;
[anotherString release];

这会导致在它的 init 方法中分配的字符串发生内存泄漏吗?由于该字符串未被引用且未被自动释放。如果我不在 init 方法中分配一个字符串,那么当我在分配 anotherString 之前调用 ait.string 会发生什么?

4

4 回答 4

1

我想你需要

@property (nonatomic, retain) NSString *string;

在你的界面和

@synthesize string;

在您的实现中 self.string 工作。

然后,当你这样做

self.string = [[NSString alloc] init];

在您的 init 方法中,字符串实际上的保留计数为 2,因为[[NSString alloc] init]将返回保留计数为 1 的字符串,并且 usingself.string =将再次保留该对象,因为该属性被声明为“保留”。这将导致内存泄漏,但您可以通过以下方式修复:

-(id)init
{
  if(self = [super init]){
    self.string = @"initString";
  }
}

或类似的。

然后,在实际问题上,如果您按照上述操作,在重新分配 init 时分配的字符串不会泄漏,self.string =因为标记为“保留”的属性会在保留新对象之前释放其当前对象。

如果您没有self.string在 init 方法中分配一个字符串,那没关系,因为它self.string只会返回nil,然后您可以在程序中处理它。

于 2011-03-12T08:38:02.387 回答
0
@interface it:NSObject
{
  NSString* string;
}

//you should declare a property in order to call it with 'self' prefix
@property (nonatomic, retain) NSString* string;

@end


@implementation it

//you should synthesize your property
@synthesize string;

-(id)init
{
  if(self = [super init]){
    //you don't to initialize NSString right here (memory leak will have place)
    //self.string = [[NSString alloc]init];

    //you can store a default value like this (can be omitted):
    self.string = @"Default value";
  }
  return self;
}

-(void)dealloc
{
   [self.string release];
   [super release];
}
@end

在这个类中关于内存管理的一切都会好起来的。

于 2011-03-12T08:33:35.207 回答
0

这会导致在它的 init 方法中分配的字符串发生内存泄漏吗?由于该字符串未被引用且未被自动释放。

对,就是这样。你似乎明白了。

如果我不在 init 方法中分配一个字符串,那么当我在分配 anotherString 之前调用 ait.string 会发生什么?

您的意思是在以下情况下您不确定 unknownObject 指的是什么?:-

It *ait = [[It allow] init];
NSString *unknownObject = ait.string;

这是无稽之谈。您是否忘记添加访问器方法?

Objective-c 不使用“点语法”来访问实例变量,例如 Java。如果你有你的类'it'的一个实例,你只能通过调用访问器'getter'方法从该实例外部访问'string'变量。这不是可选的 self.string 只是方法调用 [self string] 的快捷方式,并且您显示的代码中不存在此方法。

假设访问器方法是在其他地方定义的,那么您称为 string 的实例变量(这是世界上最糟糕的变量名称)等于nil。在 Objective-c 中,您必须非常小心地处理 nil 对象,因为其行为不同于许多其他语言处理类似的null

在 Objective-c 中这很好:

NSString *nilString = nil;
[nilString writeToFile:@"/this_file_cannot_exist.data"];

许多其他语言会在这里崩溃或抛出异常;这可能很危险,因为操作可能会失败,但您的应用程序将继续运行。它也可能很棒,因为在其他语言中你会看到很多这样的..

someObject = controller.currentValue()
if( someObject!=null )
  someObject.writeToFile("myFile.data")

在 Objective-c 中根本不需要 'if(..)' 行。

您必须注意不要在 init 和 dealloc 方法中调用访问器方法,因为这可能会破坏子类。代替

- (void)dealloc {
   [self.string release]; // This is [[self string] release]
   ...

你应该只使用

- (void)dealloc {
   [string release];
   ...

除了危险之外,对 [self string] 的调用也是不必要的。在您的 init 方法中也是如此

if(self=[super init]){
  self.string = [[NSString alloc]init]; // shortcut for [self setString:[[NSString alloc] init]]
  ...

只需使用

if(self=[super init]){
  string = [[NSString alloc] init];
  ...
于 2011-03-12T09:36:32.157 回答
0

为了使用 self.string,您缺少 @property。

将此添加到您的 .h 文件中

@property (readwrite, copy) NSString *string;

使用 Copy 而不是 Retain 将防止字符串发生内存泄漏,即使您释放 anotherString。

于 2011-03-12T09:45:36.527 回答