[Swift]Stockage Tableau d'Int16 dans un NSData
J'ai voulu stocker un tableau d'Int16 dans un NSData.
let tableauInt16:[Int16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Première constatation : Xcode refuse de l'encoder, Int16 n'étant pas compatible avec le protocole de AnyObject. Ce n'est pas nouveau, on en avais déjà parlé dans ce topic :
http://forum.cocoacafe.fr/topic/14449-swiftconversion-anyobject-uint64/
Tant pis pour les Int16, je teste avec un tableau d'Int.
let tableauInt:[Int] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Archivage :
let dataTableauInt = NSKeyedArchiver.archivedDataWithRootObject(tableauInt)
print ("Pour ", tableauInt.count, " valeurs, taille du NSData : ", dataTableauInt.length)
Cela consomme beaucoup de mémoire, pour stocker quelques informations :
Pour 10 valeurs, taille du NSData : 308 octets
Pour 30 valeurs, taille du NSData : 454 octets
Pour 110 valeurs, taille du NSData : 854 octets
J'ai farfouillé dans la doc et sur Internet pour voir comment stocker les chiffres sous une forme binaire compacte (sous forme d'Int16). Au final j'ai écrit ces deux méthodes bas-niveau :
func createDataArrayInt16(array: [Int16]) -> NSData {
let data = NSData(bytes: array, length: array.count * sizeof(Int16))
return data
}
Et pour lire le contenu du NSData :
func getArrayInt16(data :NSData) -> [Int16] {
let pointer = UnsafePointer<Int16>(data.bytes)
let count = data.length/sizeof(Int16)
let buffer = UnsafeBufferPointer<Int16>(start:pointer, count:count)
let array = [Int16](buffer)
return array
}
Exemple d'utilisation :
let data16 = createDataArrayInt16(tableauInt16)
print ("Pour ", tableauInt16.count, " valeurs (Int16)")
print ("=> taille du NSData : ", data16.length, " octets")
let array = getArrayInt16(data16)
print (array)
Pour 10 valeurs (Int16)
=> taille du NSData : 20 octets
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
20 octets pour 10 Int16, c'est exactement la taille théorique.
Cette manière de stocker les informations est bien plus compact. Mais est-il légitime de penser stockage binaire sous iOS ? Y a-t-il un risque technique ou un problème d'incompatibilité auquel je ne pense pas ?
Réponses
Les endians si tu envois les données sur une autre plateforme.
J'y avais pensé. Ce n'est pas un gros problème, les processeurs Intel et ARM utilisant le même codage pour les octets de poids faible/fort. Tant que cela vas avec OSX et iOS, c'est bon. Et même pour Android, d'ailleurs.
Je m'en doute, vu que les Powers PC n'utilisent pas le même codage poids faible/poids fort. C'est normal qu'Apple ai pensé à cette compatibilité en adoptant les processeurs Intel. Mais qui utilise encore des Powers PC, à part Tablier peut-être ? De toute manière, c'est juste la compatibilité OSX (procs intel) et iOS qui m'interesse.
EDIT : Une fois de plus, je suis surpris par la taille considérable des données sérialisées. iOS est une plate-forme mobile sans beaucoup de mémoire. 16 Go de base c'est peu, sans parler des anciens iPhone/iPod Touch à 8 Go. C'est étonnant qu'on ne puisse pas stocker les données d'une manière plus efficace, du moins sans passer par le bas niveau et le stockage au format binaire.
Dans ton premier exemple, tu serialises un NSArray de NSNumber pour créer ton NSData. Ce n'est pas la méthode la plus efficace pour créer un NSData de Int.
La deuxième méthode est bien meilleure et tu peux toujours utiliser NSKeyedArchiver pour sérialiser ton NSData (enfin si tu n'as que ce NSData à sauvegarder, autant utiliser writeToFile)
Une remarque à l'intention des débutants tombant sur ce topic et voulant utiliser cette méthode. Les Int et UInt occupent 32 bits (4 octets) sur un processeur 32 bits (iPhone 4, 4S et 5). Et 64 bits sur les processeurs 64 bits (iPhone 5S, 6, 6+, 6S, 6S+, etc..). Cela peut poser des problèmes de compatibilité, avec les fichiers binaires.
Il est préférable d'utiliser les Int16, Int32, UInt16 et Uint32 dont la taille est constante sur les processeurs 32 et 64 bits.
Il y a une méthode plus efficace, sans passer par le codage binaire bas-niveau ?
Oui, quand je ne peux faire autrement ! Exemple, j'ai une version ancienne et officielle d'Archicad pour faire des plans. La version actuelle coûte aux environs de 3500€. Bien trop cher pour ce que j'en fais !
Pas de version Archicad pour Atari ST ?
J'ai au moins deux logiciels qui ne marchent que sur ppc: Archicad et Labview.
Ceci dit, j'ai encore un Atari, juste pour aider l'association Aconit qui organise de temps en temps un rétro-Gaming.
Je suis toujours étonné de voir des jeunes se prendre au jeu de ces vielles disquettes !
J'étais au courant pour ton Atari et l'association Aconit. Tu en parles de temps en temps. Moi quand j'étais jeune je me suis amusé avec des manipulateurs morses, trouvé dans la cave, pour communiquer "secrètement" avec mon frère d'un étage à l'autre (avec les fils passant par l'escalier).
Alors certes ça nécessite un petit header qui prend un peu de place, donc ça prend quelques octets en plus par rapport à un stockage bas niveau. Mais au moins tu n'as pas à te poser les questions des risques et problématiques de endianness, taille d'un int selon le processeur 32/63 bits, etc.
Du coup c'est un compromis à décider. Si tu veux la plus petite taille possible à l'octet près, il faut te résigner à penser à tester ton code contre les risques de changements de processeurs & co, et faire que ton code ne soit pas portable (ça a posé pas mal de pb lors du passage de 32 à 64 bits à ceux qui faisaient des manipulations bas niveau du genre). Si tu veux un format plus sûr et pérenne et qui soit resilient et stable face à ces risques, tu seras prêt à sacrifier un header de 100 petits octets ou du genre pour avoir la stabilité.
Perso je ne pense pas que tu y gagnes énormément à vouloir gagner 10 octets par-ci et 200 octets par là par rapport à utiliser la couche d'abstraction de NSArchiver, on n'est pas sur un micro-contrôleur où chaque optimisation à l'octet près est importante.
Qu'est-ce que tais qu'Apple n'a pas encore annoncé ? ???
ça me rappelle un article qui revenait sur les fichiers générés par Word ou Excel. En gros, le regard habituel qu'en ont les informaticiens est que ce sont des formats binaires obscurs et bricolés. On se dit qu'utiliser le XML aurait été bien plus adapté.
Sauf que les contraintes dans les années 90 n'étaient pas du tout les mêmes qu'aujourd'hui. Actuellement, on va privilégier l'interopérabilité alors on préfère un format bien structuré, quitte à perdre de la place, de la mémoire et du temps machine à l'ouverture et à l'enregistrement.
Mais à l'époque, écrire directement les structures de données de la mémoire vers le disque était plus efficace.
C'était bien pire à la fin des années 1980, quand j'ai commencé à bricoler de petits jeux, sur des machines 8 bits. Le moindre octet était important, pour caser le plus possible de données dans une mémoire ridicule. Ma première application "commerciale" fut un jeu de guerre spatiale en basic, publiée dans une revue d'informatique. C'étais pour Canon X-07 (8 Ko de mémoire !).
Je crois que même dans les années 90, ce n'était pas une bonne pratique.
Ce n'est pas un gros problème housse sony xperia m5 housse sony m5
Il s'agit juste de mieux connaà®tre son métier pour diminuer les risques, diminuer le stress, améliorer les prévisions, en faire plus pour le même prix, voire tout simplement permettre des évolutions.