iosobjective-ccore-datathread-safetymkannotation

NSManagedObject as MKAnnotation and Core Data Concurrency


I am using what I think is a fairly typical implementation of a NSManagedObject subclass which conforms to MKAnnotation protocol so as to display in a MKMapView. See setters and getters:

-(CLLocationCoordinate2D)coordinate {
    CLLocationCoordinate2D coord = EMPTY_LOCATION_COORDINATE;
    BOOL validLong = (self.longitude != nil) && ([self.longitude doubleValue] != 0);
    BOOL validLat = (self.latitude != nil) && ([self.latitude doubleValue] != 0);
    if (validLong && validLat) {
        coord.longitude = [self.longitude doubleValue];
        coord.latitude = [self.latitude doubleValue];
    }

    return coord;
}

-(void)setCoordinate:(CLLocationCoordinate2D)coordinate {
    if (coordinate.latitude != EMPTY_LOCATION && coordinate.longitude != EMPTY_LOCATION) {
        self.latitude = [NSNumber numberWithDouble:coordinate.latitude];
        self.longitude = [NSNumber numberWithDouble:coordinate.longitude];
    } else {
        self.latitude = nil;
        self.longitude = nil;
    }
}

-(NSString *)title {
    NSString *str = [self.projectName copy];
    return str;
}

This is working and not causing problems in production at all.

I was debugging some Core Data concurrency issues using Core Data multi-threading assertions and I find that it is flagging the gutter as a concurrency violation. My guess is that the MKMapview that calls for the coordinate is using a background thread and technically that is not allowed. That it works in production is, conceivably, not guaranteed.

I tried to wrap the getter in a [self.managedObjectContext performBlockAndWait^(void){ //set here }]; block but that causes thread locking fail.

Should I ignore the error and move on or is there some better practice for this purpose?


Solution

  • I could not find the reason for this. I verified that the NSManagedObject is on the main queue context. It is being asked for the coordinate on a queue that is not the main queue. What I did to fix is use a proxy object as annotation passed to the MKMapview instead of passing it directly. NSObject class conforming to the MKAnnotation protocol. Initialize with the coordinate and title from my NSManagedObject, pass that instead of the real deal.