对“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];
每次游戏将某些内容保存到 standardUserDefaults 时,AlertView 就会消失,游戏会滞后一段时间(在某些设备上会滞后几秒钟)。在游戏使用 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 上)。
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).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
编辑
一个体面的错误解决方法:
简短版本:只需延迟错误触发调用,直到用户不恼火。
长版本:
因为我认为问题来自
[NSUserDefaults standardUserDefaults]
调用,所以触发了肮脏的 plist 加载循环之后 一些请求键盘布局的操作(例如UIAlert
)...我建议在应用加载时调用
[NSUserDefaults standardUserDefaults]
一次 ( 在任何引起错误的调用之前),并在整个应用生命周期中将返回的引用保留在单例类中。我不认为内存占用会很大......(我在几个应用程序中这样做,没有任何问题)。最糟糕的是,plist load*100 仅在应用程序加载时执行一次,而不是在游戏期间执行。如果问题来自
[userDefaults setXxxx:...]
调用,同样的解决方法,您可以将值保存在内存中,并稍后在userDefaults
中设置它们,例如 < em>就在同步它们之前...但是如果出现任何问题(例如崩溃),就有丢失信息的风险。我个人更喜欢在每次设置
后同步
以确保数据完整性...ENDOFEDIT
简短的回答:iOS4.3 bug,很少有机会找到解决方法...错误报告并等待下一次 iOS 更新...两周后的 WWDC...1~2 个月。
长篇大论:
查看 UIKit 组件后,这是我的猜测:
InputModeProperties.plist
包含按区域设置的所有键盘布局的列表。UIKit
将其用于多种用途,例如在显示键盘时确定可用的键盘布局。 (语言环境...)有一点很有趣,我们可以在
NSUserDefaults
中找到它的一些信息:NSGlobalDomain
,或者更有可能为每种用户的首选语言提供单独的域)当
NSUserDefaults
中没有可用的键盘时...(就像同步后一样,让我们想象一个错误这样做)...UIKit
可以尝试所有可用的键盘来确定用户一,肮脏地解析这个 4.4K plist 数百次...就像在NSUSerDefault
同步/更改之后显示UIAlertView
一样。谁知道?拥有源代码的苹果人员:)
我不会感到惊讶的是,在首选项中设置默认美国以外的键盘,然后恢复为美国将解决问题。对你的情况没用,但可以确认问题。看到另一个 4.3 bug...
正如其他人所说,不使用 NSUserDefaults 而是使用 /Documents 中的简单自定义 plist 可能是一个(in)体面的解决方法。
《小翅膀》的作品非常棒! :)
EDIT
A decent bug workaround :
Short version: Just delay the bug-triggering calls until user is not annoyed.
Long version:
Since I think the issue is coming from
[NSUserDefaults standardUserDefaults]
call, that triggers that dirty plist-loading loop AFTER some action requesting Keyboard layouts (like anUIAlert
)...I would suggest to call
[NSUserDefaults standardUserDefaults]
just one time at app loading (BEFORE any bug-causing call), and keep the returned reference in a singleton class during all app lifecycle. I don't think the memory footprint would be huge... (I'm doing this in several apps w/o any issues). At worse the plist load*100 would be done only once at app load, and not during game.If the issue comes from
[userDefaults setXxxx:...]
calls, same workaround, you could just keep values to save in memory and set them later inuserDefaults
, like just before syncing them... But at the risk of losing informations if anything goes wrong, like a crash. I personally prefer tosync
after eachset
to ensure data integrity...ENDOFEDIT
The short answer : iOS4.3 bug, very few chances to find a workaround... bugreport and wait for next iOS update... WWDC in 2 weeks... 1~2 month.
The long one:
After looking at UIKit asssembly, here are my guesses:
InputModeProperties.plist
contains a list of all keyboards layouts by locale.UIKit
use this for several things, like when showing a keyboard, to determine available keyboards layouts. (Locales...)One thing is interesting, we can find some of its informations in
NSUserDefaults
:NSGlobalDomain
, or more likely Separate domains for each of the user’s preferred languages)When no keyboard is available in
NSUserDefaults
... (Like after synchronizing, let's imagine a bug doing this)...UIKit
could try all available keyboards to determine user one, dirtily parsing this 4.4K plist hundred times... Like when showing anUIAlertView
... after aNSUSerDefault
sync/change.Who knows? The Apple folks who has the source code :)
I would not be surprised going to preferences to set a keyboard other than default US then reverting to US would solve the issue. Useless in your case, but would confirm the issue. Seen that for another 4.3 bug...
As other people said, not using NSUserDefaults but a simple custom plist in /Documents could be a (in)decent workaround.
Great work on Tiny Wings! :)
好吧,环顾四周,InputModeProperties.plist 似乎只是硬件和设备的列表。软件键盘。
查看您发布的论坛帖子,此问题似乎本质上是在加载 UITextField 对象或 UIAlertView(其中包括 UITextInputTraits.h 等)后,每当您尝试保存用户默认值时,都会出现键盘定义文件的莫名其妙的循环。这只发生在 iOS 4.3 中。
对我来说,这看起来非常像 UIKit 中的一个错误,我的猜测是 UIKit 突然无缘无故地保存了很多东西。如果是这种情况,尽管您可以避免这些元素(对于警报来说还不错,但文本字段会更棘手),但可能很难对此采取任何措施,或者您可以切换到核心数据。或者,您可以为所有选项创建一个可变字典,并在应用程序关闭时将其保存为用户默认值,并且您不太关心暂停。或者,只是等待更新。
祝你好运(顺便说一句,喜欢这个游戏)
Ok, Looking around it seems that InputModeProperties.plist is just a list of hardware & software keyboards.
Looking at the forum thread you posted this issue seems to essentially be that after loading a UITextField object or UIAlertView (which includes UITextInputTraits.h amongst others) whenever you try to save user defaults there is an inexplicable loop of a keyboards definitions file. This only happens in iOS 4.3.
It seems awfully like a bug in UIKit to me and my guess is that suddenly UIKit is saving a load of things for no real purpose. If this is the case it may be hard to do anything about it although you could avoid these elements (not too bad for the alert but the textfield will be trickier) or you could switch to core data. Alternatively, you could make a mutable dictionary for all your options and save that to user defaults when the app closes and you care less about a pause. Or, just ride out an update.
Good luck (love the game btw)
不建议同时使用 UIKit 和 OpenGL。我认为这种观点的问题不在于混合两者的概念。我强烈建议取消该警报,而是显示自定义叠加层,以便您可以完成两件事:
当我在第二代 iPod touch 上恢复游戏时,我发现 App Store 上当前发布的版本性能缓慢。
如果您想保持这些元素不变,这篇 Apple 开发者论坛帖子建议在单独的线程。为此,我建议执行以下步骤:
正如其他建议的那样,在某处保留对 NSUserDefaults 的引用。 (我通常只是这样做:
#define kSettings [NSUserDefaults standardUserDefaults]
。当然,您需要调用它一次来实例化单例。)运行
synchronize 在第二个线程上调用(根据 Apple 开发者论坛帖子)。
看看是否可以在
willResignActive
之外的其他时间调用synchronize
。当您从该方法调用 Synchronize 时,问题似乎更严重。恭喜游戏成功。
Using UIKit and OpenGL together is not recommended. I don't think that this view is the issue so much as the concept of mixing the two. I highly recommend nixing that alert and instead, show a custom overlay, so that you can accomplish two things:
I've seen slow performance with the currently released version on the App Store, when resuming the game on a second generation iPod touch.
If you want to keep those elements as is, this Apple Developer Forum post suggests running the synchronize on a separate thread. Going with that, I would suggest these steps:
As other suggested, keep a reference to NSUserDefaults somewhere. (I usually just do something like this:
#define kSettings [NSUserDefaults standardUserDefaults]
. Of course, you need to invoke it once to instantiate the singleton.)Run the
synchronize
call on a second thread (as per that Apple Developer Forum post).See if you can call
synchronize
at some other time thanwillResignActive
. The issue seems a bit worse when you call synchronize from that method.Congrats on the game.
只是查看 4.3 diff 的结果 -
也许 UIViewController 和 UIModalPresentationFormSheet 上的新功能(默认为 YES)的组合
正在导致代码中出现某种循环。
Just a shot in the dark from looking at the 4.3 diff -
Perhaps a combination of the new
on UIViewController and UIModalPresentationFormSheet (where this defaults to YES) is causing some sort of loop in your code.
假设您执行一个方法来显示警报视图,您是否尝试过以下操作?
我问的原因是,在同步
NSUserDefaults
后尝试直接执行方法时,我经常遇到奇怪的行为。否则,我们确实需要查看更多代码才能确定发生了什么。Assuming you execute a method to display the alert view, have you tried the following?
The reason I ask is that I have often experienced strange behavior when trying to execute a method straight after synchronizing
NSUserDefaults
. Otherwise, we'd really need to see a bit more code in order to determine what is going on.也许它将您的每个选项保存为单独的交易。我不知道。您可以尝试使用自己的单例 DataStorage 类和 NSMutableDictonairy 作为数据存储。并将其同步到
applicationDidEnterBackground:
和applicationWillTerminate:
上的 NSUserDefaults 中。或者即使你没有使用 NSUserDefaults 的系统设置 - 你也可以保存这个 NSMutableDictonairy 如下:ps 为小翅膀竖起大拇指。 ;)
Probably it saves each your option as separate transaction. I'm not sure. You could try to use your own singleton DataStorage class with NSMutableDictonairy as data storage. And sync it into NSUserDefaults on
applicationDidEnterBackground:
andapplicationWillTerminate:
. Or even if you're didn't use system settings with your NSUserDefaults - you could save this NSMutableDictonairy as follows:p.s. thumbs up for tiny wings. ;)