[Résolu] Problèmes avec les Settings Bundle

août 2014 modifié dans API UIKit #1

Bonjour à  tous,


 


J'essaye d'implémenter des settings pour mon application et j'ai deux problèmes, ou plutôt un problème et une question :


 


Le problème : Pourquoi, quand j'ajoutes des choses, comme un élément multi-value, je ne vois rien apparaitre dans les prefs de l'App (y compris un title). J'ai même réinitialisé le simulateur, désinstallé l'App etc. Rien à  faire.


 


La question : Comment faire pour avoir un bouton (en fait un champ de texte avec une flèche tout à  droite) qui, lors du click, affiche une page HTML ou tout du moins du texte (la partie Legal par exemple).


 


Merci pour votre aide.


Réponses

  • Hello,


     


    Voila un document qui t'aidera à  implémenter les préférences dans ton application.


    https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/UserDefaults/UserDefaults.pdf


     


     




    La question : Comment faire pour avoir un bouton (en fait un champ de texte avec une flèche tout à  droite) qui, lors du click, affiche une page HTML ou tout du moins du texte (la partie Legal par exemple).




     


    Il suffit de créer ton button et utiliser une UIWebView pour afficher le html. 


     


    PS : Je ne pense pas que tu auras des réponses pour ce genre de questions " Comment faire un button et au click...". Le grand effort c'est à  toi de le faire :). C'est très important de montrer que tu as bien essayé de résoudre ton problème, simple ou compliqué ensuite demander de l'aide.

  • AliGatorAliGator Membre, Modérateur

    Hello,
     
    Voila un document qui t'aidera à  implémenter les préférences dans ton application.
    https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/UserDefaults/UserDefaults.pdf
     
     
     
    Il suffit de créer ton button et utiliser une UIWebView pour afficher le html. 
     
    PS : Je ne pense pas que tu auras des réponses pour ce genre de questions " Comment faire un button et au click...". Le grand effort c'est à  toi de le faire :). C'est très important de montrer que tu as bien essayé de résoudre ton problème, simple ou compliqué ensuite demander de l'aide.

    Je pense que sa question sur "comment faire un bouton qui lors du click affiche les infos Légales" était dans le cadre de "comment faire en sorte que ça s'affiche comme ça... Dans son Settings.bundle" (du moins j'imagine, sinon il n'aurait pas posé la question dans son sujet portant sur Settings.bundle).



    Et la réponse est bien dans la doc ici en utilisant ce qui est décrit dans la partie "Child Pane".


  • Je pense que sa question sur "comment faire un bouton qui lors du click affiche les infos Légales" était dans le cadre de "comment faire en sorte que ça s'affiche comme ça... Dans son Settings.bundle" (du moins j'imagine, sinon il n'aurait pas posé la question dans son sujet portant sur Settings.bundle).




     


    Ah j'ai pas fait attention.


     


    @ObjectiveSwift Mea culpa :)

  • août 2014 modifié #5

    Je reviens vers vous après avoir pris le temps de lire le manuel que vous m'avez passé en lien.


     


    Alors j'ai toutefois encore deux questions (oui ma question était mal formulé concernant le bouton, c'était le Child pane), donc :


     


    1/ J'ai bien un élément child pane qui prends en paramètre un autre fichier .plist qui, lui-même, a un paramètre (de type String) qui contient du texte. Comment, quand je click sur mon child pane pourrais-je afficher le texte ? (j'ai essayé avec un fichier texte mais évidemment ça plante direct).


     


    2/ Dans les prefs, quand vous sélectionnez Twitter ou Facebook, il y a un lien pour aller directement sur les sites. Est-ce que vous avez une idée pour faire ce genre de chose ? Je n'ai rien vu de tel dans la doc.


     


    Merci pour votre aide.


  • août 2014 modifié #6

    Pour infos, sur ce lien, toutes les propriétés sont détaillés. Ceci explique pourquoi je ne voyais pas, par moment, mes modifications apportées au fichier plist (voir premier post, tout en haut). Tous les champs required doivent être présent et renseignés.


     


    Par contre, impossible d'obtenir une page uniquement avec du texte comme dans iPhoto -> Contrat de licence (dans les préférences). Idem pour le copyright situé juste en dessous de ce menu.


     


    Edit : Y a bien les groupes que je pourrais utiliser mais ils passent systématiquement le texte en majuscule.


  • août 2014 modifié #7

    Bon alors après avoir téléchargé iPhoto et ouvert le logiciel (décompression et Afficher le contenu du paquet), j'ai regardé comment faisait Apple. Ouais, un peu de hack :)


     


    Il faut dire que Xcode est vraiment pourris sur sa gestion des fichiers plist. De plus la documentation est mal documenté (un comble), il manque des éléments et elle n'est pas à  jour. Je veux bien vos retours si je me fourvoie mais pour le coup j'ai des doutes. Et qu'est-ce que c'est que cet XML de Mer..# ??? Où sont passé les attributs (par exemple) ?


     


     


    Pour aider les prochains qui rencontrerais ce genre de problème, le meilleur moyen pour éditer les fichiers est de passer par un éditeur externe et donc uniquement construire le fichier en XML via un éditeur de texte. De plus, il y a un certain nombre de chose à  savoir :


    - Tout fichier plist doit avoir son fichier strings associé (vital pour le fonctionnement des Child Pane)


    - Le StringTable des fichiers enfants doit-être renseigné :



    // Début du fichier :

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>StringsTable</key>
    <string>MON-FICHIER</string>

    - La technique1 pour obtenir ce que je cherchais à  faire est bien d'utiliser des "groupes" mais l'astuce réside dans les fichiers strings. En gros, vous avez ceci dans un fichier plist :



    <dict>
    <key>Type</key>
    <string>PSGroupSpecifier</string>
    <key>FooterText</key>
    <string>TRUC</string>
    </dict>

    Eh bien dans le fichier strings associé vous devez avoir quelque chose comme :



    "TRUC" = "Mon texte";

    Pour en revenir à  Xcode, on fait très facilement de fausses manipulations et des comportements sont vraiment "bizarre". Exemple, quand vous devez créer un fichier plist, vous devez faire un click droit pour afficher le menu contextuel et préciser que c'est un fichier de configuration pour iOS. Si vous changez de fichier et revenez, ce paramètre n'est pas pris en compte. Apparemment ce n'est pas très grave mais au début c'est déroutant, pour ne pas dire pénible.


     


    Dernier point (je reviendrais ici si j'oublis des détails), il est impératif d'ajouter vos fichiers plist et strings DANS le settings bundle via le finder...


     


    Voilà , a bientôt.


     


    EDIT :


    Version actuelle de Xcode : 5


     


    Un détail supplémentaire, Xcode et son édition des fichiers plist est quand même utile pour une chose. Dans la doc, les valeurs de certains éléments (genre AutocapitalizationType) ne sont pas correct.


     


    1/ Quand je parle de technique, c'est en fait un "hack" qui détourne le système de gestion de traduction. Vous lui indiqué un mot-clé qui devrait-être traduit dans une autre langue mais en fait vous affichez le contenu désiré.


  • AliGatorAliGator Membre, Modérateur
    Merci pour ces retours qui pourront effectivement servir à  d'autres.

    En effet, normalement Xcode saut automatiquement détecter de quel type de fichier PLIST il s'agit (un Info.plist de description d'un bundle / d'une app, ou un PLIST de Settings.bundle, ou autre...) mais il arrive qu'il ne détecte pas le type de PLIST et qu'il faille alors le choisir/forcer manuellement.

    As-tu essayé d'éditer ton fichier PLIST via l'interface Xcode... après avoir mis ton fichier Root.plist (ou Licence.plist ou le nom que tu lui as donné) DANS le Settings.bundle ? Peut-être qu'une fois que le PLIST est bien dans le Settings.bundle, Xcode détecte mieux que c'est pas n'importe quel PLIST mais un PLIST de Settings, et te propose alors les clés adéquates en auto-complétion (plutôt que de te laisser les deviner toi-même ou te proposer les mauvaises) ?

    Et sinon je confirme, pour mettre les fichiers PLIST dans le Settings.bundle, il faut le faire via le Finder, car Xcode voit le Settings.bundle non pas comme un groupe / dossier mais comme un bundle. C'est un peu chiant c'est vrai. (C'est d'ailleurs le cas pour tout autre bundle que tu voudrais mettre dans ton application, même si le seul cas concret que l'on rencontre de vouloir faire un bundle dans une app iOS c'est pour le Settings.bundle)
  • août 2014 modifié #9

     


     


    En effet, normalement Xcode saut automatiquement détecter de quel type de fichier PLIST il s'agit (un Info.plist de description d'un bundle / d'une app, ou un PLIST de Settings.bundle, ou autre...) mais il arrive qu'il ne détecte pas le type de PLIST et qu'il faille alors le choisir/forcer manuellement.

     


    En fait, se n'est pas réellement un problème de détection mais plutôt pratique. Par exemple, si tu veux afficher tel ou tel fichier plist en mode source code, tu sélectionnes ensuite d'autres fichiers, tu reviens et boum, il t'affiches la vue "normale". Pénible, de plus que ça le fait un peu quand il veut.


     



     


     


    As-tu essayé d'éditer ton fichier PLIST via l'interface Xcode... après avoir mis ton fichier Root.plist (ou Licence.plist ou le nom que tu lui as donné) DANS le Settings.bundle ? Peut-être qu'une fois que le PLIST est bien dans le Settings.bundle, Xcode détecte mieux que c'est pas n'importe quel PLIST mais un PLIST de Settings, et te propose alors les clés adéquates en auto-complétion (plutôt que de te laisser les deviner toi-même ou te proposer les mauvaises) ?

     


    Comme dis juste avant il le détecte bien, par contre et là  c'est logique, si tu fais n'importe quoi dans le fichier XML il t'affiche un message d'erreur. Le vrai problème c'est que dans la doc il est dis qu'il faut copier tes fichiers dans le bundle via le finder MAIS pour la version 4 de Xcode. A toi de deviner (quand tu n'es pas au courant), que c'est toujours valable.


     



     


     


    Et sinon je confirme, pour mettre les fichiers PLIST dans le Settings.bundle, il faut le faire via le Finder, car Xcode voit le Settings.bundle non pas comme un groupe / dossier mais comme un bundle. C'est un peu chiant c'est vrai. (C'est d'ailleurs le cas pour tout autre bundle que tu voudrais mettre dans ton application, même si le seul cas concret que l'on rencontre de vouloir faire un bundle dans une app iOS c'est pour le Settings.bundle)

     


    La v6 de Xcode ne règle apparemment rien aux problèmes.


     


    Pour info, je vais préparer un tuto avec le plus de détails possibles, je vous donnerais un lien quand il sera fait.


     


    Dernier point, j'ai supprimé des fichiers plist et strings qui n'étaient plus utiles, mais j'ai des warnings qui m'indique que ces fichiers sont manquant, même après un clean. Une idée de comment supprimer ces messages ? Ca va faire tâche pour la livraison.


     


    EDIT : problème réglé pour les fichiers manquants, je me doutais qu'il s'agissait de SVN :



    svn delete fichier
  • août 2014 modifié #10

    Comment vous récupérez des valeurs dans le Setting Bundle ? 


     


    Non parce que c'est sympa de balancer des dictionnaires et autres array les uns à  la suite des autres mais après ? Si je veux récupérer la valeur de tel key à  tel élément ? Je cherche depuis un moment mais je me suis décidé à  ré-ouvrir ce post, on reste dans la même problématique.


     


    Merci.


     


    :D


  • CéroceCéroce Membre, Modérateur

    NSUserDefaults


  • août 2014 modifié #12

    Oui mais ce genre de code :



    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSLog(@--- %@", [defaults stringForKey:@mon_identifier]);

    Ne me retourne rien, enfin un null.


     


    EDIT : J'ai bien pris une référence par copier/coller de mon fichier Root.plist, afficher comme Property List au niveau de l'élément identifier.


     


    EDIT2 : ah oui, au cas où, la valeur que je demande à  une valeur par défaut et dans les prefs, j'ai bien cette valeur affichée.


  • AliGatorAliGator Membre, Modérateur
    Ta dans ton Root.plist en question, pour la clé mon_identifier, tu dis que tu as bien qqch puisque tu as copié ta clé de là ... mais est-ce bien une String ? Parce que si c'est pas le cas (mais un Number, un Dictionary, un NSData...) alors c'est normal qu'il te retourne nil si tu demandes stringForKey.
    Dans le doute, essaye avec objectForKey:
  • août 2014 modifié #14

    En fait c'est un champs de texte, donc a priori c'est bien une String, voici le code du plist :



    <dict>
    <key>Type</key>
    <string>PSTextFieldSpecifier</string>
    <key>Title</key>
    <string>Url</string>
    <key>Key</key>
    <string>mon_identifier</string>
    <key>IsSecure</key>
    <false/>
    <key>KeyboardType</key>
    <string>URL</string>
    <key>AutocorrectionType</key>
    <string>No</string>
    <key>AutocapitalizationType</key>
    <string>None</string>
    <key>DefaultValue</key>
    <string>http://adresse.bibi</string>
    </dict>

    J'ai essayé avec objectForKey:, idem...


     


    Si je vais dans les préférences de iOS, j'ai bien http://adresse.bibi affiché.


     


    EDIT : ok ça marche, il faut juste modifié/remplacer la valeur par défaut :)


     


    Ninja !


  • AliGatorAliGator Membre, Modérateur
    août 2014 modifié #15
    Heu dans le PLIST que tu as fourni "mon_identifier" c'est une valeur, la valeur associée à  la clé que tu as nommé "Key".

    <key>Key</key>
    <string>mon_identifier</string>
    Donc si tu veux récupérer ta valeur "mon_identifier" il faut faire [... stringForKey:@Key] ! puisque c'est ainsi que tu as nommé la clé où tu as mis cette valeur "mon_identifier" ! Le texte "mon_identifier" n'est pas une clé de ton dictionnaire, une clé avec un tel nom n'existe pas dans le PLIST que tu as fourni !


    ---

    (Après peut-être que tu t'es gourré en rédigeant ton PLIST (c'est ça aussi de vouloir l'écrire à  la main directement en XML plutôt que d'utiliser l'éditeur intégré de Xcode qui t'éviterait ce genre de boulette ^^) et que tu voulais mettre une entrée dont la clé est "mon_identifier" ? Mais dans ce cas c'est ton PLIST qui n'est pas bon ;-)
  • août 2014 modifié #16

    Alors soit je n'ai rien compris ou (peut-être) je me suis mal expliqué.


     


    Tu me dis que dans ce cas il faut que je fasse un stringForKey:@Key, euh ok mais partout dans mes fichiers j'ai des key (presque tout est key en fait). Alors dans ce cas lequel choisir ? Imagine que j'ai 3 zones de textes (donc 3 fois mon code plus haut) avec des identifier différent bien sur et disons ces titles : toto, tata et titi. Je fais comment pour les différencier ?


     


    De plus, pour trouver la solution, je suis parti sur un nouveau projet, créez un nouveau Bundle Settings et je n'ai modifié que


    le default value via l'interface de Xcode, donc impossible de faire une erreur de ce genre. Voici un copier / coller :



    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>PreferenceSpecifiers</key>
    <array>
    <dict>
    <key>Title</key>
    <string>Group</string>
    <key>Type</key>
    <string>PSGroupSpecifier</string>
    </dict>
    <dict>
    <key>AutocapitalizationType</key>
    <string>None</string>
    <key>AutocorrectionType</key>
    <string>No</string>
    <key>DefaultValue</key>
    <string>toto</string>
    <key>IsSecure</key>
    <false/>
    <key>Key</key>
    <string>name_preference</string>
    <key>KeyboardType</key>
    <string>Alphabet</string>
    <key>Title</key>
    <string>Name</string>
    <key>Type</key>
    <string>PSTextFieldSpecifier</string>
    </dict>
    <dict>
    <key>DefaultValue</key>
    <true/>
    <key>Key</key>
    <string>enabled_preference</string>
    <key>Title</key>
    <string>Enabled</string>
    <key>Type</key>
    <string>PSToggleSwitchSpecifier</string>
    </dict>
    <dict>
    <key>DefaultValue</key>
    <real>0.5</real>
    <key>Key</key>
    <string>slider_preference</string>
    <key>MaximumValue</key>
    <integer>1</integer>
    <key>MaximumValueImage</key>
    <string></string>
    <key>MinimumValue</key>
    <integer>0</integer>
    <key>MinimumValueImage</key>
    <string></string>
    <key>Type</key>
    <string>PSSliderSpecifier</string>
    </dict>
    </array>
    <key>StringsTable</key>
    <string>Root</string>
    </dict>
    </plist>


    Ensuite, dans mon code, j'ai ceci :



    NSLog(@--- %@", [[NSUserDefaults standardUserDefaults] stringForKey:@name_preference]);

    Ca me retourne toujours null. Si je vais dans les prefs, change la valeur et relance l'App (après l'avoir fermé pour que le code soit a nouveau appelé) alors j'ai bien ma valeur entrée.


     


    Je veux bien des explications si j'ai compris de travers, je ne cherche qu'a comprendre.


     


    Merci.


     


    PS : mon but est bien d'avoir toto en valeur de retour dès le premier lancement de l'App et donc sans avoir à  modifier les préférences.


  • Hello,


     


    Tu ne peux pas accéder directement à  n'importe quel niveau de ton plist. Cette ligne ne marchera pas.



    NSLog(@--- %@", [[NSUserDefaults standardUserDefaults] stringForKey:@name_preference]);

    Et en plus comme il te l'a souligné @Aligator, @name_preference est la valeur de la clé "Key" et non pas une clé.


    Donc pour récupérer ta valeur il taut parcourir toute la hiérarchie de ton plist jusqu'a à  la valeur désirée.


     


    Il faut d'abord récupérer tout les objets du range supérieur ( utilise objetctForKey), jusqu'a ce que tu arrive à  l'objet ( dictionnaire dans ton cas ) qui contient la valeur recherchée. 

  • AliGatorAliGator Membre, Modérateur
    En fait, après relecture, je me demande si on est pas en train de confondre samir et moi entre la lecture du PLIST comme si c'était n'importe quel PLIST que tu aurais chargé avec un [NSDictionary dictionaryWithContentsOfFile:] et sur lequel tu chercherais à  faire un [dict objectForKey:].


    Alors que la le PLIST que tu nous montres c'est celui du Settings.bundle qui va définir les UserDefaults qui seront affichés dans tes réglages, et que tu veux aussi accéder via NSUserDefaults. Et du coup là  c'est bien ta solution à  priori...


    Désolé pour la confusion (ça fait un bail que j'ai pas fait de Settings.bundle ^^)
  • août 2014 modifié #19

    Ah ok, pas de problèmes :)


     


    Mais j'était un peu inquiet sur le coup. Par contre je suis aussi un peu déçus du fait de ne pas pouvoir récupérer les valeurs par défauts.


     


    Bon, si c'est comme ça...


     


    Merci en tout cas pour vos réponses.


     


    :p


     


     


    EDIT : Désolé Samir je viens de lire ta réponse, du coup je comprends mieux le message de Aligator et je peux t'affirmer que ma ligne de code fonctionne quand l'utilisateur a changé la valeur. Mais bon, un retour de ton côté serais bien venue pour conclure.


  • AliGatorAliGator Membre, Modérateur
    Tu as fait un [[NSUserDefaults standardDefaults] registerDefaults] quand même au démarrage de ton appli, pour qu'il register les valeurs par défaut, et que tu puisses ainsi les récupérer ?
  • août 2014 modifié #21

    Non, je le fais qu'au moment de mon code que j'ai montré dans la méthode didFinishLaunchingWithOptions de mon AppDelegate.


     


    EDIT : je le fais aussi dans mon viewController mais j'ai le même résultat.


  • Hello,


     


    Désolé je suis parti dans la mauvaise direction moi aussi ( c'est la deuxième fois en plus ;)).


     


    Tu as une discussion sur stackoverflow, mais je ne suis pas aller au bout pour bien comprendre le truc.


    http://stackoverflow.com/questions/510216/can-you-make-the-settings-in-settings-bundle-default-even-if-you-dont-open-the


  • Oui en fait, les Settings par "défaut" sont bien à  null et il faut donc les paramétrer en dur dans le code. Voilà .


  • AliGatorAliGator Membre, Modérateur
    août 2014 modifié #24
    Ou alors utiliser le fameux code qui traine sur les forums pour faire un registerDefaults qui utilise comme defaults un dictionnaire directement construit depuis le contenu du Settings.bundle/Root.plist ;)

    (Rechercher "Settings.bundle" ou bien "registerDefaults" sur le forum pour retrouver tous les sujets qui en parlent)
Connectez-vous ou Inscrivez-vous pour répondre.