【问题标题】:Memory Leak - Instruments, Objective-C内存泄漏 - Instruments,Objective-C
【发布时间】:2011-06-07 08:40:54
【问题描述】:

我有一个 UITextField,在委托类中我有一个 UITableView。代码如下:

- (BOOL) textField: (UITextField *)theTextField shouldChangeCharactersInRange: (NSRange)range replacementString: (NSString *)string {    
    value = [[theTextField.text stringByReplacingCharactersInRange:range withString:string] retain];

    [valueTable reloadData];

    return YES;
}

"value" 是一个 NSString,在我的班级顶部声明为 "NSString *value;"而“valueTable”只是一个 UITableView。当我测试内存泄漏时,我在 "value = [[theTextField.text stringByReplacing..." 行上得到 "100%" 内存泄漏,我尝试删除该行上的 "retain"。但是后来当我调用“值”时,它是 nil,这不好。

那么我该如何修复内存泄漏呢?什么是内存泄漏?谢谢!

【问题讨论】:

    标签: objective-c uitableview memory uitextfield memory-leaks


    【解决方案1】:

    你应该在完成后释放value。例如,您可以在委托的dealloc 方法中释放它:

    - (void)dealloc {
        [value release];
        // other memory management code...
        [super dealloc];
    }
    

    请参阅 Apple 关于内存管理的文档。

    【讨论】:

    • 这仅在您假设 stringByReplacingCharactersInRange 方法仅被调用一次时才是正确的。例如,如果该方法被调用 4 次,那么您将泄漏该内存 3 次,并且仅正确释放一次。 (当他的班级被释放时。)
    【解决方案2】:

    被泄露的内存是value指向的内存。

    每次您的文本字段更改时,stringByReplacingCharactersInRange... 方法都会返回一个自动释放的 NSString 对象。保留它是正确的,这样它就不会被释放。问题是你现在在某个地方拥有记忆。 (您通过保留它来拥有该 NSString。)

    下次调用该方法时,当用户更改该字段中的文本时,您会将value 指向一个完全不同的内存位置。你所保留的原始记忆仍然存在,并将继续永远存在。 (因为你从未发布过它。)

    将任何retain 方法调用与关联的release 匹配是非常重要。你可以这样做:

    ...
    if (value) {
       [value release];
    }
    value = ...;
    ...
    

    您可以将NSString *value 定义为您的类的属性,例如:

    @property (nonatomic, retain) NSString *value);
    
    /* Implementation file */
    @synthesize value;
    

    然后简单地使用:

    ...
    self.value = ...;
    ...
    

    此外,由于在调用该方法后您总是会保留内存,因此您需要在释放您的类时释放 value,正如另一个答案中提到的那样:

    - (void)dealloc {
        // Only do *one* of the two following releases
    
        // (1) If you're not using properties:
        [value release];
    
        // (2) If you are using properties:
        self.value = nil;
    
        [super dealloc];
    }
    

    编辑: 听起来您在继续之前绝对应该阅读 Apple 的内存管理指南: http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/MemoryMgmt/MemoryMgmt.html

    【讨论】:

    • 第一个示例中的 if (value) 语句是不必要的。如果valuenil,那么[value release]; 将什么也不做,如果不是,它将被释放。
    • 非常正确。这只是我在某处养成的习惯。
    【解决方案3】:

    正如其他人所提到的,问题出在以下行:

    value = [[theTextField.text
           stringByReplacingCharactersInRange:range withString:string] retain];
    

    此代码的问题是您没有在分配新值之前释放 value 的旧值。如果其他地方没有其他不可预见的问题,将代码更改为以下内容应该可以修复泄漏:

    - (BOOL)textField:(UITextField *)theTextField
           shouldChangeCharactersInRange:(NSRange)range
               replacementString:(NSString *)string {
    
        NSString *newValue = [[theTextField.text
           stringByReplacingCharactersInRange:range withString:string] retain];
        [value release];
        value = newValue;
    
        [valueTable reloadData];
    
        return YES;
    }
    
    - (void)dealloc {
       [value release];
       [super dealloc];
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-26
      • 2011-06-07
      • 1970-01-01
      • 2011-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多