2016-06-21 8 views
3

NSTextStorage 클래스를 정의하여 Apple의 TextKit을 사용하는 사용자 정의 UITextView이 있지만, 사용자 정의 텍스트보기, 텍스트 저장소 (아래 구현 됨) 및 서브 클래스를 사용할 때 20.0KB보다 큰 파일을 열어보십시오. 응용 프로그램이 메모리 누수로 인해 충돌합니다 : "Message from debugger: Terminated due to memory issue".하위 클래스 NSTextStorage로 인해 심각한 메모리 문제가 발생합니다.

이상하게도 사용자 정의 BMTextStorage을 표준 크기 인 NSTextStorage으로 바꾸면 메모리 누수없이 즉시 텍스트가로드되고 < RAM이 30MB 사용됩니다. 이 원인은 무엇입니까?

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() 
    } 

} 
+0

재정의 한 네 가지 방법 중 하나로 좁힐 수 있습니까? (그리고'processEditing()'은 아무 것도하지 않기 때문에 모두 삭제할 수 있습니다.) – NRitH

+0

@NRitH 추상 클래스에 의해 오버라이드 (override) 될 필요가 있기 때문에 쉽게 범위를 좁힐 수 없습니다. 그리고 네,'processEditing()'을 생략하면 문제가 변하지 않습니다. 제가 생각한 중단 점을 시도했지만, 큰 파일의 경우 특히 충돌하기 전에 영원히 반복됩니다. –

답변

3

와우 .... 내가 NSTextStoragestorage의 유형을 변경 한 때 고정있어, 이상한 ...

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() 
    } 

} 
+1

천재 이동! 그래도이 괴물이 무슨 일이 일어날 지 궁금해. 그리고'self'와'storage' 둘 다'beginEditing' /'endEditing'을 호출해야합니까? 그러나 메모리 문제는 지금까지 사라졌습니다. – ctietze

+1

@ctietze 이상하게도,'beginEditing'과'endEditing' 만'self'를 호출하고 괜찮습니다. 그 방법은 주로 응용 프로그램이 문서 상태를 관리하는 데 도움이된다고 생각합니다. –

+0

Apple의 API에서 거대한 코드 냄새가 나는 것 같은 느낌이 들지만 .../heck/NSTextStorage가 "추상"클래스 인 이유는 무엇입니까? Objective-C에서 아무런 의미가없는 것은이 강력한 클래스 뒤에 검은 마법이 있다는 또 다른 훌륭한 징조입니다. 팁 (팁)에 감사드립니다! +1 –