J'ai le problème lorsque j'ai essayé de faire des requêtes asynchrones au serveur à partir du thread d'arrière-plan. Je n'ai jamais eu les résultats de ces demandes. Exemple simple qui montre le problème:Demande asynchrone au serveur à partir du thread d'arrière-plan
@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
J'appelle cela de fil conducteur
asyncImgRequest = [[AsyncImgRequest alloc] init];
asyncImgRequest.delegate = self;
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
downloadImage méthode
est ci-dessous:
-(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];
}
Le problème est que imageDownloadDidFinish méthode est jamais appelée . De plus aucune des méthodes
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response
sont appelées. Toutefois, si je remplace
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
par
[self performSelector:@selector(downloadImage) withObject:nil];
tout fonctionne correctement. Je suppose que le thread d'arrière-plan meurt avant que la requête async soit terminée et que cela cause le problème mais je ne suis pas sûr. Ai-je raison avec ces hypothèses? Est-il possible d'éviter ce problème?
Je sais que je peux utiliser la demande de synchronisation pour éviter ce problème mais c'est juste un exemple simple, la situation réelle est plus complexe.
Merci d'avance.
Après avoir étudié pendant de nombreuses heures (8+) sur la façon d'effectuer une NSURLConnection asynchrone dans un NSInvocationOperation, aucune des solutions ont été aussi élégant que CFRunLoopRun() et CFRunLoopStop(). C'est BEAUCOUP mieux que de jouer avec les variables d'instance "isExecuting" en utilisant le protocole KVO. Une chose à noter est que j'ai utilisé @selector (performSelectorOnMainThread: withObject: waitUntilDone: modes :) en passant [NSArray arrayWithObject: NSDefaultRunLoopMode] comme modes. Fil principal pour satisfaire les exigences UIKit, NSDefaultRunLoopMode pour maintenir l'interaction de l'interface utilisateur lisse. Merci beaucoup! –
Je voudrais pouvoir voter plus. C'était extrêmement utile. –
Pour les projets compilés avec ARC, NSAutoReleasePool n'est pas disponible, donc le code ressemblerait à '@autoreleasepool {[self downloadImage: urlString]; CFRunLoopRun(); } ' – alokoko