Eigene Klasse die Verbindung zu einer Internet-DB herstellt: macht Probleme

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

  • Eigene Klasse die Verbindung zu einer Internet-DB herstellt: macht Probleme

    Hi,

    ich habe eine eigene Klasse die Daten in meine DB schreibt und liest. Ich connecte mit NSURLSession.

    Ich handhabe das so:
    - viewdidload: Objekt erstellen+diesem sagen was er holen soll
    - per Delegate erhalte ich von diesem Objekt dann die Daten und zeige sie im View an

    Jetzt bekomme ich sporadisch die Fehlermeldungen 1001 und 1005, die um "Verbindungsabbruch" und "Verbindungs-Timout" gehen.

    Meine Theorie:
    Wenn ein User viel und schnell zwischen Views wechselt wollen diese "Verbindungs-Objekte" Rückmeldung geben, aber da das View nicht mehr existiert kommt ein Fehler. Ich hab auch schon von einem ios8-bug gelesen, dass Header vom Server mit "keep alive" Probleme machen, da iOS diese Verbindungen irgendwie weiterverwenden will?!

    Meine Frage:
    Muss ich diesen Objekten irgendwie mitteilen dass "ihr" View nicht mehr angezeigt wird? Damit NSURLSession die Verbindung abbrechen kann.
    Ist der grundsätzliche Ablauf von mir falsch?

    DANKE!
    Daniel
  • Natürlich kannst du Sessions abbrechen: mit cancel.

    Allerdings finde ich das beschriebene Vorgehen ungünstig, da damit der Nutzer andauernd neue Downloadprozesse starten kann. Ich würde den Download von der Anzeige so trennen, dass die App den Download auch bei verstecktem View korrekt abschließen kann. Außerdem sollte der Viewcontroller merken, ob noch ein Download im Gange ist bzw. kurz zuvor abgeschlossen wurde, und dann nicht unbedingt einen neuen Download starten.
    „Meine Komplikation hatte eine Komplikation.“
  • Probiere es doch so:

    - Erzeuge eine Singleton Klasse die als "Datenbank" fungiert
    - Diese Singleton Klasse kann von deinem ViewController angesprochen werden
    - Diese Singleton Klasse fängt mit dem Download der Daten an und speichert diese
    - Du kannst in der Zwischenzeit deine Views verändern
    - Kommst du nun auf den einen ViewController wieder zurück fragt dieser das Singleton ob bereits Daten vorhanden sind, wenn ja (gib her!) sonst, download!

    Sinnvoll wäre es auch Model-Klassen anzulegen, so kann deine Singleton DB Klasse die geholten Daten in ein entsprechendes Format packen und in einem Array oder Set zum Abholen bereit ablegen.
  • Miralem23 schrieb:

    Probiere es doch so:

    - Erzeuge eine Singleton Klasse die als "Datenbank" fungiert


    Nein, Nein und nochmal Nein!

    Aber ich habe keien Lust mehr darüber zu diskutieren. Das wurde jetzt schon oft genug durchgekaut das ein Sigleton als Datenquelle der größte Murks ist den man machen kann.

    Ich muss gerade so ein Projekt reparieren und kotze jeden Tag.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Es ist überhaupt nicht mehr Aufwand eine Webservice-Klasse zu schreiben und diese zu instanzieren wenn ich sie brauche. Damit habe ich dann die Möglichkeit beliebig viele Downloads gleichzeitig zu machen ohne irgendwelche Probleme.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • [Miralem23]
    Ich sehe jetzt nicht, wo in Deinem Beispiel die Notwendigkeit für ein Singleton besteht.
    Eine Instanzvariable des App Delegate funktioniert doch genau so gut.

    [danyball]
    Die Verbindungsfehler kommen ganz bestimmt nicht, weil das aufrufende View nicht mehr existiert.
    Für mich liest es sich jedenfalls nicht so, als würde die Delegate Methode überhaupt aufgerufen – Nachrichten an nil sind schließlich erlaubt und mitunter erwünscht. Es wird sich um einen schnöden Verbindungsfehler mit der Gegenstelle im Internet handeln.

    Theorien sind übrigens denkbar ungünstige Ausgangslagen für eine Fehlerbehebung. ;)
    Reproduzierbarkeit heißt das Zauberwort.

    Im Übrigen ist die Auswertung und Nutzung des HTTP Headers 'keepalive' zur Weiterverwendung der Verbindung kein Bug sondern logisch. 'keepalive' bedeutet 'halte die Verbindung am Leben' – und genau das tut iOS.
    Sendet Dein Header also ein 'keepalive', solltest Du dem das dringend abgewöhnen.

    Ähnlich wie macmoonshine finde ich Deinen Ansatz irgendwie verkehrt.
    Jedes Mal ein neues Objekt mit einer neuen Anfrage zu erzeugen klingt irgendwie falsch. Eine zentrale Verbindungsstelle ist da sinnvoller. (Ja, ich habe das Wort 'Singleton' absichtlich vermieden, da dies nur eine [oftmals sehr schlechte] Möglichkeit der zentralen Verbindungsstelle ist)

    Diese zentrale Verbindungsstelle kann beispielsweise eine Instanzvariable im App Delegate sein, kann sich rein über Klassenmethoden realisieren lassen oder kann ein eigener Hintergrundprozess sein.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Super Anregungen, danke dafür schonmal.

    - die Antworten vom Server einige Zeit zu cachen find ich ne gute Idee! Kann ios nicht Anfragen/deren Antwort irgendwie cachen?

    - Zur "zentralen Verbindungsstelle":
    Instanzvariable im App Delegate klingt gut. Die wär dann 1 Objekt meiner bisherigen "Verbindungsklasse". Wie kann so eine zentrale Stelle unterscheiden welche Antworten sie an welchen Delegate "zurück schickt"? Es kann passieren dass ich mehrere Anfragen parallel mache. Falls die ausm Internet geladen werden müssen, muss ja der View ja verständigt werden wenn die Anfrage fertig ist.
  • danyball schrieb:



    Es kann passieren dass ich mehrere Anfragen parallel mache.


    Ehrlich gesagt verstehe ich das einfach nicht. Wenn jeder ViewController seine eigenen Daten braucht, warum hat dann nicht auch jeder ViewController seine eigene Instanz der Klasse die diese Daten beschafft? Was ist denn da das Problem? Wiso must du da irgendwas über das AppDelegate machen mit nur einem Objekt?

    Klar kannst du jetzt in dem einen Objekt eine parallelisierung einbauen aber das ist doch um längen komplizierter als eine Klasse zu machen der du sagst "Hole mir diese Daten" und dann für jeden ViewController ein eigenes Objekt.

    Ich kapiers einfach nicht.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    danyball schrieb:



    Es kann passieren dass ich mehrere Anfragen parallel mache.


    Ehrlich gesagt verstehe ich das einfach nicht. Wenn jeder ViewController seine eigenen Daten braucht, warum hat dann nicht auch jeder ViewController seine eigene Instanz der Klasse die diese Daten beschafft? Was ist denn da das Problem? Wiso must du da irgendwas über das AppDelegate machen mit nur einem Objekt?

    Klar kannst du jetzt in dem einen Objekt eine parallelisierung einbauen aber das ist doch um längen komplizierter als eine Klasse zu machen der du sagst "Hole mir diese Daten" und dann für jeden ViewController ein eigenes Objekt.

    Ich kapiers einfach nicht.

    Gruß

    Claus


    Genau so mach ich das zur Zeit noch. Die Idee mit dem zentralen Objekt kam von den Vor-Schreibern.
    View erstellt Objekt mit dem Auftrag "hole Daten". Das Objekt benachrichtigt den view dann über delegate. Dieses Objekt speicher ich _nicht_ als View-Property. Wenn der View verschwindet bevor die Daten geladen sind kann kein delegate mehr verständigt werden. --> kein Problem oder?

    Ist es evtl. besser dass ich den download der Daten "irgendwie" abbreche wenn der View verschwindet?
  • Thallius schrieb:

    Wenn jeder ViewController seine eigenen Daten braucht, warum hat dann nicht auch jeder ViewController seine eigene Instanz der Klasse die diese Daten beschafft?

    Dieser Ansatz führt offenbar zu Verbindungsabbrüchen und Timeouts. Deshalb kam mir der Gedanke einer viewunabhängigen Implementierung.
    Warum diese viewunabhängige Implementierung jetzt plötzlich mehrere Verbindungen parallel aufbauen soll weiß ich allerdings nicht.

    Vor Allem würde der ganze Delegatingansatz entzerrt, wenn die zentrale Stelle die Daten cached. Sie kann ja fröhlich weiter im Hintergrund Daten abfragen, wenn sie es für nötig hält.
    Und dann einfach via Notifications darauf hinweisen, dass sich diverse Daten geändert haben.
    Also statt generell ein -didReceiveContactInformation an ein Delegate zu senden und das an entsprechende Empfänger zu verteilen lieber eine DidReceiveContactInformationNotification in den Äther blasen.
    Wer sich für Kontaktinformationen interessiert fragt sie dann gezielt bei der zentralen Datenquelle nach.

    Quasi den Postboten (Delegate) durch ein Postfach (Spezielle auf den Datentyp zugeschnittene Methode) und eine Benachrichtigungs-SMS (Notification) ersetzen.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • danyball schrieb:


    Dieses Objekt speicher ich _nicht_ als View-Property....

    Ist es evtl. besser dass ich den download der Daten "irgendwie" abbreche wenn der View verschwindet?


    Aehm und wer hält dann eine REferenz auf das Object wenn nicht der ViewController? Vielleicht leigt da ja Dein Problem, dass Dir das Objekt einfach unter dem Arsch weggelöscht wird weil es keiner mehr referenziert.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    danyball schrieb:


    Dieses Objekt speicher ich _nicht_ als View-Property....

    Ist es evtl. besser dass ich den download der Daten "irgendwie" abbreche wenn der View verschwindet?


    Aehm und wer hält dann eine REferenz auf das Object wenn nicht der ViewController? Vielleicht leigt da ja Dein Problem, dass Dir das Objekt einfach unter dem Arsch weggelöscht wird weil es keiner mehr referenziert.

    Gruß

    Claus


    Ok, da hab ich direkt noch Fragen dazu:
    - Wann wird so ein unreferenziertes Objekt gelöscht? Oder bleibt das dann ewig im Speicher? (also auch nach Verständigung des Delegates)
    - Wenn ich das Objekt als view-property speichern. Wird es doch dann gelöscht wenn die view verrschwindet, richtig? Und eine evtl. NSURLSession-Verbindung zum Server abgebrochen, richtig?
  • Wann ein Objekt endgültig gelöscht wird weis nur das system. Da hat keiner wirklich Einfluss drauf. In dem Moment wo die letzte Referenz auf ein Objekt gelöscht wird dann kann es halt jederzeit verschwinden oder auch noch wochenlang weiterlaufen....

    Aber du hast meine Frage nicht beantwortet. Wer hält die Referenz auf deine Datenklasse wenn du keine property angelegt hast?

    Gruss

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Achso.. das Objekt kann auch noch länger weiter existieren. Das ist ja schlecht...

    Stimmt sorry: Kann ich dir nicht genau sagen. Denke keiner hält eine Referenz:

    Quellcode

    1. //viewDidLoad:
    2. WebserviceManager *loginManager = [[WebserviceManager alloc]init];
    3. //...
    4. [loginManager sendData];


    Das wars. Und irgendwann erhält das View eben Antwort per Delegate.
  • Thallius schrieb:

    Ja aber nur wenn der nicht schon vom System weggeräumt wurde.

    Gruß

    Claus


    Ok, also pack ich alle Webservice-Objekte in ein Array als property?! (hab meistens mehrere). View weg, objekte weg.
    Objekte die über Views hinweg existieren sollen als AppDelegate-property (oder andere Vorschläge von oben) ?!

    Sollte ich dann vor dereferenzierung die nssessionConnection "per Hand" abbrechen, oder passiert das automatisch?