Breaking the RTFD loading process down into subtasks is a good idea. It might 
be worth trying to sidestep the issue using NSAttributedString. You can try 
loading the data yourself as Mike suggested and then use initWithRTFD or 
initWithRTFDFileWrapper. Once you have the text in an attributed string you can 
swap its content into your NSTextView/NSTextStorage using 
-replaceCharactersInRange:withAttributedString:

However, I suspect the problem will remain. The exception is coming from 
Apple's internal NSRTFReader class, which we can be reasonably certain is 
utilized by all RTF/RTFD loading code paths. To really fix this you're probably 
going to be stuck with ugly code that either:

1. Preprocess the RTFD to remove the data that Apple's code can't handle, eg: 
strip tab stops as someone else suggested.
2. Use method swizzling to patch Apple's buggy methods at runtime, eg: replace 
-[NSRTFReader defaultParagraphStyle] to avert the conditions that lead to the 
exception, before it gets thrown in the first place.

One other potential debugging aid: NSExceptionHandler. You can register your 
own handler, perhaps in a way that prevents AppKit from killing your app 
outright when an exception occurs (this used to be possible but I don't know 
the current behavior). But as Mike said, this isn't a real solution for 
shipping software. Generally speaking once an app has thrown an exception its 
state can't be relied upon. So you should only use this for testing to gather 
additional debug information.

~Martin Wierschin

