数组索引越界问题(NSRangeException)出现在-[NSManagedObjectContext save:]中。

12

我的iOS应用程序在-[NSManagedObjectContext save:]时出现NSRangeException崩溃。任何其他有用的信息都找不到了。我该怎么修复这个问题?我没有任何内存地址或其他可以使用的信息...

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

这是我用来使我的 save: 线程安全的代码:

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

我的xcdatamodeld(相关部分):

xcdatamodeld

编辑:我已经编辑了代码以反映我的更改,使我的NSManagedObjectContext线程安全。现在,我所有的操作都在一个我上面初始化的CoreDataHelper实例上执行。我发现如果进入一次会话,添加一条消息,然后进入另一个会话并在那里添加一条消息,就会导致崩溃。我已经添加了我的xcdatamodeld


1
索引6超出范围[0 .. 5],这意味着您正在尝试从仅有6个对象的数组中访问第7个对象。并添加异常断点,它将直接显示该行是什么。 - user4261201
@Nandu,是一个由6个对象组成的数组中的第7个对象。 - vikingosegundo
@Nandu 添加异常断点后发现错误出现在[NSManagedObjectContext save:]... 现在该怎么办? - vrwim
我在dataTaskWithRequest()中有很多回调。我获取对话,然后获取每个对话的消息,通过在对话请求的回调中获取消息来完成此操作。所有回调都包装在异步调度中,以便我可以进行GUI操作。有人能提供任何帮助吗?我猜测在这些异步回调中访问NSManagedObject存在问题? - vrwim
1
这对我来说像是一个线程问题。NSManagedObjects不是线程安全的。您必须在创建它的相同线程中访问它。我知道您说过使保存方法线程安全,但我敢打赌您正在从多个线程访问NSManagedObject上下文。最简单的解决方案可能是创建一个单例对象,并让它为您完成所有工作。然后只需在任何线程中需要时访问该单例即可。 - Victor Engel
显示剩余7条评论
3个回答

2

我显然将我的对话和消息之间的一对多关系设置为“有序”。这是不正确的...... 我已经将我的NSManagedObject的类更改为使用NSMutableSet而不是NSMutableOrderedSet。

显然,这会导致保存方法中的NSRangeException...


0

你说你已经将你的保存方法变成了线程安全的。能否请你展示一些代码?

通常我会这样做:

// 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;
}

我已经添加了我的代码。我使用了一个全局的NSLock,在我的save方法周围锁定和解锁它。 - vrwim
如果您在不同的线程上使用MOC,那么该锁将毫无帮助。对于MOCBusters的一个规则是:不要跨线程操作。您能分享一下您正在使用的dispatch_async代码吗? - Warren Burton
谢谢。我对 NSLock 完全不熟悉...你可以尝试使用 performBlockperformBlockAndWait,因为同步是这些方法的目的。你可以在这里找到更多信息:https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/ - donmarkusi
@donmarkusi,我现在在初始化NSManagedObjectContext时使用NSPrivateQueueConcurrencyType,但仍然导致我的应用程序崩溃。错误仍然相同。我开始觉得这可能是CoreData的一个错误。我将尝试创建一个具有该漏洞的最小应用程序。 - vrwim
你使用苹果建议的performBlockAndWait还是performBlock呢?是啊,一个最小化的应用程序会很有趣。 - donmarkusi

0

我不能接受这个答案,但是我可以告诉你我没有在AppDelegate中创建NSArray。我投票支持你的建议添加异常断点。 - vrwim
添加异常断点显示错误出现在[NSManagedObjectContext save:]中...现在该怎么办? - vrwim
错误发生在我插入新对象之后,但并不总是发生,这很奇怪。错误仅在默认的managedObjectContext上的.save(&error)方法上发生,该managedObjectContext为(UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext。我不知道我应该分享什么。我正在dataTaskWithRequest:completionHandler中创建NSManagedObject(通过dispatch_async(dispatch_get_main_queue())发送到主队列),但直到我在此completionHandler之外创建对象时才出现错误。 - vrwim
在模拟器中运行应用程序会得到更好的错误信息;我编辑了我的问题。 - vrwim
当在“recordToManyChangesForObject:inRow:usingTimestamp:inserted:”方法上设置断点(访问错误索引的方法)运行应用程序时,我有一种感觉,即在我的完成处理程序中保存的同时也在其他完成处理程序中保存了。有没有办法确保方法不会重叠执行? - vrwim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接