4

I have recently released an update to my app in the App Store. The testing brought no crashes but I noticed when it was released in the App Store, that one scenario crashed my app on my 5s. This scenario was not crashing during development. I have received a report from a user saying it also crashed in one scenario on their 5s, which is the same as what I was doing.

I'm at an intermediate stage of iOS development and this is my first experience with diagnosing a crash report.

Update: Please scroll to the bottom of the questions for further updates on the issues

Within Xcode, I have the following crash report for my app on my 5s:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000060
Triggered by Thread:  0

Thread 0 Crashed:
0   CoreData                        0x00000001822f8af4 _propertyAtIndexForEntityDescription + 24
1   CoreData                        0x00000001822f0330 snapshot_get_value_as_object + 304
2   Foundation                      0x0000000183080a78 -[NSObject(NSKeyValueCoding) valueForKeyPath:] + 288
3   Foundation                      0x00000001831613cc -[NSSortDescriptor compareObject:toObject:] + 140
4   CoreData                        0x0000000182305d9c +[NSFetchedResultsController(PrivateMethods) _insertIndexForObject:inArray:lowIdx:highIdx:sortDescriptors:] + 284
5   CoreData                        0x00000001823dd808 -[NSFetchedResultsController(PrivateMethods) _createNewSectionForObject:] + 492
6   CoreData                        0x0000000182305b58 -[NSFetchedResultsController(PrivateMethods) _postprocessInsertedObjects:] + 528
7   CoreData                        0x00000001823025f8 -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 2036
8   CoreFoundation                  0x000000018259b760 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 16
9   CoreFoundation                  0x00000001824e82b0 _CFXNotificationPost + 2060
10  Foundation                      0x000000018307a744 -[NSNotificationCenter postNotificationName:object:userInfo:] + 68
11  CoreData                        0x0000000182301dd8 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 84
12  CoreData                        0x0000000182301d58 -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] + 360
13  CoreData                        0x0000000182300348 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2224
14  CoreData                        0x00000001822ff264 -[NSManagedObjectContext save:] + 152
15  Lopey                       0x000000010004da3c -[LopeyAddEntryViewController save:] (LopeyAddEntryViewController.m:828)
16  UIKit                           0x00000001855e50ac -[UIApplication sendAction:to:from:forEvent:] + 96
17  UIKit                           0x00000001855e50ac -[UIApplication sendAction:to:from:forEvent:] + 96
18  UIKit                           0x00000001855e5040 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 20
19  UIKit                           0x00000001855ce51c -[UIControl _sendActionsForEvents:withEvent:] + 372
20  UIKit                           0x00000001855e4a40 -[UIControl touchesEnded:withEvent:] + 580
21  UIKit                           0x00000001855e46d4 -[UIWindow _sendTouchesForEvent:] + 688
22  UIKit                           0x00000001855df36c -[UIWindow sendEvent:] + 1168
23  UIKit                           0x00000001855b0b4c -[UIApplication sendEvent:] + 252
24  UIKit                           0x00000001855aec3c _UIApplicationHandleEventQueue + 8496
25  CoreFoundation                  0x00000001825a77f0 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 20
26  CoreFoundation                  0x00000001825a6b4c __CFRunLoopDoSources0 + 252
27  CoreFoundation                  0x00000001825a4de4 __CFRunLoopRun + 628
28  CoreFoundation                  0x00000001824e5dcc CFRunLoopRunSpecific + 448
29  GraphicsServices                0x00000001881cdc08 GSEventRunModal + 164
30  UIKit                           0x0000000185616fc0 UIApplicationMain + 1152
31  Lopey                       0x000000010005a40c main (main.m:16)
32  libdyld.dylib                   0x000000018f0e3a9c start + 0

I also have a bit further down:

Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x0000000000000000   x2: 0x0000000000000000   x3: 0x0000000000000000
    x4: 0x0000000000000001   x5: 0x0000000000000074   x6: 0x0000000000000074   x7: 0x0000000000000000
    x8: 0x0000000000000060   x9: 0x0000000000000020  x10: 0x0000000100124540  x11: 0x000000100000001f
   x12: 0x00000001001245a0  x13: 0x0000000178242d60  x14: 0x0000000000000034  x15: 0x0000000004060401
   x16: 0x000000018a1c96e6  x17: 0x000000018234e2d4  x18: 0x0000000000000000  x19: 0x0000000000000000
   x20: 0x000000017043b580  x21: 0x0000000000000011  x22: 0x000000017043c1e0  x23: 0x0000000000000006
   x24: 0x000000018265d35b  x25: 0x000000018f715000  x26: 0x000000018f715000  x27: 0x0000000000000002
   x28: 0x00000001780dbd60  fp: 0x000000016fdfc850   lr: 0x00000001822f0334
    sp: 0x000000016fdfc840   pc: 0x00000001822f8af4 cpsr: 0x60000000

