88 votes

Gestion des connexions multiples à NSURLConnection asynchrones

J'ai une tonne de répéter le code de ma classe qui ressemble à la suivante:

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
                                                              delegate:self];

Le problème avec les requêtes asynchrones, c'est quand vous avez diverses demandes, et vous avez un délégué affecté à les traiter tous comme une seule entité, beaucoup de ramification et laid code commence à formuler:

Quel type de données sommes-nous revenir? Si elle contient ceci, fais cela, d'autre le faire à d'autres. Il serait utile je pense être en mesure de marquer ces requêtes asynchrones, un peu comme vous êtes en mesure de balise de vues avec des Identifiants.

J'étais curieux de savoir quelle est la stratégie la plus efficace pour la gestion d'une classe qui gère plusieurs requêtes asynchrones.

77voto

Matt Gallagher Points 10431

J'ai suivi des réponses dans un CFMutableDictionaryRef gérés par le NSURLConnection associés. c'est à dire:

connectionToInfoMapping =
    CFDictionaryCreateMutable(
        kCFAllocatorDefault,
        0,
        &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);

Il peut sembler étrange d'utiliser ce lieu de NSMutableDictionary mais je le fais parce que ce CFDictionary ne conserve que ses clés (les NSURLConnection) alors que NSDictionary des copies de ses clefs (et NSURLConnection ne prend pas en charge la copie).

Une fois cela fait:

CFDictionaryAddValue(
    connectionToInfoMapping,
    connection,
    [NSMutableDictionary
        dictionaryWithObject:[NSMutableData data]
        forKey:@"receivedData"]);

et maintenant, j'ai une "info" dictionnaire de données pour chaque connexion que je peux utiliser pour suivre les informations relatives à la connexion et le "info" dictionnaire contient déjà une mutable objet de données que je peux utiliser pour stocker les données de réponse comme elle vient.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSMutableDictionary *connectionInfo =
        CFDictionaryGetValue(connectionToInfoMapping, connection);
    [[connectionInfo objectForKey:@"receivedData"] appendData:data];
}

19voto

jbarnhart Points 181

J’ai un projet où j’ai deux NSURLConnections distinctes et voulait utiliser le même délégué. Ce que j’ai fait créer deux propriétés dans ma classe, un pour chaque connexion. Puis, dans la méthode du délégué, je vérifie pour voir si quelle connexion c’est

Cela me permet aussi d’annuler une connexion spécifique par son nom si nécessaire.

16voto

Pat Niemeyer Points 499

Sous-classement NSURLConnection pour contenir les données est propre, moins de code que certains des autres réponses, plus souple, et nécessite moins de pensée au sujet de gestion de références.

// DataURLConnection.h
#import <Foundation/Foundation.h>
@interface DataURLConnection : NSURLConnection
@property(nonatomic, strong) NSMutableData *data;
@end

// DataURLConnection.m
#import "DataURLConnection.h"
@implementation DataURLConnection
@synthesize data;
@end

L'utiliser comme vous le feriez NSURLConnection et d'accumuler les données dans sa base de données de la propriété:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    ((DataURLConnection *)connection).data = [[NSMutableData alloc] init];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [((DataURLConnection *)connection).data appendData:data];
}

C'est tout.

Si vous voulez aller plus loin, vous pouvez ajouter un bloc de servir comme un rappel avec juste quelques lignes de code:

// Add to DataURLConnection.h/.m
@property(nonatomic, copy) void (^onComplete)();

Réglez comme ceci:

DataURLConnection *con = [[DataURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
con.onComplete = ^{
    [self myMethod:con];
};
[con start];

et à l'appeler quand le chargement est fini, comme ceci:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    ((DataURLConnection *)connection).onComplete();
}

Vous pouvez étendre le bloc pour accepter les paramètres ou de passer la DataURLConnection comme argument de la méthode qui en a besoin dans le pas-args bloc comme indiqué

8voto

petershine Points 1540

CE N'EST PAS UNE NOUVELLE RÉPONSE. S'IL VOUS PLAÎT LAISSEZ-MOI VOUS MONTRER COMMENT J'AI FAIT

Afin de distinguer les différents NSURLConnection au sein même de la classe délégué méthodes, j'utilise NSMutableDictionary, de fixer et de retirer le NSURLConnection, à l'aide de son (NSString *)description de la touche. L'objet que j'ai choisi pour setObject:forKey est l'URL unique qui est utilisé pour initier la NSURLRequest, le NSURLConnection utilise. Une fois mis en NSURLConnection est évaluée à -(void)connectionDidFinishLoading:(NSURLConnection *)de connexion, il peut être retiré à partir du dictionnaire.

// This variable must be able to be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection
NSMutableDictionary *connDictGET = [[NSMutableDictionary alloc] init];
//...//

// You can use any object that can be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection
[connDictGET setObject:anyObjectThatCanBeReferencedFrom forKey:[aConnectionInstanceJustInitiated description]];
//...//

// At the delegate method, evaluate if the passed connection is the specific one which needs to be handled differently
if ([[connDictGET objectForKey:[connection description]] isEqual:anyObjectThatCanBeReferencedFrom]) {
// Do specific work for connection //

}
//...//

// When the connection is no longer needed, use (NSString *)description as key to remove object
[connDictGET removeObjectForKey:[connection description]];

5voto

Brad The App Guy Points 13329

J’ai pris une des approches sont de ne pas utiliser le même objet que le délégué pour chaque connexion. Au lieu de cela, je crée une nouvelle instance de ma classe l’analyse pour chaque connexion qui est tirée et le délégué à cette instance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X