Trouble creating a custom annotation class in ios - iphone

I'm trying to make a custom MKAnnotation class so it can hold additional information but i keep getting this error :
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '- [AnnotationForId setCoordinate:]: unrecognized selector sent to instance 0x16f63340'
I've tried looking up how to create one and i've followed what i've found online and i'm confused at why i keep getting this error.
Here is my custom annotation class.
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#interface AnnotationForId : NSObject <MKAnnotation >{
NSString *title;
NSString *subtitle;
CLLocationCoordinate2D coordinate;
NSInteger shopId;
}
#property(nonatomic)NSInteger shopId;
#property (nonatomic, copy) NSString * title;
#property (nonatomic, copy) NSString * subtitle;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#end
I've synthesized the property variables in .m class.
I try to call the custom class in my main controller:
for(Shop *shops in feed.shops){
NSLog(#"reached");
AnnotationForId *shop = [[AnnotationForId alloc] init];
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(shops.latitude, shops.longitude);
shop.coordinate = coords;
//[[CLLocationCoordinate2DMake(shops.latitude, shops.longtitude)]];
shop.title = shops.name;
shop.subtitle = #"Coffee Shop";
[map addAnnotation:shop];
}
Any help to why this isnt working would be awesome.
Thanks.

It seems like you're trying to set your readonly property.
You declared it as readonly:
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
But then you're trying to use setter:
shop.coordinate = coords;
readonly means that no setter will be defined for other classes to leverage.
Edit:
I think you should add convenience initializer to your AnnotationForId class like:
-(id)initWithCoordinate:(CLLocationCoordinate2D)coord
{
self = [super init]; // assuming init is the designated initialiser of the super class
if (self)
{
coordinate = coord;
}
return self;
}
So your code will look like this:
for(Shop *shops in feed.shops){
NSLog(#"reached");
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(shops.latitude, shops.longitude);
AnnotationForId *shop = [[AnnotationForId alloc] initWithCoordinate:coords];
//[[CLLocationCoordinate2DMake(shops.latitude, shops.longtitude)]];
shop.title = shops.name;
shop.subtitle = #"Coffee Shop";
[map addAnnotation:shop];
}

This is Simple Example For how to Create Custom AnnotationView.
Create custom AnnotationView:
#import <MapKit/MapKit.h>
#interface AnnotationView : MKPlacemark
#property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *subtitle;
// you can put here any controllers that you want. (such like UIImage, UIView,...etc)
#end
And in .m file
#import "AnnotationView.h"
#implementation AnnotationView
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate addressDictionary:(NSDictionary *)addressDictionary
{
if ((self = [super initWithCoordinate:coordinate addressDictionary:addressDictionary]))
{
self.coordinate = coordinate;
}
return self;
}
#end
// Use Annotation Add #import "AnnotationView.h" in your relevant .m file:
CLLocationCoordinate2D pCoordinate ;
pCoordinate.latitude = LatValue;
pCoordinate.longitude = LanValue;
// Create Obj Of AnnotationView class
AnnotationView *annotation = [[AnnotationView alloc] initWithCoordinate:pCoordinate addressDictionary:nil] ;
annotation.title = #"I m Here";
annotation.subtitle = #"This is Sub Tiitle";
[self.mapView addAnnotation:annotation];
Above is simple Example of how to create AnnotationView.

You have given the property as readonly, which sets only a getter method for the property. So please make the property retain and try it once again.

Related

Using a custom annotation when adding it to map

I'm having trouble accessing my custom annotation class when adding it to a mapview. I have the custom class working properly but i when i add it to the map i'm not sure how to access the custom annotation through this delegate:
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
i've tried looking online and havent found anything. any help would be great.
Its called like this:
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(shops.latitude, shops.longitude);
AnnotationForId *shop = [[AnnotationForId alloc] initWithCoordinate:coords];
//[[CLLocationCoordinate2DMake(shops.latitude, shops.longtitude)]];
shop.title = shops.name;
shop.subtitle = #"Coffee Shop";
shop.shopId = shops.id;
[map addAnnotation:shop];
This is Simple Example For how to Create Custom AnnotationView.
Create custom AnnotationView:
#import <MapKit/MapKit.h>
#interface AnnotationView : MKPlacemark
#property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *subtitle;
// you can put here any controllers that you want. (such like UIImage, UIView,...etc)
#end
And in .m file
#import "AnnotationView.h"
#implementation AnnotationView
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate addressDictionary:(NSDictionary *)addressDictionary
{
if ((self = [super initWithCoordinate:coordinate addressDictionary:addressDictionary]))
{
self.coordinate = coordinate;
}
return self;
}
#end
// Use Annotation Add #import "AnnotationView.h" in your relevant .m file:
CLLocationCoordinate2D pCoordinate ;
pCoordinate.latitude = LatValue;
pCoordinate.longitude = LanValue;
// Create Obj Of AnnotationView class
AnnotationView *annotation = [[AnnotationView alloc] initWithCoordinate:pCoordinate addressDictionary:nil] ;
annotation.title = #"I m Here";
annotation.subtitle = #"This is Sub Tiitle";
[self.mapView addAnnotation:annotation];
Test the annotation to see if it's the same class as your custom class:
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
MKAnnotationView *mkav = nil;
if ([annotation isKindOfClass:[AnnotationForId class]])
{
// This should be safe now.
AnnotationForId *aid = annotation;
// Whatever you wanted to add, including making your own view.
}
return mkav;
}

Property not found on ViewController

I am beginning in iOS development. I've been searching a solution for days and I can't get it. I got the following code:
#interface SAProfileViewController : UITableViewController {
#public NSNumber *userId;
}
#property (weak, nonatomic) IBOutlet UIView *awesomeProfileHeader;
#property (nonatomic, assign) NSNumber *userId;
#end
As you can see I am declaring my property, and after that I do this :
#implementation SAProfileViewController
#synthesize userId = _userId;
...
On an other ViewController I import SAProfileViewController.
#import "SAProfileViewController.h"
...
-(void)goToUserProfile :(id) sender
{
UITapGestureRecognizer *gesture = (UITapGestureRecognizer *) sender;
SAProfileViewController *controller = [[SAProfileViewController alloc] init];
controller.userId = gesture.view.tag; // << HERE THE ERROR APPEARS
[self.navigationController pushViewController:controller animated:YES];
}
That's it, this is my code and I get the following error:
"Property 'userId' not found on object of type 'SAProfileViewController *'
Thanks in advance.
You have done a mistake with the property type.
Change
#property (nonatomic, assign) NSNumber *userId;
to
#property (nonatomic, retain) NSNumber *userId;
Than you have to create a NSNumber instance of gesture.view.tag like this
controller.userId = [NSNumber numberWithInteger:gesture.view.tag];
OR you can change your userId to NSInteger instead of NSNumber*
#property (nonatomic, assign) NSInteger userId;
(you have to do this for the object attribute userId, too)

