55 votes

Pouvez-vous définir les paramètres par défaut dans Settings.bundle même si vous n'ouvrez pas l'application Paramètres

J'ai une application iPhone avec les paramètres.bundle qui gère les différents paramètres pour mon application. Je peux définir des valeurs par défaut dans ma racine.fichier plist (à l'aide de la propriété Valeur par défaut), mais ils ne servent la première fois que l'utilisateur ouvre l'application des paramètres. Est-il possible d'obtenir ces valeurs écrit lorsque votre application s'installe? Je sais que je peux juste écrire du code qui vérifie pour le premier lancement de mon application et puis les écrire, mais alors qu'ils sont à deux endroits différents.

Voici une entrée de ma racine.plist comme exemple:

<dict>
    <key>Type</key>
    <string>PSToggleSwitchSpecifier</string>
    <key>Title</key>
    <string>Open To Top Location</string>
    <key>Key</key>
    <string>open_top_location</string>
    <key>DefaultValue</key>
    <string>YES</string>
    <key>TrueValue</key>
    <string>YES</string>
    <key>FalseValue</key>
    <string>NO</string>
</dict>

Le résultat final devrait être que si je demande 'open_to_top_location" je reçois un OUI, au lieu de ne pas être là du tout jusqu'à ce que la première fois que l'utilisateur ouvre l'application des Paramètres.

Des idées?

94voto

PCheese Points 2777

Si je vous ai bien compris, vous voulez éviter d'avoir des valeurs par défaut définies deux fois (une fois en tant que "DefaultValue" clés dans vos Paramètres.bundle/Racine.fichier plist, et une fois dans votre application le code d'initialisation) de sorte que vous n'avez pas à garder synchronisés.

Depuis Les Paramètres.bundle est stocké à l'intérieur de l'app bundle, vous pouvez juste lire les valeurs par défaut. J'ai mis en place un exemple de code qui ressemble à des Paramètres de faisceau et lit les valeurs par défaut pour chaque clé. Notez que cela ne signifie pas écrire les touches par défaut; si elles n'existent pas, vous aurez besoin de lire et d'enregistrer à chaque lancement (n'hésitez pas à changer cela). Je n'ai fait que certains superficielle des tests, donc assurez-vous que cela fonctionne pour vous dans tous les cas.

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:@"name"];
    NSLog(@"name before is %@", name);

    // Note: this will not work for boolean values as noted by bpapa below.
    // If you use booleans, you should use objectForKey above and check for null
    if(!name) {
        [self registerDefaultsFromSettingsBundle];
        name = [[NSUserDefaults standardUserDefaults] stringForKey:@"name"];
    }
    NSLog(@"name after is %@", name);
}

- (void)registerDefaultsFromSettingsBundle {
    NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
    if(!settingsBundle) {
        NSLog(@"Could not find Settings.bundle");
        return;
    }

    NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:@"Root.plist"]];
    NSArray *preferences = [settings objectForKey:@"PreferenceSpecifiers"];

    NSMutableDictionary *defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
    for(NSDictionary *prefSpecification in preferences) {
        NSString *key = [prefSpecification objectForKey:@"Key"];
        if(key && [[prefSpecification allKeys] containsObject:@"DefaultValue"]) {
            [defaultsToRegister setObject:[prefSpecification objectForKey:@"DefaultValue"] forKey:key];
        }
    }

    [[NSUserDefaults standardUserDefaults] registerDefaults:defaultsToRegister];
    [defaultsToRegister release];
}

12voto

Lawrence Johnston Points 9723

Voici mon code basé sur la réponse de @ PCheese qui ajoute la prise en charge des clés sans valeur par défaut et des sous-fenêtres enfants.

 - (void)registerDefaultsFromSettingsBundle {
    [[NSUserDefaults standardUserDefaults] registerDefaults:[self defaultsFromPlistNamed:@"Root"]];
}

- (NSDictionary *)defaultsFromPlistNamed:(NSString *)plistName {
    NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
    NSAssert(settingsBundle, @"Could not find Settings.bundle while loading defaults.");

    NSString *plistFullName = [NSString stringWithFormat:@"%@.plist", plistName];

    NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:plistFullName]];
    NSAssert1(settings, @"Could not load plist '%@' while loading defaults.", plistFullName);

    NSArray *preferences = [settings objectForKey:@"PreferenceSpecifiers"];
    NSAssert1(preferences, @"Could not find preferences entry in plist '%@' while loading defaults.", plistFullName);

    NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
    for(NSDictionary *prefSpecification in preferences) {
        NSString *key = [prefSpecification objectForKey:@"Key"];
        id value = [prefSpecification objectForKey:@"DefaultValue"];
        if(key && value) {
            [defaults setObject:value forKey:key];
        } 

        NSString *type = [prefSpecification objectForKey:@"Type"];
        if ([type isEqualToString:@"PSChildPaneSpecifier"]) {
            NSString *file = [prefSpecification objectForKey:@"File"];
            NSAssert1(file, @"Unable to get child plist name from plist '%@'", plistFullName);
            [defaults addEntriesFromDictionary:[self defaultsFromPlistNamed:file]];
        }        
    }

    return defaults;
}
 

