我正在尝试按照XMLPerformance示例来创建自己的xml解析器。到目前为止,我正在努力使自动释放池工作,我在重新创建池时会崩溃。
我将问题缩小到这个测试用例:
#import <SenTestingKit/SenTestingKit.h>
@interface PoolCrashTest : SenTestCase
{
@private
NSURLConnection *connection;
NSAutoreleasePool *downloadAndParsePool;
BOOL done;
}
@property (nonatomic, retain) NSURLConnection *connection;
@property (nonatomic, assign) NSAutoreleasePool *downloadAndParsePool;
- (void)downloadAndParse:(NSURL *)url;
@end
#import "PoolCrashTest.h"
@implementation PoolCrashTest
@synthesize downloadAndParsePool, connection;
- (void)downloadAndParse:(NSURL *)url {
done = NO;
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
self.connection = [[NSURLConnection alloc]
initWithRequest:theRequest delegate:self];
if (connection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
} while (!done);
}
self.connection = nil;
[downloadAndParsePool release];
self.downloadAndParsePool = nil;
}
#pragma mark NSURLConnection Delegate methods
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data {
[downloadAndParsePool drain];
此行后崩溃^
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
}
- (void)testPoolCrash
{
NSURL *dumpURL = [NSURL URLWithString:@"file:///some.xml"];
[NSThread detachNewThreadSelector:@selector(downloadAndParse:)
toTarget:self withObject:dumpURL];
sleep(10);
}
@end
有人可以解释如何在线程中运行的NSURLConnection委托中正确清除自动释放池吗?
我试图尽可能接近遵循XMLPerformance ...我主要以默认项目设置为目标。
答案 0 :(得分:2)
release
和drain
具有相同的效果。在GC环境中,release
是任何对象的无操作 ,因此必须使用drain
。我只使用drain
。
然而,NSAutoreleasePool
对象并不是你应该成为你班级财产的东西;如果你将它们限制在一个词法范围内,它们将最适合你。您可以通过以下几种方式在上面发布的代码中使用池,这就足够了。
请记住,当您旋转运行循环时,它将弹出进出调用以在常用模式下运行运行循环;所以你可以这样做:
if (connection != nil) {
do {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
[pool drain];
} while (!done);
}
并且你将耗尽在运行循环的特定回合中创建的任何自动释放的对象。因为运行循环的这次调用将调用连接的委托回调,所以当该池耗尽时,将清除在委托回调中创建的任何自动释放的对象。
如果您对此不满意,可以在委托方法中放置一个池,具体取决于您的委托方法可能需要做多少工作:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Do whatever work you want here
[pool drain];
}
在你的情况下,它会产生大致相同的效果。
我强烈建议您执行上面第一个示例,并消除您现在拥有的自动释放池行为。将NSAutoreleasePool
个对象保存到单个词法范围有助于在必要时从调试到安全异常处理。
答案 1 :(得分:1)
你过度释放你的游泳池。
我正在重新阅读您的问题,以确保我理解,但如果您查看NSAutoreleasePool Documentation,您会看到release
和drain
不应 使用。 (这与简单地两次调用release
几乎完全相同。)仅使用drain
:
在垃圾收集环境中,不需要自动释放池。但是,您可以编写一个框架,该框架旨在在垃圾收集和引用计数环境中工作。在这种情况下,您可以使用自动释放池向收集器提示该集合可能是合适的。在垃圾收集环境中,如果需要,向池中发送排泄消息会触发垃圾回收;然而,释放是一种无操作。在参考计数环境中,排水与释放具有相同的效果。 因此,通常情况下,您应该使用drain而不是release。
修改 This previous question可能会帮助您了解如何在多线程环境中使用定期耗尽的NSAutoreleasePool
。