简体   繁体   中英

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?

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.

First, the coordinate should be implemented as a transient including a magic keyPathsForValuesAffectingCoordinate method. You can start with an uncached transient for simplicity and then perhaps add the additional code to cache it if necessary.

Second, validation should be done using Core Data. https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/ObjectValidation.html#//apple_ref/doc/uid/TP40001075-CH20-SW1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM