Verbindung zur Web-DB

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Verbindung zur Web-DB

    Hallo zusammen!

    Meine App soll an ein Benutzerkonto einer größeren Webanwendung gekoppelt werden - d.h. für einen Benutzer wird in der Webanwendung ein Zugriffscode erstellt, dieser wird in der App eingegeben, die App holt sich die Benutzerdaten von der Webanwendung. Funktioniert FAST perfekt, aber...

    Quellcode

    1. class ConnectionToMysql {
    2. var zugriffscode = ""
    3. var serverUrl = ""
    4. func verifyCodeFromWebApp(Code: String)->Int {
    5. zugriffscode = Code
    6. let kunde = self.getItems()
    7. print("Der Kunde heisst \(kunde.nachname)")
    8. if kunde.nachname != "" {
    9. print ("Pairinggcode erkannt \(Code)")
    10. return 1
    11. } else {
    12. print("Fehler im Code \(Code)")
    13. return 0
    14. }
    15. }
    16. func getItems() -> Kunde {
    17. var kunde = Kunde()
    18. serverUrl += "meine_beispieldomain.php?aktion=new_device&zugriffscode=\(zugriffscode)"
    19. print(serverUrl)
    20. let url = URL(string: serverUrl)
    21. if let url = url {
    22. let session = URLSession(configuration: .default)
    23. let task = session.dataTask(with: url, completionHandler: {
    24. (data, response, error) in
    25. if error == nil {
    26. // Datenübertragung möglich
    27. kunde = self.parseJson(data: data!)
    28. print("in getItems() heisst der Kunde \(kunde.nachname)")
    29. } else {
    30. print("Etwas lief schief \(error!)")
    31. }
    32. })
    33. print("Task ausgeführt")
    34. task.resume()
    35. }
    36. print("in getItems() vor der Rückgabe heisst der Kunde \(kunde.nachname)")
    37. return kunde
    38. }
    39. func parseJson(data:Data) -> Kunde {
    40. var kunde = Kunde()
    41. do {
    42. let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as! [Any]
    43. // Weil unsere Antwort vom Srever ein Array ist (wenn auch mit nur einem Element), müssen wir durchiterieren
    44. for jsonResult in jsonArray {
    45. let jsonDict = jsonResult as! [String: String]
    46. kunde.ID = Int(jsonDict["ID"]!)!
    47. kunde.nachname = jsonDict["nachname"]!
    48. print("Direkt nach dem Lesen heisst der Kunde \(kunde.nachname)")
    49. kunde.vorname = jsonDict["vorname"]!
    50. kunde.geburtsdatum = jsonDict["geburtsdatum"]!
    51. kunde.strasse = jsonDict["strasse"]!
    52. kunde.plz = jsonDict["plz"]!
    53. kunde.ort = jsonDict["ort"]!
    54. kunde.telefonnummer = jsonDict["telefonnummer"]!
    55. kunde.telefonnummer2 = jsonDict["telefonnummer2"]!
    56. kunde.mobil = jsonDict["mobil2"]!
    57. kunde.mobil2 = jsonDict["mobil"]!
    58. kunde.email = jsonDict["email"]!
    59. kunde.fax = jsonDict["fax"]!
    60. }
    61. } catch {
    62. print ("Es ist etwas schief gelaufen \(error)")
    63. }
    64. print("in parseJson() heisst der Kunde \(kunde.nachname)")
    65. return kunde
    66. }
    67. }
    Alles anzeigen
    Wenn man nun den Ausgaben in der Konsole folgt....

    Task ausgeführt
    in getItems() vor der Rückgabe heisst der Kunde
    Der Kunde heisst
    Fehler im Code OLE-O5AZOY1JOW59
    Pairing missglückt
    Direkt nach dem Lesen heisst der Kunde Silzer
    in parseJson() heisst der Kunde Silzer
    in getItems() heisst der Kunde Silzer

    sieht man, dass in der Funktion getItems() ZUERST das Objekt Kunde zurückgegeben wird (welches zu diesem Zeitpunkt aber noch leer ist), DANN ERST wird die Funktion parseJson() aufgerufen und das Objekt mit Inhalten gefüllt.

    Das ist insofern unpraktisch, weil ich gerne in der zuallererst aufgerufenen Funktion verifyCodeFromWebApp() gerne eine Rückmeldung hätte, ob der vom Benutzer eingegebene Zugangscode richtig war - in diesem Fall soll nämlich der Benutzer dazu aufgerufen werden ein Benutzerpasswort für die App auf diesem Gerät festzulegen - bei falschem Zugangscode aber nicht.

    Im Prinzip muss das hier erhaltene Objekt kunde :


    Quellcode

    1. if error == nil {
    2. // Datenübertragung möglich
    3. kunde = self.parseJson(data: data!)
    4. print("in getItems() heisst der Kunde \(kunde.nachname)")
    5. } else {
    zurück an verifyCodeFromWebApp oder es müsste eine Boolean-Variable zurückgegeben werden abhängig davon, ob hier die Funktion parseJson() Erfolg hatte oder nicht.

    Ich habe versucht den Code hier und da etwas umzustellen, stehe aber irgendwie auf dem Leitung...
  • Du musst berücksichtigen, dass die dataTask der URLSession asynchron läuft: Wenn das Ende Deiner Funktion getItems() erreicht wird, liegen noch keine Daten vor. Genau dafür hat die genannte Methode ihren completionHandler: Die Verarbeitung des Inhalts solltest Du von dort initiieren und dann alle abhängigen Objekte - z. B. über Notifications - über neue Daten informieren.

    Deine Verify-Funktion kennt also nicht nur die Status "Code gültig" oder "Code ungültig", sondern auch "Code noch nicht verifiziert". Das Programm muss damit umgehen können...

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von MyMattes ()

  • Dankeschön - im Prinzip beschreibt es genau das Problem - nur die Lösung fehlt mir. Denn...

    Quellcode

    1. if error == nil {
    2. // Datenübertragung möglich
    3. kunde = self.parseJson(data: data!)
    4. print("in getItems() heisst der Kunde \(kunde.nachname)")
    5. return kunde
    6. }


    So kann ich kein return einbauen (Unexpected non-void return value in a void function).

    Das ganze wurde zuvor aus einer View heraus aufgerufen:


    Quellcode

    1. Button(action: {
    2. print("Ok")
    3. let verbindung = ConnectionToMysql()
    4. let testergebnis = verbindung.verifyCodeFromWebApp(Code: self.zugangscode)
    5. if testergebnis == 1 {
    6. print("Überprüfung erfolgreich")
    7. self.register_pushed.toggle()
    8. } else {
    9. print("Pairing missglückt")
    10. }
    11. }, label: {
    12. HStack {
    13. Text("Registriere mein iPhone")
    14. }
    15. .font(.largeTitle)
    16. .frame(minWidth: 0, maxWidth: .infinity)
    17. .foregroundColor(.white)
    18. .background(Color.blue)
    19. })
    Alles anzeigen
    Hier wird der Rückgabewert "testergebnis" erwartet. da abhängig vomn dessen Wert die @State Variable register_pushed ihren Wert verändert (oder nicht) - was zu einer weiteren View weiterleitet. Auf diese @State-Variable habe ich aus dem completionHandler keinen Zugriff - wie leite ich hier also zur nächsten View, in der der Benutzer aufgefordert werden soll, sein Passwort festzulegen?

    Im Prinzip bräuchte ich evtl. die Möglichkeit einfach per Code zur nächsten View weiterzuleiten, statt der Button aus der ersten View, richtig? Hier stosse ich aber mit meinen Swift-Kenntnissen an Grenzen.
  • flori-software schrieb:

    Im Prinzip bräuchte ich evtl. die Möglichkeit einfach per Code zur nächsten View weiterzuleiten, statt der Button aus der ersten View, richtig? Hier stosse ich aber mit meinen Swift-Kenntnissen an Grenzen.
    Es mag ja auch sein, dass ich auf'm Schlauch stehe, aber ich sehe Dein Problem nicht in der Verzweigung auf irgendwelche Views, sondern grundsätzlicher Art: Wenn / falls Deine App die Registrierung zwingend benötigt, solltest Du sie quasi "modal" behandeln: Auch wenn der eigentliche Datenempfang asynchron läuft, sperrt Deine App weitere Aktionen bis die Registrierung erfolgt ist bzw. eine Fehlerbehandung notwendig ist.

    Ich würde dafür z. B. eine UIProgressView mit entsprechendem Text implementieren und bei Erfolgt oder Time-Out beenden.

    Ist die Registrierung nicht zwingend, müssen eben alle Views auch ohne dieser sinnvolle Ergebnisse liefern und später - z. B. per NSNotification - aktualisiert werden.

    Also ich glaube, Du hast weniger ein Swift- als mehr ein konzeptionelles Problem.

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Vielen Dank Mattes,

    abr ich glaube, du überschätzt ein bißchen meine Swift-Fähigkeiten. Auch wenn ich mich seit ca. 1 Jahr immer mal wieder ein bißchen mit Swift beschäftige, sind meine Kenntnisse immer noch rudimentär. Bin im Augenblick immer noch mehr in der PHP-Welt zu Hause. :)

    Der konzeptuelle Gedanke war mir durchaus klar, asynchrone Scriptdurchführung bin ich z.B. von AJAX gewohnt - hier war mir nur nicht klar, wie ich eine sichtbare Aktion starten kann nachdem die Verarbeitung von JSON zu Ende ist. Habe jetzt folgendes gefunden:

    Quellcode

    1. protocol ConnectionToMySqlDelegate {
    2. func itemsDownloaded(Item: Kunde)
    3. }




    Dieses Protokoll habe ich über der Klasse ConnectionToMySql festgelegt und in die Klasse selbst eine variable eingebaut:

    Quellcode

    1. var delegate: ConnectionToMySqlDelegate?
    2. // code... code... code...
    3. if error == nil {
    4. // Datenübertragung möglich
    5. kunde = self.parseJson(data: data!)
    6. print("in getItems() heisst der Kunde \(kunde.nachname)")
    7. self.delegate?.itemsDownloaded(Item: kunde)
    8. } else {
    9. print("Etwas lief schief \(error!)")
    10. }
    Auf die ich zugreife sobald JSON-Daten geparst sind. Weiterhin lege ich fest, dass die View ebenso der Protokoll entsprechen soll...

    Quellcode

    1. struct ContentView: View, ConnectionToMySqlDelegate {
    2. @State var zugangscode: String = "" // Zugangscode zum Koppeln
    3. @State private var login_pushed: Bool = false // Zustand der LogInTaste nach dem Koppeln
    4. @State private var register_pushed: Bool = false
    5. func itemsDownloaded(Item: Kunde) {
    6. print("Das Protokoll-Dings erfolgreich aufgerufen")
    7. register_pushed.toggle()
    8. }
    verknüpfe es noch innerhalb des Buttons...


    Quellcode

    1. Button(action: {
    2. print("Ok")
    3. let verbindung = ConnectionToMysql()
    4. verbindung.delegate = self
    5. verbindung.verifyCodeFromWebApp(Code: self.zugangscode)
    -> nun wird nach erfolgreicher Verarbeitung der JSON-Daten die Funktion itemsDownloaded() aufgerufen - hier könnten die Kundendaten z.B. auch noch in die lokale Datenbank geschrieben werden etc. Jedenfalls verändere ich hier den Wert der @State - Variable register_pushed - was den NavigatioonLink aktiviert und zur nächsten View weiterleitet, wie ich es haben wollte.

    Jetzt funktioniert es - vielen Dank fürs Mitdenken!