UITextView 冻结来自 textViewShouldBeginEditing 的 iPad 应用程序。 (无效字形索引)
UITextView freezes iPad app from textViewShouldBeginEditing. (Invalid Glyph Index)
所以我已经研究这个 bug 大约一个星期了,对于我来说,我无法弄清楚发生了什么。
由于保密问题,我不能post写太多代码,但我会尽力解释一切。
发生的事情是我们通过代码填充 UITextField,并且最初将文本显示为灰色。然后用户可以执行以下两项操作之一:
1) 点击一个显示 "commit" 的按钮并调用一个方法,该方法执行以下我们将调用的方法 "commitData"。它执行以下操作:
- 向撤消管理器注册提交
- 将文本从灰色更改为黑色
- 向我们的应用程序注册文本字段已更新,需要在应用程序关闭时保存
2) 点击带有灰色文本的文本字段,然后调用以下默认的苹果方法 textViewShouldBeginEditing。从这里我们调用选项 1 中列出的 "commitData" 方法,如下所示:
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
if ([[self box] hasGreyedOutText])
[[self box] commitData];
[self setActiveTextView:textView];
return YES;
}
我们遇到的问题是点击按钮提交变灰的文本效果非常好,我们 运行 没有遇到任何问题。
然而
当我们点击文本字段并触发 textViewShouldBeginEditing 方法时,我们的 iPads 可能会冻结并让用户等待几分钟才能完成。当我说冻结时,我的意思是整个 iPad 冻结。在这种情况下,iPad 时钟甚至不会更新。
发生这种情况时,我们会在控制台中收到错误代码:
!!! _NSLayoutTreeLineFragmentRectForGlyphAtIndex invalid glyph index 2147483647
按照上述步骤,我们可以从所有硬件中获取上述错误代码以显示,但只能在 iPad 2 上重现冻结(但是准确率为 100%)。
- 关于此的说明,我的同事通过诊断发现发生此错误时我们只有大约 8MB 的可用 RAM。然而,我们只在 iPad 2 上使用过这么小的 RAM,所以这可能只是巧合。
我觉得这可能与线程有关,我们可能需要在从 textViewShouldBeginEditing 方法返回 YES 后以某种方式调用我们的方法,但我不太确定我应该如何处理。
如果有人对如何解决这个问题有任何想法,或者甚至可以为我指明正确方向的想法,我将非常感激。我已经查看了所有可能想到的地方,并且 none 我找到的与错误代码相关的解决方案最终都有效。
我无法调试,所以我猜测可能是非主线程UI操作造成的。因此,我的建议是确保您的 UI 代码在 mainThread 中。试试这个:
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
dispatch_async(dispatch_get_main_queue(), ^{
if ([[self box] hasGreyedOutText])
[[self box] commitData];
[self setActiveTextView:textView];
}
return YES;
}
所以我已经研究这个 bug 大约一个星期了,对于我来说,我无法弄清楚发生了什么。
由于保密问题,我不能post写太多代码,但我会尽力解释一切。
发生的事情是我们通过代码填充 UITextField,并且最初将文本显示为灰色。然后用户可以执行以下两项操作之一:
1) 点击一个显示 "commit" 的按钮并调用一个方法,该方法执行以下我们将调用的方法 "commitData"。它执行以下操作:
- 向撤消管理器注册提交
- 将文本从灰色更改为黑色
- 向我们的应用程序注册文本字段已更新,需要在应用程序关闭时保存
2) 点击带有灰色文本的文本字段,然后调用以下默认的苹果方法 textViewShouldBeginEditing。从这里我们调用选项 1 中列出的 "commitData" 方法,如下所示:
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
if ([[self box] hasGreyedOutText])
[[self box] commitData];
[self setActiveTextView:textView];
return YES;
}
我们遇到的问题是点击按钮提交变灰的文本效果非常好,我们 运行 没有遇到任何问题。
然而
当我们点击文本字段并触发 textViewShouldBeginEditing 方法时,我们的 iPads 可能会冻结并让用户等待几分钟才能完成。当我说冻结时,我的意思是整个 iPad 冻结。在这种情况下,iPad 时钟甚至不会更新。
发生这种情况时,我们会在控制台中收到错误代码:
!!! _NSLayoutTreeLineFragmentRectForGlyphAtIndex invalid glyph index 2147483647
按照上述步骤,我们可以从所有硬件中获取上述错误代码以显示,但只能在 iPad 2 上重现冻结(但是准确率为 100%)。
- 关于此的说明,我的同事通过诊断发现发生此错误时我们只有大约 8MB 的可用 RAM。然而,我们只在 iPad 2 上使用过这么小的 RAM,所以这可能只是巧合。
我觉得这可能与线程有关,我们可能需要在从 textViewShouldBeginEditing 方法返回 YES 后以某种方式调用我们的方法,但我不太确定我应该如何处理。
如果有人对如何解决这个问题有任何想法,或者甚至可以为我指明正确方向的想法,我将非常感激。我已经查看了所有可能想到的地方,并且 none 我找到的与错误代码相关的解决方案最终都有效。
我无法调试,所以我猜测可能是非主线程UI操作造成的。因此,我的建议是确保您的 UI 代码在 mainThread 中。试试这个:
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
dispatch_async(dispatch_get_main_queue(), ^{
if ([[self box] hasGreyedOutText])
[[self box] commitData];
[self setActiveTextView:textView];
}
return YES;
}