Hi there -
When typing inside of a UITextView (editing is allowed, using NSAttritbuedString), occasionally my application will crash. The following crash thread is below.
What I gather is that the Application is losing a ram allocation, but I can't tell if it is to my actual textView or if it loses an allocation of the TextStorage string, or something else entirely. I bolded the items I view as significant, but I'm not sure as to how to better debug this issue.
For clarity, I run a check* on textViewDidChangeSelection and textView shouldChangeTextIn to make sure the NSAttributedSTring defaultAttributes will be correct on the next keystroke (tangent: why btw the textview clears defaultAttributes after every keystroke is curious to me).
*the check is a function to get the most recent character behind the current selection, pull the attributes from that range, then enforce that textView will keep those attributes when the next keystroke comes into the system.
Does anyone know how to better troubleshoot this issue? Am I even looking in the right place?
Thank you for your help and time -
Charlie
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00001c20beedec58
Exception Note: EXC_CORPSE_NOTIFY
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [56227]
VM Regions Near 0x1c20beedec58:
CoreAnimation 0000000120d2d000-0000000120d4d000 [ 128K] rw-/rwx SM=PRV
-->
MALLOC_NANO 0000600000000000-0000600008000000 [128.0M] rw-/rwx SM=PRV
Application Specific Information:
objc_msgSend() selector name: getBytes:maxLength:usedLength:encoding:options:range:remainingRange:
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff67e5a81d objc_msgSend + 29
1 com.apple.CoreFoundation 0x00007fff2ec29bf9 CFStringGetBytes + 753
2 com.apple.CoreFoundation 0x00007fff2ec7ffa2 __CFStringCheckAndReplace + 391
3 com.apple.CoreFoundation 0x00007fff2ec7fdf7 -[__NSCFString appendString:] + 40
4 com.apple.AppKit 0x00007fff2c8d7ee9 -[NSTextInputContext(NSTextInputContext_RemoteTextInput_UIKitOnMac) attributedString_RTI] + 330
5 com.apple.AppKit 0x00007fff2c8d55a5 -[NSTextInputContext(NSInputContext_WithCompletion) attributedStringWithCompletionHandler:] + 50
6 com.apple.AppKit 0x00007fff2c8d48fa -[NSTextInputContext attributedString] + 146
7 com.apple.AppKit 0x00007fff2c62a17f -[NSBridgedTextCorrectionController annotatedSubstringForProposedRange:actualRange:] + 71
8 com.apple.AppKit 0x00007fff2c0efa1a -[NSTextCheckingController annotatedSubstringForProposedRange:wrap:completionHandler:failureHandler:] + 445
9 com.apple.AppKit 0x00007fff2c0ef856 -[NSTextCheckingController annotatedSubstringForProposedRange:completionHandler:] + 84
10 com.apple.AppKit 0x00007fff2c0ef7f7 -[NSTextCheckingController _markUncheckedAfterMovementFromRange:] + 116
11 com.apple.AppKit 0x00007fff2c0ef74e -[NSTextCheckingController didChangeSelectionFromRange:] + 102
12 com.apple.AppKit 0x00007fff2c629789 -[NSBridgedTextCorrectionController observeValueForKeyPath:ofObject:change:context:] + 318
13 com.apple.Foundation 0x00007fff313ac470 NSKeyValueNotifyObserver + 335
14 com.apple.Foundation 0x00007fff3149b72c NSKeyValueDidChange + 437
15 com.apple.Foundation 0x00007fff3139f1bc -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 741
16 com.apple.Foundation 0x00007fff313c9e65 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 68
17 com.apple.Foundation 0x00007fff3153903e _NSSetRangeValueAndNotify + 295
18 com.apple.AppKit 0x00007fff2c8d9b2f __90-[__NSTextInputContextRTISystemDelegate inputSystemService:inputSessionDocumentDidChange:]_block_invoke + 261
19 com.apple.AppKit 0x00007fff2c8da306 ___NSMainRunLoopPerformBlockInModes_block_invoke + 25
20 com.apple.CoreFoundation 0x00007fff2ec9da7c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
21 com.apple.CoreFoundation 0x00007fff2ec9d9c4 __CFRunLoopDoBlocks + 379
22 com.apple.CoreFoundation 0x00007fff2ec9cebd __CFRunLoopRun + 2450
23 com.apple.CoreFoundation 0x00007fff2ec9bece CFRunLoopRunSpecific + 462
24 com.apple.HIToolbox 0x00007fff2d8caabd RunCurrentEventLoopInMode + 292
25 com.apple.HIToolbox 0x00007fff2d8ca6f4 ReceiveNextEventCommon + 359
26 com.apple.HIToolbox 0x00007fff2d8ca579 _BlockUntilNextEventMatchingListInModeWithFilter + 64
27 com.apple.AppKit 0x00007fff2bf25829 _DPSNextEvent + 883
28 com.apple.AppKit 0x00007fff2bf24070 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1352
29 com.apple.AppKit 0x00007fff2bf15d7e -[NSApplication run] + 658
30 com.apple.AppKit 0x00007fff2bee7b86 NSApplicationMain + 777
31 com.apple.AppKit 0x00007fff2c209615 _NSApplicationMainWithInfoDictionary + 16
32 com.apple.UIKitMacHelper 0x00007fff60269e00 UINSApplicationMain + 322
33 com.apple.UIKitCore 0x00007fff6fa3c22f UIApplicationMain + 2130
34 maccatalyst.com.alpha.XXXXXXX 0x000000010ef435ca 0x10ef3e000 + 21962
Hi Bart / Tomeu -
I owe the community an update, and I hope this helps you, too.
TLDR; preliminary findings: watch where and how you call on defaultAttributes (and any other properties) of your UITextView. Developing on newer hardware offers affordances older hardware does not.
Background: my problem user runs a 2014 MacbookPro. He would report seemingly random crashes anywhere between 30-45 mins of use, with crash intervals exponentially decreasing after the first crash, limiting out around 3-5mins (i.e. first at 45mins, next at 15mins, then every 3-5 mins a crash.)
I refactored my 'typingAttributes retention' methods; it appears the solution has worked. ~5days of no crashing.
Here was the problem code (I'm a newb, as you can tell):
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool
if textView.selectedRange.location > 1 && textView.attributedText.length >= 2 && appeared {//viewDidAppear Bool
pullSetDefaults(at: self.selectedRange.location - 1)
}
//otherstuff//return blah
}
Where pullSetDefaults:
func pullSetDefaults(at: Int) {
if !(at < self.attributedText.length) {return}
var defaultsAtts = self.attributedText.attributes(at: at, effectiveRange: nil)
referenceToTextView.typingAttributes = defaultsAtts
}
Well... I'm frankly dumbfounded at my idiocy. It turns out the problem was separating the textView object/references across methods, to my credit: still in the same class though. On my newer MacBook Pro, I never experienced the crashes, but I presume on older computers the calls overlap, causing a bad address error.
New code that doesn't crash:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if textView.selectedRange.location > 1 && textView.attributedText.length >= 2 && appeared {
textView.typingAttributes = currentAttributes //(a variable computed elsewhere, still probably a bad idea)
}
//otherstuff//return blah
}
I'm not brave enough to try to run the typingAttributes retention in the shouldChangeText in yet, but I imagine that would help, too, since the call to the textview isn't split across methods.
Hope this helps! Cheers,
Charlie