【问题标题】:Instruments Leaks shows non-existent method callInstruments Leaks 显示不存在的方法调用
【发布时间】:2011-12-27 17:17:48
【问题描述】:

要么我根本不懂 Instruments Leaks 工具,要么我快疯了。我已经在我的 iphone 应用程序上运行了该工具,它显示了一些泄漏。如果我理解正确,对于其中一个泄漏,它说它是由我的方法“writeHeading”分配的 NSDate 对象。分配对象的方法是:“dateWithTimeIntervalSinceReferenceDate:”。但是,我的 writeHeading 方法没有使用该方法。事实上,我的整个应用程序中的任何地方都没有使用该方法。

有人知道这里会发生什么吗?

这是writeHeading的代码:

- (void) writeHeading:(CLHeading *)heading
{
    if (self.inFlight) {
        [log writeHeading:heading];
    } else {
        IGC_Event *event = [[IGC_Event alloc] init];
        event.code = 'K';
        event.timestamp = heading.timestamp;    
        event.heading = heading;
        [self addEvent:event];
        [event release];
    }
}

这是 Instruments 的截图:

这是 IGC_Event 的定义(根据多个响应者的要求):

@interface IGC_Event : NSObject {
    int code;
    CLLocation *location;
    CLHeading *heading;
    NSString *other;
    NSDate *timestamp;
}

@property int code;
@property (nonatomic, retain) CLLocation *location;
@property (nonatomic, retain) CLHeading *heading;
@property (nonatomic, retain) NSString *other;
@property (nonatomic, retain) NSDate *timestamp;

@end


@implementation IGC_Event

@synthesize code;
@synthesize location;
@synthesize heading;
@synthesize other;
@synthesize timestamp;

@end

【问题讨论】:

  • IGC_Event 是否释放其 dealloc 方法中的时间戳和标题?
  • 应该的。 IGC_Event 时间戳只是具有合成 getter 和 setter 的属性。我将在问题中添加 IGC_Event 的定义以明确说明
  • 好的,但你是在 dealloc 中释放它们吗?请问可以包含dealloc方法吗?
  • 现在问题中显示了完整的定义。 @synthesize 指令应生成具有正确释放调用的 dealloc 方法。你认为我应该添加一个空的dealloc吗?
  • 不,dealloc 方法不是由@synthesize 生成的。所以有你的泄漏(实际上是 4 个潜在的泄漏)。我将其添加为答案

标签: ios xcode instruments memory-leaks


【解决方案1】:

假设没有 ARC,您需要确保 IGC_Event 对象释放其时间戳和其他可能已保留或复制的引用。

所以在 IGC_Event 中你需要一个这样的 dealloc:

- (void) dealloc {

    [timestamp release];
    [location release];
    [heading release];
    [other release];


    [super dealloc];
}

Leaks 只是告诉您该时间戳对象是在哪里创建的,而不是您应该在哪里发布它。

当然,这可能不是您唯一泄漏的地方,但那里有 4 个潜在的泄漏点。

【讨论】:

  • 该死,你当然是完全正确的。在我看来,我将 XCode 4 的新自动保留管理与旧方法混为一谈。由于我还没有切换到新方法,我应该自己发布。非常感谢
【解决方案2】:

当编译器运行您的代码时,有您直接调用的方法(在您的屏幕截图中,它们旁边有一个小人物),然后是在核心框架中调用的方法。有问题的方法来自这段代码:

event.timestamp = heading.timestamp;

如果您愿意,您可以自己管理此过程:

NSDate *eventTimestamp = heading.timestamp;
event.timestamp = eventTimestamp;

顺便说一句,存储该时间戳是完全多余的,并且使用了不必要的内存,因为您还将标题及其所有属性存储在 event.heading 中,因此您可以随时使用event.heading.timestamp 访问该时间戳。但是,您可能有其他原因将其单独存储。

【讨论】:

  • 谢谢。我已经按照您显示的方式重写了它,现在 dateWithTimeIntervalSinceReferenceDate 显示在您的两行中的第一行。您知道 dateWithTimeIntervalSinceReferenceDate 调用的来源吗?我知道存储时间戳是重复的,但这样更容易:IGC_Event 还可以存储除了 CLHeading 之外的其他对象,这些对象本身可能没有时间戳。
  • 猜测,但可能每次复制 NSDate 对象时都会调用它,或者 CLHeading 时间戳不是 NSDate 对象,而是可以分配给一个但需要这些方法调用的日期类型在引擎盖下实现它。无论哪种方式,它都是您可以放心忽略的实现细节。 :)
  • 我猜你是对的。也许 CLHeading 时间戳获取器是由编译器内联的,或者其他什么。所以我想我需要专注于如何处理导致它泄漏的时间戳。
【解决方案3】:

你有IGC_Event 类的实现吗?其timestamp 属性的设置器是否有可能调用dateWithTimeIntevalSinceReferenceDate:? (据我所知,这不是一件不合理的事情。这将确保其时间戳本身属于 NSDate 类,而不是子类。它还将确保它独立于传入的时间戳。)

(免责声明:我真的不是一个Objective-C-er。如果这看起来像一个愚蠢的问题,那么它可能是!)

【讨论】:

  • 这当然不是一个愚蠢的问题,如果 IGC_Event 是这样定义的,它可能就是问题所在。但是 IGC_Event 中的时间戳只是一个 @property(非原子,保留)NSDate *timestamp,具有合成的 setter 和 getter。那里没有什么特别的东西。
猜你喜欢
  • 2010-10-18
  • 2011-06-08
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 2010-09-27
  • 2012-05-14
  • 1970-01-01
  • 2011-10-10
相关资源
最近更新 更多