在多线程的同时检索数据

时间:2011-10-11 16:38:46

标签: multithreading core-data ios4 nsmanagedobjectcontext

我在从数据库加载数据时使用多线程。

我正在做以下

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
               ^{
                   // Get data
                   NSDate *pastDate = [CommonHelper getSelectedDateYearBackComponents:[NSDate date]];
                   NSPredicate *predicate = [NSPredicate predicateWithFormat:@"users == %@ && startDate >= %@", objUser,pastDate];
                   NSMutableArray *fetchArray = [DataAccess searchObjectsInUserContext:@"userIngo" :predicate :@"startDate" :NO];

                   if ([fetchArray count] > 0)
                   {
                       dispatch_async(dispatch_get_main_queue(), 
                                     ^{
                                         // Reload table
                                         [self.tableView reloadData]; });
                   }

                   else 
                   {
                       dispatch_async(dispatch_get_main_queue(), 
                        ^{  // calling Webservice
                         });
                   }
                });

其中users是我尝试获取数据的实体,objUser是我从用户实体检索数据的用户对象

我的searchObjectsInUserContext代码就像这样

+(NSMutableArray *) searchObjectsInLabContext: (NSString*) entityName : (NSPredicate *) predicate : (NSString*) sortKey : (BOOL) sortAscending
 {
i3EAppDelegate *appDelegate = (i3EAppDelegate *)[[UIApplication sharedApplication] delegate];

NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
[context setUndoManager:nil];
[context setPersistentStoreCoordinator:[appDelegate persistentStoreCoordinator]];

// Register context with the notification center
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:context];

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
[request setEntity:entity]; 
[request setFetchBatchSize:10];
[request setReturnsObjectsAsFaults:NO];

// If a predicate was passed, pass it to the query
if(predicate != nil)
{
    [request setPredicate:predicate];
}

// If a sort key was passed, use it for sorting.
if(sortKey != nil)
{
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [request setSortDescriptors:sortDescriptors];
    [sortDescriptors release];
    [sortDescriptor release];
}

NSError *error;

NSMutableArray *mutableFetchResults = [[context executeFetchRequest:request error:&error] mutableCopy];

if (mutableFetchResults == nil) {

    // Handle the error.
    // NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    exit(-1);  // Fail

}

[request release];
appDelegate = nil;

return [mutableFetchResults autorelease];
  }

因此,在我的searchObjectInUserContext中,我使用多个managedObjectContext,以便在Fred McCann在他的blog post中解释多线程时不会给我带来问题。

但是,我的问题是在我的searchObjectsInUserContext中NSMutableArray *mutableFetchResults,因为即使数据库中有数据,它有时会返回0。

有人可以帮我解决我做错的事吗?

1 个答案:

答案 0 :(得分:2)

  1. 您正在泄露您创建的上下文;你永远不会释放它。
  2. 无需注册为观察者,因为您永远不会使用该上下文进行保存。
  3. 为什么要制作上下文的可变副本?这很少有用。
  4. 您如何知道数据库中有数据?
  5. 此方法是在后台线程上运行吗?
  6. 更新

    你的获取没有任何问题,所以我怀疑这个问题可能是时间问题。这个fetch是在另一个线程保存之前运行的吗?这可以解释你所看到的行为。

    另外,为什么你在后台线程上运行它?您是否看到需要像这样的后台搜索的性能问题?

    更新2

    首先,我仍然怀疑是否需要背景提取。这通常是在遇到性能问题时保留的,因为提取非常快。

    其次,您获取后台队列,但之后您不会对所获取的数据执行任何操作。你不要把它交给桌子(无论如何都是坏的),你只需要把它扔掉。

    如果您只是为了计数而不提取,请执行-[NSManagedObjectContext -countForFetchRequest: error:]。它会更快,无需后台队列调用。

    如果您希望对结果采取某些措施,则会遇到问题。 NSManagedObject的实例无法跨越线程/队列边界。因此,获取后台队列对UI的影响很小。您需要来获取主队列/主线程上的这些对象。如果不这样做,您将崩溃,因为Core Data不允许它。

    最后,你的背景队列对你造成的伤害大于弊,而且他们没有解决你想要解决的问题。