ios - 来自多个类和线程的异步核心数据

标签 ios objective-c multithreading core-data asynchronous

在我之前的问题中试图弄清楚确切的问题是什么之后: fetchedObjects (NSArray) count return 0 when it's full of objects 我很确定我需要我的核心数据与多个类和线程异步。 我尝试连续多次调用我的核心数据,一个接一个,我没有问题。 但显然我需要从多个类和线程读取/写入它。 我使用 @synchronized 进行了验证,但仍然没有,我在核心数据的 fetchedObjects 数组中有 0 条记录,但其中有数据。

正确的做法是什么?

编辑 1:

如果我尝试使用 NSTimer 安排上面的代码,则它只能运行一次:

TrapService.mm:

self.managedObjectContext = appDelegate.managedObjectContext;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];
    NSError *error = nil;
    NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
    NSLog(@"fetchedObjects.count: %d", fetchedObjects.count);

编辑 2:

我使用核心数据的另一个代码示例,执行一次,然后所有关于核心数据的操作什么也不做,或者返回包含 0 条记录的数组。

TrapService.mm:

- (void)initializeQuadTree
{
    self.qTree = [[QuadTree alloc] init];
    self.qTree = [dbat addCoordinatesToQuadTree:self.qTree];
}

- (Traps*)getCloseTrapFromTree:(CLLocation*)location
{
    return [dbat getCloseTrapFromTree:self.qTree andLocation:location];
}

DataBaseAllTraps.m:

- (QuadTree*)addCoordinatesToQuadTree:(QuadTree*)quadTree
{
    if (quadTree == nil) {
        quadTree = [[QuadTree alloc] init];
    }

    BOOL success = YES;

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    NSError *error = nil;
    NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
    if (fetchedObjects == nil || fetchedObjects.count == 0)
    {
        NSLog(@"addCoordinatesToQuadTree - localizedDescription: %@, userInfo: %@", error.localizedDescription, error.userInfo);
        success = NO;
    }

    NSLog(@"addCoordinatesToQuadTree - fetchedObjects.count: %d", fetchedObjects.count);

    if (success)
    {
        for (CoreDataAllTraps *trap in fetchedObjects)
        {
            double latitude = trap.lat.doubleValue;
            double longitude = trap.lon.doubleValue;

            double closePointLat = trap.close_point_lat.doubleValue;
            double closePointLon = trap.close_point_lon.doubleValue;

            DummyAnnotation *trapAnnotation = [[DummyAnnotation alloc] init];

            if (closePointLat != 0.0 || closePointLon != 0.0) trapAnnotation.coordinate = CLLocationCoordinate2DMake(closePointLat, closePointLon);
            else trapAnnotation.coordinate = CLLocationCoordinate2DMake(latitude, longitude);

            [quadTree insertObject:trapAnnotation];
        }
    }
    else
    {
        for (Traps *trap in kNETROADS_CONTEXT.arrayOfAllTraps)
        {
            double latitude = trap.lat;
            double longitude = trap.lon;

            double closePointLat = trap.closePointLat;
            double closePointLon = trap.closePointLon;

            DummyAnnotation *trapAnnotation = [[DummyAnnotation alloc] init];

            if (closePointLat != 0.0 || closePointLon != 0.0) trapAnnotation.coordinate = CLLocationCoordinate2DMake(closePointLat, closePointLon);
            else trapAnnotation.coordinate = CLLocationCoordinate2DMake(latitude, longitude);

            [quadTree insertObject:trapAnnotation];
        }
    }
    NSLog(@"TOTAL NUMBER OF TRAPS (%s): %i", __PRETTY_FUNCTION__, success?fetchedObjects.count:[Netroads sharedInstance].arrayOfAllTraps.count);
    return quadTree;
}

- (Traps*)getCloseTrapFromTree:(QuadTree*)quadTree andLocation:(CLLocation*)location
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    NSArray *closeTraps = [quadTree neighboursForLocation:location.coordinate limitCount:1];

    if (closeTraps.count == 0) { return nil; }

    // NSAssert(closeTraps.count > 0, @"closeTraps.count == 0, get close trap from quad tree.");

    int trapID = 0;
    DummyAnnotation *trapLocation = closeTraps.firstObject;

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:self.managedObjectContext];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ == %f AND %@ == %f", CLOSE_POINT_LAT, trapLocation.coordinate.latitude, CLOSE_POINT_LON, trapLocation.coordinate.longitude];
    [fetchRequest setEntity:entity];
    [fetchRequest setPredicate:predicate];
    [fetchRequest setFetchLimit:1];

    NSError *error = nil;
    NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

    if (fetchedObjects != nil && fetchedObjects.count > 0) { // We have close point
        CoreDataAllTraps *trap = fetchedObjects.firstObject;
        trapID = trap.trapID.intValue;
    }
    else { // We do not have close point, use normal coordinates (lat, lon)
        NSLog(@"%s error: %@\n%@", __PRETTY_FUNCTION__, error.localizedDescription, error.userInfo);

        fetchRequest = [[NSFetchRequest alloc] init];
        entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:self.managedObjectContext];
        predicate = [NSPredicate predicateWithFormat:@"%@ == %f AND %@ == %f", LAT, trapLocation.coordinate.latitude, LON, trapLocation.coordinate.longitude];
        [fetchRequest setEntity:entity];
        [fetchRequest setPredicate:predicate];
        [fetchRequest setFetchLimit:1];

        error = nil;
        fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

        if (fetchedObjects != nil && fetchedObjects.count > 0) {
            CoreDataAllTraps *trap = fetchedObjects.firstObject;
            trapID = trap.trapID.intValue;
        }
        else {
            NSLog(@"%s error: %@\n%@", __PRETTY_FUNCTION__, error.localizedDescription, error.userInfo);
        }
    }

    if (trapID > 0) {
        return [self getTrap_trapID:trapID];
    }
    else {
        return nil;
    }
}

编辑 3:

我正在创建一个新的 MOC,但仍然没有,同样的问题:

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

最佳答案

我没有分析你的代码。 (我太懒了。:-))但是当我搜索一个存档时,我什么也没找到。

请记住,发生了什么:在标准设置中,您有一个 SQL-DB 作为后端。每个线程/队列都有不同的上下文,它们(部分)在获取请求时取出 SQL-DB 的数据,并(部分)在保存请求时保存它。

没有上下文自动将其更改(包括插入和删除)推送到数据库或另一个上下文。没有上下文会自动从数据库或另一个上下文中提取另一个上下文推送的更改。因此,必须以“手动”方式将数据从上下文传输到另一个上下文。

只要您没有删除,您就可以在一个上下文使用保存完成时简单地存储数据,并在另一个线程上收听保存通知。

关于ios - 来自多个类和线程的异步核心数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21826633/

相关文章:

ios - 将 Core Data/sqlite 记录迁移到新版本(从 Library 到 Documents 文件夹)

ios - PopViewController 奇怪的行为

c++ - boost::thread 在程序启动之前挂起?

multithreading - 将带有引用的迭代器移到线程中

ios - clang : error: linker command failed with exit code 1 (use -v to see invocation) when doing unit test on xcode

ios - 我是否将相同的对象与 prepareForSegue 传回?

ios - 修改 UISearchBar 取消按钮字体文字颜色和样式

作为类成员的线程的 c++11 vector

ios - 从数组中的数组获取 JSON 数据

javascript - PhoneGap : Unable to change volume of html5 Audio object in ios