> On Mar 26, 2021, at 11:22 AM, Mike Abdullah via Cocoa-dev 
> <cocoa-dev@lists.apple.com> wrote:
> 
> This does seem quite surprising. However, here’s the thing: this code is very 
> strange approach to take.
> 
> Number 1: Cocoa doesn’t support exceptions as an error-handling mechanism 
> except where explicitly stated and supported. You’re trying to use them, 
> which is asking for trouble. The system doesn’t guarantee proper handling of 
> memory if an exception does throw.
> 
> Number 2: Your error handling approach is back-to-front. You’re trying an 
> operation, seeing if it fails, then attempting to guess from the current 
> state (which might have changed in the meantime) why it might have failed.
> 
> Instead, use the proper error APIs and approach:
> 
> 1. Load the data from disk, e.g. +[NSData 
> dataWithContentsOfURL:options:error:]
> 
> If that fails you can introspect the error to your heart’s content to find 
> out what went wrong
> 
> 2. Load the data into your text view. I’m not sure if there’s an API to do 
> that in a single step or not, dunno.
> 
> I also note that your code explicitly is trying to read an RTFD which if 
> memory serves can be a document *bundle* format, so perhaps at step 1 you’d 
> have to go with a file wrapper. But the path you specify is .rtf so I’m 
> guessing you really do have a basic file and can load it as data.
> 
> Mike.
> 
>> On 26 Mar 2021, at 11:11, Mark Allan via Cocoa-dev 
>> <cocoa-dev@lists.apple.com> wrote:
>> 
>> Hi folks,
>> 
>> Some users are reporting a crash that I can't reproduce, and in an attempt 
>> to gain additional diagnostics from a user, I wrapped the affected line in a 
>> try/catch block.  For two users it resolve the crash, but for a third, it's 
>> still crashing at the same point!
>> 
>> The crash occurs when a user attempts to open the "About" window from my 
>> app's main menu item. I'm not using the standard about panel as there's a 
>> few additional items I need to display, one of which is an NSTextView which 
>> I populate with the contents of an RTF file from within the app bundle.
>> 
>> I've symbolicated the crash log to find it's happening when populating that 
>> TextView. The line in question now reads as follows:
>> 
>>      @try {
>>              [self.aboutBox.creditsTextView readRTFDFromFile:[[NSBundle 
>> mainBundle] pathForResource:@"Credits" ofType:@"rtf"]];
>>      } @catch (NSException *exception) {
>>              NSLog(@"Error loading the contents of the text file for the 
>> About Box. %@", exception);
>>              //Check we have a file at the expected path 
>>              if([[NSFileManager defaultManager] fileExistsAtPath:[[NSBundle 
>> mainBundle] pathForResource:@"Credits" ofType:@"rtf"]]){
>>                      NSLog(@"Yes. Found the RTF credits file");
>>                      // check the attributes in case somehow there's no 
>> permission to read the file
>>                      NSDictionary *fileAttributes = [[NSFileManager 
>> defaultManager] attributesOfItemAtPath:[[NSBundle mainBundle] 
>> pathForResource:@"Credits" ofType:@"rtf"] error:nil];
>>                      NSLog(@"RTF file has following attributes %@", 
>> fileAttributes);
>>              }
>>              else {
>>                      NSLog(@"Nope, file not found");
>>              }
>>      }
>> 
>> This is the crash log from the newest build (with the try/catch around that 
>> line):
>> 
>>> Performing @selector(showAboutBox:) from sender NSMenuItem 0x600000634540
>>> *** Terminating app due to uncaught exception 'NSInvalidArgumentException', 
>>> reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
>>> terminating with uncaught exception of type NSException
>>> abort() called
>>> 
>>> Application Specific Backtrace 1:
>>> 0   CoreFoundation                      0x00007fff206ea6af 
>>> __exceptionPreprocess + 242
>>> 1   libobjc.A.dylib                     0x00007fff204223c9 
>>> objc_exception_throw + 48
>>> 2   CoreFoundation                      0x00007fff2079ea9a -[__NSCFString 
>>> characterAtIndex:].cold.1 + 0
>>> 3   CoreFoundation                      0x00007fff2079c953 -[__NSArrayM 
>>> insertObject:atIndex:].cold.2 + 0
>>> 4   CoreFoundation                      0x00007fff20610421 -[__NSArrayM 
>>> insertObject:atIndex:] + 1135
>>> 5   UIFoundation                        0x00007fff23c223ab 
>>> __defaultTabStops_block_invoke + 161
>>> 6   libdispatch.dylib                   0x00007fff203cd7c7 
>>> _dispatch_client_callout + 8
>>> 7   libdispatch.dylib                   0x00007fff203ce96b 
>>> _dispatch_once_callout + 20
>>> 8   UIFoundation                        0x00007fff23c229d7 
>>> -[NSMutableParagraphStyle setTabStops:] + 199
>>> 9   UIFoundation                        0x00007fff23c3c697 -[NSRTFReader 
>>> defaultParagraphStyle] + 75
>>> 10  UIFoundation                        0x00007fff23c3c5be -[NSRTFReader 
>>> _mutableParagraphStyle] + 112
>>> 11  UIFoundation                        0x00007fff23c36113 controlClass + 
>>> 1757
>>> 12  UIFoundation                        0x00007fff23c356b4 -[NSRTFReader 
>>> attributedString] + 76
>>> 13  UIFoundation                        0x00007fff23c311a6 
>>> _NSReadAttributedStringFromURLOrData + 3213
>>> 14  UIFoundation                        0x00007fff23d46985 
>>> -[NSAttributedString(NSAttributedStringUIFoundationAdditions) 
>>> initWithURL:options:documentAttributes:error:] + 228
>>> 15  AppKit                              0x00007fff23677d9a -[NSTextView 
>>> readRTFDFromFile:] + 126
>>> 16  MyAppHere                             0x0000000105fa18a7 MyAppHere+ 
>>> 227495
>>> 17  AppKit                              0x00007fff230af7fd 
>>> -[NSApplication(NSResponder) sendAction:to:from:] + 283
>>> 18  AppKit                              0x00007fff231b2611 -[NSMenuItem 
>>> _corePerformAction] + 413
>> 
>> 
>> Any ideas what's going on? Other than the file not being found, why else 
>> might the object at line 3 in the backtrace be nil...and more interestingly, 
>> why is the exception not being caught?
>> 
>> Thanks
>> Mark
>> _______________________________________________
>> 
>> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
>> 
>> Please do not post admin requests or moderator comments to the list.
>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>> 
>> Help/Unsubscribe/Update your Subscription:
>> https://lists.apple.com/mailman/options/cocoa-dev/mabdullah%40karelia.com
>> 
>> This email sent to mabdul...@karelia.com
> 
> _______________________________________________
> 
> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
> 
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
> 
> Help/Unsubscribe/Update your Subscription:
> https://lists.apple.com/mailman/options/cocoa-dev/martin%40nisus.com
> 
> This email sent to mar...@nisus.com

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to