MacCatalyst <> UITextView Crashing

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

Answered by CharlesMiller008 in 424912022

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

I think I have the same problem as you.


I have several UITextview to write and the text of several of them is used to display as attributedString in a read-only UITextView.

As you type in an UITextView it sometimes crashes apparently randomly. It does not happen with all users nor is there a way to reproduce the crash.

I am also not clear what the crash can cause because no method of my app appears in the crash log other than main.

In the iOS version this crash has never occurred and they share the same code. So I have a feeling it might be a Mac Catalyst bug.


I also use textViewDidChangeSelection to check the selectedRange.


If you want I can put my crash logs in case it helps.


Bart.

Accepted Answer

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

MacCatalyst &lt;&gt; UITextView Crashing
 
 
Q