标签: nstextstorage

在NSTextStorage中混淆编码异常

我有一个简单的文本编辑器的NSDocument子类(使用Lion的基于新文档的应用程序模板,几乎没有自定义),我遇到了一个奇怪的错误,将文件内容加载到文本存储中.

这是我的代码:

- (void)loadTextContentIntoStorage
{
  if (!self.textStorage || !textContentToLoad)
    return;

  ...

  [self.textStorage beginEditing];

//  NSLog(@"storage: %@ length: %lu textContent: %@", self.textStorage, (unsigned long)self.textStorage.length, textContentToLoad);
//  [self.textStorage replaceCharactersInRange:NSMakeRange(0, self.textStorage.length) withString:textContentToLoad];
  [self.textStorage replaceCharactersInRange:NSMakeRange(0, 0) withString:@"hello world"];

  ..

  [self.textStorage endEditing];
}
Run Code Online (Sandbox Code Playgroud)

当我发生错误时:

  • 在Xcode中运行应用程序(作为调试版本)
  • 打开任何文件
  • 退出应用程序(不关闭文档)
  • 再次从Xcode运行应用程序

它崩溃-replaceCharactersInRange:withString:了"无法将字符串0x10004d430中的字节转换为_NSCStringEncoding".

但它只是发生在每一推出的应用程序(第三发射不会崩溃,它自动重新打开它坠毁试图打开上次的文件).它也只发生在我从Xcode运行应用程序时.发布版本从未在发布时崩溃.

我认为这可能是自动保存系统的编码问题,但是当我注释掉该代码并将@"hello world"字符串加载到文本视图中时它甚至会崩溃(如上面的代码所示).同样,注释掉NSLog()并没有显示任何奇怪的东西.文本存储有效(从xib文件加载),文本存储长度为0,textContent是要打开的文件的内容.

---编辑---

我已经知道这个问题在某种程度上与com.apple.security.app-sandbox权利有关.如果启用了权利/沙箱,那么我的应用程序不会崩溃.如果禁用了权利或app-sandbox功能,那么我的应用程序会在尝试恢复以前打开的文档的每次启动时崩溃.

我只注意到在xcode内部进行构建/运行时崩溃,因为这是我唯一一个禁用沙箱的构建配置.

--- /编辑---

有没有人有任何想法?完整的例外如下,完整的源代码在github上:https://github.com/abhibeckert/Dux/blob/master/Dux/DuxTextView.m

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', …
Run Code Online (Sandbox Code Playgroud)

macos cocoa objective-c nstextstorage

20
推荐指数
2
解决办法
936
查看次数

如何扩展NSTextStorage?

根据文档,我尝试子类化NSTextStorage并在文本视图中使用它:

/*
 NSTextStorage is a semi-abstract subclass of NSMutableAttributedString. It
 implements change management (beginEditing/endEditing), verification of
 attributes, delegate handling, and layout management notification. The one
 aspect it does not implement is the actual attributed string storage --- this is
 left up to the subclassers, which need to override the two
 NSMutableAttributedString primitives:

 - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str;
 - (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range;

*/
Run Code Online (Sandbox Code Playgroud)

所以我尝试使用delegate来处理具有相同功能的所有需要​​的事件:

@implementation MyTextStorage

