Skip to content

Commit ff6c880

Browse files
authored
Fix crash when pasting images in post composer (#1214)
The app would crash with 'attempt to create backwards NSTextRange from 1 to 0' when pasting images into a post. This was caused by the text system trying to query text ranges while they were being modified. Fixed by: - Storing the original selected range before text storage modifications - Completing all text storage edits before updating the selection - Deferring selection updates to the next run loop cycle to avoid conflicts with the text system's internal state - Adding bounds checking to ensure valid cursor positions This prevents race conditions between our selection updates and the text system's attribute queries.
1 parent 40b6fb8 commit ff6c880

File tree

1 file changed

+18
-6
lines changed

1 file changed

+18
-6
lines changed

App/Composition/CompositionMenuTree.swift

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,18 +219,30 @@ final class CompositionMenuTree: NSObject {
219219

220220
// Directly modify the textStorage instead of setting a whole new attributedText on the UITextView, which can be slow and jumps the text view around. We'll need to post our own text changed notification too.
221221
let storage = textView.textStorage
222+
let originalSelectedRange = textView.selectedRange
222223
storage.beginEditing()
223224
storage.replaceCharacters(in: textView.selectedRange, with: string)
224225
textView.font = font
225226
textView.textColor = textColor
226-
if
227-
let selection = textView.selectedTextRange,
228-
let afterImagePosition = textView.position(from: selection.end, offset: 1)
229-
{
230-
textView.selectedTextRange = textView.textRange(from: afterImagePosition, to: afterImagePosition)
231-
}
232227
storage.endEditing()
233228

229+
// Calculate new cursor position after the inserted image
230+
let newCursorLocation = originalSelectedRange.location + string.length
231+
232+
// Defer the selection update to avoid conflicts with the text system
233+
// This prevents the crash when the system tries to query text ranges during the update
234+
DispatchQueue.main.async { [weak textView] in
235+
guard let textView = textView else { return }
236+
237+
// Ensure the new position is within valid bounds
238+
if newCursorLocation <= textView.textStorage.length {
239+
textView.selectedRange = NSRange(location: newCursorLocation, length: 0)
240+
} else {
241+
// If somehow we're beyond the text bounds, place cursor at the end
242+
textView.selectedRange = NSRange(location: textView.textStorage.length, length: 0)
243+
}
244+
}
245+
234246
NotificationCenter.default.post(name: UITextView.textDidChangeNotification, object: textView)
235247
}
236248

0 commit comments

Comments
 (0)