2009-05-07 8 views
2

J'ai récemment appris le SDK Apple (pour iPhone, etc) et suis tombé sur quelque chose que je ne peux pas comprendre. Dans les documents pour "Using NSURLConnection" deErreur ou confusion dans la documentation Apple SDK sur NSURLConnection?

J'ai trouvé un morceau d'explication étrange et un exemple de code. D'abord, il est dit:

Le téléchargement commence immédiatement après la réception du message initWithRequest: delegate:. Il peut être annulé à tout moment avant que le délégué ne reçoive un connectionDidFinishLoading: ou une connexion: didFailWithError: message en envoyant un message d'annulation à la connexion.

Ensuite, il montre le morceau de code suivant:

 
    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 

    } 

Alors, il me semble que le téléchargement doit commencer immédiatement dans un autre thread dès theConnection est initialisé. Cela est clair car le code est non bloquant et renvoie des messages au délégué, dans ce cas, self. Pourtant, l'allocation (autorelease style) de receivedData se produit après l'autre thread est démarré. N'est-ce pas une condition de course dangereuse? Cela ne peut-il pas entraîner un plantage, une fuite de mémoire ou une perte de données dans le cas d'une réponse très rapide du serveur (par exemple un périphérique de bouclage supérieur) ou dans le cas d'une planification de threads malencontreuse? Cela n'aurait-il pas plus de sens d'allouer receiveData avant l'initialisation de Connection, et ensuite de le relâcher dans le cas else ci-dessus?

Je suis si confuse par ce morceau de code, j'espère que quelqu'un pourra me donner un peu de lumière. Merci pour toute information,

Rudi Cilibrasi

Répondre

6

Il n'y a pas de condition de course. Le téléchargement est démarré en arrière-plan sur un thread séparé, mais les messages envoyés au délégué pour vous informer de la progression du téléchargement sont toujours appelés sur le thread qui a démarré le téléchargement.

Vous pouvez certainement allouer le NSData avant la création de la connexion, si cela vous est plus clair. Vous pouvez même l'allouer dans la connexion: didReceiveData: méthode, si vous voulez vous assurer que le NSData n'a pas été alloué sauf s'il y avait des données à stocker.

Je pense que l'exemple est écrit de la manière la plus courte possible, afin de ne pas confondre la présentation avec beaucoup de code non pertinent.

De 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

Cela a du sens. Pouvez-vous donner une URL qui supporte l'affirmation que tous les messages de délégation sont envoyés par le fil principal s'il vous plaît pour mon étude? Merci pour l'aide et l'info. –

+1

Il est également intéressant de noter que les messages de délégation de NSURLConnection sont rassemblés via la boucle d'exécution et ne peuvent donc se produire qu'une fois le contrôle renvoyé. – rpetrich

+0

Merci beaucoup pour l'aide Mark Bessey et rpetrich. C'est clair pour moi maintenant et je l'apprécie. –

2

Il n'y a pas de condition de course ici. NSURLConnection utilise le NSRunLoop pour distribuer ses évènements. Par conséquent, aucune donnée ne peut vous parvenir avant que la boucle d'événement suivante ne commence. Cela signifie qu'aucun appel à connection:didReceiveData: ne se produira avant la prochaine boucle d'événement, peu importe le moment où les données reviennent réellement, et que connection:didReceiveData: sera appelé sur le thread qui a lancé le chargement. Donc vous avez le reste de cette boucle d'exécution pour tout mettre en ordre. "Immédiatement" signifie ici "vous n'avez pas besoin de faire quoi que ce soit pour le démarrer."

Ceci n'est pas une conjecture ou un détail d'implémentation modifiable; C'est basé sur les principes de conception de Cocoa. Pour mieux comprendre Cocoa, supposons que presque tout se passe sur le thread principal. Alors que les frameworks peuvent occasionnellement engendrer des threads comme détail d'implémentation, ils donnent toujours l'illusion qu'ils ne le font pas.Les opérations asynchrones, par nature, apparaîtront donc toujours sur une boucle d'événement ultérieure. Coopérative, pas préventive, multitâche est la façon Cocoa.

+0

Cela m'apprendra à laisser la fenêtre de mon navigateur ouverte si longtemps avant de répondre à quelque chose ... Oui, je viens de répéter complètement Mark, qui a la bonne réponse. –

+0

Upvoted, puisque vous avez ajouté quelques détails supplémentaires sur le NSRunLoop que je n'ai pas tout à fait obtenir. –

+0

Merci. A l'origine, je me suis égaré dans ce sujet en cherchant quelque chose d'autre, mais il a soulevé quelques questions intéressantes qui m'intéressaient, et votre réponse était une lecture bien écrite, informative et agréable - j'aime beaucoup la dernière ligne, J'ai abordé mes propres pensées abruptes sur la façon dont un fil pourrait déclencher un événement dans un autre sans briser les choses (je pensais préémitive, mais coopératif ... qui a un sens). – RonLugge

Questions connexes