类方法:是否正确避免内存泄漏?

时间:2010-02-06 11:43:25

标签: objective-c

首先,我是本网站的新用户,因此,请提前感谢您的帮助。

我的iPhone应用程序有一个类,其主要作用是封装我对来自Web服务器的一堆原始字节处理数据的方式。每当我需要从该数据中显示定义类型的信息时(例如,这些原始字节中包含的一条建议),我就调用方法getAdviceFromGame。此方法通过最后调用NSString类方法构建可显示的NSString(stringWithUTF8String类方法发回的对象是自动释放的,根据方法命名规则 - 没有init,名称中没有alloc)。请注意,我没有在我的方法名称中加上“New”,因为调用者不拥有该方法发回的对象。

以下是方法:

-(NSString*) getAdviceFromGame:(NSInteger)number
                    ofLine:(NSInteger)line {
// Returns the advice at line specified as argument.
NSInteger currentOffset;
NSRange currentRange;
NSInteger offsetAdvice;
NSInteger length;
char currentCString[100];

if (line == 1)
    offsetAdvice = OFF_ADVICE1;
else
    offsetAdvice = OFF_ADVICE2;

// Length is the same whateve is the line.
length = LEN_ADVICE1;

// Point to the begnning of the requested game.
currentOffset = OFF_G1_SET + (number - 1) * LEN_SET;
// Point to the selected advice.
currentOffset = currentOffset + offsetAdvice;
// Skip TL
currentOffset = currentOffset + 2;

currentRange.location = currentOffset;
currentRange.length = length;

NSLog(@"Avant getBytes");

// Get raw bytes from pGame.
// Contains a C termination byte.
[pGame getBytes:currentCString range:currentRange];

// Turn these raw bytes into an NSString.
// We return an autoreleased string.
return [NSString stringWithUTF8String:currentCString];

}

从我的观点来看,这种方法并不重要,从内存管理的角度来看,因为我只发回一个“自动释放”的对象。注意:pGame是NSData类型的内部类变量。

在我的应用程序中,为了理解自动释放对象的行为方式,我在 - (void)applicationDidFinishLaunching:(UIApplication *)应用程序函数中循环了10000次这个方法,并且在 - (void)tabBarController中也是10000次相同的方法:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController。这样,我可以调用大量的分配。

在代码执行期间,当应用程序启动时,我可以通过alloc测量工具看到分配的对象大小正在增长(从400K到800K)。然后,当applicationDidFinishLaunching方法结束时,金额将降至400K。因此我猜这个池已被操作系统“排干”(垃圾管理的种类)。

当我点击标签栏时,由于循环,再次进行大量分配。此外,我可以看到大小增长(因为分配和发送了数千个NSString)。完成后,大小将降至400K。

因此,我的第一个问题是: 问题1:我们能否准确知道何时自动释放池将被“排空”或“清除”? Q2:这是在OS / GUI方法结束时发生的,例如didSelectViewController吗? 问题3:调用getAdviceFromGame的人是否必须在使用之前保留我的方法发回的对象?

现在我有另一个(更复杂的)方法,我在内部分配一个可变字符串,我正在处理它,然后再发回NSString:

-(NSString*) getBiddingArrayFromGame:(NSInteger)number
                           ofRow:(NSInteger)row
                          ofLine:(NSInteger)line {
NSInteger offset;
char readByte;
NSMutableString *cardSymbol = [[NSMutableString alloc] initWithString:@""];
NSRange range;

// Point to the begnning of the requested game.
offset = OFF_G1_SET + (number - 1) * LEN_SET;

// Returns the array value from cell (row, line)
// We must compute the offset of the line.
// We suppose that the offset cannot be computed, but
// only deduced from line number through a table.
switch (line) {
    case 1:
        offset = offset + OFF_LINE1;
        break;
    case 2:
        offset = offset + OFF_LINE2;
        break;
    case 3:
        offset = offset + OFF_LINE3;
        break;
    case 4:
        offset = offset + OFF_LINE4;
        break;
    default:
        // This case should not happen but for robustness
        // we associate any extra value with a valid offset.
        offset = OFF_LINE4;
        break;
}

// Skip TL bytes
offset = offset + 2;

// From the offset and from the row value, we can deduce
// the offset in the selected line.
offset = offset + (row - 1);

// Now, we must read the byte and build a string from
// the byte value.
range.location = offset;
range.length = 1;
[pGame getBytes:&readByte range:range];

// We must extract the family type.
// If the family if of type "Special" then we must build by
// hand the value to display. Else, we must build a string
// with the colour symbol and associated character by reading
// in the card character table.
switch (readByte & CARD_FAMILY_MASK) {
    case COLOUR_CLUBS:
        // "Trèfles" in French.
        [cardSymbol appendString:CLUBS_UTF16];
        break;
    case COLOUR_DIAMONDS:
        [cardSymbol appendString:DIAMONDS_UTF16];
        break;
    case COLOUR_HEARTS:
        [cardSymbol appendString:HEARTS_UTF16];
        break;
    case COLOUR_SPADES:
        [cardSymbol appendString:SPADES_UTF16];
        break;
    case COLOUR_SPECIAL:
        break;
    case COLOUR_ASSET:
    default:
        break;
}

[cardSymbol autorelease];

// Return the string.
return [NSString stringWithString:cardSymbol];

}

