Problème de tâches asyncrones

AsKaAsKa Membre
décembre 2014 modifié dans API UIKit #1

Bonjour à  tous, 

 

Comme indiqué dans ma présentation je suis développeur sous Android à  la base et je me vois confronté ici à  un problème que j'aurai sans mal résolu à  l'aide d'une Asynctask.

 

J'ai déjà  fait le tour des posts similaires sur le forum, malheureusement bien que semblant traiter du même sujet, je n'ai jamais pu résoudre mon problème à  l'aide des réponses apportées.

 

Pour vous expliquer le contexte, je dois reprendre le code d'un stagiaire débutant en iOS également qui a commencé le développement d'une application de gestion.

 

Ici en l'occurrence il devait récupérer les contacts à  l'aide d'une requête JSON et les afficher.

Il y parvient mais je ne suis pas satisfait de la manière dont les tâches asynchrones ont été gérée.

 

Voici les parties de codes qui vous éclaireront sans doute mieux :


 


Mon controller avec mon UITableView :



- (void)viewDidLoad
{

[super viewDidLoad];

[self AffHUD];
listContacts = [[NSMutableArray alloc]init];


[_segmentedControl setTintColor:[UIColor colorWithRed:0/255.0f green:122/255.0f blue:255/255.0f alpha:1.0f]];
[_segmentedControl setSelectedSegmentIndex:NO];

if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ){
[_navBar setFrame:CGRectMake(0, 0, self.view.frame.size.width, 65)];
}
else{
[_navBar setFrame:CGRectMake(0, 0, self.view.frame.size.width, 80)];
}


_navBar.barTintColor=[UIColor colorWithRed:35/255.0f green:83/255.0f blue:138/255.0f alpha:1.0f];


OE = [[OpenE alloc]init]; // Classe dans laquelle se trouve les requêtes JSON de communication
[defaults setObject:[OE sessionID] forKey:@SESSION_ID];
defaults = [NSUserDefaults standardUserDefaults];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSMutableArray * domain = [[NSMutableArray alloc]init];

NSMutableArray * fields = [[NSMutableArray alloc]init];
[fields addObject:@id];
[fields addObject:@name];
[fields addObject:@display_name];
[fields addObject:@phone];
[fields addObject:@mobile];
[fields addObject:@fax];
[fields addObject:@email];
[fields addObject:@website];
[fields addObject:@city];
[fields addObject:@zip];
[fields addObject:@street];
[fields addObject:@is_company];
[fields addObject:@customer];
[fields addObject:@supplier];
[fields addObject:@function];


[OE search_read:@res.partner second:fields third:[OE get_userContext] fourth:0 fifth:0 sixth:[OE sessionID] seve:@"" eighth:domain nine:[defaults objectForKey:@PORT] ten:[defaults objectForKey:@SERVER]];
[defaults setObject:[OE sessionID] forKey:@session_id];

});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), dispatch_get_main_queue(), ^{

[self displayContacts];

});
}
 

Ma methode search_read de la Classe OpenE



