@jamie_sq or anyone have any thoughts regarding this issue related to NSFetch and sectionHeaders?
The code in question has worked for years but started failing on iOS 16.
After seeing this post and realizing it had something to do with section ordering and seeing that it seems to only happen on devices using foreign languages we looked more carefully at our code and realized that the nameFirstLetter method of our NSManagedObject which is the ONLY Entity in our CoreData database and which returns the string used for sectionNameKeyPath was not properly handling Unicode characters.
nameFirstLetter method simply grabs the first character of NAME field on the NSManagedObject. Name is an actual stored field and this method takes the first character and returns it. We improved this to use rangeOfComposedCharacterSequenceAtIndex. That works ok until we tried to do [str localizedUppercaseString] on it. And NOW we see exactly the crash our customers are seeing.
-(NSString *)nameFirstLetter
{
if(self.name != nil) {
return [self.name substringWithRange:[self.name rangeOfComposedCharacterSequenceAtIndex:0]];
/* The above works with the issue that sections show up for lower case letters and then again for uppercase.
As soon as we do the following the NSFetchResultController CRASHES with the _computeSectionInfo error */
return [[self.name substringWithRange:[self.name rangeOfComposedCharacterSequenceAtIndex:0]] localizedUppercaseString];
}
else
return @"?";
}
We don't understand why this should be a problem given that the NSFetchResultController is initialized to do localizedCaseInsensitiveCompare? This is how we set up the FetchControllers sorts.
-(void)initializeFetchedResultsController
{
// Already inititialized
if(_fetchedResultsController != nil) return;
// Create and configure a fetch request for Charts
NSManagedObjectContext *moc = ((iPhemerisAppDelegate *)[[UIApplication sharedApplication] delegate]).coreDataUtil.pc.viewContext;
if(!moc) {
NSLog(@"*** SavedChartView MOC NOT READY");
return;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Charts" inManagedObjectContext:moc];
[fetchRequest setEntity:entity];
// Create the sort descriptors array
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
NSSortDescriptor *chartTypeDescriptor = [[NSSortDescriptor alloc] initWithKey:@"chartType" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:nameDescriptor, chartTypeDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Create and initialize the fetch results controller.
_sectionNameKeyPath = @"nameFirstLetter";
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc sectionNameKeyPath:_sectionNameKeyPath cacheName:nil];
_fetchedResultsController.delegate = self;
}