内存泄漏 - 格式化字符串以每秒显示时间

时间:2009-06-22 01:12:57

标签: iphone objective-c cocoa-touch memory

嘿伙计们。我有一个方法每秒调用一次,我想用它来显示我的应用程序一直在做它的工作时间。目前我正在使用的类(我没有创建)有一个名为progress的属性,它存储了总秒数。

我已经写了一些代码,它需要这些秒并将其格式化为可读字符串。我是新手,所以请原谅我,如果这不是最好的代码。我欢迎任何建议:

// hours, minutes, and seconds are instance variables defined as integers
int totalSeconds = (int)streamer.progress;

hours = totalSeconds / (60 * 60);

if (hours > 0)
    formattedTimeString = [NSString stringWithFormat:@"%d:", hours]; // WRONG

minutes = (totalSeconds / 60) % 60;
seconds = totalSeconds % 60;
[formattedTimeString stringByAppendingFormat:@"%d:%d", minutes, seconds]; // WRONG

基本上我希望它显示为“3:35”,例如显示3分35秒。我只想显示小时部分,如果它是一个小时,在这种情况下它将是“2:3:35”例如(任何人都可以推荐一种更好的格式化方法吗?)。

我遇到的问题是我实际创建/设置字符串的位置(标记为错误的行)。由于这是每秒完成的,如果我不断要求新的字符串对象,我很容易就会泄漏。我想我可以通过在方法结束时释放foramttedTimeString来解决这个问题,但这是否是正确的方法呢? NSMutableString会以任何方式帮助吗? Cocoa还有更好的方法吗?我已经在#iphonedev @ freenode询问,他们说我必须自己写这个方法,但我想我会再问一次。

提供上下文:这是一个互联网广播流媒体应用程序(我知道已有很多,但我只是练习)。我希望能够显示流媒体播放的时间。

对不起,如果这个问题很愚蠢,嘿,就像我说我是新手一样。

4 个答案:

答案 0 :(得分:4)

我会这样做:

int totalSeconds = (int)streamer.progress;
hours = totalSeconds / (60 * 60);
minutes = (totalSeconds / 60) % 60;
seconds = totalSeconds % 60;

if ( hours > 0 ) {
    formattedTimeString = [NSString stringWithFormat:@"%d:%02d:%02d", hours, minutes, seconds];
} else {
    formattedTimeString = [NSString stringWithFormat:@"%d:%02d", minutes, seconds];
}

现在最后,formattedTimeString是所需的时间,但你不“拥有”它 - 你必须保留它,或者如果你想保留它,就把它存储在“copy”属性中。

请注意,%02d会为您提供两个数字,即零填充数字,这通常是您在部分时间内所需的数字。

要了解如何使用stringByAppendingFormat,它看起来像这样:

NSString* formattedTimeString = @"";
if ( hours > 0 ) {
    formattedTimeString = [formattedTimeString stringByAppendingFormat:@"%d:", hours];
}
formattedTimeString = [formattedTimeString stringByAppendingFormat:@"%d:%02d", minutes, seconds];

然而在这种情况下,你会得到像3:4:05这样的时间,而不是更理想的3:04:05。

请注意,每次都会覆盖formattedTimeString,但这样就可以了,因为你不会随时“拥有”它,所以你不负责释放它。

最后,要使用可变字符串查看它,它可能如下所示:

NSMutableString* formattedTimeString = [NSMutableString string];
if ( hours > 0 ) {
    [formattedTimeString appendFormat:@"%d:", hours];
}
[formattedTimeString appendFormat:@"%d:%02d", minutes, seconds];

同样,时间结果是不受欢迎的3:4:05,并且你最后没有自己的formattedTimeString,所以它必须保留或存储一个copy属性以保持它。

答案 1 :(得分:2)

要将增量知道为时间单位,您还可以执行以下操作:

// as part of init...
self.gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];


// in the timer or wherever you are tracking time deltas...
static NSUInteger unitFlags = 
    NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;

NSDateComponents *components = [gregorian components:unitFlags
                        fromDate:myBaseTime
                          toDate:[NSDate date] options:0];

然后您可以使用类似[components minute]的内容来引用这些部分。 请记住,您必须在dealloc中发布日历。

答案 2 :(得分:1)

你的代码看起来很不错。您没有泄漏任何内存,因为您创建的字符串对象的保留计数为零,系统将清除它。但是,如果formattedTimeString不是函数中的局部变量,则需要在结尾处保留它以防止这种情况发生!为此,您需要将[formattedTimeString retain]添加到代码块的末尾,然后在替换字符串对象之前添加[formattedTimeString release]。

作为一般规则,名称包含“alloc”,“copy”,“create”和“new”的函数返回已保留的对象(意味着它们的保留计数为+1)。当你完成使用它们时,你有责任对这些对象进行释放或自动释放 - 或者它们只是开始堆积在内存中。

“stringWithFormat:”,“imageNamed:”和“arrayWithCapacity:”之类的函数都返回保留计数为零的对象 - 因此您可以安全地丢弃它们(就像您在代码示例中一样)。如果你想保留它们,你应该调用retain来确保在你使用它们时不会清理它们。

所有这一切,我认为主要的问题是你使用stringByAppendingFormat:。由于您使用的NSString不可变,因此该调用返回 new 字符串。你想说:

formattedTimeString = [formattedTimeString stringByAppendingFormat:@“%d:%d”,分钟,秒];

或者,您可以使用NSMutableString。既然这是你一遍又一遍地做的事情,我建议你这样做。从技术上讲,无论哪种方式都很好。

希望有所帮助!整个保留/释放事情可能会让人感到困惑。请记住,每个对象都有一个“retainCount”,一旦它达到零,就不知道该对象或它的数据会发生什么。

答案 3 :(得分:0)

嘿谢谢你们,我很欣赏这些回复。

我最终做到了这一点,但它确实有效,但我想知道你们是否看到它有任何问题:

int totalSeconds = (int)streamer.progress;

[formattedTimeString setString:@""];

hours = totalSeconds / (60 * 60);

if (hours > 0)
    [formattedTimeString appendFormat:@"%d:", hours];

minutes = (totalSeconds / 60) % 60;
seconds = totalSeconds % 60;

[formattedTimeString appendFormat:@"%02d:%02d", minutes, seconds];

然后当然在viewDidLoad我实例化实例变量formattedTimeString

formattedTimeString = [[NSMutableString alloc] initWithCapacity:8];

我没有在第一个代码片段中保留/释放,因为我认为没有必要,但我可能是错的。然而,我在dealloc方法中释放,所以我应该没事。