问题
我需要了解 TextKit 的工作原理以及如何使用它来构建文本编辑器。我需要弄清楚如何仅绘制最终用户与之交互的可见文本,或者确定如何在 processEditing 方法中将属性仅应用于可见文本而不将属性应用于整个更改的文本范围。
背景
iOS 7 推出了 TextKit。我有一个完全实现 TextKit 的标记器和代码(请参阅 Apple 的 TextKitDemo 项目——下面提供了一个链接)......并且它可以工作。但是,它真的很慢。当文本被 NSTextStorage 解析时,它要求您在 processEditing 方法中在同一线程上对已编辑文本的整个范围进行着色。将工作卸载到线程并没有帮助。简直太慢了。我已经到了只能重新归因修改后的范围的地步,但如果范围太大,过程会很慢。在某些情况下,整个文档在进行更改后可能会失效。
以下是我的一些想法。请让我知道这些中的任何一个是否会起作用,或者可能会推动我朝着正确的方向前进。
1) 多个 NSTextContainers
阅读文档,我似乎可以在 NSLayoutManager 中添加多个 NSTextContainers。我假设通过这样做,我不仅应该能够定义可以在 NSTextContainer 中绘制的行数,而且我还应该能够知道最终用户可以看到哪个 NSTextContainer。我知道如果我走这条路,我将需要投入大量时间来看看它是否可行。初步测试表明您只需要一个 NSTextContainer。所以我必须继承 NSLayout 或创建一个包装器,其中布局管理器确定哪些文本进入哪个文本容器。呸。另外,我不知道 TextKit 是如何让我知道是时候绘制一个特定的 NSTextContainer 了……也许这不是它的工作原理!
2) 使用 NSLayoutManager 使范围无效
使用 invalidateLayoutForCharacterRange:actualCharacterRange: 使 layoutManager 无效。但这实际上是做什么的,它将如何减轻文本归因阶段的负担?它什么时候让我知道需要突出显示特定文本?另外,我看到 NSLayoutManager 会懒惰地绘制字形......如何?什么时候?这对我有什么帮助?我如何利用这个调用,以便我可以在它实际布置文本之前归因于支持字符串?
3) 覆盖 NSLayoutManager drawGlyphsForGlyphRange:atPoint: 方法。
我真的不想这样做。话虽如此,在 Mac OS X 中,NSAttributedStrings 具有临时属性的概念,其中样式信息仅用于表示。这大大加快了突出显示的过程!问题是,它在 iOS 7 TextKit 框架中不存在(或者它在那里,我只是不知道)。我相信,通过覆盖此方法,它将为我提供与使用临时属性相同的速度......因为我可以在此方法中回答所有布局、颜色和格式问题,而无需触及 NSTextStorage 属性细绳。唯一的问题是,我不知道这个方法相对于 NSLayoutManager 类中提供的其他方法是如何工作的。它是否保持宽度和高度的状态?当 NSTextContainer 太小时,它会修改它的大小吗?此外,它仅绘制已添加到文本缓冲区中的字符的字形。它不会重新绘制整个屏幕。只有一小部分......这很好。我对如何使用它有一些想法……但我真的不想布置字形。那是太多的工作,我还没有找到一个很好的例子来做到这一点。
我将非常感谢您提供的任何帮助。
作为感谢,我列出了我在过去几年中使用过的所有框架和参考资料,这些框架和参考资料帮助我达到了现在的水平,希望它们对你有所帮助。
语法高亮框架:
- http://colorer.sourceforge.net/
- https://github.com/MikeJ1971/Glint(不支持字符串、注释等)
- https://projects.gnome.org/gtksourceview/features.html(为令牌生成提供了一个不错的库。与 GTK 一起工作,但可能会为不同的布局管理器重写)
- http://parsekit.com/(很好的解析器。但是,当需要修复范围时,您必须包装 API 以创建状态机)
- http://svn.gna.org/viewcvs/etoile/trunk/Etoile/Languages/LanguageKit/
- https://github.com/CodaFi/IDEKit(令人惊叹的工作。这段代码中有很多好主意。我的问题是我完全不知道它是如何修复范围的,或者即使它确实如此)
- http://www.crimsoneditor.com/(一个旧的 Windows 代码编辑器。它有一个非常好的标记器——虽然有点难以阅读。它不使用正则表达式。话虽如此,我的标记逻辑是关闭的这段代码,它比上面列出的任何框架都快得多)
资源:
- http://cocoafactory.com/blog/2012/10/29/how-to-use-custom-nsattributedstring-attributes/
- https://github.com/objcio/issue-5-textkit
- http://alexgorbatchev.com/SyntaxHighlighter/
- http://docs.xamarin.com/samples/TextKitDemo/(苹果的演示)
- http://cocoadev.com/ImplementSyntaxHighlighting(一定要阅读所有的子文章。很棒的东西)
这些框架中的大多数都是相同的。它们要么不考虑范围的上下文切换(或者您必须编写包装器以提供上下文),要么它们不会在用户修改文本(例如字符串、多行注释等)时修复上下文范围。最后一个要求非常重要。因为如果分词器无法确定哪些范围受到更改的影响,您最终将不得不再次解析和属性整个字符串。唯一的例外是 Crimson 编辑器。这个分词器的问题是它在分词时不保存状态。在绘图时,算法使用标记来确定绘图状态。它从文档的顶部开始,直到到达可见的文本范围。不用说,
另一个问题是这些框架没有遵循 Apple 所做的相同 MVC 模式——这是意料之中的。具有完整工作编辑器的框架都使用由它们构建的 API(即 GTK、Windows 等)提供的钩子,这些钩子为它们提供关于何时何地绘制到屏幕哪个部分的信息。就我而言,TextKit 似乎要求您在 processEditing 中归因于整个更改范围。
也许我的观察是错误的。(我希望他们是!!)也许,例如 ParseKit,它将为我需要它做的工作而我根本不明白如何使用它。如果是这样,请告诉我!再次感谢!