`
linwwwei
  • 浏览: 223607 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

多线程操作数据库 (CoreData)

阅读更多
1: 主线程修改了数据库的某一条记录,但是子线程没有发生变化,反过来一样的问题。这种情况一般是发生在app有多个NSManagedObjectContext,两个线程分别对其进行了读写操作。

2: 有时候程序会莫名其妙的crash掉,这个有很多原因:
          a: 有时候是因为两个线程同时读写数据库中的同一条记录。
          b: 有时候根本找不到是哪里的原因。
          这两种情况一般是发生在app只有一个NSManagedObjectContext,两个线程都对其进行了读写操作。

在实际的开发当中,我遇到了各种各样的问题,如果是多线程操作数据库的话,个人建议:
1: 最好一个线程对应一个NSManagedObjectContext。如果只有一个NSManagedObjectContext,并且多个线程对其进行操作,回出现许多不清不楚的问题。
2:在每一个线程对应一个NSManagedObjectContext的时候,尽量一个线程只读写与其对应的context。在其完成操作的时候通知另外的线程去修改其对应的context。在apple的api中有NSManagedObjectContextDidSaveNotification, 它可以帮助你通知修改其它的contexts。
eg: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChangesForNotification:) name:NSManagedObjectContextDidSaveNotification object:childThreadManagedObjectContext];

- (NSManagedObjectContext*)childThreadContext
{
    if (childThreadManagedObjectContext != nil)
    {
        return childThreadManagedObjectContext;
    }
   
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil)
    {
        childThreadManagedObjectContext = [[NSManagedObjectContext alloc] init];
        [childThreadManagedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    else
    {
        DLog(@"create child thread managed object context failed!");
    }
   
    [childThreadManagedObjectContext setStalenessInterval:0.0];
    [childThreadManagedObjectContext setMergePolicy:NSOverwriteMergePolicy];
   
    //////init entity description.
    pChildThreadEntityDec = [NSEntityDescription entityForName:@"student" inManagedObjectContext:childThreadManagedObjectContext];
    if (pChildThreadEntityDec == nil)
    {
        DLog(@"error init entity description!");
    }
   
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChangesForNotification:) name:NSManagedObjectContextDidSaveNotification object:childThreadManagedObjectContext];
   
    return childThreadManagedObjectContext;
}

- (void)mergeOnMainThread:(NSNotification *)aNotification
{
    [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:aNotification];
}

- (void)mergeContextChangesForNotification:(NSNotification *)aNotification
{
    [self performSelectorOnMainThread:@selector(mergeOnMainThread:) withObject:aNotification waitUntilDone:YES];
}
上面的代码只是简单利用NSManagedObjectContextDidSaveNotification,当子线程修改了数据库以后,通知主线程去修改其对应的context。当然childThreadManagedObjectContext的创建是在创建子线程的时候进行的。

- (void)startChildThread
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
   
    if ([[manageDatabase sharedInstance] childThreadContext] == nil)
    {
        DLog(@"create child thread context failed.");
    }
   
    [NSTimer scheduledTimerWithTimeInterval:10000.0 target:self selector:@selector(printCurrentData) userInfo:nil repeats: YES];

   
    [runLoop run];
    [pool release];
}

注:实际上在什么时候创建都可以,只要保证在第一次用的之前创建好就可以了。上面是childThreadManagedObjectContext发生改变时,通知主context修改,所以在修改数据库时,一般都是修改childThreadManagedObjectContext。
eg:
- (void)saveDatabase:(student*)inObject withAge:(NSNumber *)inAge
{
    if (inObject==nil || inAge==nil)
    {
        return;
    }
    NSError* pError;
   
    if (self.age != nil)
    {
        [self.age release];
        self.age = nil;
    }
    self.age = [[NSNumber alloc] initWithInt:[inAge intValue]];
   
    if ([NSThread currentThread] == [NSThread mainThread])
    {
        [self performSelector:@selector(saveWithChildThread:) onThread:[dataBaseAppDelegate shareDelegate].viewController.pShowController.pChildThread withObject:inObject waitUntilDone:NO];
    }
    else
    {
        inObject.stuAge = inAge;
        if (![childThreadManagedObjectContext save:&pError])
        {
            NSLog(@"save failed: %@, %@", pError, [pError userInfo]);
        }
    }
}

- (void)saveWithChildThread:(student*)inStudent
{
    NSError* pError;
   
    NSManagedObjectID* tempObjectID = [inStudent objectID];
    student* tempStudet = (student*)[childThreadManagedObjectContext objectWithID:tempObjectID];
    tempStudet.stuAge = age;
   
    if (![childThreadManagedObjectContext save:&pError])
    {
        NSLog(@"save failed: %@, %@", pError, [pError userInfo]);
    }
}
这里修改数据库都是通过saveWithChildThread去修改的。当然上面 if ([NSThread currentThread] == [NSThread mainThread]),如果时在主线程也可以直接调用saveWithChildThread,而不用放到子线程修改,这里只是为了统一。每个context只在其对应的线程中修改。
分享到:
评论

相关推荐

    iPhone 多线程 CoreData使用源代码

    在提供的"ThreadedCoreData"源代码中,你可能会找到关于这些概念的实际实现,包括如何初始化和使用后台上下文,如何在多线程中执行CoreData操作,以及如何在操作完成后安全地更新UI。通过研究这些代码,你可以更深入...

    CoreData数据库操作和版本管理

    在"CoreData数据库操作和版本管理"这个主题中,我们将深入探讨如何利用CoreData进行数据操作以及如何有效地管理数据库的版本。 1. **CoreData基本概念** - **实体(Entity)**:类似于关系数据库中的表,代表一种...

    Core Data多线程操作

    本教程将深入探讨如何在多线程环境下进行Core Data的操作,包括创建(Create)、读取(Read)、更新(Update)和删除(Delete)数据。 1. **Core Data多线程基础** - **Main Queue Context**:主线程上下文,通常...

    iOS数据库篇(二)CoreData的创建与使用

    2. NSPersistentContainer:这是CoreData的新特性,它包含了一个主队列上下文(Main Queue Context)和一个后台队列上下文(Background Queue Context),用于多线程环境下数据的读写。 3. NSManagedObjectContext...

    PCCoredataDemo:支持多线程的coredata封装库

    `PCCoredataDemo`的核心特性就是对CoreData的多线程支持,这使得开发者可以在后台线程中执行耗时的数据库操作,而不会阻塞主线程,从而保持UI的流畅性。通常,多线程操作CoreData需要考虑上下文(ManagedObject...

    CoreData简单使用dome

    - 当处理大量数据时,为避免阻塞主线程,可以在后台线程执行CoreData操作。 - 保存操作可能会引发错误,确保处理好这些异常情况。 - 优化查询性能,避免过于复杂的NSPredicate和过多的排序。 总之,CoreData为...

    CoreData的简单操作

    5. **Relationships**:利用CoreData的实体关系,可以轻松地处理一对多、一对一或多对多的关系。 6. **Faulting and Uniquing**:CoreData的懒加载机制和唯一性保证,有助于减少内存消耗。 总的来说,CoreData为...

    CoreData iOS

    - 检测并解决并发问题:在多线程环境中使用CoreData需要注意的问题。 - CoreDate与SQLite的关系:虽然CoreData不直接使用SQL,但默认情况下它使用SQLite作为其后台存储。 - 错误处理和调试技巧:如何在开发过程中...

    QGLCoreDataPlugin:使用多线程管理CoreData数据

    然而,随着应用规模的扩大,单线程的CoreData操作可能会成为性能瓶颈。为了解决这个问题,我们可以利用多线程技术来优化数据管理,这就是"QGLCoreDataPlugin"项目所关注的核心内容。 QGLCoreDataPlugin是一个...

    CoreData添加、删除、查询

    CoreData是苹果公司提供的一种强大...在实际项目中,你可能需要处理更复杂的情况,如多线程下的数据管理、批量操作、关系数据的处理等。了解并熟练掌握CoreData的这些基本操作,对于开发Apple平台的应用程序至关重要。

    iOS CoreData 的小Demo

    因为CoreData不是线程安全的,所以在多线程环境中使用时,需要特别注意。Demo可能展示了如何在后台线程进行数据操作,并在主线程上更新UI。 10. **错误处理**: 在进行数据操作时,应始终检查并处理可能出现的...

    CoreDataDemo:CoreData一些demo,包括后台操纵,多线程导入大数据等

    1. **后台操作与多线程**:在iOS应用中,主线程主要负责UI更新,而数据操作通常会消耗较多时间,因此为了保证用户体验,数据的读写工作应该在后台线程进行。CoreData支持在后台上下文中执行操作,这样可以避免阻塞...

    CoreData数据验证

    在iOS应用开发中,CoreData是一个强大的对象关系映射(ORM)框架,用于管理应用程序...通过合理利用实体属性验证和自定义验证方法,可以构建健壮的数据模型,同时在多线程环境下正确处理数据操作,保证应用的稳定运行。

    CoreData增删改查

    可以使用后台线程进行复杂的数据操作,并通过通知或代理方法更新UI。 8. **故障点与恢复**: CoreData的故障点和恢复机制允许在不丢失用户数据的情况下处理错误。通过捕获并处理NSPersistentStoreSaveError,可以...

    有关CoreData简单使用

    -此外,封装还可以帮助处理并发和错误处理,确保在多线程环境中正确地操作数据。 4. 注释的重要性: -对于初学者来说,良好的注释可以帮助理解代码的意图和工作原理,从而更快地掌握CoreData的使用。 -在封装...

    Swift CoreData简单用法

    本教程将深入讲解如何使用Swift来简单实现CoreData的数据库操作,包括增、删、改、查以及处理关系表。 ### 一、CoreData基本概念 1. **实体(Entity)**:类似于数据库中的表,是数据模型的基本单位。 2. **属性...

    多线程编程指南

    - **CoreData框架**:处理数据库操作时的线程安全问题。 - **CoreFoundation(核心框架)**:提供了底层的线程安全支持。 综上所述,多线程编程是软件开发中一个复杂而重要的主题,它涉及到多方面的技术和设计考虑...

    xcode 中 CoreData的第三方包的使用 项目源码

    - **PromiseKit+CoreData**:结合PromiseKit,将异步编程带入CoreData,简化了多线程操作。 4. **引入第三方库**: 在Xcode项目中,通常通过CocoaPods或Carthage来管理第三方库。首先,需要在Podfile或Cartfile中...

    CoreData的使用包括实体关联的数据插入.字段中存储对象

    CoreData中的实体(Entity)类似于数据库中的表,每个实体可以包含多个属性(Attribute),这些属性对应表中的列。实体间可以通过关系(Relationship)进行连接,如同数据库中的外键。关系可以是一对一、一对多或多...

Global site tag (gtag.js) - Google Analytics