Asynchrone/synchrone

RocouRocou Membre

Bonjour,

Dans mon application en SwiftUI pour MacOS, j'ai une méthode me permettant de récupérer l'adresse IP de la machine du réseau sur laquelle tourne un serveur PostgreSQL.

Mon problème est que l'application tente de se connecter au serveur avant que l'adresse IP ait été récupérée.
Je ne sais pas comment traiter ce problème.

  • J'ai essayé en appelant la méthode dans applicationDidFinishLaunching
  • Avec des DispatchQueue.main.async
  • Avec des async et await
  • Un ProgressView

Mais rien à faire. Parfois, sur ma machine de développement sur laquelle tourne la base PostegreSQL, la récupération de l'adresse IP est plus rapide et cela fonctionne mais sur une autre machine du réseau, rien à faire, ça ne fonctionne pas, la récupération est trop lente.

Je dois me planter quelque part mais où ?...

Le côté asynchrone est vraiment ma bête noire... :(

Mots clés:

Réponses

  • Eric P.Eric P. Membre

    Bonjour,

    Peut-être avec :
    func perform(
    _ aSelector: Selector,
    with anArgument: Any?,
    afterDelay delay: TimeInterval
    )

  • CéroceCéroce Membre, Modérateur
    8 avril modifié #3

    Salut,

    D'après ta description il faut d'abord récupérer l'adresse IP, puis se connecter au serveur. Ce ne sont donc pas des opérations asynchrones entre-elles, elles ne peuvent pas se faire en parallèle. Et en même temps, il ne faut pas non plus qu'elles bloquent le thread principal (interface utilisateur) de l'appli.

    Avec async/await ça donnerait quelque chose comme ça:

    @MainActor // Thread UI
    func connectToDB() { 
        Task { // Les opérations serveur sont asynchrones par rapport à l'UI
            do {
                // Les deux opérations se succèdent dans la même Task
                let ipAddress = try await getDBServerAddress()
                try await connectToDBServer(ipAddress)
                Task { // Repasser sur le thread UI
                    didConnectToDB()
                }
            } catch {
                Task { // Traiter l'erreur sur le thread UI
                    showError(error)
                }
            }
        }
    }
    
    @MainActor
    func didConnectToDB() {
    
    }
    
    @MainActor 
    func showError(_ error: Error) {
    
    }
    

    (il faut plus comprendre le principe que l'implémentation exacte).
    La difficulté ne vient pas tant de l'asynchronisme que de la manière de passer les données entre les threads.

    Mon exemple est assez abstrait, aussi n'hésite pas à donner du code pour que nous puissions t'aider d'avantage.

  • LarmeLarme Membre

    Si je comprends bien le problème, ton app ne peut pas tourner tant que tu n'as pas récupérer l'adresse, c'est ça ?
    Dans ce cas, mets un écran pour ça. C'est le plus simple.
    Et seulement une fois que l'adresse a été récupérer, tu peux naviguer dans ton app.

  • RocouRocou Membre

    Merci pour vos pistes.
    Bon, j'ai l'impression que cette fois, ça fonctionne. J'avais pourtant l'impression d'avoir déjà testé cette configuration...
    Voici le code:

    la connexion :

    let appSettings = AppSettings.shared
     guard let connection = seConnecter(appSettings: appSettings) else {
            return resultat
        }
    
        do {
            let statement = try connection.prepareStatement(text: requeteSQL)
            let cursor = try statement.execute()
            for row in cursor {
                let columns = try row.get().columns
                if columns.indices.contains(indexColonne) {
                    resultat = try columns[indexColonne].string()
                    break // On prend seulement la première ligne
                }
            }
            cursor.close()
    
        } catch {
            print("Erreur lors de l'exécution des requêtes: \(error)")
        }
    
        connection.close()  // Fermer la connexion
        return resultat
    }
    //...
    

    La classe :

    class AppSettings: ObservableObject {
        static let shared = AppSettings()
    
    
        @Published var ipServeurAdresse: String = ""
     //...
    
        private init() {
            if let ipserveur = getServerIPAddress()
            {
                ipServeurAdresse = ipserveur
    
            }
            }
    
    }
    

    la fonction pour se connecter à la base:

        func seConnecter(appSettings: AppSettings) -> PostgresClientKit.Connection?
        {
         var configuration = PostgresClientKit.ConnectionConfiguration()
    
               configuration.host = appSettings.ipServeurAdresse
    
    
                configuration.port = 123456
                configuration.database = "serveur"
                configuration.user = "toto"
                configuration.credential = .scramSHA256(password: appSettings.mdp)
                configuration.ssl = false
    
                let connection = try PostgresClientKit.Connection(configuration: configuration)
    
                return connection
            } catch {
                print("Erreur de connection à la base de données : \(error)")
                return nil
            }
    
        }
        }
    

    Concernant la fonction de recherche de l'adresse IP du serveur PostgreSQL, je la trouve assez merdique et probablement dangereuse. Si quelqu'un sait comment réaliser cela en swift pur, je suis preneur...

    func getServerIPAddress() -> String? {
     let task = Process()
    
    
        task.launchPath = "/bin/bash"
        task.arguments = ["-c", "ps aux | grep postgres | grep -v grep | awk '{print $14}' | head -n 1 | cut -d ':' -f 1"]
    
        let pipe = Pipe()
        task.standardOutput = pipe
        task.launch()
    
        let data = pipe.fileHandleForReading.readDataToEndOfFile()
        let output = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .newlines)
    
        if let output = output, let firstIndex = output.firstIndex(of: "("), let lastIndex = output.firstIndex(of: ")") {
            let ipAddress = output[..<firstIndex]
            return String(ipAddress)
        } else {
            return output
        }
    }
    
  • RocouRocou Membre

    @Larme a dit :
    Si je comprends bien le problème, ton app ne peut pas tourner tant que tu n'as pas récupérer l'adresse, c'est ça ?
    Dans ce cas, mets un écran pour ça. C'est le plus simple.
    Et seulement une fois que l'adresse a été récupérer, tu peux naviguer dans ton app.

    J'avais testé sans y parvenir: une vue avec un progressView en attendant de recevoir l'IP. Cependant, la confection tentait malgré tout de se faire avant d'avoir reçu l'IP.

  • CéroceCéroce Membre, Modérateur

    Concernant la fonction de recherche de l'adresse IP du serveur PostgreSQL, je la trouve assez merdique et probablement dangereuse. Si quelqu'un sait comment réaliser cela en swift pur, je suis preneur...

    Ah, le serveur PostgreSQL tourne en local? Je n'ai pas vraiment d'idée pour faire mieux, et puis ça dépasse mes compétences.

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