Search code examples
objective-cpropertiescllocationsubclassing

How to override a readonly property in a subclass of CLLocation?


I am subclassing CLLocation in order to add a property:

#import <UIKit/UIKit.h>
@import CoreLocation;

@interface MyLocation : CLLocation

@property (nonatomic, copy) NSString *name;

@end

The problem is I need to be able to update MyLocation's coordinate property, which is declared as readonly in the superclass:

// CLLocation.h
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;

Following some similar answers here, I created a private extension where I redeclare coordinate as readwrite:

@interface MyLocation ()

@property(nonatomic, assign, readwrite) CLLocationCoordinate2D coordinate;

@end

Since the compiler complains about that, I also added the @dynamic keyword:

@implementation MyLocation

@dynamic coordinate;

@end

Then I create a method to update an instance of my subclass with another coordinate:

@implementation MyLocation

@dynamic coordinate;

-(void)updateCoordinate:(CLLocationCoordinate2D)newCoordinate
{
    self.coordinate = newCoordinate;
}

@end

The problem is when I call -updateCoordinate I get a crash with the message -[MyLocation setCoordinate:]: unrecognized selector sent to instance meaning that what I did doesn't work as I hopped. I guess there is no setter for coordinate in CLLocation.m?

Can someone explain what's going on here and suggest any solution?


Solution

  • You should just make a copy of the CLLocation in this case. It's immutable for a reason. For example:

    - (void)locationManager:(CLLocationManager *)manager
        didUpdateToLocation:(CLLocation *)new
               fromLocation:(CLLocation *)old{
    
    
        new = [[[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(old.coordinate.latitude, -1.000028276362)
                                                 altitude:old.altitude
                                       horizontalAccuracy:old.horizontalAccuracy
                                         verticalAccuracy:old.verticalAccuracy
                                                timestamp:old.timestamp] autorelease];
    
        return new 
    }