22

I have a weird problem with a bugfix for Tiny Wings. In my game i use something like:

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

for saving some preferences and the highscore table. At the end of the game when the gameover screen appears the game saves the highscores to the standardUserDefaults. It works very well until the game displayed an UIAlertView like this:

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

After the AlertView disappeared everytime the game save somthing to the standardUserDefaults the game lags for a while (on some devices for several seconds). This also happens after the game used an UITextField for inputting the player name. There is not any lag in the game before one of the two UIKit Elements are used but after the use of them the game lags until i restart the app. I have analysed the problem with the Performance Tools and the "I/O Activity" Instrument shows that there are hundreds of "open - read - close" accesses to the

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

which causes the lags.

I totaly have no clue what to do. Any ideas?

Edit:
there is a thread in the apple developer forum http://devforums.apple.com/message/424374#424374 where somebody has an equal problem and it seems that it only appears with iOS 4.3. I have tested it and the lags only happens on my 4.3 devices (not on a 3.1 iPod Touch and 4.2 iPad).

4

6 回答 6

3

编辑

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

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

长版:

由于我认为问题来自呼叫,因此在某些请求键盘布局(如 )的操作之后[NSUserDefaults standardUserDefaults]触发了肮脏的 plist 加载循环......UIAlert

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

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

ENDOFEDIT


简短的回答: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 中存在的冲突(错误)导致那个肮脏的 plist 加载循环感到惊讶。
  • 你说大约100个电话?这类似于 plist 中语言环境/布局的数量!

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

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

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

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

小翅膀的伟大工作!:)

于 2011-05-27T23:47:23.380 回答
3

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

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

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

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

于 2011-05-26T14:12:11.633 回答
2

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

  1. 使“准备就绪”警报与游戏图形相匹配。
  2. 完全避免这个问题。

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

如果您想保持这些元素不变,这篇 Apple 开发者论坛帖子建议在单独的线程上运行同步。随之而来的是,我建议以下步骤:

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

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

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

祝贺比赛。

于 2011-05-29T12:52:24.513 回答
1

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

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

于 2011-05-26T09:03:23.963 回答
1

只是从 4.​​3 的差异看黑暗中的一个镜头-

也许是新的组合

- (BOOL)disablesAutomaticKeyboardDismissal

在 UIViewController 和 UIModalPresentationFormSheet(默认为 YES)上会导致代码中出现某种循环。

于 2011-05-23T10:11:24.283 回答
1

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

[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。否则,我们真的需要查看更多代码才能确定发生了什么。

于 2011-05-24T06:13:56.487 回答