MVC async request

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

  • MVC async request

    Hallo,

    meine App ist nach dem MVC aufgebaut, so meine ich es zumindest :D . Nun habe ich folgendes Schema:

    TableViewController -> Controller -> SqliteExecution -> SqliteConnection.

    Das heißt: Der TVC kennt meinen Controller den ich mir über das AppDelegate hole, der TVC ruft z.B. die Methode getKunden -> [Kunden] auf vom Controller. Der Controller kennt meine SqliteExecution, er ruft dort die Methode getKunden -> [NSArray] auf.
    Und die SqliteExecution ruft von SqliteConnection execute -> [String] auf.

    Solange alles Synchron läuft ist auch alles gut.

    Jetzt habe ich aber das gleiche mit JSONExecution und JSONConnection nur das jetzt die Anfrage asynchron ist.

    Spoiler anzeigen

    Quellcode

    1. JSONConnection
    2. //NSURLConnection delegate function
    3. func connectionDidFinishLoading(connection: NSURLConnection!) {
    4. var err: NSError?
    5. //Finished receiving data and convert it to a JSON objec
    6. var resultAsArray: NSMutableArray?
    7. let jsonResult: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err)
    8. if let dictionary = jsonResult as? NSDictionary {
    9. resultAsArray = NSMutableArray()
    10. resultAsArray?.addObject(dictionary)
    11. } else {
    12. if let array = jsonResult as? NSMutableArray {
    13. resultAsArray = array
    14. }
    15. }
    16. delegate?.didRecieveResponse(resultAsArray)
    17. }
    Alles anzeigen



    Spoiler anzeigen

    Quellcode

    1. JSONExecution
    2. func getAllKunden() {
    3. self.connection.request("123")
    4. }
    5. func getAllNames() {
    6. self.connection.request("123")
    7. }
    8. func didRecieveResponse(results: NSMutableArray?) {
    9. println(results)
    10. }
    Alles anzeigen



    Spoiler anzeigen

    Quellcode

    1. Controller
    2. func getAllKunden() {
    3. self.jsonExecution.getAllKunden()
    4. }
    5. func getAllNames() {
    6. self.jsonExecution.getAllNames()
    7. }



    Spoiler anzeigen

    Quellcode

    1. TVC
    2. func barButtonItemAction(sender: UIBarButtonItem!) {
    3. self.controller?.getAllKunden()
    4. self.tableView.reloadData()
    5. }



    Ich weiß jetzt nicht, wie soetwas elegant zu lösen ist?! Wenn in Exectuion self.connection.request("123") aufgerufen wird, kommt das ergebnis nach kurzer Zeit bei didRecieveResponse an, aber ich würde gerne nach dem Aufruf das Ergebnis in getAllKunden in ein Kunden Object packen und das Objekt zurückgeben.


    Wie macht man soetwas für geöhnlich?!


    Gruß
  • Wenn ich in meiner NavigationBar vom TVC ein Button habe und dieser Button ein AlertView öffnen soll, wo ich bestätigen kann, dass ich etwas herunterladen möchte, wo sollte ich diesen ganzen Code für die AlertView und dem Herunterladen hin schreiben etwar ebenfalls in der Klasse des TVC?!
  • eminwargo schrieb:

    gritsch schrieb:

    entweder die connection auf synchron umstellen oder eben einen callback oder block verwenden der aufgerufen wird sobald die daten vorhanden sind.
    Kann mir einer sagen was der Unterschied zwischen Callbacks und Blocks ist?!
    naja, callback ist halt einfach eine rückruffunktion (oder methode), ein block ist hingegen ein completter code-block den du zb nur für diesen einen zweck erstellen und dem aufruf mitgeben kannst. dieser ruft ihn dann auf sobald er fertig ist, ein fehler auftritt etc...
  • gritsch schrieb:

    naja, callback ist halt einfach eine rückruffunktion (oder methode), ein block ist hingegen ein completter code-block den du zb nur für diesen einen zweck erstellen und dem aufruf mitgeben kannst. dieser ruft ihn dann auf sobald er fertig ist, ein fehler auftritt etc...
    Dann wären doch in meinem Fall Callbacks hilfreich?! Denn ich habe ja meine View die den Controller aufruft, der wieder mit dem Model Object was per JSON ausliest und das ganze Asynchron läuft damit der ActivityIndicator weiter läuft.

    PS: Sind Completion Handler nicht auch etwas ähnliches?!
  • eminwargo schrieb:

    gritsch schrieb:

    naja, callback ist halt einfach eine rückruffunktion (oder methode), ein block ist hingegen ein completter code-block den du zb nur für diesen einen zweck erstellen und dem aufruf mitgeben kannst. dieser ruft ihn dann auf sobald er fertig ist, ein fehler auftritt etc...
    Dann wären doch in meinem Fall Callbacks hilfreich?! Denn ich habe ja meine View die den Controller aufruft, der wieder mit dem Model Object was per JSON ausliest und das ganze Asynchron läuft damit der ActivityIndicator weiter läuft.
    PS: Sind Completion Handler nicht auch etwas ähnliches?!
    naja, alles irgendwie das selbe (technisch unterschiedlich) aber der einfach heit halber wurden eben blocks eingeführt.
    du kannst davon verwenden was am besten passt.
  • eminwargo schrieb:

    PS: Sind Completion Handler nicht auch etwas ähnliches?!
    Ein Completion-Handler ist ein Callback. Ein Callback (oder Completion-Handler) muss aber nicht als Block implementiert werden. Früher hat man in C dafür beispielsweise Zeiger auf Funktionen verwendet. Solcher Code dürfte sich recht häufig in Core-Foundation finden.
    „Meine Komplikation hatte eine Komplikation.“
  • Gibt es bei diesem Code, etwas zu bemängeln:

    Quellcode

    1. func requestAsynchronous(term: String, completion: (NSMutableArray!, NSURLResponse!, NSError!) -> Void) {
    2. let request = self.request(term)
    3. NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue()) { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
    4. let result = self.parseData(data)
    5. completion(result, response, error)
    6. }
    7. }
  • macmoonshine schrieb:

    Du berücksichtigst weder den übergebenen Fehler noch den Fehlercode in der Serverantwort.
    Das ist ja eine Completion in einer Completion und da möchte ich einfach die Paramter übergeben um sie später dann in der Aufrufenden Klasse auszuwerten, "completion(result, response, error)".
    Und in der Methode self.parseData(data) überprüfe ich erst data auf nil bevor ich damit arbeite.

    Kurze Frage noch: Wenn ich die asynchrone sendAsynchronousRequest Methode in einem Completion Aufrufe ist das dann irgendwie doppelt gemoppelt in Bezug auf Asynchronisation oder bleibt der Aufruf bei einem mal?!
    Außerdem wenn ich in der Completion, requestAsynchronous, die Methode sendSynchronousRequest Aufrufe wäre sie dann Asynchron geworden durch den Aufruf.
  • eminwargo schrieb:

    Und in der Methode self.parseData(data) überprüfe ich erst data auf nil bevor ich damit arbeite.
    Wenn der Server dir beispielsweise einen 404-Fehler liefert, bekommst du Daten und die Fehlervariable zeigt auf nil. Das verarbeitest du nicht. Abgesehen davon solltest du den NSError ebenfalls auswerten, z. B. ins Log schreiben; oder willst du jedes mal den Debugger anwerfen, nur um den Fehlertext zu sehen?

    eminwargo schrieb:

    Kurze Frage noch: Wenn ich die asynchrone sendAsynchronousRequest Methode in einem Completion Aufrufe ist das dann irgendwie doppelt gemoppelt in Bezug auf Asynchronisation oder bleibt der Aufruf bei einem mal?!
    Das ist dann asynchron zu dem (und fast allen anderen) Threads, der die Anfrage schickt. Asynchrone Anfragen blockieren keinen Thread, da sie in der Runloop laufen. Die schaut nach, ob es neue Daten gibt und reicht sie an das Delegate weiter. Dazwischen lässt sie, lax gesagt, den Thread weiterlaufen.
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    eminwargo schrieb:

    Und in der Methode self.parseData(data) überprüfe ich erst data auf nil bevor ich damit arbeite.
    Wenn der Server dir beispielsweise einen 404-Fehler liefert, bekommst du Daten und die Fehlervariable zeigt auf nil. Das verarbeitest du nicht. Abgesehen davon solltest du den NSError ebenfalls auswerten, z. B. ins Log schreiben; oder willst du jedes mal den Debugger anwerfen, nur um den Fehlertext zu sehen?
    Wärst du damit zufrieden:
    Spoiler anzeigen

    Quellcode

    1. func getAllKunden(term: String, completion: (NSMutableArray!, NSURLResponse!, NSError!) -> Void) {
    2. connection.requestAsynchronous(term, completion: { (data: NSMutableArray!, response: NSURLResponse!, error: NSError!) -> Void in
    3. completion(data, response, error)
    4. })
    5. }

    Quellcode

    1. func requestAsynchronous(term: String, completion: (NSMutableArray!, NSURLResponse!, NSError!) -> Void) {
    2. let request = self.request(term)
    3. NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue()) { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
    4. if response == nil || error == nil {
    5. completion(nil, response, error)
    6. }
    7. let result = self.parseData(data)
    8. completion(result, response, error)
    9. }
    10. }

  • Was heisst: Ich soll damit zufrieden sein? Das ist dein Programm und du musst damit zufrieden sein.

    Du wertest übrigens immer noch nicht den Statuscode der HTTP-Antwort aus. Wie verhält sich dein Parser, wenn man ihn mit ein bisschen unerwartetem HTML füttert?

    Was soll übrigens NSOperationQueue() erreichen? Du legst damit jedes eine neue Operation-Queue an, in der dein Completion-Handler ausgeführt wird. Willst du das wirklich und wer hält diese Queue im Speicher?
    „Meine Komplikation hatte eine Komplikation.“
  • Du sollst nicht über den Code entscheiden:D, ich wollte nur wissen, ob du selbst für dich damit zufrieden wärst.

    Den Werte ich aus, wenn ich getAllKunden vom ViewController aufrufe.

    NSOperationQueue wenn ich ehrlich, hab ich das in den meisten Beispielcodes gefunden.


    Mit einer NSOperationQueue können NSOperations im Hintergrund abgearbeitet werden. So kann beispielsweise eine langlaufende Berechnung in den Hintergrund verlagert werden:
  • eminwargo schrieb:

    Du sollst nicht über den Code entscheiden:D, ich wollte nur wissen, ob du selbst für dich damit zufrieden wärst.
    Nein, siehe oben. ;)

    eminwargo schrieb:

    NSOperationQueue wenn ich ehrlich, hab ich das in den meisten Beispielcodes gefunden.
    Operation-Queues sind dafür gedacht, mehrere Operations zu verarbeiten. Ich würde nicht jedes mal eine neue Queue anlegen.
    „Meine Komplikation hatte eine Komplikation.“
  • eminwargo schrieb:

    macmoonshine schrieb:

    Operation-Queues sind dafür gedacht, mehrere Operations zu verarbeiten. Ich würde nicht jedes mal eine neue Queue anlegen.
    Was könnte ich den sonst verwenden, denn sendAsynchronousRequest verlangt ein NSOperationQueue als Parameter?!
    Was muss man denn machen, damit man ein Objekt mehrmals verwenden kann?
    „Meine Komplikation hatte eine Komplikation.“