Можете ли вы сделать настройки в Настройках. По умолчанию, даже если вы не открываете приложение «Настройки»

У меня есть приложение iPhone с параметром settings.bundle, который обрабатывает различные настройки для моего приложения. Я могу установить значения по умолчанию в файле root.plist (используя свойство DefaultValue), но они будут использоваться только при первом запуске пользователем приложения настроек. Есть ли способ получить эти значения, выписанные при установке приложения? Я знаю, что могу просто написать код, который проверяет первый запуск моего приложения, а затем записывать его, но тогда они находятся в двух разных местах.

Вот пример из моего root.plist в качестве примера:

 Type PSToggleSwitchSpecifier Title Open To Top Location Key open_top_location DefaultValue YES TrueValue YES FalseValue NO  

Конечным результатом должно быть то, что если я попрошу «open_to_top_location», я получаю ДА, а не его вообще не до тех пор, пока пользователь не откроет приложение «Настройки».

Есть идеи?

Если вы правильно поняли, вы хотите, чтобы значения, заданные по умолчанию, были указаны дважды (один раз как «DefaultValue» в файле Settings.bundle / Root.plist и один раз в коде инициализации вашего приложения), поэтому вам не нужно их хранить синхронизации.

Поскольку Settings.bundle хранится в самом пакете приложений, вы можете просто прочитать значения по умолчанию, указанные там. Я собрал несколько примеров кода, который смотрит на набор настроек и читает значения по умолчанию для каждого ключа. Обратите внимание, что это не выдает ключи по умолчанию; если они не существуют, вам нужно будет их прочитать и зарегистрировать при каждом запуске (не стесняйтесь изменять это). Я только сделал некоторые беглые тесты, поэтому убедитесь, что он работает для вас во всех случаях.

 - (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]; } 

Вот мой код, основанный на ответе @ PCheese, который добавляет поддержку ключей без значения по умолчанию и дочерних окон.

 - (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; } 

Вот версия Swift: назовите ее:

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. self.registerDefaultsFromSettingsBundle() return true } 

