【问题标题】:Sub-Classing NSTextStorage Causes Significant Memory Issues子类 NSTextStorage 会导致严重的内存问题
【发布时间】:2016-06-21 19:11:02
【问题描述】:

我有一个自定义的UITextView,它通过定义一个自定义的NSTextStorage 类来利用 Apple 的 TextKit,但是,当我将我的子类用于自定义文本视图的文本存储(如下所示)并尝试打开任何文件时大于 20.0KB,应用程序由于内存泄漏而崩溃:“Message from debugger: Terminated due to memory issue”。

奇怪的是,如果我用标准的NSTextStorage 替换我的自定义BMTextStorage,文本会立即加载而没有任何内存泄漏,并且使用

TextView.swift

class TextView : UITextView {

    required init(frame: CGRect) {

        // If I replace the following line with simply 
        // "let textStorage = NSTextStorage()"
        // I can open any file of any size and not have a memory leak
        // issue, using only about 20-30MB of RAM. If I ran this code
        // as is, it can open most files less than 20KB but will 
        // crash otherwise.
        let textStorage = BMTextStorage() 

        let layoutManager = NSLayoutManager()

        layoutManager.allowsNonContiguousLayout = true

        let textContainer = NSTextContainer(size: CGSizeMake(.max, .max))

        textContainer.widthTracksTextView = true
        textContainer.heightTracksTextView = true
        textContainer.exclusionPaths = [UIBezierPath(rect: CGRectMake(0.0, 0.0, 40.0, .max))]

        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)

        super.init(frame: frame, textContainer: textContainer)

        textStorage.delegate = self
        layoutManager.delegate = self

    }

}

BMTextStorage.swift

typealias PropertyList = [String : AnyObject]

class BMTextStorage : NSTextStorage {

    override var string: String {
        return storage.string
    }

    private var storage = NSMutableAttributedString()

    override func attributesAtIndex(location: Int, effectiveRange range: NSRangePointer) -> PropertyList {
        return storage.attributesAtIndex(location, effectiveRange: range)
    }

    override func replaceCharactersInRange(range: NSRange, withString str: String) {
        storage.replaceCharactersInRange(range, withString: str)
        edited([.EditedAttributes, .EditedCharacters], range: range, changeInLength: str.length - range.length)
    }

    override func setAttributes(attrs: PropertyList?, range: NSRange) {
        storage.setAttributes(attrs, range: range)
        edited([.EditedAttributes], range: range, changeInLength: 0)
    }

    override func processEditing() {
        super.processEditing()
    }

 }

【问题讨论】:

  • 你能把它缩小到你覆盖的四种方法之一吗? (并且processEditing() 可以完全删除,因为它没有任何作用。)
  • @NRitH 我无法缩小范围,因为抽象类需要重写这些方法。是的,如果我省略processEditing(),问题不会改变我想我尝试了断点,但它只是在崩溃之前永远循环,尤其是对于大文件

标签: swift uitextview textkit nstextstorage


【解决方案1】:

哇....很奇怪,当我将storage 的类型更改为NSTextStorage...时,它得到了修复。

typealias PropertyList = [String : AnyObject]

class BMTextStorage : NSTextStorage {

    overrride var string: String {
        return storage.string
    }

    private var storage = NSTextStorage()

    override func attributesAtIndex(location: Int, effectiveRange range: NSRangePointer) -> PropertyList {
        return storage.attributesAtIndex(location, effectiveRange: range)
    }

    override func replaceCharactersInRange(range: NSRange, withString str: String) {
        storage.replaceCharactersInRange(range, withString: str)
        edited([.EditedAttributes, .EditedCharacters], range: range, changeInLength: str.length - range.length)
    }

    override func setAttributes(attrs: PropertyList?, range: NSRange) {
        storage.setAttributes(attrs, range: range)
        edited([.EditedAttributes], range: range, changeInLength: 0)
    }

    override func processEditing() {
        super.processEditing()
    }

 }

【讨论】:

  • 天才之举!不过,我想知道这会打破什么样的怪异案例。你现在需要为selfstorage 打电话给beginEditing/endEditing 吗? ? 但是到目前为止内存问题已经消失了。
  • @ctietze 奇怪的是,我只给beginEditingendEditing 调用self 并且效果很好。我相信这些方法主要用于帮助应用程序管理文档状态
  • 我不禁觉得这是来自 Apple API 的大量代码气味......另外,为什么 /heck/ NSTextStorage 是一个“抽象”类,而这在 Objective- 中毫无意义 - C 是另一个很好的迹象,表明这个强大的班级背后有一些黑魔法。不过,谢谢你的提示! +1
  • 很棒的发现! 4年后​​span>
  • 知道了。在 draw 方法中调用 setApperance()。 :facepalm: 感谢您的发现,即使是在 2021 年!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多