Проблемы с чтением настроек при использовании InAppSettingsKit - PullRequest
5 голосов
/ 12 июля 2011

Я использую модули InAppSettingsKit для управления своими настройками.

Я могу включить его в свой проект до такой степени, чтобы я мог создать страницу настроек, которая правильно взаимодействует с моим проектом. У меня есть root.plist, который я могу изменить, и когда я впервые запускаю свое приложение на симуляторе, я вижу отраженные изменения.

Однако, по жизни, я не могу получить доступ к настройкам в NSUserDefaults через мой код. Когда я запускаю приведенный ниже код, я могу просмотреть содержимое [NSUserDefaults standardUserDefaults]. Тем не менее, я вижу только несколько общих настроек, которые не связаны с материалом в моем файле plist

NSUserDefaults* d = [NSUserDefaults standardUserDefaults];

NSDictionary* dict = [d dictionaryRepresentation];

NSString* descKey;
NSString* descObject;
NSString* classTypeForKey;
NSString* classTypeForObject;
id myObject;

for (id key in dict) {
    myObject = [dict objectForKey:key];
    classTypeForObject = [[myObject class] description];
    classTypeForKey = [[key class] description];
    descKey = [key description];
    descObject = [myObject description];
}

Так, где InAppSettingsKit помещает настройки? В документе написано [NSUserDefaults standardUserDefaults], поэтому я в растерянности.

Ответы [ 6 ]

6 голосов
/ 13 июля 2011

Я думаю, что ваша проблема связана с неправильным пониманием концепции. Root.plist не хранит никаких настроек, а лишь определяет, как Settings.app и InAppSettingsKit работают с вашими userDefaults.

Когда ваше приложение запускается в первый раз, userDefaults нет. Обычно вы начинаете с установки соответствующих настроек по умолчанию, читая в статическом userDefaults.plist из ваших ресурсов:

// Load the default values for the user defaults
NSString* pathToUserDefaultsValues = [[NSBundle mainBundle]
                                      pathForResource:@"userDefaults" 
                                      ofType:@"plist"];
NSDictionary* userDefaultsValues = [NSDictionary dictionaryWithContentsOfFile:pathToUserDefaultsValues];

// Set them in the standard user defaults
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValues];
4 голосов
/ 10 октября 2012

Вот код Ojas, модифицированный немного дальше для учета ARC.

Вы, вероятно, вызовете initializeSettings из вашего AppDelegate didFinishLaunchingWithOptions.

#import "IASKSettingsReader.h"
...

- (void)initializeSettings
{
    // standard stored preference values
    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

    // settings files to process
    NSMutableArray *preferenceFiles = [[NSMutableArray alloc] init];

    // begin with Root file
    [preferenceFiles addObject:@"Root"];

    // as other settings files are discovered will be added to preferencesFiles
    while ([preferenceFiles count] > 0) {

        // init IASKSettingsReader for current settings file
        NSString *file = [preferenceFiles lastObject];
        [preferenceFiles removeLastObject];
        IASKSettingsReader *settingsReader = [[IASKSettingsReader alloc]
                                              initWithFile:file];

        // extract preference specifiers
        NSArray *preferenceSpecifiers = [[settingsReader settingsBundle]
                                         objectForKey:kIASKPreferenceSpecifiers];

        // process each specifier in the current settings file
        for (NSDictionary *specifier in preferenceSpecifiers) {

            // get type of current specifier
            NSString *type = [specifier objectForKey:kIASKType];

            // need to check child pane specifier for additional file
            if ([type isEqualToString:kIASKPSChildPaneSpecifier]) {
                [preferenceFiles addObject:[specifier objectForKey:kIASKFile]];
            }
            else {
                // check if current specifier has a default value
                id defaultValue = [specifier objectForKey:kIASKDefaultValue];

                if (defaultValue) {
                    // get key from specifier and current stored preference value
                    NSString *key = [specifier objectForKey:kIASKKey];
                    id value = [defaults objectForKey:key];

                    // update preference value with default value if necessary
                    if (key && value == nil) {
                        [defaults setObject:defaultValue forKey:key];
                    }
                }
            }

        }

    }

    // synchronize stored preference values
    [defaults synchronize];
}
3 голосов
/ 15 июля 2011

Теперь все имеет смысл. Я пытался зарегистрировать значения по умолчанию в предыдущих попытках заставить все работать, но я думал, что смогу сделать это, используя файл Root.plist. Но, конечно, методы registerDefaults просто видят высокоуровневые записи StringsTable и PreferenceSpecifiers. Спасибо за указание на это Ортвин.

Таким образом, вместо создания отдельного файла userDefault.plist я обнаружил следующий код, который анализирует файл root.plist, чтобы вручную добавить значения по умолчанию для NSUserDefaults. Я не могу вспомнить, где я взял это, но это, кажется, работает хорошо. Если есть причины, почему я не должен делать это таким образом, не стесняйтесь уточнять:

    - (void)setDefaults {

        //get the plist location from the settings bundle
        NSString *settingsPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Settings.bundle"];
        NSString *plistPath = [settingsPath stringByAppendingPathComponent:@"Root.plist"];

        //get the preference specifiers array which contains the settings
        NSDictionary *settingsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
        NSArray *preferencesArray = [settingsDictionary objectForKey:@"PreferenceSpecifiers"];

        //use the shared defaults object
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

        //for each preference item, set its default if there is no value set
        for(NSDictionary *item in preferencesArray) {

            //get the item key, if there is no key then we can skip it
            NSString *key = [item objectForKey:@"Key"];
            if (key) {

                //check to see if the value and default value are set
                //if a default value exists and the value is not set, use the default
                id value = [defaults objectForKey:key];
                id defaultValue = [item objectForKey:@"DefaultValue"];
                if(defaultValue && !value) {
                    [defaults setObject:defaultValue forKey:key];
                }
            }
        }

        //write the changes to disk
        [defaults synchronize];
        }
}
2 голосов
/ 13 февраля 2012