0voto

Une version de plus du même thème. J'ai gardé le soutien de Lawrence Johnston pour les vitrages enfants et ajouté le support i18n / l10n.

 // This code is folklore, first created by an unknown person and copied, pasted
// and published by many different programmers, each (hopefully) of whom added
// some improvemrnts. (c) the People of the Earth
- (NSDictionary *)defaultsFromPlistNamed:(NSString *)plistName {
    NSString *settingsBundlePath = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
    if (!settingsBundlePath) {
        NSAssert(settingsBundlePath, @"Could not find Settings.bundle while loading defaults.");
        return nil;
    }

    NSBundle *settingsBundle = [NSBundle bundleWithPath:settingsBundlePath];
    if (!settingsBundlePath) {
        NSAssert(settingsBundle, @"Could not load Settings.bundle while loading defaults.");
        return nil;
    }

    NSString *plistFullName = [settingsBundle pathForResource:plistName ofType:@"plist"];
    if (!plistName) {
        NSAssert1(settings, @"Could not find plist '%@' while loading defaults.", plistFullName);
        return nil;
    }

    NSDictionary *settings_dic = [NSDictionary dictionaryWithContentsOfFile:plistFullName];
    if (!settings_dic) {
        NSAssert1(settings_dic, @"Could not load plist '%@' while loading defaults.", plistFullName);
        return nil;
    }

    NSArray *preferences = [settings_dic objectForKey:@"PreferenceSpecifiers"];
    NSAssert1(preferences, @"Could not find preferences entry in plist '%@' while loading defaults.", plistFullName);

    NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
    for(NSDictionary *prefSpecification in preferences) {
        NSString *key = [prefSpecification objectForKey:@"Key"];
        if (key) {
            id value = [prefSpecification objectForKey:@"DefaultValue"];
            if(value) {
                [defaults setObject:value forKey:key];
                NSLog(@"setting %@ = %@",key,value);
            } 
        }

        NSString *type = [prefSpecification objectForKey:@"Type"];
        if ([type isEqualToString:@"PSChildPaneSpecifier"]) {
            NSString *file = [prefSpecification objectForKey:@"File"];
            NSAssert1(file, @"Unable to get child plist name from plist '%@'", plistFullName);
            if (file) {
                [defaults addEntriesFromDictionary:[self defaultsFromPlistNamed:file]];
            }
        }        
    }

    return defaults;
}

- (void)registerDefaultsFromSettingsBundle {
    [[NSUserDefaults standardUserDefaults] registerDefaults:[self defaultsFromPlistNamed:@"Root"]];
}
 

Appelez [self registerDefaultsFromSettingsBundle]; de - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

if(x) {NSAssert(x);return nil;} semble stupide, mais je me sens paresseux pour faire quelque chose.

0voto

nschum Points 3621

Une approche différente: la génération de code

Le texte suivant génère un Objectif-C fichier avec une seule fonction qui enregistre les valeurs par défaut pour l'utilisateur Root.plist.

xsltproc settings.xslt Settings.bundle/Root.plist > registerDefaults.m

Dans peut être exécuté automatiquement à l'aide d'un "Run Script" phase de construction dans XCode. La phase doit être placé avant "Compiler les Sources". (xsltproc est livré avec OS X.)

"Run Script" screenshot

C'est un peu la base et ne gère pas les fichiers imbriqués, mais peut-être que quelqu'un a une utilisation pour elle.

les paramètres.xslt

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8" omit-xml-declaration="yes" indent="no" />

  <xsl:template match="dict">
    <xsl:choose>
      <xsl:when test="key[.='DefaultValue']/following-sibling::*[position()=1 and self::true]">
        @"YES",
      </xsl:when>
      <xsl:when test="key[.='DefaultValue']/following-sibling::*[position()=1 and self::false]">
        @"NO",
      </xsl:when>
      <xsl:otherwise>
        @"<xsl:value-of select="key[.='DefaultValue']/following-sibling::*[1]"/>",
      </xsl:otherwise>
    </xsl:choose>
    @"<xsl:value-of select="key[.='Key']/following-sibling::*[1]"/>",
  </xsl:template>

  <xsl:template match="/">
    void registerDefaults() {

    NSDictionary *defaults =
    [NSDictionary dictionaryWithObjectsAndKeys:
    <xsl:apply-templates select="descendant::key[.='DefaultValue']/.."/>
    nil];

    [[NSUserDefaults standardUserDefaults] registerDefaults: defaults];
    }
  </xsl:template>

</xsl:stylesheet>

La est basée sur le travail de Benjamin Ragheb.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X