问题
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