As can be seen in the logs, I am using Core Data with NSFetchedResultsController. I have a UITableViewController that gets populated as a result of the user clicking a button in the UINavigationBar, adding some entries into a a few UITextFields and pressing "Save". That is the point it crashed. However, I have to mention that it doesn't crash every time. In fact, before the crash, I had added in 45 entries consecutively and after it, I added in 100 with no crashes. It has only happened once.

The point in the app where it is crashing is when I press Save (which will dismiss the ViewController and return back to the UITableView. With this in mind, it is either the actual "saving" of the NSManagedObjectContext, or it's the loading of the UITableView. My money is on the former but I'm not really sure.

Here's my code for the NSManagedObjectContext in the App Delegate:

- (NSManagedObjectContext *)managedObjectContext
{
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

    if (coordinator != nil) {
        NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        moc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;

        [moc setPersistentStoreCoordinator: coordinator];

        _managedObjectContext = moc;
    }

    return _managedObjectContext;
}

Here's my Save method in the App Delegate:

- (void)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            //NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}

As mentioned, I'm fairly new to development and this is the first time I've seen a crash log that needs investigating. Any direction in this would really be appreciated. Is it also something relating to the 64-bit processor in the 5s? (Perhaps this would explain why I can't reproduce it elsewhere?).

Update 1

My app is iOS 7 only. My 5s is only iOS 7 and I've tested my app on iOS 8 but on a 4s and experienced no similar crashes. Also, I've tested on an iPad Mini as well, so this is an iPhone 5s only issue.

Update 2

Showing the code that saves the new objects below. It may look complicated but essentially the name, event, etc is based on auto-completion which is based on which objects are already in Core Data, etc.

- (IBAction)save:(id)sender
{
    NSManagedObjectContext *context = [self managedObjectContext];

    // Insert a new transaction
    Transaction *transaction = [NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:context];
    Item *itemType = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:context];

    itemType.amount = self.itemTextField.text;
    transaction.item = itemType;
    transaction.wasReceived = @(self.isReceivedSegment.selectedSegmentIndex == 0);

    Person *enteredPerson = (Person *)[Person personWithName:self.nameTextField.text inManagedObjectContext:context];
    transaction.whoBy = enteredPerson;

    Occasion *enteredOccasion = (Occasion *)[Occasion occasionWithTitle:self.occasionTextField.text inManagedObjectContext:context];
    transaction.occasion = enteredOccasion;

    Subevent *enteredSubevent = (Subevent *)[Subevent subeventWithTitle:self.subeventTextField.text inManagedObjectContext:context];
    transaction.subevent = enteredSubevent;

    NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *components = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
                                          fromDate:self.datePicker.date];
    [components setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
    NSDate *selectedDate = [cal dateFromComponents:components];

    Date *date = (Date *)[Date occasionWithDate:selectedDate inManagedObjectContext:context];
    transaction.dates = date;

    NSError *error = nil;
    if (![context save:&error])
    {
        // Error
    }

    [self dismissViewControllerAnimated:YES completion:nil];
}

Within the UITableViewController, my fetchedResultsController is below:

- (NSFetchedResultsController *)fetchedResultsController
{
    NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
    if (_fetchedResultsController != nil)
    {
        return _fetchedResultsController;
    }
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Transaction" inManagedObjectContext:managedObjectContext];
    fetchRequest.entity = entity;

    // I am implementing a search here so we can either search by name or event with the prediate filtering out the information.
    if ([self.timelineSearchBar.text length] > 0) {
        NSPredicate *predName = [NSPredicate predicateWithFormat:@"whoBy.name CONTAINS[c] %@", self.timelineSearchBar.text];
        NSPredicate *predOccasion = [NSPredicate predicateWithFormat:@"occasion.title CONTAINS[c] %@", self.timelineSearchBar.text];

        // Adding in another predicate for searching by subevent
        NSPredicate *predSubOccasion = [NSPredicate predicateWithFormat:@"subevent.title CONTAINS[c] %@", self.timelineSearchBar.text];

        // creating the orCompoundPredicate for the two conditions
        NSPredicate *compPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predName, predOccasion, predSubOccasion]];

        [fetchRequest setPredicate:compPredicate];
    }
    // Sorting by date and by name.
    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"dates.dateOfEvent" ascending:NO];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"whoBy.name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];

    fetchRequest.sortDescriptors = @[sort, sortDescriptor];

    fetchRequest.fetchBatchSize = 20;
    NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"sectionDateFormatter" cacheName:nil];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;
    return _fetchedResultsController;
}

Hope this is helpful!

Update 3

