我试图从后台线程向服务器做异步请求时遇到了问题。我从来没有得到这些要求的结果。这说明了什么问题简单的例子:从后台线程到服务器的异步请求
@protocol AsyncImgRequestDelegate
-(void) imageDownloadDidFinish:(UIImage*) img;
@end
@interface AsyncImgRequest : NSObject
{
NSMutableData* receivedData;
id<AsyncImgRequestDelegate> delegate;
}
@property (nonatomic,retain) id<AsyncImgRequestDelegate> delegate;
-(void) downloadImage:(NSString*) url ;
@end
@implementation AsyncImgRequest
-(void) downloadImage:(NSString*) url
{
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:20.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
receivedData=[[NSMutableData data] retain];
} else {
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[delegate imageDownloadDidFinish:[UIImage imageWithData:receivedData]];
[connection release];
[receivedData release];
}
@end
然后我把这种从主线程
asyncImgRequest = [[AsyncImgRequest alloc] init];
asyncImgRequest.delegate = self;
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
方法downloadImage如下表所示:
-(void) downloadImage
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[asyncImgRequest downloadImage:@"http://photography.nationalgeographic.com/staticfiles/NGS/Shared/StaticFiles/Photography/Images/POD/l/leopard-namibia-sw.jpg"];
[pool release];
}
的问题是方法imageDownloadDidFinish永远不会调用。此外,没有方法
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response
被调用。但是如果我更换
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
通过
[self performSelector:@selector(downloadImage) withObject:nil];
一切工作正确。我假设后台线程在异步请求完成之前就已经死了,这导致了问题,但我不确定。我对这个假设是否正确?有什么办法可以避免这个问题吗?
我知道我可以使用同步请求来避免这个问题,但它只是一个简单的例子,实际情况更复杂。
在此先感谢。
研究关于如何在NSInvocationOperation内执行一个异步NSURLConnection的几个小时(8个)之后,没有一个解决方案是像CFRunLoopRun()和CFRunLoopStop()一样优雅。这比使用KVO协议执行“isExecuting”实例变量要好得多。有一点需要注意的是,我使用@selector(performSelectorOnMainThread:withObject:waitUntilDone:modes :)作为模式传递[NSArray arrayWithObject:NSDefaultRunLoopMode]。主线程满足UIKit的要求,NSDefaultRunLoopMode保持UI交互的顺畅。非常感谢! – 2009-12-19 10:40:49
希望我能投票更多。这非常有帮助。 – 2012-01-24 17:37:09
对于使用ARC编译的项目,“NSAutoReleasePool”不可用,所以代码看起来像“@autoreleasepool {[self downloadImage:urlString]; CFRunLoopRun(); }' – alokoko 2012-03-06 21:12:54