Array Index Out of Bounds issue (NSRangeException) in -[NSManagedObjectContext save:]
Asked Answered
L

3

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.

Lovmilla answered 22/4, 2015 at 9:54 Comment(12)
does it also happen within the simulator ? Error message will probably be more explicit thereRimple
"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.Hydrogenous
@Nandu, the 7th object in an array of 6 objects.Regelation
@Rimple 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)Lovmilla
@Nandu Adding an exception breakpoint shows that the error occurs in [NSManagedObjectContext save:]... What do I do now?Lovmilla
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 NSManagedObjects in these async callbacks?Lovmilla
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.Eager
@VictorEngel Could you post an answer with how I can make this singleton work on one thread? I'll try it out thenLovmilla
There are several ways to make a singleton. There is an example at #7569435 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.Eager
@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.Lovmilla
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.Lovmilla
this isn't thread safe at all AFAICSRosalinarosalind
L
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...

Lovmilla answered 30/4, 2015 at 8:16 Comment(0)
Y
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

Yale answered 22/4, 2015 at 9:59 Comment(5)
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.Lovmilla
Adding an exception breakpoint shows that the error occurs in [NSManagedObjectContext save:]... What do I do now?Lovmilla
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 NSManagedObjects 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.Lovmilla
Running the app in the simulator gave a better error; I edited my question.Lovmilla
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?Lovmilla
B
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;
}
Ballance answered 28/4, 2015 at 14:47 Comment(5)
I have added my code. I have used a global NSLock that I lock and unlock around my save method.Lovmilla
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 toNarrative
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: developer.apple.com/library/ios/documentation/Cocoa/Reference/…Ballance
@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.Lovmilla
and do you use performBlockAndWait or performBlock as suggested by apple? yeah a minimal app would be interesting.Ballance

© 2022 - 2024 — McMap. All rights reserved.