正如您所看到的,这不是很复杂,但从内存管理的角度来看更为关键,因为我“内部”分配并初始化NSString。因为我在方法结束时使用它,我只能在调用stringWithString之前自动释放它:cardSymbol(实际上我想释放它以便它现在被释放)否则它可以在stringWithString:cardSymbol方法之前释放。好吧,我对这样做的方式不满意,但也许这是正确的方法。

因此,我的最后一个问题是:这是正确的方法吗?

我担心在到达stringWithString之前清除自动释放池:cardSymbol。

最诚挚的问候, 弗朗兹

2 个答案:

答案 0 :(得分:0)

  

问题1:我们能否准确知道何时自动释放池将“耗尽”或“清除”?

     

Q2:这是在OS / GUI方法结束时发生的,例如didSelectViewController吗?

是的,每个事件循环都会自动释放一次自动释放池。

  

问题3:调用getAdviceFromGame的人是否必须在使用之前保留我的方法发回的对象?

如果有人想在特定事件周期之后保留对象,是的。如果没有,则不必,因为在您当前的事件处理方法返回之前,autorelease d对象保证处于活动状态。

  

请注意,我没有在我的方法名称中加上“New”,因为调用者不拥有该方法发回的对象。

非常好!但我还建议您将方法名称从getAdviceFromGame:ofLine更改为adviceFromGame:ofLine。通常在Cocoa中,当使用get...时,作为方法参数传递的指针返回某些内容时会使用[pGame getBytes:&readByte range:range];

至于第二部分,你可以使用而不是你的行

[cardSymbol autorelease];

// Return the string.
return [NSString stringWithString:cardSymbol];

序列

NSString*s=[SString stringWithString:cardSymbol];
[cardSymbol release];
return s;

甚至只是

return [cardSymbol autorelease];

因为NSMutableStringNSString的子类。但是,即使在iPhone上,自动释放池中的一个对象也无关紧要。

答案 1 :(得分:0)

首先,您在该代码中的任何位置都没有类方法,但您的问题标题表示您确实有类方法。因此,我建议再次重新阅读Objective-C guide(严肃地说 - 我在前5年中每六个月读一次这个东西,我编写了Objective-C并且每次都学到了东西)。

  

因此我的第一个问题是:Q1:可以   我们确切地知道什么时候自动释放   游泳池将被“排干”或“清除”?   Q2:这是否发生在最后   OS / GUI等方法   didSelectViewController? Q3:必须   有人打电话给getAdviceFromGame   保留我发回的对象   使用前的方法?

自动释放池没有神奇之处。关于它们如何工作的documentation is quite clear

对于基于UIKit的应用程序,有一个由运行循环管理的自动释放池。每次通过runloop都会导致释放池耗尽。如果您通过runloop一次性分配大量临时对象,那么您可能需要创建并排空自己的自动释放池(您的代码没有任何内容表明您需要这样做)。

  

如你所见,这不是很好   复杂但更重要的是   从内存管理的角度来看   我“内部”分配和初始化   NSString的。因为我在结束时使用它   方法,我只能自动发布它   在打电话之前   stringWithString:cardSymbol(事实上我   我想释放它   现在解除分配)否则它可以   之前被解除分配   stringWithString:cardSymbol方法。   好吧,我对这种方式不满意   这样做但也许是正确的   这样做的方法。

除非您明确创建并排空自动释放池,否则您的字符串不会从您身下消失。池的排水没有任何自动化。

没有理由创建可变字符串的不可变副本。只需返回可变字符串。如果你真的真的想要创建一个不可变的副本,那么就像Yuji推荐的那样。