Подтвердить что ты не робот

Сотни доступа к "InputModeProperties.plist" отстают от моей игры (iPhone)

У меня есть странная проблема с исправлением для Tiny Wings. В моей игре я использую что-то вроде:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];      
[userDefaults setFloat:musicVolume forKey:@"musicVolume"];

для сохранения некоторых настроек и таблицы рекордов. В конце игры, когда появляется экран игры на экране, игра сохраняет рекордные значения в стандартеUserDefaults. Он работает очень хорошо, пока игра не отображает UIAlertView следующим образом:

UIAlertView *alert = [[UIAlertView alloc] init];
[alert setTitle:@"Get ready!"];
[alert setDelegate:self];
[alert addButtonWithTitle:@"Ok"];
[alert show];
[alert release];

После того, как AlertView исчезнет всякий раз, когда игра сохранит somthing до standardUserDefaults, игра немного отстает (на некоторых устройствах в течение нескольких секунд). Это также происходит после того, как в игре используется UITextField для ввода имени игрока. В игре нет какого-либо отставания до того, как будет использован один из двух элементов UIKit, но после их использования игра задержится, пока я не перезапущу приложение. Я проанализировал проблему с Инструментами производительности, а инструмент "Активность ввода/вывода" показывает, что есть сотни "открытых чтений и закрытий" для доступа к

/System/Library/Frameworks/UIKit.framework/InputModeProperties.plist

что приводит к задержкам.

Я не знаю, что делать. Любые идеи?

Edit:
в форуме разработчиков Apple есть нить http://devforums.apple.com/message/424374#424374, где у кого-то одинаковая проблема, и кажется, что она появляется только с iOS 4.3. Я протестировал его, и задержки произошли только на моих 4.3 устройствах (не на 3,1 iPod Touch и 4.2 iPad).

4b9b3361

Ответ 1

ИЗМЕНИТЬ

Поврежденный обход ошибки:

Краткая версия: Просто задерживайте вызывающие ошибки вызовы, пока пользователь не будет раздражен.

Длинная версия:

Так как я думаю, что проблема исходит от вызова [NSUserDefaults standardUserDefaults], который запускает этот грязный цикл загрузки plist ПОСЛЕ, некоторые действия запрашивают раскладки клавиатуры (например, UIAlert)...

Я бы предложил позвонить [NSUserDefaults standardUserDefaults] только один раз при загрузке приложения (ПЕРЕД), и сохранить возвращаемую ссылку в одноэлементном классе во время жизненного цикла приложения. Я не думаю, что объем памяти будет огромным... (я делаю это в нескольких приложениях без каких-либо проблем). В худшем случае plist load * 100 будет выполняться только один раз при загрузке приложения, а не во время игры.

Если проблема связана с вызовами [userDefaults setXxxx:...], одним и тем же обходным путем, вы можете просто сохранить значения для сохранения в памяти и установить их позже в userDefaults, как непосредственно перед их синхронизацией... Но рискуя потерять информацию, если все идет не так, как крушение. Я лично предпочитаю sync после каждого set для обеспечения целостности данных...

ENDOFEDIT


Короткий ответ: ошибка iOS4.3, очень мало шансов найти обходной путь... bugreport и ждать следующего обновления iOS... WWDC через 2 недели... 1 ~ 2 месяца.

Длинный:

Посмотрев на сборку UIKit, вот мои догадки:

  • InputModeProperties.plist содержит список всех макетов клавиатур по языку.
  • UIKit используйте это для нескольких вещей, например, при показе клавиатуры, чтобы определить доступные раскладки клавиатур. (Locales...)
  • Интересно одно: мы можем найти некоторые из его сведений в NSUserDefaults:

    NSLog(@"%@", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
    ==> {
    AppleKeyboards =     (          // I have two keyboard in preferences
       "[email protected]=French;sw=AZERTY", // french  first
       "[email protected]=US;sw=QWERTY"      // english second
    );
    ...
    
  • Но эта информация не сохраняется в настройках приложений, в отличие от вашей оценки. (NSGlobalDomain или, более вероятно, отдельные домены для каждого из предпочитаемых вами языков)
  • Таким образом, я не удивлюсь, что в UIKit + NSUserDefaults существует конфликт (ошибка), вызывающий этот грязный цикл загрузки plist.
  • Около 100 звонков вы говорите? Это что-то вроде количества языковых/макетов в plist!

Если в NSUserDefaults нет клавиатуры... (Как и после синхронизации, представьте себе, что это ошибка)... UIKit может попробовать все доступные клавиатуры, чтобы определить пользователя один, грязно разобрав эту 4.4K plist сто раз... Как при показе UIAlertView... после NSUSerDefault синхронизации/изменения.

Кто знает? Пользователи Apple, у которых есть исходный код:)

Я бы не стал удивляться тому, что предпочитаю устанавливать клавиатуру, отличную от США по умолчанию, а затем возвращаться в США, чтобы решить эту проблему. Бесполезно в вашем случае, но подтвердите эту проблему. Видно, что для другой ошибки 4.3...

Как говорили другие люди, не используя NSUserDefaults, но простой пользовательский plist в /Documents может быть приемлемым способом (in).

Отличная работа над крошечными крыльями!:)

