11

I am having a issue subclassing MKPolygon.

I want to add a simple int tag property but I keep getting an instance of MKPolygon instead of my custom class, so calling setTag: causes an exception.

The problem is that MKPolygons are created using a class method: polygonWithCoordinates: count: and I dont know how to turn that into an instance of my class (which includes the tag property).

How would you go about adding a tag property to MKPolygon?

Thank you!

Zebs
  • 5,378
  • 2
  • 35
  • 49

6 Answers6

20

You should both use a category (as @Seva suggests) and objc_setAssociatedObject (as @hoha suggests).

@interface MKPolygon (TagExtensions)
@property (nonatomic) int tag;
@end

@implementation MKPolygon (TagExtensions)
static char tagKey;

- (void) setTag:(int)tag {
    objc_setAssociatedObject( self, &tagKey, [NSNumber numberWithInt:tag], OBJC_ASSOCIATION_RETAIN );
}

- (int) tag {
    return [objc_getAssociatedObject( self, &tagKey ) intValue];
}

@end

You may also want to look at Associative References section of the ObjC Guide, in addition to the API @hoha linked to.

Noah Witherspoon
  • 57,021
  • 16
  • 130
  • 131
skue
  • 2,057
  • 15
  • 18
5

Looks like developers of MKPolygon didn't make it inheritance friendly. If all you want is to add some tag to this instances you can

1) keep a map (NSDictionary or CFDictionary) from MKPolygon instance addresses to tags. This solution works well if all tags are required in the same class they are set.

2) use runtime to attach tag to polygons directly - objc_setAssociatedObject (Objective-C Runtime Reference)

hoha
  • 4,418
  • 17
  • 15
2

I'm facing the same problem. A simple solution is to just use the Title property of the MKPolygon to save what you would save in Tag. At least in my case where I don't need an object reference but a simple number, it works

oblApps
  • 65
  • 6
  • title is available on MKPolygon because MKPolygon conforms to the MKAnnotation protocol. But tittle and subtitle are readonly properties. I am therefore wondering how you managed to set a value on the title property? – pnizzle Mar 09 '15 at 23:13
1
SpecialPolygon *polygon = [SpecialPolygon polygonWithCoordinates:count:];
[polygon setInt: 3];

The key is that by using the SpecialPolygon factory method instead of the MKPolygon one, you'll get the desired SpecialPolygon subclass.

Alexsander Akers
  • 15,967
  • 12
  • 58
  • 83
  • 1
    maybe, maybe not. the assumption is not guaranteed for all convenience constructors. the convenience constructor may call `[[[self class] alloc] init...]`, or it may specify the class in the convenience ctor: `[[MKPolygon alloc] init...]`. if the former, then you're ok, but the latter will not return a `SpecialPolygon`. the problem is that it's kinda hackish/unsupported, and not guaranteed to work the same across multiple releases. so you have to make your own convenience constructor which also initializes the tag, and checks the return type. however, it's a nice solution in some cases, so +1 – justin Mar 13 '11 at 04:53
  • If it's the latter, you change it to the former. But it should just be `self` instead of `[self class]` because `self` is a Class. – Alexsander Akers Mar 13 '11 at 21:41
  • 1
    Doesn't work in the case of MKPolygon subclass. [SpecialPolygon polygonWithCoordinates:count:] will give you an MKPolygon. – elsurudo Jan 30 '13 at 13:19
0

Are you talking about MKPolygons created by your code, or elsewhere? If the former, just override the polygonWithStuff method. If the latter, consider a category over MKPolygon. Then all MKPolygons in your project will have a tag in them.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • 1
    I'm afraid there is not much use in overriding `polygonWithCoordinates:count:` because there is no corresponding `init<...>` method to call in new implementation. – hoha Mar 13 '11 at 02:26
  • The category approach sounds interesting, I have never used categories but I will try it right now and tell you how it went. – Zebs Mar 13 '11 at 02:36
0

since it looks like the authors went out of their way to prevent you from subclassing (at least, that's one possible motivation for the public interface), consider using a form of composition:

http://en.wikipedia.org/wiki/Object_composition

justin
  • 104,054
  • 14
  • 179
  • 226
  • Often a good alternative... but that won't necessarily work here if he has to pass his new objects to API methods that expect MKPolygon objects. – skue Mar 13 '11 at 16:15