vendredi 23 mars 2012

Code de session en ligne pour les gros objets (Plus un avertissement)

Dans le chapitre 9 du Développement Plus pour iPhone, Nous avons écrit un ensemble de classes qui imitait le comportement des GameKit peer-to-peer connectivité, mais pour les connexions réseau régulier (fonctionne uniquement avec GameKit connexions Bluetooth et réseau local). Fondamentalement, nous avons écrit une classe qui vous permet d'envoyer et de recevoir tout ce qui peut être emballé dans une instance de NSData. Comme il est relativement trivial à mettre en œuvre pour la plupart des classes de NSCoding, cela signifie passer des objets entre les apps iOS deux (ou une iOS et une application Mac) devient assez facile. Vous n'avez pas d'interroger les données, ou de s'inquiéter de chunking les données. Vous avez juste faire un appel de méthode et passer une instance NSData pour envoyer des données, puis mettre en œuvre une méthode déléguée pour recevoir des données de retour de l'autre extrémité. La vie est belle, non?

Hmm...

Peut-être pas. Il ya une limitation assez grand dans la mise en œuvre du livre. C'est la mise en oeuvre, conçu pour passer des petits paquets de données (se déplace jeu TicTacToe), tout conservé en mémoire. Si vous essayez d'envoyer une image de bonne taille à la connexion d'autres, probablement vous à court de mémoire assez rapidement.

Il ya quelque temps, j'ai été confronté exactement à cette situation. Pour une application kiosque qui MartianCraft a été écrit pour un client, j'ai eu besoin d'envoyer de grandes images prises avec un appareil photo reflex numérique à partir d'un programme Cocoa de Mac à un programme d'iPad et aussi nécessaire pour envoyer des photos prises avec l'appareil de l'iPad est de retour à l'application Mac Cocoa. Ces images, comprimé, variait d'environ un à environ cinq megs. J'ai attrapé la classe à partir OnlineSession More, En pensant, j'ai eu le code réseau essentiellement fait, et regardé ma demande de descendre dans un flamboiement de ... bien ... pas la gloire, c'est sûr. Non seulement l'iPad à court de mémoire, il a manqué de mémoire rapide ... beaucoup plus vite que prévu. Même l'envoi des images plus petites caméras iPad souvent causé peu de mémoire se bloque.

Il y avait deux problèmes fondamentaux avec la classe OnlineSession lorsque vous essayez de l'utiliser pour l'envoi de gros volumes de données. Tout d'abord, comme j'ai dit, c'est qu'il s'appuyait uniquement sur la mémoire physique. Étant donné que les limites physiques de l'iPad d'origine, ce fut problématique. Mais il y avait un autre problème, beaucoup plus grand.

Le deuxième problème était que pendant le processus de chunking les données à envoyer, le code a continué à faire des copies inutiles des données. Dit simplement, j'ai fait une erreur n00b. L'erreur n'a pas d'impact de l'application TicTacToe parce que le jeu serait se déplace facilement dans le tampon d'émission, mais c'est une erreur que j'ai faite avant et devrait définitivement avons connu mieux.

Alors, quoi, précisément, a été cette erreur, demandez-vous?

L'utilisation régulière de NSData dataWithBytes constructeur de commodité: longueur: lors de la création de la nouvelle instance NSData pour stocker la partie de l'image qui ne s'insère pas dans le tampon d'émission. Si vous lisez la description de dataWithBytes: longueur: il dit très clairement que cela fait une copie des données que vous fournissez. Donc, chaque fois qu'un paquet a été envoyé, le code serait de créer une nouvelle instance NSData pour tenir le reste qui ne rentrait pas dans le tampon, et il serait copier toutes les données non envoyés restantes pour chaque paquet. Ouch.

Donc, comme un exemple simple, si nous devions envoyer une image 5 meg, et le tampon d'émission a été fixé à 128k, le code serait de faire une copie 4,825 meg après le premier paquet a été envoyé, puis une copie de 4.75 meg, après le deuxième paquet a été envoyé, une copie de 4,265 meg après le troisième paquet, et ainsi de suite. Après chaque paquet, une autre copie légèrement plus petit des données a été faite. Une progression descendante qui mangent mémoire rapide.

Après beaucoup de jurons à moi, j'ai fait quelques modifications de la classe de faire deux choses.

Tout d'abord, je suis passé à l'aide de dataWithBytes NSData: NoCopy: longueur: qui utilise les données fournies en place sans faire de copie. Ce gardé l'empreinte mémoire beaucoup plus petit. Dans certains cas, car les images DSLR ont été si grande et si notre application nécessaire pour envoyer tant d'années, j'ai toujours rencontré des problèmes de mémoire. Ainsi, la deuxième chose que j'ai faite a été d'ajouter la mise en cache système de fichiers de la file d'attente sortante afin que tous les objets codés en attente d'être envoyés n'ont pas eu à tenir en mémoire pour l'application de fonctionner correctement.

La nouvelle version des fonctions de classe exactement comme celle de la livre, alors vous devriez être capable de tout rendez-remplacer les OnlineSession du chapitre 9 avec celui-ci sans apporter aucune modification à votre code d'application.

Vous pouvez télécharger la nouvelle version ici.

Aucun commentaire: