У меня возникла проблема, когда я пытался выполнять асинхронные запросы на сервер из фонового потока. Я никогда не получал результатов этих запросов. Простой пример, который показывает проблему:Асинхронный запрос к серверу из фонового потока
@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];
все работает правильно. Я предполагаю, что фоновый поток умирает до запроса async, завершает работу, и это вызывает проблему, но я не уверен. Правильно ли я с этими предположениями? Есть ли способ избежать этой проблемы?
Я знаю, что могу использовать запрос синхронизации, чтобы избежать этой проблемы, но это просто простой пример, реальная ситуация сложнее.
Заранее спасибо.
После исследования в течение многих часов (8+) о том, как выполнить асинхронный NSURLConnection внутри NSInvocationOperation, ни одно из решений не было такой же элегантный, как CFRunLoopRun() и CFRunLoopStop(). Это намного лучше, чем возиться с переменными экземпляра «isExecuting», используя протокол KVO. Следует отметить, что я использовал @selector (выполнитьSelectorOnMainThread: withObject: waitUntilDone: modes :), передавая [NSArray arrayWithObject: NSDefaultRunLoopMode] в качестве режимов. Основной поток для удовлетворения требований UIKit, NSDefaultRunLoopMode, чтобы поддерживать взаимодействие с пользовательским интерфейсом. Большое спасибо! –
Жаль, что я не смог проголосовать больше. Это было очень полезно. –
Для проектов, скомпилированных с помощью ARC, 'NSAutoReleasePool' недоступен, поэтому код будет выглядеть как' @autoreleasepool {[self downloadImage: urlString]; CFRunLoopRun(); } ' – alokoko