преобразованная функция:

 func registerDefaultsFromSettingsBundle(){ //NSLog("Registering default values from Settings.bundle"); let defs: NSUserDefaults = NSUserDefaults.standardUserDefaults() defs.synchronize() var settingsBundle: NSString = NSBundle.mainBundle().pathForResource("Settings", ofType: "bundle")! if(settingsBundle.containsString("")){ NSLog("Could not find Settings.bundle"); return; } var settings: NSDictionary = NSDictionary(contentsOfFile: settingsBundle.stringByAppendingPathComponent("Root.plist"))! var preferences: NSArray = settings.objectForKey("PreferenceSpecifiers") as NSArray var defaultsToRegister: NSMutableDictionary = NSMutableDictionary(capacity: preferences.count) for prefSpecification in preferences { if (prefSpecification.objectForKey("Key") != nil) { let key: NSString = prefSpecification.objectForKey("Key")! as NSString if !key.containsString("") { let currentObject: AnyObject? = defs.objectForKey(key) if currentObject == nil { // not readable: set value from Settings.bundle let objectToSet: AnyObject? = prefSpecification.objectForKey("DefaultValue") defaultsToRegister.setObject(objectToSet!, forKey: key) NSLog("Setting object \(objectToSet) for key \(key)") }else{ //already readable: don't touch //NSLog("Key \(key) is readable (value: \(currentObject)), nothing written to defaults."); } } } } defs.registerDefaults(defaultsToRegister) defs.synchronize() } 

Версия Swift 3

  func registerDefaultsFromSettingsBundle(){ guard let settingsBundle = Bundle.main.path(forResource: "Settings", ofType: "bundle") else { print("Could not locate Settings.bundle") return } guard let settings = NSDictionary(contentsOfFile: settingsBundle+"/Root.plist") else { print("Could not read Root.plist") return } let preferences = settings["PreferenceSpecifiers"] as! NSArray var defaultsToRegister = [String: AnyObject]() for prefSpecification in preferences { if let post = prefSpecification as? [String: AnyObject] { guard let key = post["Key"] as? String, let defaultValue = post["DefaultValue"] else { continue } defaultsToRegister[key] = defaultValue } } UserDefaults.standard.register(defaults: defaultsToRegister) } 

Совместимая версия Swift 2

 func registerDefaultsFromSettingsBundle(){ let defaults = NSUserDefaults.standardUserDefaults() defaults.synchronize() let settingsBundle: NSString = NSBundle.mainBundle().pathForResource("Settings", ofType: "bundle")! if(settingsBundle.containsString("")){ NSLog("Could not find Settings.bundle"); return; } let settings = NSDictionary(contentsOfFile: settingsBundle.stringByAppendingPathComponent("Root.plist"))! let preferences = settings.objectForKey("PreferenceSpecifiers") as! NSArray; var defaultsToRegister = [String: AnyObject](minimumCapacity: preferences.count); for prefSpecification in preferences { if (prefSpecification.objectForKey("Key") != nil) { let key = prefSpecification.objectForKey("Key")! as! String if !key.containsString("") { let currentObject = defaults.objectForKey(key) if currentObject == nil { // not readable: set value from Settings.bundle let objectToSet = prefSpecification.objectForKey("DefaultValue") defaultsToRegister[key] = objectToSet! NSLog("Setting object \(objectToSet) for key \(key)") } } } } defaults.registerDefaults(defaultsToRegister) defaults.synchronize() } 

Еще одна версия той же темы. Я поддержал поддержку Лоуренса Джонстона для детских стекол и добавил поддержку 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"]]; } 

Вызовите [self registerDefaultsFromSettingsBundle]; из - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

if(x) {NSAssert(x);return nil;} выглядит глупо, но мне лениво что-то делать с этим.

Другой подход: генерация кода

Следующее создает файл Objective-C с единственной функцией, которая регистрирует значения по умолчанию для Root.plist.

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

In может запускаться автоматически, используя фазу сборки «Run Script» в XCode. Фаза должна быть помещена перед «Компиляция источников». (xsltproc поставляется с OS X.)

Скриншот «Запустить сценарий»

Это несколько базовый и не обрабатывает вложенные файлы, но, возможно, кто-то использует его.

settings.xslt

      @"YES",   @"NO",   @"",   @"",   void registerDefaults() { NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:  nil]; [[NSUserDefaults standardUserDefaults] registerDefaults: defaults]; }   в      @"YES",   @"NO",   @"",   @"",   void registerDefaults() { NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:  nil]; [[NSUserDefaults standardUserDefaults] registerDefaults: defaults]; }   в      @"YES",   @"NO",   @"",   @"",   void registerDefaults() { NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:  nil]; [[NSUserDefaults standardUserDefaults] registerDefaults: defaults]; }   

Основано на работе Бенджамина Рагеба .

Для более быстрой версии 2.2 версии требуется быстрое расширение строки для восстановления stringByAppendingPathComponent :

 extension String { func stringByAppendingPathComponent(path: String) -> String { let nsSt = self as NSString return nsSt.stringByAppendingPathComponent(path) } } func registerDefaultsFromSettingsBundle() { guard let settingsBundle = NSBundle.mainBundle().pathForResource("Settings", ofType: "bundle") else { log.debug("Could not find Settings.bundle") return } let settings = NSDictionary(contentsOfFile: settingsBundle.stringByAppendingPathComponent("Root.plist"))! let preferences = settings["PreferenceSpecifiers"] as! NSArray var defaultsToRegister = [String: AnyObject]() for prefSpecification in preferences { guard let key = prefSpecification["Key"] as? String, let defaultValue = prefSpecification["DefaultValue"] else { continue } defaultsToRegister[key] = defaultValue } NSUserDefaults.standardUserDefaults().registerDefaults(defaultsToRegister) } 
  • Заменить несколько символов в строке в Objective-C?
  • Трассировка стека или дополнительная информация о необработанном исключении в Xcode / iPhone
  • IOS 6: ориентация устройства на пейзаж
  • iPhone - API для функции «Текст в речь»
  • как скрыть навигационную панель, когда я нажимаю навигационный controller?
  • iTunes Connect Скриншоты Размеры для всех устройств iOS (iPhone / iPad / Apple Watch)
  • Звук перекрывается несколькими нажатиями кнопок
  • Как преобразовать NSTimeInterval (секунды) в минуты
  • Вызов метода для неинициализированного объекта (нулевой указатель)
  • возвращает дату в час в будущем
  • UITableView прокручивается с определенной скоростью?
  • Давайте будем гением компьютера.