Невозможно прочитать значения из Settings.bundle - PullRequest
8 голосов
/ 21 июля 2011

Я некоторое время пассивно использовал этот сайт и прочитал FAQ, поэтому я надеюсь, что смогу сохранить их как минимум.

У меня есть вопрос о файлах Settings.bundle в Objective-C. Я использовал следующие руководства для реализации одного из них:

Как создать файл настроек iPhone Руководство по программированию приложений iOS - реализация настроек приложения

Я использую и Xcode 4.1, и последний Xcode 3. Я использовал версию 3 для создания Settings.bundle и его plist, поскольку нашел, что редактор списков Xcode 4 несколько глючит.

Это содержимое моего 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 Simulator на мгновение становится черным, когда он пытается запустить приложение, а затем меня возвращают на главный экран.

Xcode 4 показывает довольно странное поведение. Ему удается показать пользовательский интерфейс моего приложения на секунду или две, а затем возвращает меня на главный экран симулятора iPhone. Это также указывает на то, что SIGABRT находится немного дальше в моем коде, где я пытаюсь получить значение из ответа JSON:

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

Поскольку строка JSON генерируется сценарием PHP с использованием параметров GET, передаваемых моим приложением - одним из них является идентификатор пользователя из Settings.bundle - неудивительно, что это не должно работать. Однако он не должен завершаться сбоем, так как я улавливаю эту ошибку ранее в своем коде, но это, вероятно, не связано с моей проблемой настроек. Однако настоящая боль в шее заключается в том, что Xcode (вид) падает вместе с моим приложением в iPhone Simulator. Во-первых, 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, а также прочитал некоторые темы на этом сайте, но не смог найти решение.

Ответы [ 3 ]

8 голосов
/ 22 июля 2011

Я наконец-то смог решить эту проблему во многом благодаря вышеупомянутому руководству: Добавление пакета настроек в приложение для iPhone .

Там написано:

[...] важно понимать, что до тех пор, пока пользователь фактически не изменит значение параметра, на самом деле ничего не будет установлено.Если вы проверите настройку в вашем приложении, оно фактически вернет 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 Simulator, пока искалдля решения, и это не сработало).Это может повлиять только на iPhone Simulator, хотя у меня еще не было возможности протестировать его на моем физическом устройстве.Мой код инициализации теперь выглядит так (в 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, это несколько чуждо мне, так что может быть что-то, на что стоит обратить внимание, если вы получаете nil-значения от вашего объекта NSUserDefaults.

Это стоило мне около трех дней на исправление, поэтому я надеюсь, чторешение может пригодиться для некоторых.: -)

1 голос
/ 23 сентября 2015

Следующая ссылка была полезна для меня, чтобы понять поведение, которое вы упоминаете, и я надеюсь, что вам тоже поможет. Короче говоря, значения параметров пакета по умолчанию не копируются в nsuserdefaults и должны быть зарегистрированы вручную. Nsuserdefaults будет отражать только последние значения, которые пользователь изменяет в приложении настроек, но не значения по умолчанию

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

0 голосов
/ 22 июля 2011

Поскольку строка JSON генерируется сценарием PHP с использованием параметров GET, передаваемых моим приложением - одним из них является идентификатор пользователя из Settings.bundle - неудивительно, что это не должно работать.Однако он не должен завершаться сбоем, так как я улавливаю эту ошибку ранее в своем коде, но это, вероятно, не связано с моей проблемой настроекОднако настоящая боль в шее заключается в том, что Xcode (вид) падает вместе с моим приложением в iPhone Simulator.Во-первых, Xcode продолжает работать нормально, за исключением того факта, что я не могу прервать программу, которая все еще работает.Я могу нажать кнопку остановки в Xcode, но безрезультатно.Когда я пытаюсь выйти из XCode, он спрашивает меня, следует ли завершить работающую программу, и когда я нажимаю «Да», он аварийно завершает работу, и мне приходится принудительно завершать его.

Как отмечалось выше, это было исправленоизменив отладчик на GDB.Кроме того, оказалось, что компилятору явно не понравилось то, что я пытался присвоить NSString значение nil, которое вызывало исключение:

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

Я исправил это, проверив if ([jsonResponse objectForKey: @"from"] == nil) и теперь мое приложение по крайней мере больше не падает.Однако проблема NSUserDefaults сохраняется.

Я также обратился к следующему руководству:

Добавление набора настроек в приложение для iPhone

Я установилпо умолчанию в моем приложении didFinishLaunchingWithOptions, как описано в статье, но безрезультатно.Я все еще не могу получить доступ к значению настроек из своего кода.

Я был бы благодарен за подсказку, чтобы направить меня в правильном направлении, поскольку я совершенно не понимаю, что может объяснить это странное поведение.

Спасибо!

...