将 NSAutoreleasePool 与 NSURLConnection 结合使用
我正在尝试遵循 XMLPerformance 示例来制作我自己的 xml 解析器。到目前为止,我在使自动释放池工作时遇到了最困难的时期,当我重新创建池时,我就崩溃了。
我将问题范围缩小到这个测试用例:
PoolCrashTest.h
#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
PoolCrashTest.m
#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...我的目标是使用大部分默认项目设置的 Lion。
I am trying to follow the XMLPerformance example to make an xml parser of my own. So far I'm having the hardest time making autorelease pools work, I get a crash the instant I recreate a pool.
I narrowed down the issue to this test case:
PoolCrashTest.h
#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
PoolCrashTest.m
#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];
crash after this line ^
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
Can someone explain how to properly purge autorelease pool in a NSURLConnection delegate running in a thread?
I have tried to follow XMLPerformance as close as possible... I'm targeting Lion with mostly default project settings.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您过度释放了您的池。
我正在重新阅读您的问题以确保我理解,但是如果您查看NSAutoreleasePool 文档 你会看到
release
和drain
不应同时使用。 (这与简单地调用release
两次几乎相同。)仅使用drain
:编辑: 上一个问题可能会帮助您了解如何使用定期排出的
NSAutoreleasePool
一个多线程环境。You're over-releasing your pool.
I'm re-reading your question to make sure I understand, but if you check out the NSAutoreleasePool Documentation you'll see that
release
anddrain
should not both be used. (It's nearly identical to simply callingrelease
twice.) Only usedrain
:Edit: This previous question might help you understand how you should use a periodically-drained
NSAutoreleasePool
in a multi-threaded environment.当克雷格说你过度释放你的池时,他是正确的。在非GC环境中,
release
和drain
具有相同的效果。在 GC 环境中,release
对于任何对象都是无操作的,因此必须使用drain
来代替。我只会使用drain
。然而,
NSAutoreleasePool
对象并不是真正应该成为类属性的东西;如果您将它们的使用限制在词汇范围内,它们将最适合您。您可以通过多种方式在上面发布的代码中使用池,这就足够了。请记住,当您旋转运行循环时,它将在通用模式下运行运行循环的调用中弹出或弹出;所以你可以这样做:
并且你将耗尽在运行循环的特定回合中创建的任何自动释放的对象。由于运行循环的调用将调用连接的委托回调,因此当该池耗尽时,在委托回调中创建的任何自动释放的对象都将被清除。
如果您对此不满意,您可以在委托方法中放置一个池,具体取决于委托方法可能要做的工作量:
在您的情况下,它会产生大致相同的效果。
我强烈建议您执行类似于上面第一个示例的操作,并消除您现在拥有的自动释放池行为。将 NSAutoreleasePool 对象保留在单个词法范围内可以方便从调试到必要时安全异常处理的一切。
craig is correct when he says you're over-releasing your pool. In a non-GC environment,
release
anddrain
have the same effect. In a GC environment,release
is a no-op for any object, sodrain
must be used instead. I'd just usedrain
.However,
NSAutoreleasePool
objects aren't really things you should be making a property of your class; they'll work best for you if you restrict their use to a lexical scope. There are a couple of ways you could use a pool in the code you posted above which would be sufficient.Remember when you're spinning your run loop that it's going to be popping in and out of the call to run the run loop in the common modes; so you could do this instead:
and you'd be draining any autoreleased objects created in the particular turn of the run loop. Because the connection's delegate callback will be called due to this invocation of the run loop, any autoreleased objects created in the delegate callback will be cleaned up when this pool drains.
If you're not comfortable with this, you could place a pool inside your delegate method depending on how much work your delegate method is likely to be doing:
And in your case, it would have roughly the same effect.
I would strongly recommend doing something like my first example above and eliminating the autorelease pool behavior you have right now. Keeping
NSAutoreleasePool
objects to a single lexical scope facilitates everything from debugging to safe exception handling when it becomes necessary.