Ответ 2

Хорошо. Оглядываясь, кажется, что InputModeProperties.plist - это всего лишь список аппаратных и программных клавиатур.

Глядя на тему форума, вы опубликовали эту проблему, по-видимому, заключается в том, что после загрузки объекта UITextField или UIAlertView (включая UITextInputTraits.h среди других) всякий раз, когда вы пытаетесь сохранить пользовательские значения по умолчанию, существует необъяснимый цикл файла определений клавиатуры, Это происходит только в iOS 4.3.

Кажется, это ужасно похоже на ошибку в UIKit для меня, и я предполагаю, что внезапно UIKit спасает нагрузку вещей без реальной цели. Если это так, может быть сложно что-либо сделать, хотя вы можете избежать этих элементов (не так уж плохо для предупреждения, но текстовое поле будет более сложным), или вы можете переключиться на основные данные. Кроме того, вы можете сделать изменяемый словарь для всех своих опций и сохранить его по умолчанию для пользователей, когда приложение закрывается, и вы не заботитесь о паузе. Или просто вытащите обновление.

Удачи (любите игру кстати)

Ответ 3

Использование UIKit и OpenGL вместе не рекомендуется. Я не думаю, что эта точка зрения является проблемой, так как концепция смешивания этих двух. Я настоятельно рекомендую установить это предупреждение и вместо этого показать пользовательский оверлей, чтобы вы могли выполнить две вещи:

  • Сделайте предупреждение "Get Ready" подходящим для игровой графики.
  • Избегайте этой проблемы вообще.

Я видел медленную производительность с выпущенной в настоящее время версией в App Store при возобновлении игры на iPod touch второго поколения.

Если вы хотите сохранить эти элементы как есть, этот пост форума разработчиков Apple предлагает запустить синхронизацию в отдельном потоке. Идя с этим, я бы предложил следующие шаги:

  • Как и другие рекомендации, держите ссылку на NSUserDefaults где-то. (Обычно я просто делаю что-то вроде этого: #define kSettings [NSUserDefaults standardUserDefaults]. Конечно, вам нужно вызвать его один раз, чтобы создать экземпляр Singleton.)

  • Запустите вызов synchronize во втором потоке (согласно сообщению Apple Developer Forum).

  • Посмотрите, можно ли вызывать synchronize в другое время, чем willResignActive. Проблема кажется немного хуже, когда вы вызываете синхронизацию с этим методом.

Поздравляем с игрой.

Ответ 4

Просто в темноте, глядя на 4.3 diff -

Возможно, комбинация нового

- (BOOL)disablesAutomaticKeyboardDismissal

на UIViewController и UIModalPresentationFormSheet (где это значение по умолчанию равно YES) вызывает какой-то цикл в вашем коде.

Ответ 5

Предполагая, что вы выполняете метод отображения представления предупреждения, вы пробовали следующее?

[self performSelector:@selector(displayAlert) withObject:nil afterDelay:0.5];

- (void)displayAlert {
  UIAlertView *alert = [[UIAlertView alloc] init];
  [alert setTitle:@"Get ready!"];
  [alert setDelegate:self];
  [alert addButtonWithTitle:@"Ok"];
  [alert show];
  [alert release];
}

Я прошу, что я часто испытывал странное поведение при попытке выполнить метод сразу после синхронизации NSUserDefaults. В противном случае нам действительно нужно увидеть немного больше кода, чтобы определить, что происходит.

Ответ 6

Вероятно, он сохраняет каждый ваш вариант как отдельную транзакцию. Я не уверен. Вы можете попытаться использовать свой собственный класс DataStorage Singleton с NSMutableDictonairy в качестве хранилища данных. И синхронизируйте его с NSUserDefaults на applicationDidEnterBackground: и applicationWillTerminate:. Или даже если вы не используете системные настройки с помощью NSUserDefaults - вы можете сохранить этот NSMutableDictonairy следующим образом:

tempData = [NSMutableData data];
archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:tempData];
[archiver encodeObject:mutableDict forKey:@"data"];
[archiver finishEncoding];
result = [tempData writeToFile:archivePath atomically:YES];
[archiver release];

p.s. большие пальцы вверх для крошечных крыльев.;)