0

I'm developing an iOS app with latest SDK.

I have a selector on the following method and I need to pass another argument:

- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    NSLog(@"viewForAnnotation");

    MKAnnotationView *annotationView = nil;

    // if it's the user location, just return nil.
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;

    if ([annotation isKindOfClass:[ShopAnnotation class]])
    {
        // try to dequeue an existing pin view first
        static NSString *ReusableAnnotationIdentifier = @"reusableShopAnnotationIdentifier";

        MKPinAnnotationView *pinView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:ReusableAnnotationIdentifier];

        if (!pinView)
        {
            // if an existing pin view was not available, create one
            MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc]
                                                  initWithAnnotation:annotation reuseIdentifier:ReusableAnnotationIdentifier];

            customPinView.pinColor = MKPinAnnotationColorPurple;
            customPinView.animatesDrop = YES;
            customPinView.canShowCallout = YES;

            // add a detail disclosure button to the callout which will open a new view controller page
            UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            [rightButton addTarget:self
                            action:@selector(showDetails:)
                  forControlEvents:UIControlEventTouchUpInside];

            customPinView.rightCalloutAccessoryView = rightButton;

            return customPinView;
        }
        else
        {
            pinView.annotation = annotation;
        }

        annotationView = pinView;
    }

    return annotationView;
}

I need to pass an object to showDetails::

        // add a detail disclosure button to the callout which will open a new view controller page
        UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [rightButton addTarget:self
                        action:@selector(showDetails:)
              forControlEvents:UIControlEventTouchUpInside];

This is how showDetails is implemented:

- (void) showDetails:(id)sender
{
    NSLog(@"Show Details");
    DetailViewController* mvc = [[DetailViewController alloc] initWithNibName:@"DetailViewController_iPhone" bundle:nil];

    mvc.delegate = self;

    [self presentModalViewController:mvc animated:YES];
}

This is ShopAnnotation interface:

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <CoreData/CoreData.h>

@interface ShopAnnotation : NSObject <MKAnnotation>

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, readonly, strong) NSString *title;
@property (nonatomic, readonly, strong) NSString *subtitle;
@property (nonatomic, readonly, strong) NSManagedObject* shop;

-(id)initWithCoordinate:(CLLocationCoordinate2D) c
                  title:(NSString *) t
               subtitle:(NSString *) st
                   shop:(NSManagedObject*) shop;

@end

How can I add another argument to showDetails and how can I pass it?

showDetails will be:

- (void) showDetails:(id)sender shop:(NSManagedObject*)shop

And, what is this (id)sender? It is an annotation I could use to pass this NSManagedObject.

zoul
  • 102,279
  • 44
  • 260
  • 354
VansFannel
  • 45,055
  • 107
  • 359
  • 626
  • What type of argument you want to add to showDetails? – Rajan Balana Feb 07 '13 at 10:50
  • @RajanBalana I've added more details to my question. It will be a `NSManagedObject`. – VansFannel Feb 07 '13 at 10:52
  • There are much easier ways to do what you want than subclassing, tagging (please don't), etc. Best is to use the map view's conveniently built-in delegate method calloutAccessoryControlTapped. See these for examples: http://stackoverflow.com/questions/9462699/how-to-recognize-which-pin-was-tapped, http://stackoverflow.com/questions/9797047/how-to-keep-data-associated-with-mkannotation-from-being-lost-after-a-callout-po, http://stackoverflow.com/questions/9876042/annotation-details-after-detail-disclosure-pressed. –  Feb 07 '13 at 13:29

3 Answers3

1

See how you're passing a "sender" parameter in your "showDetails:" method?

Why not subclass "UIButton" (e.g. name it "VansFannelButton") and give that new object's "@interface" a bonus ivar which can be your payload.

Then you can do:

- (void) showDetails: (VansFannelButton*) sender
{
    if (sender)
    {
         // do something with the managed object payload
         NSManagedObject * mObject = [sender payload];
    }
}
zoul
  • 102,279
  • 44
  • 260
  • 354
Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
0

Use Associated Objects for passing more argument to buttons's object

Refer associated-objects link.

Paresh Navadiya
  • 38,095
  • 11
  • 81
  • 132
  • Using associated objects for this is a hack. Why pollute the `UIButton` class when you can easily localize the changes using a subclass or the button’s tag? – zoul Feb 07 '13 at 11:18
0

You can try adding a property

int ID;

into your ShopAnnotation class, and when you are populating the ShopAnnotation class you can easily set your own unique ID. Then in

- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
     if (!pinView)
    {
        // if an existing pin view was not available, create one
        MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc]
                                              initWithAnnotation:annotation reuseIdentifier:ReusableAnnotationIdentifier];

        customPinView.pinColor = MKPinAnnotationColorPurple;
        customPinView.animatesDrop = YES;
        customPinView.canShowCallout = YES;

        // add a detail disclosure button to the callout which will open a new view controller page
        UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [rightButton addTarget:self
                        action:@selector(showDetails:)
              forControlEvents:UIControlEventTouchUpInside];
        //Set tag of the button same as ID
        rightButton.tag=((ShopAnnotation*)annotation).ID;

        customPinView.rightCalloutAccessoryView = rightButton;

        return customPinView;
    }
}

And in you showDetails action you can do the following

- (void) showDetails:(id)sender
{
     UIButton *btn=(UIButton*)sender;
     ShopAnnotation *selectedAnnotation=nil;
     for(ShopAnnotation *a in arrAnnotations){
         if(a.ID == btn.tag){
             selectedAnnotation=a; break;
         }
     }

   // Use your ShopAnnotation for you further processing.
 }

I hope this helps..

Thanks.

iphonic
  • 12,615
  • 7
  • 60
  • 107