Я изменил код Сэма для обработки дочерних панелей, указанных в отдельных файлах:

#import "IASKSettingsReader.h"

- (void)initializeSettings
{
    // standard stored preference values
    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

    // settings files to process
    NSMutableArray *preferenceFiles = [[NSMutableArray alloc] init];

    // begin with Root file
    [preferenceFiles addObject:@"Root"];

    // as other settings files are discovered will be added to preferencesFiles
    while (![preferenceFiles isEmpty]) {

        // init IASKSettingsReader for current settings file
        NSString *file = [[preferenceFiles lastObject] retain];
        [preferenceFiles removeLastObject];
        IASKSettingsReader *settingsReader = [[IASKSettingsReader alloc]
                                              initWithFile:file];
        [file release];

        // extract preference specifiers
        NSArray *preferenceSpecifiers = [[settingsReader settingsBundle] 
                                         objectForKey:kIASKPreferenceSpecifiers]; 

        // process each specifier in the current settings file
        for (NSDictionary *specifier in preferenceSpecifiers) {

            // get type of current specifier
            NSString *type = [specifier objectForKey:kIASKType];

            // need to check child pane specifier for additional file
            if ([type isEqualToString:kIASKPSChildPaneSpecifier]) {
                [preferenceFiles addObject:[specifier objectForKey:kIASKFile]];
            }
            else {
                // check if current specifier has a default value
                id defaultValue = [specifier objectForKey:kIASKDefaultValue];

                if (defaultValue) {
                    // get key from specifier and current stored preference value
                    NSString *key = [specifier objectForKey:kIASKKey];
                    id value = [defaults objectForKey:key];

                    // update preference value with default value if necessary
                    if (key && value == nil) {
                        [defaults setObject:defaultValue forKey:key];                        
                    }
                }
            }

        }

        [settingsReader release];
    }

    [preferenceFiles release];

    // synchornize stored preference values
    [defaults synchronize];
}
1 голос
/ 18 июля 2015

Я основал свой ответ на ответе @Ojas. Но я преобразовал это в Свифт. Я надеюсь, что это полезно для людей, использующих Swift

func processDefaultSettings() {

    let defaults = IASKSettingsStoreUserDefaults().defaults

    // settings files to process
    var preferenceFiles = [String]()

    // begin with Root file
    preferenceFiles.append("Root")

    // as other settings files are discovered will be added to preferencesFiles
    while !preferenceFiles.isEmpty {

        // init IASKSettingsReader for current settings file
        let file = preferenceFiles.last
        let settingsReader = IASKSettingsReader(file: file)
        preferenceFiles.removeLast()

        // extract preference specifiers
        if let preferenceSpecfiers = settingsReader.settingsDictionary[kIASKPreferenceSpecifiers] as? NSArray {

            // process each specifier in the current settings file
            for specifier in preferenceSpecfiers {

                // get type of current specifier
                let type = specifier[kIASKType] as! String

                // need to check child pane specifier for additional file
                if type == kIASKPSChildPaneSpecifier {
                    preferenceFiles.append(specifier[kIASKFile] as! String)
                }
                else {
                    // check if current specifier has a default value
                    if let defaultValue = specifier[kIASKDefaultValue] as AnyObject? {

                        // get key from specifier and current stored preference value
                        if let key = specifier[kIASKKey] as? String {

                            if let value = defaults.objectForKey(key) {
                                // Nothing to do - already set
                            }
                            else {
                                let appDefaults = [key: defaultValue]
                                defaults.registerDefaults(appDefaults)
                            }
                        }
                    }
                }
            }
        }
        // synchornize stored preference values
        defaults.synchronize()
    }
}
0 голосов
/ 01 февраля 2012

Я изменил ответ Стива на его собственный вопрос выше, и мне кажется, что мне подходит следующее:

В вашем подклассе IASKAppSettingsViewController-

- (void)viewDidLoad
{
    [super viewDidLoad];


    NSDictionary* settingsBundle = [self.settingsReader settingsBundle];
    NSArray *preferencesArray = [settingsBundle objectForKey:@"PreferenceSpecifiers"];
    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

    //for each preference item, set its default if there is no value set
    for(NSDictionary *item in preferencesArray) {

        //get the item key, if there is no key then we can skip it
        NSString *key = [item objectForKey:@"Key"];
        if (key) {

            //check to see if the value and default value are set
            //if a default value exists and the value is not set, use the default
            id value = [defaults objectForKey:key];
            id defaultValue = [item objectForKey:@"DefaultValue"];
            if(defaultValue && !value) {
                [defaults setObject:defaultValue forKey:key];
            }
        }
    }

    //write the changes to disk
    [defaults synchronize];

}

...