12

My iOS application just crashed with a NSRangeException on -[NSManagedObjectContext save:]. Nothing else helpful anywhere to be found. How am I supposed to fix this? I don't get any memory address or anything that I can work with...

2015-04-22 14:16:38.078 heavenhelp[33559:1734247] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 6 beyond bounds [0 .. 5]'
*** First throw call stack:
(
    0   CoreFoundation                      0x0167f746 __exceptionPreprocess + 182
    1   libobjc.A.dylib                     0x00f40a97 objc_exception_throw + 44
    2   CoreFoundation                      0x01553b73 -[__NSArrayM objectAtIndex:] + 243
    3   CoreData                            0x00859cf3 -[NSSQLCore recordToManyChangesForObject:inRow:usingTimestamp:inserted:] + 2531
    4   CoreData                            0x00856a0b -[NSSQLCore _populateRow:fromObject:timestamp:inserted:] + 2923
    5   CoreData                            0x00776e24 -[NSSQLCore prepareForSave:] + 1764
    6   CoreData                            0x00775e3d -[NSSQLCore saveChanges:] + 461
    7   CoreData                            0x0073f15e -[NSSQLCore executeRequest:withContext:error:] + 638
    8   CoreData                            0x0083ee75 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 5349
    9   CoreData                            0x008492ff gutsOfBlockToNSPersistentStoreCoordinatorPerform + 191
    10  libdispatch.dylib                   0x035f4bef _dispatch_client_callout + 14
    11  libdispatch.dylib                   0x035d7b0d _dispatch_barrier_sync_f_invoke + 144
    12  libdispatch.dylib                   0x035d723f dispatch_barrier_sync_f + 105
    13  CoreData                            0x008383f7 _perform + 183
    14  CoreData                            0x0073ec8b -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 459
    15  CoreData                            0x0076ee09 -[NSManagedObjectContext save:] + 1529
    16  heavenhelp                          0x000b6834 _TF10heavenhelp11saveContextFT_T_ + 324
    17  heavenhelp                          0x0015368d _TFC10heavenhelp26ConversationViewController17viewWillDisappearfS0_FSbT_ + 701
    18  heavenhelp                          0x001536ef _TToFC10heavenhelp26ConversationViewController17viewWillDisappearfS0_FSbT_ + 63
    19  UIKit                               0x020a4292 -[UIViewController _setViewAppearState:isAnimating:] + 706
    20  UIKit                               0x020a4904 -[UIViewController __viewWillDisappear:] + 106
    21  UIKit                               0x020bcd1d -[UIViewController(UIContainerViewControllerProtectedMethods) beginAppearanceTransition:animated:] + 200
    22  UIKit                               0x020cafec -[UINavigationController _startCustomTransition:] + 1028
    23  UIKit                               0x020d8e00 -[UINavigationController _startDeferredTransitionIfNeeded:] + 712
    24  UIKit                               0x020d9a51 -[UINavigationController __viewWillLayoutSubviews] + 57
    25  UIKit                               0x02253750 -[UILayoutContainerView layoutSubviews] + 213
    26  UIKit                               0x01fce57a -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 668
    27  libobjc.A.dylib                     0x00f56771 -[NSObject performSelector:withObject:] + 70
    28  QuartzCore                          0x01d5ee47 -[CALayer layoutSublayers] + 144
    29  QuartzCore                          0x01d52925 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 403
    30  QuartzCore                          0x01d5277a _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
    31  QuartzCore                          0x01caec52 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 284
    32  QuartzCore                          0x01cb00e5 _ZN2CA11Transaction6commitEv + 487
    33  QuartzCore                          0x01cb07fc _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
    34  CoreFoundation                      0x015a086e __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
    35  CoreFoundation                      0x015a07b0 __CFRunLoopDoObservers + 400
    36  CoreFoundation                      0x015961ea __CFRunLoopRun + 1226
    37  CoreFoundation                      0x01595a5b CFRunLoopRunSpecific + 443
    38  CoreFoundation                      0x0159588b CFRunLoopRunInMode + 123
    39  GraphicsServices                    0x046cc2c9 GSEventRunModal + 192
    40  GraphicsServices                    0x046cc106 GSEventRun + 104
    41  UIKit                               0x01f3b106 UIApplicationMain + 1526
    42  heavenhelp                          0x000a5c94 main + 180
    43  libdyld.dylib                       0x0361fac9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

This is the code I used to make my save: thread-safe:

static var onceToken: dispatch_once_t = 0
static var singleton: CoreDataHelper!
static var sharedInstance: CoreDataHelper {
    get {
        dispatch_once(&onceToken, {
            self.singleton = CoreDataHelper()
        })
        return singleton
    }
}

My xcdatamodeld (the relevant part):

xcdatamodeld

Edits: I have edited the code to reflect my changes to make my NSManagedObjectContext thread-safe. Everything I do now, I do on one instance of my CoreDataHelper that I initialise as above. I have found I can trigger a crash by going into one conversation, adding a message, going into another conversation and adding a message there. I have added my xcdatamodeld.

Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
vrwim
  • 13,020
  • 13
  • 63
  • 118
  • does it also happen within the simulator ? Error message will probably be more explicit there – vib Apr 22 '15 at 09:56
  • 1
    "index 6 beyond bounds [0 .. 5] " This means you are trying to access 7th object from array that is having 6 objects only. And add an exceptional break point, it will show you directly whats that line. – user4261201 Apr 22 '15 at 09:58
  • @Nandu, the 7th object in an array of 6 objects. – vikingosegundo Apr 22 '15 at 09:59
  • @vib I can't reproduce the erorr right now, I'll see what that breakpoint says when I can reproduce (I hope I can, otherwise this bug might remain in the release version) – vrwim Apr 22 '15 at 10:00
  • @Nandu Adding an exception breakpoint shows that the error occurs in `[NSManagedObjectContext save:]`... What do I do now? – vrwim Apr 22 '15 at 12:07
  • I have quite a lot of callbacks in `dataTaskWithRequest()`. I fetch conversations and then I fetch the messages for each conversation, which I do by fetching the messages in the callback of the conversation request. All callbacks are wrapped in async dispatches, so that I can do GUI stuff. Anyone that can shed any light? I'm guessing there's a problem with accessing `NSManagedObject`s in these async callbacks? – vrwim Apr 27 '15 at 07:37
  • 1
    This smells like a threading issue to me. NSManagedObjects are not thread safe. You must access one in the same thread from which it was created. I know you said you made the save method thread safe, but I'll bet you are accessing the NSManagedObject context from more than one thread. The simplest solution may be to create a singleton object and have it do all the work for you. Then just access that singleton when you need to from any thread. – Victor Engel Apr 28 '15 at 16:15
  • @VictorEngel Could you post an answer with how I can make this singleton work on one thread? I'll try it out then – vrwim Apr 28 '15 at 16:52
  • There are several ways to make a singleton. There is an example at http://stackoverflow.com/questions/7568935/how-do-i-implement-an-objective-c-singleton-that-is-compatible-with-arc that is pretty straightforward. Just use that +sharedInstance method to get your object and send that object whatever method calls you want. Since it's a singleton, it will automatically perform those methods on the same thread. – Victor Engel Apr 28 '15 at 17:35
  • @VictorEngel I have created the singleton instance, and have added the code with what I did. You mentioned that one should access the `NSManagedObject` from one thread only. Does it matter that I access it async on the main thread? The app still crashes for some crazy reason. I have logged `insertedObjects` each time before a save, but this seems all right. I am at a total loss here. – vrwim Apr 29 '15 at 09:39
  • I apparently still had set my One-to-Many set to `Ordered` while my implementation was a `NSMutableSet`. Setting this to `false` seems to have solved the problem... That is a stupid little bug that has annoyed me for quite a while. – vrwim Apr 29 '15 at 11:52
  • this isn't thread safe at all AFAICS – Daij-Djan Apr 30 '15 at 08:36

3 Answers3

2

I had apparently set my one-to-many relationship between conversations and messages to "ordered". This was not correct... I had already changed my NSManagedObject's class to use NSMutableSet instead of NSMutableOrderedSet.

Apparently this results in an NSRangeException in the save method...

vrwim
  • 13,020
  • 13
  • 63
  • 118
0

Somewhere in AppDelegate you are creating NSArray,

By adding Exception Breakpoint you can check the line which causes error.

method to add Exception Breakpoint is on the following links.

http://blog.manbolo.com/2012/01/23/xcode-tips-1-break-on-exceptions https://developer.apple.com/library/ios/recipes/xcode_help-breakpoint_navigator/articles/adding_an_exception_breakpoint.html

vrwim
  • 13,020
  • 13
  • 63
  • 118
aBilal17
  • 2,974
  • 2
  • 17
  • 23
  • I can't accept the answer, but I can tell you I am not creating an `NSArray` in `AppDelegate`. I voted you up for the suggestion of adding an exception breakpoint. – vrwim Apr 22 '15 at 10:02
  • Adding an exception breakpoint shows that the error occurs in `[NSManagedObjectContext save:]`... What do I do now? – vrwim Apr 22 '15 at 12:06
  • Well the error occurs after I insert a new object, but it doesn't always occur, which is weird. The error simply occurs on the `.save(&error)` method on the default managedObjectContext `(UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext`. I don't know what I should share. I am creating `NSManagedObject`s in the `completionHandler` of a `dataTaskWithRequest:`(sent to the main queue by `dispatch_async(dispatch_get_main_queue())`), but the error doesn't occur until I create objects outside of this `completionHandler`. – vrwim Apr 22 '15 at 12:15
  • Running the app in the simulator gave a better error; I edited my question. – vrwim Apr 22 '15 at 12:18
  • When running the app with a breakpoint on the `recordToManyChangesForObject:inRow:usingTimestamp:inserted:` method (the one that accesses the wrong index), I got the feeling that I was saving in my completionhandlers, while saving in other completionhandlers. Is there a way to make sure methods don't overlap in execution? – vrwim Apr 24 '15 at 18:06
0

you said you have made your save-method thread save. can you please show some code?

usually i'm doing something like this:

// create object with concurrency where you need it
[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];


// wrapper for saving
- (BOOL)saveContext
{
    __block BOOL success = NO;

    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil)
    {
        [managedObjectContext performBlockAndWait:^{
            if([managedObjectContext hasChanges])
            {
                NSError *error = nil;
                success = [managedObjectContext save:&error];

                if (success == NO)
                {
                    NSLog(@"Unresolved error %@", error.localizedDescription);
                }
            }
        }];
    }

    return success;
}
donmarkusi
  • 346
  • 2
  • 13
  • I have added my code. I have used a global `NSLock` that I lock and unlock around my `save` method. – vrwim Apr 28 '15 at 15:10
  • That lock is going be no help if you are using the MOC on a different thread than which you created it. The one rule for MOCBusters is DO NOT CROSS THREADS. Can you share the dispatch_async code you are using to – Warren Burton Apr 28 '15 at 15:24
  • thanks. i'm not familiar with `NSLock` at all... you can try to use `performBlock` or `performBlockAndWait` because syncronising is the purpose of those methods. you can find more information about it here: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/ – donmarkusi Apr 28 '15 at 15:25
  • @donmarkusi I am now using `NSPrivateQueueConcurrencyType` when I init my `NSManagedObjectContext`, but this still crashes my app. Same error. I'm starting to think this is a bug in CoreData. I'll try to create a minimal app that has the bug. – vrwim Apr 29 '15 at 09:52
  • and do you use `performBlockAndWait` or `performBlock` as suggested by apple? yeah a minimal app would be interesting. – donmarkusi Apr 29 '15 at 11:28