I wanted to try reproduce the issue. The steps to reproduce the first time involved updating from a previous version of the app. I had the App store version on my device before the update, and when the update was released, I updated to that, created a new entry and that's the point it crashed. I ran the old version of my app, and upgraded to this new version in Xcode and when the app was upgraded and ready to go, I added a new entry and with an Exception Breakpoint, it crashed at transaction.dates = date; in the Save method listed above, in update 2. The breakpoint was reporting: Thread 1: EXC_BAD_ACCESS (code=1,address=0x60).

I performed the steps again, without the breakpoint and it stopped at the same line of code with the same error.

Update 4

This crash only occurs if I update my app to the latest version and add a new entry straight away. If however I re-run the app before adding a new entry, the device doesn't crash.

Update 5

With some further testing, I have discovered that this crash is as a result of updating to this new version on an iPhone 5s and an iPad Air only. The app doesn't crash on any other device. With this latest version of the app, I have brought iCloud synchronisations. In the App Delegate, I have the code below which will get run when the user chooses to select to use iCloud in the tutorial of the update. It is with this scenario that the app crashes.

- (void)initialMigrationOfLocalDataToiCloud
{    
    NSURL *storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL];

    NSPersistentStore *currentStore = self.persistentStoreCoordinator.persistentStores.lastObject;

    NSURL *cloudURL = [self grabCloudPath:@"CloudLogs"];
    NSString *cloudStoreTitle = @"LopeyCloud";

    NSDictionary *options = @{NSPersistentStoreUbiquitousContentURLKey: cloudURL,
                              NSPersistentStoreUbiquitousContentNameKey: cloudStoreTitle,                               NSMigratePersistentStoresAutomaticallyOption : @YES,
                              NSInferMappingModelAutomaticallyOption : @YES};

    [self.persistentStoreCoordinator migratePersistentStore:currentStore toURL:storeURL options:options withType:NSSQLiteStoreType error:nil];

}

I have the lightweight migration there because the user may be updating from a previous version, etc.

With an exception breakpoint set (and even without it), the app will crash at the transaction.dates = date; code in the save method, as per Update 2. I'm not allowed to jump out of the code or do anything with this. Walking through the debugger, I can't see what the value of transaction.dates is, but date is not nil. Even if I don't set a breakpoint, the app will crash at the same line of code here.

I hope this makes sense.

amitsbajaj
  • 1,304
  • 1
  • 24
  • 59
  • Looks like the NSFetchedResultsController tries to sort the inserted objects, but crashes while trying to access one of the object's properties. Can you show us the code in which you insert new objects, and also how do you set up sort descriptors for the fetch request? The way you set up and save `managedObjectContext` is pretty standard and I don't think it causes the issue. – Michał Ciuba Sep 02 '14 at 14:53
  • Thanks so much for the response Michal - I appreciate that and I have updated the question at the end with the save method and with the fetchRequest - hope it makes sense - I'm happy to provide any further required information – amitsbajaj Sep 02 '14 at 15:02
  • I've just updated my question with Update 3 - where I'm able to reproduce the issue.. but lost on what the issue is – amitsbajaj Sep 02 '14 at 15:46
  • Did the model change during the update? Was a migration performed? – quellish Sep 02 '14 at 20:38
  • Thanks @quellish - appreciate the response - a migration wasn't performed during this particular upgrade with no model change, but an older version did perform a model change and migration before this - two versions ago.. however the transaction.dates = date wasn't part of the attributes that were changed - this is a great point though - interestingly, the crash ONLY occurs if I add an entry right after updating the app. However, if I update the app, close it and run it again and add an entry, it doesn't crash.. – amitsbajaj Sep 02 '14 at 20:45
  • Can you set an exception breakpoint in your project, install the old app store version, then run your latest code through the debugger on xcode to see what line it crashes on and what the various values are? – Bek Sep 02 '14 at 22:24
  • Thanks @Bek - I have updated the question and the Updates at the bottom reflect the information of which line it crashes on, with which message and also the situations in the Update 5. I really hope this makes sense – amitsbajaj Sep 03 '14 at 11:38
  • Can you confirm that date is actually an NSDate object and not some other type? To see if it's an issue with the iCloud migration, comment out that code and then repeat the same process. I hope you are able to resolve the issue. – Bek Sep 03 '14 at 12:16
  • Thank you @Bek and me too, I really hope to be able to solve this. I can confirm that date is indeed an NSDate. Also, with choosing not to use iCloud (so the method in Update 5 doesn't get called), I experience no crashes at all. What's really bizarre is that I experience no crashes if I just run the app again and then add an entry. So confused as to what's going on! – amitsbajaj Sep 03 '14 at 13:18
  • @Lavanya managed to figure it out? – Devfly Apr 13 '15 at 11:14

0 Answers0