在尝试弄清楚我之前的问题后,究竟是什么问题:
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];
答案 0 :(得分:2)
我没有分析你的代码。 (我太懒了。:-))但是当我搜索一次保存时,我找不到。
请记住,发生了什么:在标准设置中,您有一个SQL-DB作为后端。每个线程/队列都有不同的上下文,它们(部分地)在获取请求中取出SQL-DB的数据,并(部分地)将其保存在保存请求中。
没有上下文将其更改(包括插入和删除)自动推送到数据库或其他上下文。没有上下文从DB或其他上下文中自动推送另一个上下文推送的更改。因此,必须以“手动”方式将数据从上下文传输到另一个数据。
只要你没有删除,只需在使用save完成一个上下文时存储数据,并在另一个线程上监听did save通知。
答案 1 :(得分:1)
阅读有关如何使用CoreData in a concurrent fashion的Apples文档。
基本上,每个线程使用单独的NSManagedObjectContext
并且不在这些线程之间传递对象非常重要,但只能通过NSManagedObjectID
引用它们。
上面的代码示例需要有关您起诉该代码的位置的更多信息。但令我惊讶的是
self.managedObjectContext = appDelegate.managedObjectContext;
如果没有在主线程上运行,这与并发指南要做的完全相反。使用该行,您只需创建指向appDelegate.managedObjectContext
的指针。这不是一个新对象!
如果以正确的方式完成,通常不需要同步或添加锁等。
要给出一个好的答案,虽然你的问题太模糊,但需要一个相当冗长的答案。但也许在阅读Apple的文档后,您可以部分解决您的问题并回过头来解决问题。这可以更容易地得到令人满意的回答。