Le moyen le plus propre d'intercepter une réponse Asynchrone

Salut à  tous,


 


Je travaille avec les web socket pour faire des appelles Asynchrones sur le serveur. J'utilise pour ça une lib qui s'appelle SocketRocket  qui fonctionne de la manière suivante : 



1- Pour envoyer un message (Requête) : 



NSString * msg = @JSON String;
[_webSocket send:msg];

2- On récupère la réponse en suite dans la méthode delegate de la lib :

 



- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {

// Ici le seul moyen de savoir de quel message il s'agit, c'est le message lui même (id, path, ...)
[self handleResponseMessage:message];
}

3- J'ai crée un delegate qui s'occupe de chaque type de réponse, et qu'on implémente dans le controlleur adéquat.


 


Sauf que le problème de cette solution : 

1- Pas propre


2- ça crash quand on lance une requête sur le ViewControlleur A et on reçoit la réponse sur le ViewControlleur B et que la méthode delegate n'est pas implémentée sur le B, Bim, ça crash.


 


Ce que je veux savoir, est ce qu'il y a un moyen plus simple, par exemple utiliser des call back de type :

 



- (void)sendMessage:(id)object : {
[_webSocket send:object];
if(success) {
//.....
}
else
}

Ou potentiellement une autre méthode issue de vos expérience. 


Merci d'avance.


Mots clés:

