objective-c - 无法从 Settings.bundle 读取值

标签 objective-c xcode4 settings.bundle root.plist

我被动地使用这个网站已经有一段时间了,并且已经阅读了常见问题解答,所以我希望能够将这些内容保持在最低限度。

我对 Objective-C 中的 Settings.bundle 文件有疑问。我一直在使用以下指南来实现其中之一:

  • How to create an iPhone preferences file
  • iOS Application Programming Guide - Implementing Application Preferences
  • 我同时使用 Xcode 4.1 和最新的 Xcode 3。我使用版本 3 创建 Settings.bundle 及其 plist,因为我发现 Xcode 4 的 plist 编辑器有些问题。

    这些是我的 Root.plist 的内容:

    <?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>Root</string>
    <key>PreferenceSpecifiers</key>
    <array>
        <dict>
            <key>Type</key>
            <string>PSGroupSpecifier</string>
            <key>Title</key>
            <string>Authentication</string>
        </dict>
        <dict>
            <key>Type</key>
            <string>PSTextFieldSpecifier</string>
            <key>Title</key>
            <string>User ID</string>
            <key>Key</key>
            <string>user_id_key</string>
            <key>DefaultValue</key>
            <string>1234</string>
            <key>IsSecure</key>
            <false/>
            <key>KeyboardType</key>
            <string>Alphabet</string>
            <key>AutocapitalizationType</key>
            <string>None</string>
            <key>AutocorrectionType</key>
            <string>No</string>
        </dict>
    </array>
    </dict>
    </plist>
    

    我可以毫无问题地访问 iOS 设置菜单中的设置,还可以更改我目前拥有的单个条目的值。该值在 iOS 模拟器和我的物理 iOS 设备(iPhone 4)上的 session 之间存储。

    不过,我似乎无法从我的代码中访问此值。让我向您展示我是如何尝试实现它的(在我的应用程序的 ViewController.m 中):

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        myDefaults = [NSUserDefaults standardUserDefaults];
    
        // DEBUG
        userID = [myDefaults stringForKey:@"user_id_key"];
        // userID = [NSString stringWithString:@"1234"];
    
        // DEBUG
        jsonBackendURL = @"http://example.com/jsonBackend.php";
        passphrase     = @"secretPassphrase";
    
        theURLConnectionController = [[URLConnectionController alloc] initWithCallerObject:self];
        [theURLConnectionController getConnectionAndUpdate:NO];
    }
    

    奇怪的是,当我尝试在 Xcode 3 中运行该应用程序时,我既没有收到任何错误消息(如 SIGABRT 等),也没有收到任何调试器输出。 iPhone 模拟器的屏幕在尝试启动应用程序时变黑了一会儿,然后我被带回了主屏幕。

    Xcode 4 表现出一些相当奇怪的行为。它设法显示我的应用程序的用户界面一两秒钟,然后将我带回 iPhone 模拟器的主屏幕。它还在我尝试从 JSON 响应中获取值的代码中以某种方式指示 SIGABRT:

    NSString *arrivalToday = [NSString stringWithString:[jsonResponse objectForKey:@"from"]];
    

    由于 JSON 字符串是由 PHP 脚本使用我的应用程序传入的 GET 参数生成的(其中之一是来自 Settings.bundle 的用户 ID),所以这不起作用也就不足为奇了。但是它不应该崩溃,因为我在我的代码中早些时候发现了这个错误,但这可能与我的设置问题无关。一个真正令人头疼的问题是 Xcode(某种程度上)与我在 iPhone 模拟器中的应用程序一起崩溃。首先,Xcode 保持正常工作,除了我无法中止似乎仍在运行的程序这一事实。我可以单击 Xcode 中的停止按钮,但没有任何效果。当我尝试退出 Xcode 时,它​​询问我是否应该终止正在运行的程序,当我单击"is"时,它真的崩溃了,我不得不强制退出它。

    幸运的是,Xcode 4 为我提供了我的应用程序的调用堆栈:

    2011-07-21 11:41:04.539 OneClickCheckIn[2098:b303] http://example.com/json.php?user=(null)&pass=secretPassphrase&getStartToday
    2011-07-21 11:41:04.888 OneClickCheckIn[2098:b303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSPlaceholderString initWithString:]: nil argument'
    *** Call stack at first throw:
    (
    0   CoreFoundation                      0x00de25a9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x00f36313 objc_exception_throw + 44
    2   CoreFoundation                      0x00d9aef8 +[NSException raise:format:arguments:] + 136
    3   CoreFoundation                      0x00d9ae6a +[NSException raise:format:] + 58
    4   Foundation                          0x007ca14c -[NSPlaceholderString initWithString:] + 105
    5   Foundation                          0x007d3266 +[NSString stringWithString:] + 72
    6   OneClickCheckIn                     0x00002b5c -[OneClickCheckInViewController updateInterfaceWithJsonResponse:] + 172
    7   OneClickCheckIn                     0x0000e82c -[URLConnectionControllerDelegate connectionDidFinishLoading:] + 364
    8   Foundation                          0x007de112 -[NSURLConnection(NSURLConnectionReallyInternal) sendDidFinishLoading] + 108
    9   Foundation                          0x007de06b _NSURLConnectionDidFinishLoading + 133
    10  CFNetwork                           0x030fa48e _ZN19URLConnectionClient23_clientDidFinishLoadingEPNS_26ClientConnectionEventQueueE + 220
    11  CFNetwork                           0x031c56e1 _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 293
    12  CFNetwork                           0x031c59cf _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 1043
    13  CFNetwork                           0x030f0c80 _ZN19URLConnectionClient13processEventsEv + 100
    14  CFNetwork                           0x030f0acf _ZN17MultiplexerSource7performEv + 251
    15  CoreFoundation                      0x00dc38ff __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
    16  CoreFoundation                      0x00d2188b __CFRunLoopDoSources0 + 571
    17  CoreFoundation                      0x00d20d86 __CFRunLoopRun + 470
    18  CoreFoundation                      0x00d20840 CFRunLoopRunSpecific + 208
    19  CoreFoundation                      0x00d20761 CFRunLoopRunInMode + 97
    20  GraphicsServices                    0x0101a1c4 GSEventRunModal + 217
    21  GraphicsServices                    0x0101a289 GSEventRun + 115
    22  UIKit                               0x00042c93 UIApplicationMain + 1160
    23  OneClickCheckIn                     0x00002609 main + 121
    24  OneClickCheckIn                     0x00002585 start + 53
    25  ???                                 0x00000001 0x0 + 1
    )
    terminate called throwing an exception(lldb) 
    

    这就是我现在想到的所有相关信息。我在 Google 上进行了广泛的研究,也阅读了该网站上的一些主题,但找不到解决方案。

    最佳答案

    我终于能够解决它,很大程度上要感谢上面提到的指南:Adding a settings bundle to an iPhone App .

    上面写着:

    [...] it is important to understand that until the user actually changes the value of the setting nothing is actually set. If you check for the setting in your application it will actually return nil unless you set a default value. To do that add the following to the applicationDidFinishLaunching (or didFinishLaunchingWithOptions) method:

    // Set the application defaults
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@"YES" forKey:@"enableRotation"];
    [defaults registerDefaults:appDefaults];
    [defaults synchronize];
    

    我没有意识到这一点。此外,在我看来,NSDictionary 中的值必须以某种形式初始化,否则用户以后的更改也不会生效(我一直在寻找时一次又一次地尝试更改 iPhone 模拟器中的值寻求解决方案,但没有奏效)。不过这可能只会影响 iPhone 模拟器,我还没有机会在我的物理设备上测试它。我的初始化代码现在看起来像这样(在 AppDelegate 中):

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        // Override point for customization after application launch.
        NSUserDefaults *defaults  = [NSUserDefaults standardUserDefaults];
        NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
                                 @"1234", @"user_id_key",
                                 @"http://example.com/json.php", @"json_url_key",
                                 @"secretPassphrase", @"passphrase_key",
                                 nil];
    
        [defaults registerDefaults:appDefaults];
        [defaults synchronize];
    
        self.window.rootViewController = self.viewController;
        [self.window makeKeyAndVisible];
        return YES;
    }
    

    使用该代码,我可以稍后在我的代码中轻松访问 NSUserDefaults 值:

    - (void) reloadPreferences {
        myDefaults = [NSUserDefaults standardUserDefaults];
    
        userID         = [myDefaults objectForKey:@"user_id_key"];
        jsonBackendURL = [myDefaults objectForKey:@"json_url_key"];
        passphrase     = [myDefaults objectForKey:@"passphrase_key"];
    }
    

    我还花了一些时间寻找有关 NSDictionary 的键值对顺序的错误,直到我意识到在定义中值首先出现,然后是键。来自 Perl 背景,这对我来说有点陌生,因此如果您从 NSUserDefaults 对象获取 nil 值,可能需要注意这一点。

    这花了我大约三天的时间来修复,所以我希望这个解决方案可能对某些人派上用场。 :-)

    关于objective-c - 无法从 Settings.bundle 读取值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6774491/

    相关文章:

    iphone - 检查 NSString 是否同时包含字母和数字

    objective-c - AVCam 项目在 iPad 上崩溃

    ios - 在 Storyboard xcode 4 中添加的 View Controller 的 .h 和 .m 文件

    ios - 核心数据、Xcode 4.5 和在数据模型中创建获取的请求

    ios - NSDictionary 在 Objective-C 中设置 Bundle 为空

    iphone - 在 TableView 中保存和加载 UISwitch 状态

    ios - 扩展单元转换

    iphone - 为什么我不能将子 Pane plist 文件添加到项目的 Settings.bundle 中?

    iPhone Xcode Settings.bundle Plist

    ios - 如何使用 inappSettings 设置 2 个不同的设置页面