2009-05-07 8 views
2

Ich habe kürzlich das Apple SDK (für iPhone usw.) gelernt und bin auf etwas gestoßen, das ich nicht verstehen kann. In den Dokumenten für "Using NSURLConnection" vonFehler oder Verwirrung in der Apple SDK-Dokumentation zu NSURLConnection?

fand ich eine seltsame Erklärung und Beispielcode. Zuerst heißt es:

Der Download beginnt sofort nach dem Empfang der initWithRequest: delegate: Nachricht. Sie kann jederzeit abgebrochen werden, bevor der Delegat eine Verbindung erhältDidFinishLoading: oder Verbindung: didFailWithError: Nachricht, indem der Verbindung eine Abbruchnachricht gesendet wird.

Als nächstes zeigt es das folgende Stück Code:

 
    NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; 

    if (theConnection) { 

    // Create the NSMutableData that will hold 

    // the received data 

    // receivedData is declared as a method instance elsewhere 

    receivedData=[[NSMutableData data] retain]; 

    } else { 

    // inform the user that the download could not be made 

    } 

So scheint es mir, dass der Download muss sofort in einem anderen Thread starten, sobald theConnection initialisiert wird. Dies ist klar, da der Code nicht blockiert ist und Nachrichten an den Delegaten, in diesem Fall an sich, zurücksendet. Doch die Zuweisung von receivedData (Autorelease-Stil) passiert nach der andere Thread wird gestartet. Ist das nicht eine unsichere Race Condition? Könnte dies nicht zu einem Absturz, Speicherleck oder Datenverlust führen, wenn eine sehr schnelle Serverantwort (z. B. über ein Loopback-Gerät) oder eine unglückliche Thread-Planung vorliegt? Wäre es nicht sinnvoller receivedData zuzuweisen, bevor die Verbindung initialisiert wird, und dann einfach im obigen else-Fall freizugeben?

Ich bin so verwirrt von diesem Stück Code, hoffe, dass jemand etwas Licht für mich darauf werfen kann. Vielen Dank für jede Info,

Rudi Cilibrasi

Antwort

6

Es gibt keine Race-Bedingung. Der Download wird im Hintergrund in einem separaten Thread gestartet, aber die Nachrichten, die an den Delegaten gesendet werden, um Sie über den Download-Fortschritt zu informieren, werden immer beim Thread aufgerufen, der den Download gestartet hat.

Sie können die NSData sicher zuweisen, bevor die Verbindung erstellt wird, wenn Ihnen das klarer ist. Sie könnten es sogar in der Verbindung zuweisen: didReceiveData: method, wenn Sie sicherstellen wollten, dass die NSData nur dann zugeordnet wurden, wenn Daten gespeichert werden mussten.

Ich denke, das Beispiel ist so geschrieben, wie es ist, es so kurz wie möglich zu machen, um die Präsentation nicht mit viel irrelevantem Code zu verwechseln.

Von the documentation for NSURLConnection:

NSURLConnection’s delegate methods allow an object to receive informational callbacks about the asynchronous load of a URL request. Other delegate methods provide facilities that allow the delegate to customize the process of performing an asynchronous URL load.

Note that these delegate methods will be called on the thread that started the asynchronous load operation for the associated NSURLConnection object.

+0

Das macht Sinn. Kannst du eine URL angeben, die die Behauptung unterstützt, dass alle Delegationsnachrichten durch den Hauptthread gesendet werden, bitte für meine Studie? Danke für die Hilfe und Infos. –

+1

Interessant ist auch, dass die NSURLConnection-Delegierungsnachrichten durch die Ausführungsschleife gemarshallt werden und daher nur auftreten können, wenn die Steuerung an sie zurückgegeben wird. – rpetrich

+0

Vielen Dank für die Hilfe Mark Bessey und Rpetrich. Das ist mir jetzt klar und ich weiß es zu schätzen. –

2

Es gibt hier keine Race-Bedingung. NSURLConnection verwendet die NSRunLoop, um seine Ereignisse zu senden. Daher können keine Daten zu Ihnen gelangen, bis die nächste Ereignisschleife beginnt.

Dies bedeutet, dass bis zur nächsten Ereignisschleife keine Aufrufe an connection:didReceiveData: auftreten werden, unabhängig davon, wann die Daten tatsächlich zurückkommen und dass connection:didReceiveData: für den Thread aufgerufen wird, der die Ladeoperation gestartet hat. Sie haben also den Rest dieser Laufschleife, um alles in Ordnung zu bringen. "Sofort" bedeutet hier "Sie müssen nichts tun, um es zu starten."

Dies ist keine Vermutung oder ein veränderliches Implementierungsdetail; Es basiert auf den Designprinzipien von Cocoa. Um Cocoa am besten zu verstehen, gehen Sie davon aus, dass fast alles im Hauptthread auftritt. Während die Frameworks gelegentlich Threads als Implementierungsdetail erzeugen können, liefern sie immer die Illusion, dass sie dies nicht tun.Asynchrone Operationen erscheinen daher immer auf einer späteren Ereignisschleife. Kooperativ, nicht präemptiv, Multitasking ist der Cocoa-Weg.

+0

Das bringt mir bei, mein Browserfenster so lange offen zu lassen, bis ich tatsächlich auf etwas reagiere .... Ja, ich habe Mark gerade komplett wiederholt, wer hat die richtige Antwort. –

+0

Upvoted, da Sie einige zusätzliche Details zum NSRunLoop hinzugefügt haben, die ich nicht ganz bekommen habe. –

+0

Danke. Ich habe mich ursprünglich in diesen Thread verirrt und etwas anderes gesucht, aber es hat einige interessante Fragen aufgeworfen, auf die ich neugierig war, und deine Antwort war eine gut geschriebene, informative und unterhaltsame Lektüre - ich mag die letzte Zeile am meisten, so wie sie Ich sprach meine eigenen abrupten Gedanken darüber an, wie ein Thread ein Ereignis in einem anderen auslösen könnte, ohne die Dinge zu unterbrechen (ich dachte präemptiv, aber kooperativ ... das macht Sinn). – RonLugge