首先,我是本网站的新用户,因此,请提前感谢您的帮助。
我的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。
最诚挚的问候, 弗朗兹
答案 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];
因为NSMutableString
是NSString
的子类。但是,即使在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推荐的那样。