Réponses

  • Elle paraà®t un peut bizarre ton architecture, vu le crash que tu décris ...


     


    Pour répondre précisément à  ta question. Il faut simplement utiliser un framework synchrone, et pas asynchrone.


    (Mais ce n'est pas une bonne idée, il vaut mieux apprendre à  se servir correctement de requêtes asynchrones pour éviter les blocages de l'UI pendant les requêtes)




  • Elle paraà®t un peut bizarre ton architecture, vu le crash que tu décris ...
    Il faut simplement utiliser un framework synchrone, et pas asynchrone.




     


    Franchement, ce n'est pas la mienne, c'est imposé par un soit disant architecte technique qui ne connait rien en mobile. J'utilisait avant des requêtes Asynchrone en Http (AFNetworking) et c'était super propre. 



     

  • CéroceCéroce Membre, Modérateur

    En gros, tu lances une requête avec le VC A et entre temps, le VC B est à  l'écran, s'est mis en délégué, et ça plante parce qu'il ne se conforme pas au protocole. ALORS POURQUOI DIABLE SE METTRE EN Dà‰Là‰GUà‰ ?!


     


    Alors, je comprends que le VC a besoin de savoir quand il y a de nouvelles données pour se rafraà®chir, mais ce n'est pas la bonne manière de faire, justement pour le problème que tu évoques: on n'est pas sûr qu'il sera toujours en vie quand la réponse sera reçue.


     


    La manière classique est d'avoir un objet dans la couche Modèle qui lance les requêtes et récupère les résultats. Lui, reste là , quoi que soit affiché à  l'écran. La difficulté est alors que cet objet prévienne qu'il faut une Mà J de l'IHM, par un des mécanismes habituels (bloc, délégation, notification center, voire KVO si tu n'as pas froid aux yeux).


  • if ([delegate respondsToSelector:@selector()]) n'est même pas implémentée ?



  • ALORS POURQUOI DIABLE SE METTRE EN Dà‰Là‰GUà‰ ?!




    Et si le B, a besoin de se mettre à  jour lui aussi ? C'est ça le problème.


     


     




     


    La manière classique est d'avoir un objet dans la couche Modèle qui lance les requêtes et récupère les résultats. Lui, reste là , quoi que soit affiché à  l'écran. La difficulté est alors que cet objet prévienne qu'il faut une Mà J de l'IHM, par un des mécanismes habituels (bloc, délégation,....)





    C'est exactement ce qui a été fait, en effet j'ai créer un singleton qui est responsable d'envoyer et recevoir les requêtes/réponses du serveur, et qui notifie les controlleurs des éventuelles mise à  jour. Ce que je cherche c'est un moyen PLUS PROPRE.



  • if ([delegate respondsToSelector:@selector()]) n'est même pas implémentée ?




    Yes

  • FKDEVFKDEV Membre
    novembre 2015 modifié #8

    Ta solution est pas mauvaise, maintenant si tu veux continuer dans cette voie, ton singleton doit pouvoir dispatcher les messages à  destination de deux ViewControllers. 


    Ton problème se situe peut-être au niveau du protocol de communication, si tes messages sont des "réponses", tu dois pouvoir retrouver qui a posé la question. Il doit y avoir un moyen dans ton protocole de rapprocher la réponse de la question (un numéro de message, par exemple).


  • CéroceCéroce Membre, Modérateur


    Et si le B, a besoin de se mettre à  jour lui aussi ? C'est ça le problème.




    Il suffit qu'il se conforme au protocole, alors ?


    Le seul problème que je voie est s'il y a plusieurs VC affichés en même temps.


     


    Ensuite, la délégation n'est pas sale, juste un peu lourde. Si ça te gène, on peut souvent utiliser des blocs à  la place.

  • Tel quel, sans tout casser, voici ce que tu pourrais faire:


     


     


    Un NSMutableDictionary *responses, dans lequel tu as en clé un id de requête et en value, la réponse.


     


    Quand tu fais un sendMessage:, retourne un id (pour responses), que ton objet garde.


     


    Quand tu as une réponse, ou un changement de value, si le delegate ne répond pas au selector, envoie une notification (dans l'doute où la durée de vie de tes objets soit différente et que tu n'aies qu'un seul delegate).


     


    Quand tu reviens sur un VC, tu peux récupérer la valeur de response si elle existe déjà , et potentiellement faire une nouvelle requête si elle est potentiellement obsolète.



     

  • FKDEVFKDEV Membre
    novembre 2015 modifié #11

    On s'excite sans trop savoir ce que tu fais, mais en gros, avec ton canal de communication tu as deux possibilités:


     


    A/ un pur jeu de question/réponse. Cela peut-être indiqué si le contenu des réponses n'a pas à  être persistent, par exemple dans tous les cas où tu envoie une information vers ton serveur et tu souhaites avoir une confirmation/autorisation de prise en compte. Ou dans les cas où un seul VC va être intéressé par les données. Par exemple si tu as un VC qui doit  afficher des photos de lieux, qui n'ont pas besoin d'être rattaché ces photos à  d'autres objets.


     


    B/ une mise à  jour de donnée, par exemple une liste d'albums favoris qui va persister pendant la durée de vie de l'application. Dans ce cas le view controller peut faire une demande de mise à  jour, mais la réponse ne lui ai pas forcément seulement destinée seulement à  lui. C'est ton modèle de donnée qui va être mis-à -jour et comme indiqué par Céroce, une notification va être émise pour prévenir tous les VC potentiellement intéressés par cette liste. Et ce sont les VC qui décideront de se mettre à  jour s'ils utilisent cette liste.


     


    Dans les deux cas, la notion de delegate unique n'est pas adpaté. 


    Si tu es dans la situation A/ tu dois utiliser une liste de delegate à  prévenir avec un système de clé comme indiqué par Larme.


    Si tu es dans la situation A/ mais qu'en plus chaque delegate peut avoir plusieurs questions en cours, alors il te faut une liste d'objets "requete en cours" dont chacune aura un delegate à  prévenir (attention aux retain cycles). Néanmoins ton singleton qui s'occupe du tuyau devra être capable de retrouver les objets "requête en cours" correspondant aux réponses. Et ça je ne pense pas que l'utilisation de websockets brutes te le permettent, il te faut protocole de communication adapté. Sauf erreur, je crois, il n'y a pas de notion de question/réponse en websocket comme dans http.


  • CéroceCéroce Membre, Modérateur

    On s'excite sans trop savoir ce que tu fais

    Oui, je crois que le mieux est qu'Ali nous explique davantage sa problématique, avant de donner des solutions à  des problèmes qu'il n'a pas.
  • Le crash décrit pourrait provenir d'une notification envoyée à  un contrôleur qui n'existe plus.


  • Pour répondre à  la question initiale, si ton singleton stocke une liste des questions en cours, il peut y associer un block, ce qui te permettra d'ecrire le code de traitement de la réponse à  côté de la question.

    Quand la réponse arrive, le block est exécuté par le singleton.

    Le cas où l'initiateur de la requête a été supprimé entre-temps, peut être pris en compte dans le block (mot clé weak, weakSelf).
Connectez-vous ou Inscrivez-vous pour répondre.