설정 앱을 열지 않아도 Settings.bundle의 설정을 기본값으로 할 수 있습니까?
내 응용 프로그램의 다양한 설정을 처리하는 settings.bundle이있는 iPhone 응용 프로그램이 있습니다. 내 root.plist 파일 (DefaultValue 속성 사용)에서 기본값을 설정할 수 있지만이 값은 사용자가 설정 앱을 처음 열 때만 사용됩니다. 응용 프로그램을 설치할 때 이러한 값을 기록하는 방법이 있습니까? 내 앱의 첫 번째 실행을 확인하는 코드를 작성한 다음 작성할 수 있지만 두 위치에 있습니다.
다음은 내 root.plist의 항목입니다.
<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>
최종 결과는 'open_to_top_location'을 요청하면 사용자가 설정 앱을 처음 열 때까지 전혀 존재하지 않는 대신 YES가 표시됩니다.
어떤 아이디어?
내가 올바르게 이해했다면 기본값을 두 번 (Settings.bundle / Root.plist 파일에서 "DefaultValue"키로 한 번, 앱 초기화 코드에서 한 번) 두 번 지정하지 않도록하여 보관할 필요가 없습니다. 동조.
Settings.bundle은 App 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()
}
같은 테마의 버전이 하나 더 있습니다. 저는 Lawrence Johnston의 자식 창 지원을 유지하고 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;} 멍청 해 보이지만 뭔가를하기가 게으르다.
다른 접근 방식 : 코드 생성
다음은 Root.plist의 기본값을 등록하는 단일 함수로 Objective-C 파일을 생성합니다.
xsltproc settings.xslt Settings.bundle/Root.plist > registerDefaults.m
In은 XCode에서 "스크립트 실행"빌드 단계를 사용하여 자동으로 실행할 수 있습니다. 단계는 "소스 컴파일"앞에 배치되어야합니다. (xsltproc는 OS X와 함께 제공됩니다.)

This is somewhat basic and doesn't handle nested files, but maybe somebody has a use for it.
settings.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>
The is based on the work of Benjamin Ragheb.
A much cleaner swift 2.2 version, requires a quick extension on string to restore 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)
}
ReferenceURL : https://stackoverflow.com/questions/510216/can-you-make-the-settings-in-settings-bundle-default-even-if-you-dont-open-the
'Program Club' 카테고리의 다른 글
| 조건에서 변수를 업데이트하는 가장 빠른 방법은 무엇입니까? (0) | 2021.01.06 |
|---|---|
| .htm 또는 .html 확장자-어느 것이 정확하고 다른 것은 무엇입니까? (0) | 2021.01.06 |
| unique_ptr 부스트 상당? (0) | 2021.01.06 |
| Java 프리미티브는 스택 또는 힙으로 이동합니까? (0) | 2021.01.06 |
| vs. font-weight : bold & (0) | 2021.01.06 |