Сотни обращений к «InputModeProperties.plist» отстают от моей игры (iPhone) - PullRequest
22 голосов
/ 17 мая 2011

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

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

для сохранения некоторых настроек и таблицы рекордов.В конце игры, когда появляется экран игры, игра сохраняет рекорды в стандартных пользовательских настройках.Это работает очень хорошо, пока игра не отобразит UIAlertView, как это:

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

После того, как AlertView исчезал каждый раз, когда игра сохраняет что-то в standardUserDefaults, игра на некоторое время зависает (на некоторых устройствах на несколько секунд).Это также происходит после того, как игра использовала UITextField для ввода имени игрока.В игре нет никаких задержек до использования одного из двух элементов UIKit, но после их использования игра зависает до тех пор, пока я не перезапущу приложение.Я проанализировал проблему с Performance Tools, и инструмент «I / O Activity» показывает, что существуют сотни «открытых - прочитанных - закрытых» обращений к

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

, что вызывает лаги.

Я совершенно не знаю, что делать.Есть идеи?

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

Ответы [ 6 ]

3 голосов
/ 28 мая 2011

РЕДАКТИРОВАТЬ

A Приличный Обход ошибки:

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

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

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

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

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

ENDOFEDIT


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

Длинный:

После просмотрав UIKit asssembly, вот мои догадки:

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

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

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

Кто знает?Ребята из Apple, у которых есть исходный код:)

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

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

Отличная работа на TinyКрылья!:)

3 голосов
/ 26 мая 2011

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

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

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

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

2 голосов
/ 29 мая 2011

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

  1. Сделайте так, чтобы предупреждение «Get Ready» соответствовало игровой графике.
  2. Избегайте этой проблемы вообще.

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

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

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

  2. Выполните вызов synchronize во второй ветке (согласно этому сообщению на форуме разработчиков Apple).

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

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

1 голос
/ 26 мая 2011

Вероятно, он сохраняет каждый ваш вариант как отдельную транзакцию. Я не уверен. Вы можете попробовать использовать свой собственный одноэлементный класс DataStorage с 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. большие пальцы за крошечные крылья. ;)

1 голос
/ 24 мая 2011

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

[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.В противном случае нам действительно нужно было бы увидеть немного больше кода, чтобы определить, что происходит.

1 голос
/ 23 мая 2011

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

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

- (BOOL)disablesAutomaticKeyboardDismissal

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

...