2016-01-10 54 views
7

我正在寫Swift中的iOS 9應用程序。我有一個託管UITextView的視圖控制器,我正在爲它分配一個自定義的NSTextStorage對象。 NSTextStorage現在只是基本的。一切工作正常和文本的UITextView中顯示出來,但是當我點擊的文字進行編輯,應用程序崩潰,但以下情況除外:iOS:UITextView與自定義NSTextStorage崩潰

2016-01-10 11:24:32.931 PagesWriter[23750:6939530] requesting caretRectForPosition: with a position beyond the NSTextStorage (529) 
2016-01-10 11:24:33.040 PagesWriter[23750:6939530] requesting caretRectForPosition: with a position beyond the NSTextStorage (529) 
2016-01-10 11:24:33.168 PagesWriter[23750:6939530] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSCFString _getBlockStart:end:contentsEnd:forRange:stopAtLineSeparators:]: Range {529, 0} out of bounds; string length 245' 
*** First throw call stack: 
(0x181ea5900 0x181513f80 0x181ea5848 0x18278a02c 0x1827e963c 0x186cc6124 0x186b1c818 0x186cc5fbc 0x186d59e68 0x186bdeb60 0x186bde454 0x186fac1f8 0x187501f64 0x186bc2e84 0x186bc4f40 0x186fa65ac 0x186faea5c 0x186bc5c18 0x186bbf1f8 0x186bbed2c 0x186c2047c 0x186c20828 0x186d5811c 0x186d57f94 0x186d57448 0x187118dbc 0x186d3c5b8 0x186bca9b0 0x18711a3bc 0x186b89b58 0x186b868dc 0x186bc8820 0x186bc7e1c 0x186b984cc 0x186b96794 0x181e5cefc 0x181e5c990 0x181e5a690 0x181d89680 0x183298088 0x186c00d90 0x1000615ec 0x18192a8b8) 
libc++abi.dylib: terminating with uncaught exception of type NSException 

如果我從UITextView中刪除我的自定義NSTextStorage對象,它作品。

我的視圖控制器在故事板中使用模態segue加載。我加載文本內容和配置的UITextView和NSTextStorage對象viewDidLoad方法:

class TextEditorViewController: UIViewController { 
    @IBOutlet weak var textView: UITextView! 

    // Set by parent view controller during transition 
    var URL: NSURL? 

    var textStorage: NSTextStorage? 

    override func viewDidLoad() { 
    super.viewDidLoad() 

    textStorage = CustomTextStorage() 
    textView.textStorage.removeLayoutManager(textView.layoutManager) 
    textStorage!.addLayoutManager(textView.layoutManager) 
    dispatch_async(UtilityQueue) { 
     do { 
     let text = try NSString(contentsOfURL: self.URL!, encoding: NSUTF8StringEncoding) 
     dispatch_async(MainQueue) { 
      self.textStorage!.replaceCharactersInRange(NSRange(location: 0, length: 0), withString: text as String) 
     } 
     } catch { /* handle error */ } 
    } 
    } 
} 

UtilityQueueMainQueue是保存到相應的調度隊列的引用幫手內容。

我定製NSTextStorage類看起來是這樣的:

class CustomTextStorage: NSTextStorage { 
    let backingStore = NSMutableAttributedString() 

    override var string: String { 
    return backingStore.string 
    } 

    override func attributedAtIndex(location: Int, effectiveRange range: NSRangePointer) -> [String: AnyObject] { 
    return backingStore.attributesAtIndex(location, effectiveRange: range) 
    } 

    override func replaceCharactersInRange(range: NSRange, withString str: String) { 
    backingStore.replaceCharactersInRange(range, withString: str) 
    edited(.EditedCharacters, range: range, changeInLength: str.characters.count - range.length) 
    } 

    override func setAttributes(attires: [String: AnyObject]?, range: NSRange) { 
    backingStore.setAttributes(attires, range: range) 
    edited(.EditedAttributes, range: range, changeInLength: 0) 
    } 

    override func processEditing() { 
    /* Placeholder; will be adding code here in the future. */ 
    super.processEditing() 
    } 
} 

任何想法?預先感謝您的幫助。

+0

我在Mac應用程序看到一個非常類似的錯誤。我有一個預感,這與Swift有關。你有沒有找到根本原因? –

+1

我已確認在swift中編寫的NSTextStorage子類將顯示此問題。 Objective-C中的相同實現完美地工作。我在https://bugreport.apple.com/上提交了一個蘋果雷達,你也應該這樣做。 –

+0

謝謝@ChristianNiles。我沒有找到解決辦法。我剛剛創建並初始化UITextView以編碼並將其從故事板場景中移出。 –

回答

-1

你必須以其他方式擁有你的客戶存儲。你可以嘗試

+0

歡迎來到stackoverflow!請使用下面的評論框,一旦你有足夠的聲譽,你將能夠評論任何帖子。 :) –

0

我不知道它是否仍然相關,但你幾乎是正確的。

您需要分別撥打beginEditing()endEditing()

將字符串轉換爲NSString用於編輯回調的長度計算(否則表情符號和其他一些情況將無法正常工作)。

由於性能問題,請使用NSTextStorage作爲backingStore。

你會得到這樣的事情:

final class ExampleStorage : NSTextStorage { 

    private let container = NSTextStorage() 

    override var string: String { 
     return container.string 
    } 

    override func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedStringKey : Any] { 
     return container.attributes(at: location, effectiveRange: range) 
    } 

    override func replaceCharacters(in range: NSRange, with str: String) { 
     beginEditing() 
     container.replaceCharacters(in: range, with: str) 
     edited([.editedAttributes, .editedCharacters], range: range, changeInLength: (str as NSString).length - range.length) 
     endEditing() 
    } 

    override func setAttributes(_ attrs: [NSAttributedStringKey : Any]?, range: NSRange) { 
     beginEditing() 
     container.setAttributes(attrs, range: range) 
     edited([.editedAttributes], range: range, changeInLength: 0) 
     endEditing() 
    } 
} 
+0

您能否澄清爲什麼您應該使用NSTextStorage作爲後備存儲?性能問題是什麼? –

+0

我沒有做一些具體的調查。在我一兩年前在iOS上豐富的編輯器實現經驗之後,這是一種神的感覺。你也可以用NSMutableAttributedString找到一些[與內存相關的問題](https://stackoverflow.com/a/37953430/588673) –

相關問題