【问题标题】:Unable to read values from Settings.bundle无法从 Settings.bundle 读取值
【发布时间】:2011-10-10 02:38:32
【问题描述】:

我一直在被动使用这个网站,并阅读了常见问题解答,因此我希望能够将这些内容保持在最低限度。

我对 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)上的会话之间存储。

    但是,我似乎无法从我的代码中访问该值。让我向您展示我是如何尝试实现它的(在我的应用程序的 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 显示了一些相当奇怪的行为。它设法显示我的应用程序的 UI 一两秒钟,然后带我回到 iPhone 模拟器的主屏幕。它还表明 SIGABRT 在我的代码中更远的地方,我尝试从 JSON 响应中获取值:

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

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

    幸运的是,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 进行了广泛的研究,也阅读了该网站上的一些主题,但我找不到解决方案。

    【问题讨论】:

    • 我已经能够找出 Xcode 4 崩溃的问题。我已将 Xcode 4 配置为使用显然导致崩溃的新 LLDP 调试器。我把它改回 GDB 解决了这个问题。
    • 我也使用了 [myDefaults synchronize],正如一些没有改变任何东西的建议。

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


    【解决方案1】:

    以下链接有助于我理解您提到的行为,我希望也能帮助您。简而言之,设置包的默认值不会复制到nsuserdefaults,需要手动注册。 nsuserdefaults 只会反映用户在设置应用中修改的最新值,而不是默认值

    http://ijure.org/wp/archives/179

    【讨论】:

      【解决方案2】:

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

      上面写着:

      [...] 重要的是要了解,在用户实际更改设置值之前,实际上没有设置任何内容。如果您检查应用程序中的设置,除非您设置默认值,否则它实际上会返回 nil。为此,请将以下内容添加到 applicationDidFinishLaunching(或 didFinishLaunchingWithOptions)方法中:

      // 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 值,这可能需要注意。

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

      【讨论】:

        【解决方案3】:

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

        如上所述,已通过将调试器更改为 GDB 来解决此问题。此外,结果编译器显然不喜欢我试图将 nil 值分配给引发异常的 NSString:

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

        我通过检查 if ([jsonResponse objectForKey:@"from"] == nil) 解决了这个问题,现在我的应用程序至少不再崩溃了。 NSUserDefaults 问题仍然存在。

        我还参考了以下教程:

        Adding a settings bundle to an iPhone App

        我在我的应用程序中设置了默认值 didFinishLaunchingWithOptions 如文章中所述,但无济于事。我仍然无法从我的代码中访问设置值。

        我会很感激能指导我朝着正确方向前进的提示,因为我完全不知道什么可以解释这种奇怪的行为。

        谢谢!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-01-06
          • 1970-01-01
          • 2020-10-16
          • 2019-03-11
          • 2018-05-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多