数以百计的"InputModeProperties.plist"访问滞后于我的游戏(iPhone)



我对小翅膀的错误修复有一个奇怪的问题。在我的游戏中,我使用类似的东西:

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];

每次游戏将某些内容保存到标准用户默认值时,警报视图消失后,游戏会滞后一段时间(在某些设备上会滞后几秒钟)。这也发生在游戏使用 UITextField 输入玩家姓名之后。在使用两个UIKit元素之一之前,游戏中没有任何延迟,但是在使用它们之后,游戏会滞后,直到我重新启动应用程序。我分析了性能工具的问题,"I/O 活动"工具显示有数百个"打开 - 读取 - 关闭"访问

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

这会导致滞后。

我完全不知道该怎么办。有什么想法吗?

编辑:
苹果开发者论坛 http://devforums.apple.com/message/424374#424374 中有一个帖子,有人有同样的问题,似乎它只出现在iOS 4.3中。我已经测试过它,滞后只发生在我的 4.3 设备上(不是在 3.1 iPod touch 和 4.2 iPad 上)。

编辑

一个不错的错误解决方法:

简短版本:只需延迟错误触发调用,直到用户不烦恼。

长版本:

由于我认为问题来自[NSUserDefaults standardUserDefaults]调用,因此在请求键盘布局(如UIAlert)的某些操作之后,它会触发肮脏的 plist-load 循环......

我建议在应用程序加载时只调用[NSUserDefaults standardUserDefaults]一次(在任何导致错误的调用之前),并在所有应用程序生命周期中将返回的引用保留在单例类中。我不认为内存占用会很大...(我在几个应用程序中执行此操作,没有任何问题)。在更糟糕的情况下,plist 加载*100 只会在应用程序加载时执行一次,而不是在游戏期间完成。

如果问题来自[userDefaults setXxxx:...]调用,同样的解决方法,您可以保留要保存在内存中的值,稍后在 userDefaults 中设置它们,就像在同步它们之前一样......但如果出现任何问题,例如崩溃,则冒着丢失信息的风险。我个人更喜欢在每次setsync以确保数据完整性......

结束编辑


简短的回答:iOS4.3错误,找到解决方法的机会很少...错误报告并等待下一次iOS更新...WWDC 在 2 周内...1~2个月。

长的一个:

在看了UIKit组合之后,以下是我的猜测:

  • InputModeProperties.plist 包含按区域设置列出的所有键盘布局的列表。
  • UIKit将其用于多种用途,例如在显示键盘时,以确定可用的键盘布局。(区域设置...
  • 有一件事很有趣,我们可以在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 中存在冲突(错误)导致脏列表加载循环。
  • 你说100个左右的电话?这有点像 plist 中的区域设置/布局数量!

NSUserDefaults中没有可用的键盘时...(就像同步后一样,让我们想象一个错误这样做)... UIKit可以尝试所有可用的键盘来确定用户 1,肮脏地解析这个 4.4K 列表一百次......就像展示UIAlertView一样...NSUSerDefault同步/更改后。

谁知道呢?拥有源代码的苹果人:)

我不会感到惊讶,去首选项设置默认美国以外的键盘,然后恢复到美国将解决问题。在您的情况下没用,但会确认问题。看到另一个 4.3 错误...

正如其他人所说,不使用NSUserDefaults而是在/Documents中使用简单的自定义plist可能是一个(不)体面的解决方法。

《小翅膀》做得很好! :)

好的,环顾四周,似乎InputModeProperties.plist只是一个硬件和软件键盘的列表。

查看您发布的论坛主题,此问题似乎本质上是在加载UITextField对象或UIAlertView(包括UITextInputTraits.h等)后,每当尝试保存用户默认值时,都会有一个莫名其妙的键盘定义循环文件。这只发生在iOS 4.3中。

对我来说,这似乎非常像 UIKit 中的一个错误,我的猜测是 UIKit 突然在没有真正目的的情况下节省了大量东西。如果是这种情况,尽管您可以避免这些元素(对于警报来说还不错,但文本字段会更棘手),或者您可以切换到核心数据,但您可能很难对此做任何事情。或者,您可以为所有选项创建一个可变字典,并在应用程序关闭时将其保存为用户默认值,并且您不太关心暂停。或者,只是完成更新。

祝你好运(顺便说一句,喜欢游戏)

建议同时使用 UIKit 和 OpenGL。我不认为这种观点是问题,而是将两者混合的概念。我强烈建议取消该警报,而是显示自定义覆盖,以便您可以完成两件事:

  1. 使"准备就绪"警报与游戏图形匹配。
  2. 完全避免此问题。

我在App Store上看到当前发布的版本在第二代iPod touch上恢复游戏时性能缓慢。

如果你想保持这些元素不变,这篇 Apple 开发者论坛帖子建议在单独的线程上运行同步。除此之外,我建议采取以下步骤:

  1. 正如其他人建议的那样,在某处保留对NSUserDefaults的引用。(我通常只是做这样的事情:#define kSettings [NSUserDefaults standardUserDefaults]。当然,您需要调用它一次才能实例化单例。

  2. 在第二个线程上运行synchronize调用(根据 Apple 开发人员论坛帖子)。

  3. 看看您是否可以在willResignActive以外的其他时间呼叫synchronize。当您从该方法调用同步时,问题似乎更糟。

恭喜游戏。

只是在黑暗中查看 4.3 差异的镜头 -

也许是新的组合

- (BOOL)disablesAutomaticKeyboardDismissal

UIViewController 和 UIModalPresentationFormSheet(默认为 YES)导致代码中的某种循环。

假设您执行了一个方法来显示警报视图,您是否尝试过以下方法?

[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后尝试直接执行方法时,我经常遇到奇怪的行为。否则,我们真的需要看到更多的代码才能确定发生了什么。

可能它将每个选项保存为单独的事务。我不确定。您可以尝试使用自己的单例数据存储类和NSMutableDictonairy作为数据存储。并将其同步到 NSUserDefaults on 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];

附言为小翅膀竖起大拇指。 ;)

相关内容

最新更新