0

我有一个小项目,我注意到我的代码中有很多漏洞。所以我开始使用自动释放。但有时,我只是无法摆脱泄漏或使用自动释放导致分析器告诉自动释放太多。这是一个返回类属性标题的函数,其中包含字体、阴影和与当前秒的对齐。我一直在玩它一段时间,试图意识到我做错了什么。有人可以看看它并告诉我哪里出错了吗?

- (NSAttributedString *)attributedTitle {
    NSMutableParagraphStyle *pStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
    [pStyle setAlignment: NSCenterTextAlignment];

    NSShadow *pShadow = [[[NSShadow alloc] init] autorelease];  

    [pShadow setShadowColor: [NSColor colorWithSRGBRed:0.11 green: 0.11 blue:0.11 alpha: 0.67]];
    [pShadow setShadowBlurRadius: 1.0];
    [pShadow setShadowOffset: NSMakeSize(0,1)];
    [pShadow set];

    NSMutableDictionary *attributes = [[[[NSMutableDictionary alloc] initWithObjectsAndKeys:
                                         [NSFont fontWithName: @"Arial Bold" size: 11], NSFontAttributeName,
                                         [NSColor colorWithDeviceWhite: 1.0 alpha: 0.83], NSForegroundColorAttributeName,
                                         pStyle, NSParagraphStyleAttributeName,
                                         pShadow, NSShadowAttributeName,
                                         nil] mutableCopy] autorelease];



    NSString *text = [[[NSString alloc] initWithFormat: @"%d", [[[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar]
                                                        components: NSSecondCalendarUnit fromDate: [[NSDate alloc] init]]second]] autorelease];

    NSAttributedString *result = [[[NSAttributedString alloc] initWithString: text attributes: attributes] autorelease];

    return result;

}

起初,这被缩短了很多 - 如果我不能使用变量,我不会使用变量,但我添加了变量并且它变得更长 - 所以这实际上只是泄漏和自动释放的一个例子。

我很确定这也可以做得更简单,但是现在我担心正确使用自动释放以及如何消除泄漏。以及为什么我有泄漏(我还有更多的代码)如果我意识到出了什么问题,我可以修复..)


好的,我把它整理好了..没有泄漏 - 缩短了..

- (NSAttributedString *)attributedTitle {
    NSMutableParagraphStyle *pStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
    [pStyle setAlignment: NSCenterTextAlignment];

    NSShadow *pShadow = [[[NSShadow alloc] init] autorelease];  

    [pShadow setShadowColor: [NSColor colorWithSRGBRed:0.11 green: 0.11 blue:0.11 alpha: 0.67]];
    [pShadow setShadowBlurRadius: 1.0];
    [pShadow setShadowOffset: NSMakeSize(0,1)];
    [pShadow set];

    NSDictionary *attributes = [[[NSDictionary alloc] initWithObjectsAndKeys:
                                [NSFont fontWithName: @"Arial Bold" size: 11], NSFontAttributeName,
                                [NSColor colorWithDeviceWhite: 1.0 alpha: 0.83], NSForegroundColorAttributeName,
                                pStyle, NSParagraphStyleAttributeName,
                                pShadow, NSShadowAttributeName,
                                nil] autorelease];

    NSDateComponents *dc = [[[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar] autorelease]
                            components: NSSecondCalendarUnit fromDate: [[[NSDate alloc] init] autorelease]];

    return [[[NSAttributedString alloc] initWithString: [[[NSString alloc] initWithFormat: @"%d", [dc second]] autorelease] attributes: attributes] autorelease];
}

但是那又如何呢?

SInt32 CFWeeksInYear(NSUInteger year)
{
    NSDateFormatter *dateFormat = [[[NSDateFormatter alloc] init] autorelease];
    [dateFormat setDateFormat:@"dd.MM.YYYY"];
    NSDate *tempMonth = [[[NSDate alloc] initWithString: [[[NSString alloc] initWithFormat: @"31.12.%ld", year] autorelease]] autorelease];
    SInt32 result = CFAbsoluteTimeGetWeekOfYear([tempMonth timeIntervalSinceReferenceDate], CFTimeZoneCopyDefault());
    return result;
}

SInt32 CFWeekOfYear(CFGregorianDate tempMonth)
{
    CFAbsoluteTime tempDate = CFGregorianDateGetAbsoluteTime (tempMonth, CFTimeZoneCopyDefault());
    return CFAbsoluteTimeGetWeekOfYear(tempDate, CFTimeZoneCopyDefault());
}

它泄漏在:

SInt32 result = CFAbsoluteTimeGetWeekOfYear([tempMonth timeIntervalSinceReferenceDate], CFTimeZoneCopyDefault());

和:

CFAbsoluteTime tempDate = CFGregorianDateGetAbsoluteTime (tempMonth, CFTimeZoneCopyDefault());

甚至在:

return CFAbsoluteTimeGetWeekOfYear(tempDate, CFTimeZoneCopyDefault());

几乎就像它与 CFTimeZoneCopyDefault() 有关但它不应该返回一个指针..

4

2 回答 2

2

您坚持认为CFTimeZoneCopyDefault“不应该返回指针......”但确实如此。

CFTimeZoneCopyDefault返回一个CFTimeZoneRef。让我们找出那是什么:

typedef const struct __CFTimeZone * CFTimeZoneRef;

是的,它是一个指针。

这个指针不是对 Cocoa 对象的引用,但它仍然是对分配的内存的引用。我们从 Core Foundation 中的函数命名约定中知道,任何带有单词“copy”的 CF 函数都在分配内存。这意味着您可以确保在使用完内存后释放内存。

释放内存* 的一种方法是使用 Core Foundation 函数CFRelease()。考虑到这一点,让我们重新审视一下您的代码:

SInt32 CFWeekOfYear(CFGregorianDate tempMonth)
{
    CFAbsoluteTime tempDate = CFGregorianDateGetAbsoluteTime (tempMonth, CFTimeZoneCopyDefault());
    return CFAbsoluteTimeGetWeekOfYear(tempDate, CFTimeZoneCopyDefault());
}

我们可以保留对 的引用CFTimeZoneRef,然后在完成后将其处理掉:

SInt32 CFWeekOfYear(CFGregorianDate tempMonth)
{
    CFTimeZoneRef tzRef = CFTimeZoneCopyDefault();
    CFAbsoluteTime tempDate = CFGregorianDateGetAbsoluteTime (tempMonth, tzRef);
    SInt32 result = CFAbsoluteTimeGetWeekOfYear(tempDate, tzRef);
    CFRelease(tzRef);
    return result;
}

当然,实际应用程序会检查 NULL 响应(等等),但您明白了。

关于自动释放:它不是解决内存管理问题的灵丹妙药。在您的示例中,您做得很好,但是我看到设计不良的应用程序耗尽了物理 RAM,因为自动释放池变得如此之大。在循环和递归方法等地方小心依赖自动释放的对象;您可以明智地分配自己的自动释放池(并释放它们)以避免此类问题。在这个论坛里,我只能这么啰嗦,所以我推荐阅读:

Apple 内存管理指南

祝你在你的努力中好运。

*CFTimeZone与其对应的 Cocoa 是“免费桥接”的NSTimeZone,这意味着您也可以将release消息发送给它(强制转换为NSTimeZone *)。

于 2012-04-05T20:24:07.143 回答
0

这就是你释放 CF 的方式。

CFTimeZoneRef tz = CFTimeZoneCopyDefault();

/* Do what you need to do with it */

CFRelease(tz);
于 2012-04-05T20:44:23.803 回答