- (id) init {
    self = [super init];

    if (self != nil) {
        storage = [[NSMutableAttributedString …
Run Code Online (Sandbox Code Playgroud)

cocoa objective-c nstextstorage

10
推荐指数
2
解决办法
2084
查看次数

修改NSTextStorage会导致插入点移动到行尾

我有一个NSTextView子类充当其NSTextStorage委托.我正在尝试做两件事:

  1. 以某种方式突出显示文本
  2. 评估文本,然后将答案附加到textview.

我在两种不同的方法中执行此操作,这两种方法都由- (void)textStorageWillProcessEditing:(NSNotification *)notification委托回调调用.

我可以很好地进行语法突出显示,但是当附加我的答案时,插入点会跳到行的末尾,我不知道为什么.我的评估方法如下所示:

NSString *result = ..;
NSRange lineRange = [[textStorage string] lineRangeForRange:[self selectedRange]];
NSString *line = [[textStorage string] substringWithRange:lineRange];
line = [self appendResult:result toLine:line]; // appends the answer

[textStorage replaceCharactersInRange:lineRange withString:line];
Run Code Online (Sandbox Code Playgroud)

这样做会很好地追加我的结果,但问题是,如上所述,插入点会跳到最后.

我试过了:

  1. 包装上面的那些调用[textStorage beginEditing]-endEditing.
  2. 在更改文本存储之前保存选择范围(即插入点),以便我可以在之后重置它,但不能骰子.

我这样做了吗?我试图以最少的hackish方式做到这一点,我也不确定这是否是进行解析/突出显示的理想场所.文档让我相信这一点,但也许这是错的.

macos cocoa nstextview nstextstorage

10
推荐指数
2
解决办法
1593
查看次数

在AppKit中测量文本宽度的性能

在AppKit中有没有办法快速测量大量NSString对象(比如一百万)的宽度?我尝试了3种不同的方法:

  • [NSString sizeWithAttributes:]
  • [NSAttributedString size]
  • NSLayoutManager(获取文本宽度而不是高度)

    以下是一些性能指标

    Count\Mechanism    sizeWithAttributes    NSAttributedString    NSLayoutManager
    1000               0.057                 0.031                 0.007
    10000              0.329                 0.325                 0.064
    100000             3.06                  3.14                  0.689
    1000000            29.5                  31.3                  7.06



    NSLayoutManager显然是要走的路,但问题在于

  • 由于创建了重量级的NSTextStorage对象,因此内存占用空间很大(根据分析器而超过1GB).
  • 创作时间长.所有花费的时间都是在创建上述字符串的过程中,这本身就是一个交易破坏者.(随后测量NSTextStorage对象,其中创建和布置的字形只需要大约0.0002秒).
  • 对于我想要做的事情,7秒仍然太慢.有更快的方法吗?在大约一秒钟内测量一百万个字符串?

    如果你想玩,是github项目.

  • cocoa objective-c nslayoutmanager nsattributedstring nstextstorage

    10
    推荐指数
    1
    解决办法
    763
    查看次数

    将文本视图的属性字符串细分为(首选)部分

    我正在尝试实现一个非常简单的文本编辑器,该文本编辑器应可同时NSTextView在macOS和UITextViewiOS上使用。该文本编辑器有一个工具栏按钮“分符”,每次单击它都会在当前光标位置插入一个新节。一节应为:

    1. 在视觉上可识别为一个部分(通过在两个后续部分之间添加视觉分隔符,并可能添加一些垂直空白),

    2. 参考。用户应该能够在编辑器中看到所有部分的列表,并且通过单击该列表中的项目,文本视图应立即滚动到该部分的开头。

    另一个问题,我问怎么解决的第一个问题,不幸的是,我还没有发现在这部分的答案,但(即使一个解决方案,仅在MacOS作品)。

    但是,这个问题集中在第二个方面:
    如何在我的文本视图中维护所有部分的列表,其中每个部分都能准确地引用相关文本?

    此任务的复杂性在于用户可以随时复制和粘贴或简单地编辑文本的任何部分。因此,我无法保留简单的段落编号数组或类似的内容。

    文本视图中几个部分的屏幕截图


    我尝试过的事情以及为什么这看起来是如此艰巨的任务:

    1. 我曾经有一个想法是继承NSTextStorage并使用可变属性字符串数组作为其内部存储。然后,我将使用的特殊子类NSTextAttachment并将其用作文本存储中的分节符指示符。问题在于,每当用户编辑文本时,文本视图仅调用以下方法

      func replaceCharacters(in range: NSRange, 
                             with str: String)
      
      Run Code Online (Sandbox Code Playgroud)

      func setAttributes(_ attrs: [NSAttributedString.Key : Any]?, 
                           range: NSRange)
      
      Run Code Online (Sandbox Code Playgroud)

      第一种方法仅传递不带任何属性的纯字符串,第二种方法仅获取属性。这意味着在第一种方法中,我无法确定替换字符是否实际上应该是分节符,因此我无法确定此时在内部文本存储数组中的哪个位置创建新元素。

      在第二种方法中,我不知道用户是否实际添加了新文本(在这种情况下,我将不得不在文本存储数组中为每个分节符属性添加一个新元素)还是用户只是更改了现有的某些属性文本(在这种情况下,先前已经创建了新的数组元素)。

    2. 我还考虑了在表视图或堆栈视图中使用多个文本视图的想法。但是,这不起作用,因为它将使用户无法选择(和删除)多个后续部分中的文本。

    3. 最后,我尝试了子类化NSLayoutManager,但是关于它的文档确实很薄,对我来说似乎是错误的地方。(毕竟,布局经理的职责是文本的布局,而不是跟踪其结构。)

    有任何想法吗?

    nslayoutmanager nstextview uitextview ios nstextstorage

    10
    推荐指数
    1
    解决办法
    203
    查看次数

    在NSTextView中替换NSTextStorage的正确方法?

    我正在制作一些文本查看器应用程序 目前我需要非常频繁和精确的线路处理能力,所以我想要继承NSTextStorage类.但我找不到任何方法来设置新的文本存储NSTextView.我能找到的唯一方法是

    -[NSLayoutManager replaceTextStorage:]
    
    Run Code Online (Sandbox Code Playgroud)

    方法.但令人困惑的是,这是我正在寻找的.因为它似乎只是替换链接的NSLayoutManagers而不是NSTextView的文本存储.

    我还考虑了子类化NSTextView和重写-textStorage方法,但如果该类不是为子类设计的,那么它将产生未定义的结果.

    有人试图在NSTextView上使用自定义NSTextStorage吗?我怎样才能做到这一点?或者这是否被设计禁止?

    cocoa nstextview subclassing nstextstorage

    9
    推荐指数
    1
    解决办法
    3145
    查看次数

    UITextView在iOS 8中崩溃,其中包含一个表的属性字符串

    在iOS 8(或甚至可能在iOS 7/7.1中)NSAttributedStringiOS上添加了渲染文本表的功能.此API 在OS X公开,但在iOS 公开.但是,可以通过将包含表的HTML传递给iOS,在iOS上创建包含文本表的属性字符串-[NSAttributedString initWithData:options:documentAttributes:error:].

    正确创建了属性字符串,但是当我尝试使用a渲染字符串时UITextView,会抛出此异常:

    <NSATSTypesetter: 0x7f8900faec90>: Exception *** -[NSConcreteTextStorage attribute:atIndex:effectiveRange:]: Range or index out of bounds raised during typesetting layout manager <NSLayoutManager: 0x7f8902e13440>
    1 containers, text backing has 1884 characters
    Currently holding 1884 glyphs.
    Glyph tree contents:  1884 characters, 1884 glyphs, 1 nodes, 64 node bytes, 7680 storage bytes, 7744 total bytes, 4.11 bytes per character, 4.11 bytes per glyph
    Layout tree contents:  1884 …
    Run Code Online (Sandbox Code Playgroud)

    objective-c uitextview nsattributedstring ios nstextstorage

    8
    推荐指数
    0
    解决办法
    904
    查看次数

    在某些情况下,NSTextStorage子类无法处理表情符号字符和更改字体

    我继承NSTextStorage做一些链接高亮和我多读我可以对 话题.一切正常,直到我输入 emoji character.

    My subclass:

    private let ims = NSMutableAttributedString()
    
    override var string: String {
        return ims.string
    }
    
    override func attributesAtIndex(location: Int, effectiveRange range: NSRangePointer) -> [String : AnyObject] {
        return ims.attributesAtIndex(location, effectiveRange: range)
    }
    
    override func replaceCharactersInRange(range: NSRange, withString str: String) {
        ims.replaceCharactersInRange(range, withString: str)
        self.edited(.EditedCharacters, range: range, changeInLength:(str as NSString).length - range.length)
    }
    
    override func setAttributes(attrs: [String : AnyObject]?, range: NSRange) {
        ims.setAttributes(attrs, range: range)
        self.edited(.EditedAttributes, range: range, changeInLength: 0)
    }
    
    Run Code Online (Sandbox Code Playgroud)

    Nothing complicated. …

    objective-c ios nstextstorage nsmutableattributedstring swift

    8
    推荐指数
    1
    解决办法
    747
    查看次数

    在 Swift 中使用 NSLayoutManager 隐藏 Markdown 字符

    我正在使用 Markdown 语法的 Mac 应用程序中的富文本编辑器。我NSTextStorage过去常常在 Markdown 语法中观察匹配项,然后NSAttributedString像这样实时地将样式应用到:

    在此处输入图片说明

    在这一点上,我已经在这方面不知所措,但我很高兴能够取得进展。:)本教程非常有帮助

    作为下一步,我想在呈现 's 字符串时隐藏 Markdown 字符NSTextView。所以在上面的例子中,一旦最后一个星号被输入,我希望* *字符被隐藏,只是sample以粗体显示。

    我正在使用NSLayoutManager委托,我可以看到匹配的字符串,但我不清楚如何使用该shouldGenerateGlyphs方法生成修改后的字形/属性。这是我到目前为止所拥有的:

    func layoutManager(_: NSLayoutManager, shouldGenerateGlyphs _: UnsafePointer<CGGlyph>, properties _: UnsafePointer<NSLayoutManager.GlyphProperty>, characterIndexes _: UnsafePointer<Int>, font _: NSFont, forGlyphRange glyphRange: NSRange) -> Int {
        let pattern = "(\\*\\w+(\\s\\w+)*\\*)" // Look for stuff like *this*
        do {
            let regex = try NSRegularExpression(pattern: pattern)
            regex.enumerateMatches(in: textView.string, range: glyphRange) {
                match, _, _ in …
    Run Code Online (Sandbox Code Playgroud)

    nslayoutmanager nstextview nstextstorage textkit

    8
    推荐指数
    2
    解决办法
    1344
    查看次数

    为nSTextStorage子类设置viewController的layoutManager时,字形索引无效

    我的目标是使用TextKit来斜体,设置某些单词的文本大小等.

    首先,我只想在文本字符串中突出显示一个字符.作为TextKit的新手(以及一般的编程),我遵循obc.io问题#5的语法高亮主题.

    当我使用内置于我创建的UITextView的NSLayoutManager时,我的文本出现在屏幕上,没有抛出异常.当我在我的视图控制器(下面)中将我的UITextView设置为我的NSTextStorage子类的布局管理器时,我收到了无效字形索引的异常错误.

    _textStorage = [BBRSyntaxHighlightTextStorage new]; 
    [_textStorage addLayoutManager: self.readerTextView.layoutManager];
    
    Run Code Online (Sandbox Code Playgroud)

    控制台输出如下:

    _NSLayoutTreeLineFragmentRectForGlyphAtIndex invalid glyph index 528
    2013-12-01 15:23:24.949 BibleReader[6077:70b] !!! _NSGlyphTreeInvalidateGlyphsForCharacterRange invalid char range 1
    2013-12-01 15:23:24.956 BibleReader[6077:70b] !!! _NSLayoutTreeLineFragmentRectForGlyphAtIndex invalid glyph index 528
    2013-12-01 15:23:24.957 BibleReader[6077:70b] !!! _NSGlyphTreeInvalidateGlyphsForCharacterRange invalid char range 1
    2013-12-01 15:23:24.957 BibleReader[6077:70b] !!! _NSGlyphTreeInvalidateGlyphsForCharacterRange character count mismatch
    2013-12-01 15:23:24.958 BibleReader[6077:70b] !!! _NSLayoutTreeLineFragmentRectForGlyphAtIndex invalid glyph index 4040
    2013-12-01 15:23:24.959 BibleReader[6077:70b] !!! _NSGlyphTreeInvalidateGlyphsForCharacterRange invalid char range 1
    
    Run Code Online (Sandbox Code Playgroud)

    我已多次阅读Apple的文本编程指南,并认为我理解文本系统是如何建立的,但不知道为什么我的字形数量会超过字形的数量......

    我分别在这里这里为我的viewController和NSTextStorage子类创建了gist .

    objective-c nslayoutmanager ios nstextstorage textkit

    7
    推荐指数
    1
    解决办法
    3790
    查看次数