Custom Annotation with a button. didSelectAnnotaionView does not seem to get called

I am having a problem with my didSelectAnnotationView getting called when I use a custom annotation view. I was hoping someone might be able to take a look and help me with what I am missing.
I actually want a method to get called when the user touches the button show in the screenshot of my custom annotation which can be seen below. I was trying to make that the calloutAccessoryView, but I am doing something wrong. Please if anyone has done custom annotation views that a user can click on please see if you can help!! This is driving me crazy. I think I have posted the relevant info here, if not ask and I will edit my post.
I am adding a custom annotation like this:
LocationObject * obj = [m_MyObject.marLocations objectAtIndex:page];
obj.title =#"A";
[mvMapView addAnnotation:obj];
My Location object used above is defined like this:
// Location Object
#interface LocationObject : NSObject <MKAnnotation>
#property (nonatomic, retain) NSString * practicename;
#property (nonatomic, retain) NSString * address1;
#property (nonatomic, retain) NSString * mapaddress1;
#property (nonatomic, retain) NSString * address2;
#property (nonatomic, retain) NSString * city;
#property (nonatomic, retain) NSString * state;
#property (nonatomic, retain) NSString * zip;
#property (nonatomic, retain) NSString * phone;
#property (nonatomic, retain) NSString * fax;
#property (nonatomic, retain) NSString * email;
#property (nonatomic, retain) NSString * longitude;
#property (nonatomic, retain) NSString * latitude;
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end // End Location Object
My viewForAnnotation does this:
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
[map.userLocation setTitle:#"I am here"];
return nil;
}
static NSString* AnnotationIdentifier = #"annotationViewID";
ViewDirectionsAnnotationView * annotationView = [[ViewDirectionsAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
int page = floor((svOfficesScrollView.contentOffset.x - svOfficesScrollView.frame.size.width / 2) / svOfficesScrollView.frame.size.width) + 1;
LocationObject * obj = [m_DentistObject.marLocations objectAtIndex:page];
double dLatitude = [obj.latitude doubleValue];
double dLongitude = [obj.longitude doubleValue];
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(dLatitude, dLongitude);
((LocationObject*)annotation).coordinate = coordinate;
annotationView.lbPracticeName.text = obj.practicename;
annotationView.lbStreet.text = obj.address1;
NSString * sCityStateZip = [NSString stringWithFormat:#"%#, %# %#", obj.city, obj.state, obj.zip];
annotationView.lbCityStateZip.text = sCityStateZip;
annotationView.lbPhoneNumber.text = obj.phone;
annotationView.canShowCallout = YES;
annotationView.annotation = annotation;
annotationView.rightCalloutAccessoryView = (UIButton *)[annotationView viewWithTag:1]; //[UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
And my Annotation View is like this:
#interface ViewDirectionsAnnotationView : MKAnnotationView
{
CLLocationCoordinate2D coordinate;
NSString * title;
NSString * subtitle;
}
#property (nonatomic, retain) IBOutlet UIView * loadedView;
#property (weak, nonatomic) IBOutlet UILabel * lbPracticeName;
#property (weak, nonatomic) IBOutlet UILabel * lbStreet;
#property (weak, nonatomic) IBOutlet UILabel * lbCityStateZip;
#property (weak, nonatomic) IBOutlet UILabel * lbPhoneNumber;
#end
And the xib for the above view looks like this:
But, my didSelectAnnotationView never gets called. Can anybody explain what I am missing?
Please, any help is appreciated this has been driving me nuts. I could have it completely wrong, but the custom view does appear so I think I am close.
Thanks for the help!!
UPDATE:
I forgot to mention about the delegate. I have checked the delegate many times and believe I have it right. In the ViewController .h file where the mapView is, I have the and I set [mapView setDelegate:self] In that same .m file is where I have implemented the viewForAnnotation method and didSelectAnnotationView. The viewForAnnotation gets called but not the other.
One more interesting piece of information is that if I click (touch) just below my custom annotation then didSelectAnnotationView does get called. I guess now I am more confused!!
UPDATE #2:
My xib is loaded this way:
In my viewForAnnotation I call initWithAnnotation. That method is as follows:
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString*)reuseIdentifier
{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self != nil)
{
[[NSBundle mainBundle] loadNibNamed:#"DirectionsAnnotation" owner:self options:nil];
if (loadedView)
{
[loadedView setFrame:CGRectMake(-(loadedView.frame.size.width/2), -(loadedView.frame.size.height), loadedView.frame.size.width, loadedView.frame.size.height)];
[self addSubview:loadedView];
}
}
return self;
}
The view which is displaying your MapView needs to be set as your delegate.
Where is your didSelectAnnotationView? Make sure that it implements the delegate protocol. E.g.
#interface MyView : UIViewController <MKMapViewDelegate>
...
#end
Then somewhere else...
[mapView setDelegate:myView];

Unrecognized selector sent to instance?

I have seen that a few others have had this problem as well.
I'm trying to follow a tutorial online that shows how to create animated pins on a MapView.
I have implemented the code as shown in the tutorial and the project builds fine except I receive this exception:
-[MKPointAnnotation iconN]: unrecognized selector sent to instance
I have a subclass of 'MKPinAnnotationView' and in the .m file I create this method:
- (void)setAnnotation:(id<MKAnnotation>)annotation {
[super setAnnotation:annotation];
//Place *place = [[Place alloc] init];
Place *place = (Place *)annotation;
//The following line is where the program sends "SIGABRT"
icon = [UIImage imageNamed:[NSString stringWithFormat:#"pin_%d.png", [place.iconN intValue]]];
[iconView setImage:icon];
}
Here are a few parts from my "model" which is called Place.h/.m.
Here is where I create the property for 'iconN'.
#property (retain, nonatomic) NSNumber *iconN;
And here I synthesize it:
#synthesize iconN = _iconN;
Any help is greatly appreciated.
EDIT:
Here is the Place.h and Place.m
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface Place : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
}
#property (retain, nonatomic) NSNumber *iconN;
#property (nonatomic, copy) NSString *title;
#property (nonatomic) CLLocationCoordinate2D coordinate;
- (id)initWithLong:(CGFloat)lon Lat:(CGFloat)lat iconNumber:(NSNumber *)iconNumber;
#end
And the Place.m
#import "Place.h"
#implementation Place
#synthesize coordinate;
#synthesize iconN = _iconN;
#synthesize title;
- (id)initWithLong:(CGFloat)lon Lat:(CGFloat)lat iconNumber:(NSNumber *)iconNumber {
self = [super init];
if (self) {
coordinate = CLLocationCoordinate2DMake(lat, lon);
self.iconN = iconNumber;
}
return self;
}
- (NSString *)title {
return [NSString stringWithFormat:#"Bus: %d", [self.iconN intValue]];
}
- (NSString *)subtitle {
return [NSString stringWithFormat:#"bus[%d] from database.", [self.iconN intValue] - 1];
}
#end
You cannot convert a MKAnnotation to a Place just by casting it. This line is wrong.
Place *place = (Place *)annotation;
You should post your Place.h and Place.m files if you're still stuck. You need to either set the iconN property on a new Place object, or create an init method in the Place class that accepts the MKAnnotation object as a parameter and sets it own internal values accordingly.
In the line
Place *place = (Place *)annotation;
has the variable place of annotation variable class (MKPointAnnotation), you are not able to bring the master class variable to a subclass in this way. Instead you'll have to make a constructor for Place from MKPointAnnotation and perform a check in the setAnnotation method that annotation is of MKPointAnnotation.
You are sending the message to the annotation but you seem to have subclasses the annotation view.
Posting as an answer what was originally just a comment:
I'm not familiar with the MapKit, but the thing that sticks out for me in this: -[MKPointAnnotation iconN]: unrecognized selector sent to instance is that the class is MKPointAnnotation. So the annotation you're receiving isn't actually a Place object, it's an MKPointAnnotation object - you can't just cast to Place. I suspect the root of your problem is where you create your annotation object in the first place.

userLocationVisble returns error

I have a mapview where i update my currentlocation with CoreLocation, but I also have checks which uses userLocation.
I still haven't found an alternative in fixing my problem
But for some reason I can't use userLocationVisible to hide the blue dot.
When I enter my MapView I start the locationManager, but before I have updated my location, the blue dot appears and my pin doesn't show up.
I've tried to use a custom MKAnnotation and init the coordinates with the newLocation from DidUpdateToLocation. But when I run this I get:
-[CustomPlacemark setCoordinate:]: unrecognized selector sent to instance 0x1de6c0
this is my CustomPlacemark:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface CustomPlacemark : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *subtitle;
-(id)initWithCoordinate:(CLLocationCoordinate2D) coordinate;
- (NSString *)subtitle;
- (NSString *)title;
#end
#import "CustomPlacemark.h"
#implementation CustomPlacemark
#synthesize coordinate;
#synthesize title, subtitle;
-(id)initWithCoordinate:(CLLocationCoordinate2D) c{
self=[super init];
if (self!=nil) {
coordinate=c;
}
return self;
}
-(NSString*)title{
return title;
}
-(NSString*)subtitle{
return subtitle;
}
-(void) dealloc
{
[title release]; title = nil;
[subtitle release]; subtitle = nil;
[super dealloc];
}
#end
Can someone also tell me why I can't use UserLocationVisible??
cordinate is read only property for customplacemark class . so u can not set cordinate property. to set cordinate property make it read and write.
change line#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
To #property (nonatomic, readwrite) CLLocationCoordinate2D coordinate;
The right way to do it will be initWithCoordinate rather than making the property readwrite
The blue dot appears when you set showsUserLocation=YES; If you want to hide the blue dot, set this to NO. Alternatively, you can determine if the user's location is visible on the screen using CoreLocation and enable showsUserLocation to YES.
Also, the blue dot is a special annotation class MKUserLocation that conforms to MKAnnotation protocol. If you are sending any messages to annotation objects that are your own class, you may want to exclude MKUserLocation annotation object.
If you want to know how to specifically deal with your custom annotation objects without sending incorrect messages to MKUserLocation class, let me know, I have the code that I can send.