我几乎知道我的iPad应用程序为什么崩溃的原因,但是我很难想出解决方案。该应用程序是一个拼图游戏应用程序。我有一个比App Store中的版本更稳定的工作版本,但是我仍然有一个讨厌的问题,我不太喜欢舔。
问题的根源在于用户 Activity 与自动保存之间的冲突。保存实际上将拼图的状态存储为属性列表。该属性列表除其他外,包括拼图中所有调色板的汇编,以及每个调色板的该调色板上所有部件的详细信息。除用户 Activity 可以更改这些详细信息外,它工作得很好。调色板本质上是一个UIView,其中包含拼图碎片作为子视图。用户可以在调色板上四处移动,也可以在调色板之间移动。
我的保存过程分两个阶段进行。第一阶段由计时器开始。该阶段会定期检查是否有一些需要保存的用户 Activity 。它将abortSave
属性设置为NO,然后触发一个非重复计时器以等待另一个时间段,然后再开始第二阶段。
在第二阶段,只要abortSave
为NO,就会进行保存。
同时,如果用户执行影响保存的任何操作,则abortSave
设置为YES。这个想法是,阶段1和阶段2之间的延迟比执行用户操作所花费的时间更长,因此,如果abortSave
为NO,则保存时应该是安全的。
此过程消除了大约95%的崩溃,但是我仍然遇到崩溃。
当然,为了使应用程序具有良好的性能,用户 Activity 以及保存操作都在后台线程中进行。
我遇到的情况类型通常是快速枚举过程中的突变,或类似的情况。本质上,某些用户操作正在保存过程中进行更改。如果我复制快速枚举的对象然后在副本上进行操作,那将无济于事。有时,错误会在复制语句中发生。如果对象是数组,则不使用快速枚举,而是使用常规的for循环遍历数组。这会有所帮助。
我希望这个问题不要太笼统。我想我可以发布一些代码,但是我不确定它的实际作用。我不想不必要地使这个问题变得混乱。
我还没有做的一件事是使用以另一种方式工作的标志:saveProcessActive
在保存发生之前立即设置为YES,并在保存完成时设置为NO。然后,如果saveProcessActive
为YES,则所有用户操作都必须停止。这种情况的问题是,这将导致用户操作的延迟,该延迟对于用户可能是可见的,但是任何延迟都可以忽略不计。它只需要保存的时间,直到下一次检查abortSave
为止。然后,中止的保存过程在确认中止请求时会将saveProcessActive
变为NO。有更好的解决方案吗?
最佳答案
在保存和在正常播放期间更改数据时,都需要同步对数据的访问。由于写入文件可能要比制作副本花费更多的时间,为了最大程度地减少锁定时间,您应该在拥有锁定的同时进行复制,然后释放锁定并
将数据写入磁盘。有几种方法可以做到这一点,但是最简单的是@synchronised
块:
-(void) save
{
NSDictionary *old = self.data;
NSDictionary *new;
@synchronized(old) {
new = [old copy];
}
[self writeData:new];
}
并记住也要同步更改:
-(void) updateDataKey:(id)key toValue:(id)val
{
NSDictionary *old = self.data;
@synchronized(old) {
old[key] = val;
}
}
data
显然不需要是NSMutableDictionary
,这只是一个方便的示例。