How to get associated object from another class
My code is :
#import <UIKit/UIKit.h>
static char NUMBER ='a';
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
#implementation Person
- (instancetype)init
{
self = [super init];
if (self) {
NSNumber *num=#10;
objc_setAssociatedObject(self, &NUMBER, num, OBJC_ASSOCIATION_RETAIN);
}
return self;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *p=[[Person alloc]init];
NSNumber *num=objc_getAssociatedObject(p, &NUMBER);
NSLog(#"%#",num);
}
#end
NSLog(#"%#",num) is null.
Why can't I get the associated object from the above code. Can't we get the associated object from another class ? Thank you!
Problem is in your key. You probably define this classes in different files. Do not use static keyword, static variables can only be accessed within a single translation unit. This means you have new copy of NUMBER for each file. Remove static keyword and add extern declaration in Person.h header:
Person.h:
extern const char NUMBER;
#interface Person : NSObject
#end
Person.m:
#import "Person.h"
#import "objc/runtime.h"
const char NUMBER ='a';
#implementation Person
- (instancetype)init
{
self = [super init];
if (self) {
NSNumber *num = #10;
objc_setAssociatedObject(self, &NUMBER, num, OBJC_ASSOCIATION_RETAIN);
}
return self;
}
#end
ViewController.m:
#import "Person.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = [[Person alloc]init];
NSNumber *num = objc_getAssociatedObject(p, &NUMBER);
NSLog(#"%#",num);
}
#end
Related
I have a superclass called SuperClass a read-only property. That looks like this:
#property (nonatomic, strong, readonly) NSArray *arrayProperty;
In a subclass I need an initializer that takes a instance of SuperClass as a parameter:
- (instancetype)initWithSuperClass:(SuperClass *)superClass
I created a GitHub sample project that shows what the problem is: https://github.com/marosoaie/Objc-test-project
I cannot do _arrayProperty = superClass.arrayProperty in the initializer.
I want to keep the property read-only in SubClass as well.
Any ideas on how this could be solved?
I know I could declare the property as readwrite in a class extension inside the SubClass implementation file, but I'm hoping that there's a better solutions than this.
Edit:
SuperClass.h
#import <Foundation/Foundation.h>
#interface SuperClass : NSObject
- (instancetype)initWithDictionary:(NSDictionary *)dictionary;
#property (nonatomic, strong, readonly) NSString *stringProperty;
#property (nonatomic, strong, readonly) NSArray *arrayProperty;
#end
SuperClass.m
#import "SuperClass.h"
#implementation SuperClass
- (instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self) {
_arrayProperty = dictionary[#"array"];
_stringProperty = dictionary[#"string"];
}
return self;
}
#end
SubClass.h:
#import <Foundation/Foundation.h>
#import "SuperClass.h"
#interface SubClass : SuperClass
#property (nonatomic, strong, readonly) NSString *additionalStringProperty;
- (instancetype)initWithSuperClass:(SuperClass *)superClass;
#end
SubClass.m:
#import "SubClass.h"
#implementation SubClass
#synthesize additionalStringProperty = _additionalStringProperty;
- (NSString *)additionalStringProperty
{
if (!_additionalStringProperty) {
NSMutableString *mutableString = [[NSMutableString alloc] init];
for (NSString *string in self.arrayProperty) {
[mutableString appendString:string];
}
_additionalStringProperty = [mutableString copy];
}
return _additionalStringProperty;
}
- (instancetype)initWithSuperClass:(SuperClass *)superClass
{
self = [super init];
if (self) {
// Doesn't work
// _stringProperty = superClass.stringProperty;
// _arrayProperty = superClass.arrayProperty;
}
return self;
}
#end
You already exposed an initializer, that writes to that readonly property -initWithDictionary:. Call that in your SubClass, instead [super init]:
- (instancetype)initWithSuperClass:(SuperClass *)superClass {
NSDictionary *dict = #{
#"array": superClass.arrayProperty,
#"string": superClass.stringProperty,
};
self = [super initWithDictionary:dict];
if (self) {
// Nothing here.
}
return self;
}
It’s quite common to have an initializer for readonly properties, although using dictionary is not that good solution. Typically, I would create:
- (instancetype)initWithArray:(NSArray *)array string:(NSString *)string;
First of all, there is a bug in your test setup: Your key in - (instancetype)initWithDictionary:(NSDictionary *)dictionary is #"array", where the array contains #"arrayProperty".
Regarding your problem:
//...
#interface SuperClass : NSObject
{
#protected // this is what you want: a protected class property, accessible in subclasses, but no where else
NSString *_stringProperty;
NSArray *_arrayProperty;
}
#property (nonatomic, strong, readonly) NSString *stringProperty;
#property (nonatomic, strong, readonly) NSArray *arrayProperty;
- (instancetype)initWithDictionary:(NSDictionary *)dictionary;
#end
// SubClass.m
//...
#implementation SuperClass
- (instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self) {
_arrayProperty = dictionary[#"arrayProperty"]; // this was #"array", so could not work
_stringProperty = dictionary[#"stringProperty"]; // same here
}
return self;
}
#end
Then it works. In addition, I would write
#interface SubClass ()
#property (nonatomic, strong, readwrite) NSString *additionalStringProperty;
#end
#implementation SubClass
- (instancetype)initWithSuperClass:(SuperClass *)superClass
{
self = [super init];
if (self) {
_stringProperty = superClass.stringProperty;
_arrayProperty = superClass.arrayProperty;
}
return self;
}
because I prefer the readwrite property in a class extension over the #synthesize magic. But this is a personal opinion.
One main issue regarding to class design still holds: What happens if (similar to your test setup) the dictionary of the superclass does not contain the key? Then it won't be initialized, which is not a good idea, because you expect them to be initialized. So you should check in the subclass if superclass.stringProperty is not nil and add a standard constructor for the superclass to avoid that the two dictionaries are uninitialized.
In your SuperClass.m:
- (instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self) {
// these were always nil, check your dictionary keys
_arrayProperty = dictionary[#"arrayProperty"];
_stringProperty = dictionary[#"stringProperty"];
}
return self;
}
In your SubClass.m:
#interface SubClass ()
#property (strong, nonatomic) NSString * additionalStringProperty;
#property (strong, nonatomic) NSString * subClassString;
#property (strong, nonatomic) NSArray * subClassArray;
#end
#implementation SubClass
- (instancetype)initWithSuperClass:(SuperClass *)superClass
{
self = [super init];
if (self) {
_subClassString = superClass.stringProperty;
_subClassArray = superClass.arrayProperty;
}
return self;
}
I tried the answers here to no avail. What ended up working for me was this answer which mentions that you should directly access the member variable (after declaring it as protected) like so:
self->_stringProperty = #"some string";
I've searched all over google, and stack overflow for a solution, but I wasn't able to find an answer that solved my problem. Sorry for the long post, as I'm trying to give as much information as I can. I'm new to iOS and Objective- c, but not programming in general due to being asked to switch over from Android by my company, so any help is appreciated.
I'm trying to assign a value to an NSString in one class from a TextField in another, but I get the error:
**-[ViewController name:]: unrecognized selector sent to instance 0x78712fe0**
when I run the app in the simulator.
Relevant code:
//UserInfo.h
#import <Foundation/Foundation.h>
#interface UserInfo : NSObject <NSCoding>
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *age;
#property (nonatomic, strong) NSString *address;
#end
//UserInfo.m
#import "UserInfo.h"
static NSString *nameKey = #"userName";
static NSString *ageKey = #"userAge";
static NSString *addressKey = #"userAddress";
static NSString *userInfoKey = #"userInfoKey";
#implementation UserInfo
#synthesize name;
#synthesize age;
#synthesize address;
- (id) initWithCoder:(NSCoder *)coder
{
self = [super init];
self.name = [coder decodeObjectForKey:nameKey];
self.age = [coder decodeObjectForKey:ageKey];
self.address = [coder decodeObjectForKey:addressKey];
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:self.name forKey:nameKey];
[coder encodeObject:self.age forKey:ageKey];
[coder encodeObject:self.address forKey:addressKey];
}
#end
//ViewController.h
#import <UIKit/UIKit.h>
#import "UserInfo.h"
#interface ViewController : UIViewController <UITextFieldDelegate, UITextViewDelegate, NSCoding>
#property (nonatomic, strong) UserInfo *userInfoObject;
#property (nonatomic, weak) IBOutlet UILabel *titleLabel;
#property (nonatomic, weak) IBOutlet UILabel *nameLabel;
#property (nonatomic, weak) IBOutlet UILabel *ageLabel;
#property (nonatomic, weak) IBOutlet UILabel *addressLabel;
#property (nonatomic, weak) IBOutlet UITextField *nameText;
#property (nonatomic, weak) IBOutlet UITextField *ageText;
#property (nonatomic, weak) IBOutlet UITextField *addressText;
#property (nonatomic, weak) IBOutlet UIButton *saveBtn;
- (IBAction)saveBtnTouched:(id)sender;
- (void) saveUserInfo;
- (void) loadUserInfo;
- (void) setUserInterfaceValues;
- (IBAction)nameText:(id)sender;
- (IBAction)ageText:(id)sender;
- (IBAction)addressText:(id)sender;
#end
//ViewController.m
#import "ViewController.h"
#import "UserInfo.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize titleLabel;
#synthesize nameLabel;
#synthesize ageLabel;
#synthesize addressLabel;
#synthesize nameText;
#synthesize ageText;
#synthesize addressText;
#synthesize saveBtn;
static NSString *userInfoKey = #"userInfoKey";
- (void)viewDidLoad {
[super viewDidLoad];
[self loadUserInfo];
if(!self.userInfoObject)
{
self.userInfoObject = [[UserInfo alloc] init];
}
[self setUserInterfaceValues];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
self.saveBtn.enabled = YES;
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField*)textField
{
return YES;
}
- (BOOL) textFieldShouldEndEditing:(UITextField *)textField
{
[self.nameText resignFirstResponder];
[self.ageText resignFirstResponder];
[self.addressText resignFirstResponder];
return YES;
}
- (IBAction)saveBtnTouched:(id)sender
{
NSLog(#"%# was entered into the name field", self.nameText.text);
NSLog(#"%# was entered into the age field", self.ageText.text);
NSLog(#"%# was entered into the address field", self.addressText.text);
[self textFieldShouldEndEditing:self.nameText];
[self textFieldShouldEndEditing:self.ageText];
[self textFieldShouldEndEditing:self.addressText];
self.userInfoObject.name = self.nameText.text;
self.userInfoObject.age = self.ageText.text;
self.userInfoObject.address = self.addressText.text;
[self saveUserInfo];
self.saveBtn.enabled = NO;
}
- (void)saveUserInfo
{
NSData *userInfoData = [NSKeyedArchiver archivedDataWithRootObject:self.userInfoObject];
[[NSUserDefaults standardUserDefaults] setObject:userInfoData forKey:userInfoKey];
}
- (void)loadUserInfo
{
NSData *userInfoData = [[NSUserDefaults standardUserDefaults] objectForKey:userInfoKey];
if(userInfoData)
{
self.userInfoObject = [NSKeyedUnarchiver unarchiveObjectWithData:userInfoData];
}
}
- (void) setUserInterfaceValues
{
self.nameText.text = self.userInfoObject.name;
self.ageText.text = self.userInfoObject.age;
self.addressText.text = self.userInfoObject.address;
}
- (IBAction)nameText:(id)sender {
}
- (IBAction)ageText:(id)sender {
}
- (IBAction)addressText:(id)sender {
}
#end
//AppDelegate.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#import "UserInfo.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController *viewController;
#end
//AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
#import "UserInfo.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
//all the other generated methods. Taken out due to space.
#end
Three breakpoints are set that are supposidly the source of the problem:
From the ViewController.m, in - (void)setUserInterfaceValues
self.nameText.text = self.userInfoObject.name;
(I assume that this applies to the other two lines below it also)
Also from the ViewController.m, in - (void)viewDidLoad
[self setUserInterfaceValues];
And finally from the AppDelegate.m, in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
self.window.rootViewController = self.viewController;
From what I understand, and have learned from searching this issue, the app is trying to send data to something that doesn't exist, the NSString name being the culprit. Others have suggested to make sure that my .xib file is connected to the ViewController, and I have verified that it is.
As another bit of information, I'm not using a storyboard for this app, and instead am using the interface builder. I'm aware that there are advantages to storyboards, and I would like to be using them, but my company uses the interface builder and does a lot of things programmatically, so I'm learning to develop without.
[EDIT]: Issue solved thanks to Ian.
I have a class
#interface AppRecord : NSObject
#property (nonatomic, retain) NSString * urlSingle;
#property (nonatomic, retain) NSArray * image_url;
#end
It is included in another class
#class AppRecord;
#interface IconDownloader : NSObject
#property (nonatomic, strong) AppRecord *appRecord;
#end
This is my root view controller
#import "IconDownloader.h"
#implementation RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageDownloadsInProgress = [NSMutableDictionary dictionary];
}
- (void)startIconDownload:(AppRecord *)appRecord forIndexPath:(NSIndexPath *)indexPath
{
IconDownloader *iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[IconDownloader alloc] init];
int imgArrCount=[appRecord.image_url count];
NSLog(#"Image array is********************** %#",appRecord.image_url);
for(int i=0;i<imgArrCount;i++)
{
iconDownloader.appRecord.urlSingle=[appRecord.image_url objectAtIndex:i];
NSLog(#"iconDownloader.appRecord.urlSingle---------------------%#",iconDownloader.appRecord.urlSingle);
}
}
}
#end
Can i assign iconDownloader.appRecord.urlSingle here, I am having null value.Please help.
This has nothing to do with forward declaration. When you forward declare a class, you should #import the .h file before using any of the class properties/methods.
The problem is property appRecord in iconDownloader is not created yet and hence is nil. In your code you should do this.
- (void)startIconDownload:(AppRecord *)appRecord forIndexPath:(NSIndexPath *)indexPath
//...
for(int i=0;i<imgArrCount;i++)
{
// First assign to the property so that it is not nil
iconDownloader.appRecord = appRecord;
// If required then make this assignment
iconDownloader.appRecord.urlSingle=[appRecord.image_url objectAtIndex:i];
}
//...
}
Alternately, you can also override the init in IconDownloader class and create the appRecord property inside it, so that it is not nil when you are assigning values.
Hope that helps!
You didnt initializing the appRecord object. thats why you get null value. Just initialize appRecord in your init method like:
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
appRecord = [[AppRecord alloc]init];
}
return self;
}
Similiarly you have to initialize the urlSingle variable inside the init definition:
-(id)init
{
self = [super init];
if (self) {
urlSingle = URL_STRING_HERE;
}
return self;
}
Now you try
I have an array, players, with two strings inside it: player1 and player2. Here is my .h file:
#import <UIKit/UIKit.h>
#interface hardOne : UIViewController {
UISwitch *hard1ON;
NSMutableArray *players;
NSString *player1, *player2;
}
#property (nonatomic, retain) IBOutlet UISwitch *hard1ON;
#property (nonatomic) BOOL switchState;
#property (nonatomic, retain) NSMutableArray *players;
- (IBAction) switchValueChanged;
#end
The array is initialized in the viewDidLoad then the data is entered into that array in two IBActions in my .m file:
#import "hardOne.h"
#interface hardOne () <UITextFieldDelegate>
#property (nonatomic, strong) IBOutlet UITextField *textFieldOne;
#property (nonatomic, strong) IBOutlet UITextField *textFieldTwo;
#end
#implementation hardOne
#synthesize hard1ON;
#synthesize players;
#synthesize textFieldOne;
#synthesize textFieldTwo;
BOOL switchState;
int counter = 0;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[hard1ON setOn:switchState animated:NO];
//read player names to user defaults
[textFieldOne setText:[[NSUserDefaults standardUserDefaults] stringForKey:#"player1"]];
[textFieldTwo setText:[[NSUserDefaults standardUserDefaults] stringForKey:#"player2"]];
self.players = [[NSMutableArray alloc] init];
NSLog(#"%#",self.players);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction) switchValueChanged
{
counter += 1;
if (counter % 2 == 0) {
switchState = 0;
} else {
switchState = 1;
}
if (hard1ON.on) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"theChange" object:nil];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:#"theChange2" object:nil];
}
}
- (IBAction) returnKey1
{
player1 = [textFieldOne text];
[self.players addObject:(player1)];
//set player1's name to user defaults
[[NSUserDefaults standardUserDefaults] setValue:[textFieldOne text] forKey:#"player1"];
}
- (IBAction) returnKey2
{
player2 = [textFieldTwo text];
[self.players addObject:(player2)];
//set player2's name to user defaults
[[NSUserDefaults standardUserDefaults] setValue:[textFieldTwo text] forKey:#"player2"];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
#end
If I use NSLog in the second IBAction, once it is complete, the array is correctly displayed in the console with the strings player1 and player2, however if I try to use the array anywhere else it is null. Could anyone point me in the right direction?
You've got two definitions for players.
One is a property. It's never initialized and so it's null. You use it as self.players and backed by the instance variable _players.
One is an instance variable. It's initialized in viewDidLoad. It's not nil.
This is almost surely a mistake.
I would try adding the array as a private instance variable i.e add it to the .m file in the #interface with
NSMutableArray *players;
then you should be able to access the array just by using "players" instead of self.players. This should be then be available throughought the whole of your class. If this doesn't work then I would say the problem doesn't lie within the scope of your variable but rather the with some other code.
I have followed this tutorial:
http://www.shawngrimes.me/2011/04/custom-map-pins-for-mapkit/#comment-193
but I can't add a title and description
(see my code here http://pastebin.com/03mDLc9q)
You are trying to set name and description as properties of your annotation's view, you should be using title and subtitle on your annotation object - MyAnnotationClass, the annotation view will use title and subtitle of this object when the callout is rendered.
I changed your code to work here: http://pastebin.com/YRGYhQev
#interface MyAnnotationClass : NSObject<MKAnnotation>
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *subtitle;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
-(id) initWithCoordinate:(CLLocationCoordinate2D) coordinate;
#end
MyAnnotationClass.m
#import "MyAnnotationClass.h"
#implementation MyAnnotationClass
-(id) initWithCoordinate:(CLLocationCoordinate2D) coordinate{
self=[super init];
if(self){
_coordinate = coordinate;
}
return self;
}
-(void) dealloc{
[_title release];
[_subtitle release];
[super dealloc];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController<MKMapViewDelegate> {
IBOutlet MKMapView *_myMapView;
NSArray *_myAnnotations;
}
#property (nonatomic, retain) NSArray *myAnnotations;
#property (nonatomic, retain) IBOutlet MKMapView *myMapView;
#end
ViewController.m
#import "ViewController.h"
#import "AppDelegate.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "PlaceMark.h"
#import "MyAnnotationClass.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize myMapView = _myMapView;
#synthesize myAnnotations = _myAnnotations;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(void) viewDidLoad{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
//Initialize annotation
MyAnnotationClass *commuterLotAnnotation=[[MyAnnotationClass alloc] initWithCoordinate:CLLocationCoordinate2DMake(appDelegate.latitude , appDelegate.longitude)];
commuterLotAnnotation.title = #"Hello title";
commuterLotAnnotation.subtitle = #"Correct";
MyAnnotationClass *overflowLotAnnotation=[[MyAnnotationClass alloc] initWithCoordinate:CLLocationCoordinate2DMake(appDelegate.latitude , appDelegate.longitude)];
overflowLotAnnotation.title = #"Hello title";
overflowLotAnnotation.subtitle = #"Correct";
//Add them to array
self.myAnnotations=[NSArray arrayWithObjects:commuterLotAnnotation, overflowLotAnnotation, nil];
//Release the annotations now that they've been added to the array
[commuterLotAnnotation release];
[overflowLotAnnotation release];
//add array of annotations to map
[_myMapView addAnnotations:_myAnnotations];
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{
static NSString *parkingAnnotationIdentifier=#"ParkingAnnotationIdentifier";
if([annotation isKindOfClass:[MyAnnotationClass class]]){
//Try to get an unused annotation, similar to uitableviewcells
MKAnnotationView *annotationView=[_myMapView dequeueReusableAnnotationViewWithIdentifier:parkingAnnotationIdentifier];
//If one isn't available, create a new one
if(!annotationView){
annotationView=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:parkingAnnotationIdentifier];
//Here's where the magic happens
annotationView.image=[UIImage imageNamed:#"apple.gif"];
annotationView.canShowCallout = YES;
}
return annotationView;
}
return nil;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
I see that the tutorial has the MyAnnotationClass interface as:
#interface MyAnnotationClass : NSObject
When I used MKAnnotation I set my annotation interface up as:
#interface MyAnnotationClass : MKAnnotationView <MKAnnotation>
Then in the MyAnnotationClass.m file I have the following methods:
- (NSString *)title{
return self.name;
}
- (NSString *)subtitle{
return self.description;
}