Is it possible to inherit from MKPolyline

久未见 提交于 2019-11-29 09:02:43

问题


I'm building a MapKit based app for iPhone.

I have a number of MKPolylines added to the map.

However, instead of having a MKPolyline, I would like to have my own Model class conforming to the MKOverlay protocol added to the map so that I can access the model properties when creating the corresponding view in mapView:viewForOverlay.

The problem is that I can't find the way to inherit from MKPolyline because it doesn't have any init methods that I can call from the subclass' init. You can only create them using the convenience methods.

How can I bring together the model properties and the MKPolyline behaviour?


回答1:


You can set an associated object attribute of the class. This allows you to bind an instance variable to an existing class. Make sure you properly clean up after yourself.




回答2:


MANIAK_dobrii's code is the way to go but I found I had to implement some additional MKMultiPoint methods to get it to work, here are my complete header and implementation files for an AnchorLine class I used:-

Header AnchorLine.h

#import <MapKit/MapKit.h>

@interface AnchorLine : NSObject <MKOverlay> {
    MKPolyline* polyline;
}

@property (nonatomic, retain) MKPolyline* polyline;

+ (AnchorLine*)initWithPolyline: (MKPolyline*) line;
@end

Implementation AnchorLine.m

#import "AnchorLine.h"

@implementation AnchorLine

@synthesize polyline;


+ (AnchorLine*)initWithPolyline: (MKPolyline*) line {
    AnchorLine* anchorLine = [[AnchorLine alloc] init];
    anchorLine.polyline = line;
    return [anchorLine autorelease];
}

- (void) dealloc {
    [polyline release];
    polyline = nil;
    [super dealloc];
}

#pragma mark MKOverlay
//@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (CLLocationCoordinate2D) coordinate {
    return [polyline coordinate];
}

//@property (nonatomic, readonly) MKMapRect boundingMapRect;
- (MKMapRect) boundingMapRect {
    return [polyline boundingMapRect];
}

- (BOOL)intersectsMapRect:(MKMapRect)mapRect {
    return [polyline intersectsMapRect:mapRect];
}

- (MKMapPoint *) points {
    return [polyline points];
}


-(NSUInteger) pointCount {
    return [polyline pointCount];
}

- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range {
    return [polyline getCoordinates:coords range:range];
}

@end

Hope that helps someone.




回答3:


It is true that MKPolyline doesn't have its own init method. In fact the only class in MKPolyline's inheritance chain that does have an init method is NSObject.

So when I subclassed MKPolyline I just overrode the init method defined by NSObject...

-(id) init {
    self = [super init];
    if(self) {
        //my initialization here
    }
    return self;
}

Then when you want to instantiate your subclass with coordinates you might do something like this...

-MyPolyline* myPolyline = (MyPolyline*)[MyPolyline polylineWithCoordinates:coordinates count:coordinateCount];



回答4:


UPDATE: There's another option (could be better) to use message forwarding for this (like -forwardingTargetForSelector or stuff).

I had the same issue today but came up with other solution. Instead of using suggested by Wayne associated object attribute stuff I just encapsulated MKPolyline in another class and transferred MKOverlay protocol's messages to it.

So I've got something like in .h:

@interface MyOverlay : NSObject <MKOverlay>
{
    MKPolyline* polyline;
    id object;
}

@property (nonatomic, retain) id object;
@property (nonatomic, retain) MKPolyline* polyline;

+ (MyOverlay*)myOverlayWithObject: (id)anObject;

@end

And in .m:

@implementation MyOverlay
@synthesize object;
@synthesize polyline;


+ (MyOverlay*)routePartOverlayWithObject: (id)anObject {    

    MyOverlay* myOverlay = [[MyOverlay alloc] init];

    ... generating MKPolyline ...

    myOverlay.polyline = ... generated polyline ...;
    routePartOverlay.object = anObject;


    return [myOverlay autorelease];
}

- (void) dealloc {
    [cdRoutePart release]; cdRoutePart = nil;
    [polyline release]; polyline = nil;

    [super dealloc];
}

#pragma mark MKOverlay
//@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (CLLocationCoordinate2D) coordinate {
    return [polyline coordinate];
}

//@property (nonatomic, readonly) MKMapRect boundingMapRect;
- (MKMapRect) boundingMapRect {
    return [polyline boundingMapRect];
}

- (BOOL)intersectsMapRect:(MKMapRect)mapRect {
    return [polyline intersectsMapRect:mapRect];
}

@end

So MyOverlay behaves like MKPolyline (conforms to MKOverlay) and at the same time I can do anything with it, having as many properties as I need.




回答5:


Whats mentioned here so far hasn't quite worked for me but I managed a solution based on the other answers and some independent research. I am not 100% certain in this but you can cast a MKPolyline into a custom sub-class only if you use the static method call that calls the right 'init' method internally.

(CustomPolyline*)[CustomPolyline polylineWithCoordinates:coordinates count:coordinateCount]

The above won't work because polylineWithCoordinates only allocates memory for an MKPolyline object and not CustomPolyline. I suspect what's happening internally is that polylineWithCoordinates calls another initializer method in a manner similar to: [MKPolyline otherInitMethod:...]. And its not allocating the proper amount of memory because its now using an MKPolyline static method call and not our CustomPolyline static call.

However if we use

(CustomPolyline*)[CustomPolyline polylineWithPoints:polyline.points count:polyline.pointCount];

It does work. I think this is because polylineWithPoints is using an initializer that returns an id not just chaining to another method call. And since we called it using the CustomPolyline class the initializer allocates memory for CustomPolyline not MKPolyline.

I could be completely wrong on why it works. But I've tested this and it seems to work fine. MKPolygon can be extended in a similar manner. In that case I think the correct static method to use is MKPolygon polygonWithCoordinates:points count:pointSet.count]]

My implementation for reference:

CustomPolyline.h

#import <MapKit/MapKit.h>

typedef enum {
    CustomPolylineTypeNone = 0,
    CustomPolylineDifferentStrokes
} CustomPolylineType;

/**
 * CustomPolyline wraps MKPolyline with additional information about a polyline useful for differentiation.
 */
@interface CustomPolyline : MKPolyline

@property CustomPolylineType type;

-(CustomPolyline*)initWithMKPolyline:(MKPolyline*)polyline;

@end

CustomPolyline.m

#import "CustomPolyline.h"

@implementation CustomPolyline

@synthesize type;

/**
 * Takes an MKPolyline and uses its attributes to create a new CustomPolyline
 */
-(CustomPolyline*)initWithMKPolyline:(MKPolyline*)polyline
{
    // We must use the this specific class function in this manner to generate an actual
    // CustomPolyline object as opposed to a MKPolyline by a different name
    return (CustomPolyline*)[CustomPolyline polylineWithPoints:polyline.points count:polyline.pointCount];
}

@end


来源:https://stackoverflow.com/questions/4949069/is-it-possible-to-inherit-from-mkpolyline

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!