核心数据:插入在全局队列崩溃的对象[ARC - iPhone模拟器6.1] [英] Core Data : inserting Objects crashed in global queue [ARC - iPhone simulator 6.1]

查看:114
本文介绍了核心数据:插入在全局队列崩溃的对象[ARC - iPhone模拟器6.1]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常简单的核心数据演示,其中只有一个按钮。



当我点击运行按钮,应用程序创建10,000个对象



更新详细信息:如果我将



更新我的意图:我知道MOC是不是线程安全的,但根据苹果文档,我们还可以使用串行队列访问MOC,并且串行队列使用多个线程。 / p>

这里我创建了Core Data堆栈:

  #pragma mark  - 核心数据栈

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

_managedObjectContext = [[NSManagedObjectContext alloc] init];

if(self.persistentStoreCoordinator){
[_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}

return _managedObjectContext;
}

- (NSManagedObjectModel *)managedObjectModel
{
if(nil!= _managedObjectModel){
return _managedObjectModel;
}

_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if(nil!= _persistentStoreCoordinator){
return _persistentStoreCoordinator;
}

NSString * storeType = NSSQLiteStoreType;
NSString * storeName = @model.sqlite;
NSURL * storeURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] ​​stringByAppendingPathComponent:storeName]];

_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];

NSError * error = nil;
if(![_ persistentStoreCoordinator addPersistentStoreWithType:storeType
configuration:nil
URL:storeURL
options:nil
error:& error])
{
NSLog(@Error:%@ \\\
,[error localizedDescription]);
NSAssert1(YES,@无法使用NSSQLiteStoreType创建存储%@,[storeURL path]);
}

return _persistentStoreCoordinator;
}

#pragma mark -
#pragma mark应用程序的文档目录

- (NSString *)applicationDocumentsDirectory
{
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString * basePath =([paths count]> 0)? [paths objectAtIndex:0]:nil;
return basePath;应用程式启动后,
}


$ b b

  @implementation AppDelegate 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//在应用程序启动后覆盖自定义点。

if(self.managedObjectContext){
;
}

return YES;
}

当我点击按钮:

   - (IBAction)runButtonDidClick:(id)sender 
{
/ **
*访问moc使用不同的线程进行死锁。
* /

[self runSave];
}

- (void)runSave
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^ {
AppDelegate * appDelegate = [[UIApplication sharedApplication ] delegate];
NSManagedObjectContext * moc = appDelegate.managedObjectContext;

if(moc){
for(int j = 0; j< 10000; ++ j){
People * people = [NSEntityDescription insertNewObjectForEntityForName:@PeopleinManagedObjectContext:moc];
people.name = @noname;
}

NSLog ********** IN SAVE%@,[NSThread currentThread]);
NSError * error = nil;
if([moc save:& error]){
;
}

NSLog(@********** OUT SAVE%@,[NSThread currentThread]);
}
});
}

有时点击运行按钮,可能是2或3或4 .. 。它崩溃了



我无法弄清楚为什么...
感谢任何帮助。





解决方案

核心数据应该总是工作在线程巫婆有moc。
performBlock performBlockAndWait 的唯一工作是照顾线程安全。随着插入到核心数据将始终运行在正确的线程。您可以在任何线程上定义moc - performBlock 总是选择正确的线程。



>

  [self.managedObjectContext performBlock:^ {
for(NSDictionary * dic in arr){
// !
}
}];

在您的情况下:

   - (void)runSave 
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^ {
AppDelegate * appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext * moc = appDelegate.managedObjectContext;

if(moc){

[moc performBlock:^ {
for(int j = 0; j< ; 10000; ++ j){
People * people = [NSEntityDescription insertNewObjectForEntityForName:@PeopleinManagedObjectContext:moc];
people.name = @noname;
} $ b b NSError * error = nil;
if([moc save:& error]){
;
}
}];
}
} );
}


I have a very simple Core Data demo, in which there is only one button.

When I click the 'run' button, the App creates 10,000 objects in a for-loop, which is running in the global queue.

Update for more detail : If I put the for-loop in main thread, it runs well.

Update for my intent : I know that MOC is not thread-safe, but according to the Apple doc, we can also use serial queue to access the MOC, and the serial queue uses more than one threads.

Here I create the Core Data stack:

#pragma mark - Core Data Stack

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

    _managedObjectContext = [[NSManagedObjectContext alloc] init];

    if (self.persistentStoreCoordinator) {
        [_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
    }

    return _managedObjectContext;
}

- (NSManagedObjectModel *)managedObjectModel
{
    if (nil != _managedObjectModel) {
        return _managedObjectModel;
    }

    _managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (nil != _persistentStoreCoordinator) {
        return _persistentStoreCoordinator;
    }

    NSString *storeType = NSSQLiteStoreType;
    NSString *storeName = @"model.sqlite";
    NSURL *storeURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:storeName]];

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];

    NSError *error = nil;
    if (![_persistentStoreCoordinator addPersistentStoreWithType:storeType
                                                   configuration:nil
                                                             URL:storeURL
                                                         options:nil
                                                           error:&error])
    {
        NSLog(@"Error : %@\n", [error localizedDescription]);
        NSAssert1(YES, @"Failed to create store %@ with NSSQLiteStoreType", [storeURL path]);
    }

    return _persistentStoreCoordinator;
}

#pragma mark -
#pragma mark Application's Documents Directory

- (NSString *)applicationDocumentsDirectory
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
    return basePath;
}

after app has launched :

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.

    if (self.managedObjectContext) {
        ;
    }

    return YES;
}

When I click the button :

- (IBAction)runButtonDidClick:(id)sender
{
    /**
     * Access the moc using different threads to make deadlock.
     */

    [self runSave];
}

- (void)runSave
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        NSManagedObjectContext *moc = appDelegate.managedObjectContext;

        if (moc) {
            for (int j = 0; j < 10000; ++j) {
                People *people = [NSEntityDescription insertNewObjectForEntityForName:@"People" inManagedObjectContext:moc];
                people.name = @"noname";
            }

            NSLog(@"**********IN SAVE %@", [NSThread currentThread]);
            NSError *error = nil;
            if ([moc save:&error]) {
                ;
            }

            NSLog(@"**********OUT SAVE %@", [NSThread currentThread]);
        }
    });
}

For clicking the run button some times, maybe 2 or 3 or 4... It crashes

I could not figure out why... Thanks for any help.

解决方案

Core data should be always work on thread witch have moc. the only job for performBlock and performBlockAndWait is that take care of thread safety. With it inserting to Core Data will always running in the right thread. You can define moc on whatever thread you want - performBlock always choose the right one.

So:

[self.managedObjectContext performBlock:^{
            for(NSDictionary *dic in arr) {
                //inserting here!
            }
}];

In your case:

- (void)runSave
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        NSManagedObjectContext *moc = appDelegate.managedObjectContext;

        if (moc) {

          [moc performBlock:^{
            for (int j = 0; j < 10000; ++j) {
                People *people = [NSEntityDescription insertNewObjectForEntityForName:@"People" inManagedObjectContext:moc];
                people.name = @"noname";
            }
            NSError *error = nil;
            if ([moc save:&error]) {
                ;
            }
         }];
        }
    });
}

这篇关于核心数据:插入在全局队列崩溃的对象[ARC - iPhone模拟器6.1]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