[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.


  • DrakenDraken Membre
    février 2016 modifié #3

    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. 


  • Joanna CarterJoanna Carter Membre, Modérateur
    Mais les fichiers .plist peuvent être utilisés sur d'autres plateformes.
  • DrakenDraken Membre
    février 2016 modifié #5

    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.

  • En relisant ton code, je m'aperçois que:

    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)
  • DrakenDraken Membre
    février 2016 modifié #7

    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.



    print("Taille Int : ", sizeof(Int), " octets")
    print("Taille UInt : ", sizeof(UInt), " octets")
    print ("--")
    print("Taille Int32 : ", sizeof(Int32), " octets")
    print("Taille UInt32 : ", sizeof(UInt32), " octets")
    print("--")
    print("Taille Int16 : ", sizeof(Int16), " octets")
    print("Taille UInt16 : ", sizeof(UInt16), " octets")



     


    Processeurs 32 bits (iPhone 4, 4S et 5)


    --


    Taille Int    :  4  octets


    Taille UInt   :  4  octets


    --


    Taille Int32  :  4  octets


    Taille UInt32 :  4  octets


    --


    Taille Int16  :  2  octets


    Taille UInt16 :  2  octets


     


     


     



     


    Processeurs 64 bits (à  partir de l'iPhone 5S)


    --


    Taille Int    :  8  octets


    Taille UInt   :  8  octets


    --


    Taille Int32  :  4  octets


    Taille UInt32 :  4  octets


    --


    Taille Int16  :  2  octets


    Taille UInt16 :  2  octets


     


     


    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.



  • En relisant ton code, je m'aperçois que:

    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.




    Il y a une méthode plus efficace, sans passer par le codage binaire bas-niveau ?

  • tabliertablier Membre
    février 2016 modifié #9

    Mais qui utilise encore des Powers PC, à  part Tablier peut-être ?



    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 ?

  • tabliertablier Membre
    février 2016 modifié #11

    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). 

  • AliGatorAliGator Membre, Modérateur
    Le problème du stockage bas niveau c'est que ce n'est pas résilient (résistant aux changements, d'API, de Processeur, etc...). C'est pour cela que le format géré par les NSArchivers sont faits, pour être indépendants de toutes ces problématiques.

    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.
  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2016 modifié #14


    taille d'un int selon le processeur 32/63 bits




     


    Qu'est-ce que tais qu'Apple n'a pas encore annoncé ?  ???


  • CéroceCéroce Membre, Modérateur
    février 2016 modifié #15

    Le problème du stockage bas niveau c'est que ce n'est pas résilient (résistant aux changements, d'API, de Processeur, etc...). C'est pour cela que le format géré par les NSArchivers sont faits, pour être indépendants de toutes ces problématiques.


    ç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 !).




  • Mais à  l'époque, écrire directement les structures de données de la mémoire vers le disque était plus efficace.




     


    Je crois que même dans les années 90, ce n'était pas une bonne pratique. 

  • Jolin0558Jolin0558 Membre
    février 2016 modifié #18

    Ce n'est pas un gros problème housse sony xperia m5 housse sony m5


  • Aucune des choses qu'améliorent les bonnes pratiques ne constituent de gros problèmes par elle-même.


    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.
Connectez-vous ou Inscrivez-vous pour répondre.