-(void) search_read:(NSString *)model second:(NSMutableArray *)fields third:(NSDictionary*)cont fourth:(int) offset fifth:(int)limit sixth:(NSString*)sortField seve:(NSString*)sortType eighth:(NSMutableArray*)dom nine:(NSString*)port ten:(NSString*)server {

@try {

if(typeConnexion==0){
URL = [NSString stringWithFormat:@http:;//%@:%@/web/dataset/search_read",server,port];
}else {
URL =[NSString stringWithFormat:@https:;//%@/web/dataset/search_read",server];
}

NSURL * serviceURL = [NSURL URLWithString:URL];
JSONRPCService * service = [JSONRPCService serviceWithURL:serviceURL version:JSONRPCVersion_2_0];


NSMutableDictionary * params = [[NSMutableDictionary alloc]init];
[params setObject:model forKey:@model];
[params setObject:fields forKey:@fields];
[params setObject:dom forKey:@domain];
[params setObject:cont forKey:@context];
[params setObject:sortField forKey:@session_id];


[[service callMethodWithName:@search_read namedParameters:params]
completion:^(JSONRPCMethodCall * methodCall,NSMutableDictionary* result,NSError * error)
{
NSLog(@Le résultat est : %@, l'erreur est : %@", result, error);
result = [result objectForKey:@records];
}];

}
@catch (NSException *exception) {
NSLog(@%@",exception);
}
}

Et voici ma méthode displayContacs qui se trouve dans mon Controller



listecontact = [OE get_contact];
conta = [[NSMutableArray alloc]init];

//construct array with different values
for (int i = 0; i<[listecontact count]; i++) {

NSDictionary *Dict = [listecontact objectAtIndex:i];
NSString *mon_id = [Dict objectForKey:@id];
NSString *name = [Dict objectForKey:@name];
NSString *entre = [Dict objectForKey:@display_name];
NSString * phon = [Dict objectForKey:@phone];
NSString * mobil = [Dict objectForKey:@mobile];
NSString * fa = [Dict objectForKey:@fax];
NSString * web_site = [Dict objectForKey:@website];
NSString * ville = [Dict objectForKey:@city];
NSString * cp = [Dict objectForKey:@zip];
NSString * rue = [Dict objectForKey:@street];
NSString *comp = [Dict objectForKey:@is_company];
NSString *custom = [Dict objectForKey:@cutomer];
NSString *supp = [Dict objectForKey:@supplier];
NSString * e_mail = [Dict objectForKey:@email];

NSString *em;
if([e_mail boolValue]==0){
em = [[NSString alloc]initWithFormat:@%@",e_mail ];
}


Contact * monContact = [[Contact alloc]init];
[monContact Contact:[mon_id intValue] name:name display:entre phone:phon mobile:mobil iscompany:[comp intValue] fax:fa email:em website:web_site city:ville zip:cp street:rue customer:[custom intValue] supplier:[supp intValue]];


int a = [comp intValue];
if(a==0){

[conta addObject:monContact];

}

}

[_tableView reloadData];
}
@catch (NSException *e) {
NSLog(@%@",e);
}

}


Ce que j'aimerais faire c'est renvoyer la valeur retourner par search_read à  mon controller et ensuite appeler displayContacts. De manière beaucoup plus propre qu'actuellement car je n'ai pas l'impression d'avoir la réelle maitrise de la gestion des événements.


 


Je ne pense pas qu'utiliser un Getter de la classe OpenE pour récupérer le résultat de chaque requête soit une bonne chose au niveau de la visibilité.


 


J'ai déjà  trouvé des éléments de réponse avec :



dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
result = [self doInBackground:params];
dispatch_async(dispatch_get_main_queue(), ^{
[self postExecute:result];
});
});

Mais je ne parviens pas à  l'implémenter sachant que ma requête est appelée dans une autre Class et non pas dans mon Controller alors que je veux traiter ma réponse dans mon Controller.


 


Je fais donc appel à  vous pour éclairer ma lanterne.


 


Je vous remercie d'avance pour vos réponses


Réponses

  • CéroceCéroce Membre, Modérateur
    novembre 2014 modifié #2
    En gros, d'après ce que je comprends, la méthode search_read fait bien la requête de manière asynchrone, mais viewDidLoad attend bêtement une seconde que les contacts aient été chargés.

    La solution serait plutôt de faire en sorte que search_read prenne un bloc en paramètre:
    -(void)searchRead: ... completion:(void ^(NSMutableDictionary *result, NSError *error))completion
    (j'espère ne pas me tromper dans la syntaxe du bloc).

    viewDidLoad pourra alors demander "dans le bloc de completion" la mise à  jour de l'IHM sur le thread principal.



  • -(void)searchRead: ... completion:(void ^(NSMutableDictionary *result, NSError *error))completion

    (j'espère ne pas me tromper dans la syntaxe du bloc).

     




    :)



    -(void)searchRead: ... completion:(void (^)(NSMutableDictionary *result, NSError *error))completion
  • CéroceCéroce Membre, Modérateur

    Bon, ben, je redonne le lien qui sert tout le temps alors...

    FuckingBlockSyntax


  • Merci pour le lien:) j'arrive pas à  me rentrer cette syntaxe dans la tête...


  • AsKaAsKa Membre
    novembre 2014 modifié #6

    Merci beaucoup pour vos réponses, je pense avoir compris le principe. Je vais maintenant tenter de le mettre en place :).


     


    Super ça fonctionne ! C'est exactement ce que je souhaitais. 


     


    Il va falloir me familiariser avec les blocks par contre, mais c'est plutôt pas mal fait.


     


    Edit : Par contre j'ai une autre question; concernant l'utilisation de  



    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), dispatch_get_main_queue(), ^{

    Est-ce que c'est la meilleure manière de faire ? Car je vois partout que les gens utilisent 



    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    result = [self doInBackground:params];
    dispatch_async(dispatch_get_main_queue(), ^{
    [self postExecute:result];
    });
    });

    Et si j'essaye d'utiliser la deuxième façon de gérer les queues, mon affichage ne s'effectue pas.


Connectez-vous ou Inscrivez-vous pour répondre.