views:

2831

answers:

3

I've boiled a very complex set of web services and searches down to the simple following code. I need to be able to add annotations to a map in response to a search (or in the sample below to the click of a button), then allow the user to click the button again and get a new set of results. In reality there will be a different number, but in the simplified example, we always add one annotation to the mapview. I believe my code should remove the existing annotations and add a new one, but it leaks 32 bytes on second and subsequent button pushes. What am I missing ? (Or retaining as the case may be!)

testViewController.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "MyMark.h"

@interface testViewController : UIViewController  {
    MKMapView *mapView;
}

@end

testViewController.m

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        // Custom initialization
     self.title=@"test";
    }
    return self;
}

- (void) storeLocationInfo: (CLLocationCoordinate2D) loc title:(NSString *)t subtitle:(NSString *)st index:(int)i {
    NSArray * annotations = [mapView annotations];
    [mapView removeAnnotations:annotations];

    MyMark * mymark=[[MyMark alloc] initWithCoordinate:loc];
    [mapView addAnnotation:mymark];
    [MyMark release];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithTitle:@"Add point to map" style:UIBarButtonItemStylePlain target:self action:@selector(addPushed)];
    [self.navigationItem setRightBarButtonItem:barButton];
    [barButton release];

    mapView=[[MKMapView alloc] initWithFrame:CGRectMake(0.0,0.0,self.view.frame.size.width,self.view.frame.size.height)];
    mapView.showsUserLocation=FALSE;
    mapView.delegate=self;
    [self.view insertSubview:mapView atIndex:0];
    [mapView release];
}

- (void) addPushed {
    MKCoordinateRegion reg = mapView.region;
    [self storeLocationInfo:reg.center title:@"price" subtitle:@"title" index:1];
}

- (void)dealloc {
    [super dealloc];
}

MyMark.h

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


@interface MyMark : NSObject<MKAnnotation> {
    CLLocationCoordinate2D coordinate;
    NSString * title;
    NSString * subtitle;
    int index;
}
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, readonly) int index;
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSString * subtitle;
-(id)initWithCoordinate:(CLLocationCoordinate2D) coordinate;
-(id)setCoordinate:(CLLocationCoordinate2D) coordinate;
-(id)setTitle:(NSString *)t subtitle:(NSString *)st index:(int)i ;

@end

MyMark.m

#import "MyMark.h"


@implementation MyMark
@synthesize coordinate, index;
@synthesize title,subtitle;

-(id)initWithCoordinate:(CLLocationCoordinate2D) c{
    coordinate=c;
    NSLog(@"%f,%f",c.latitude,c.longitude);
    return self;
}

-(id)setCoordinate:(CLLocationCoordinate2D) c{
    coordinate=c;
    NSLog(@"%f,%f",c.latitude,c.longitude);
    return self;
}

-(id)setTitle:(NSString *)t subtitle:(NSString *)st index:(int) i{
    self.title=t;
    self.subtitle=st;
    index=i;
    return self;
}

-(void) dealloc {
    [title release];
    [subtitle release];
    [super dealloc];
}
A: 

The procedure below fixed the issue - but it was fixing the symptom, not the cause. As it was being marked down (rightly so) I've removed it.

Andiih
I'm confused by this. The annotation creation looks OK - the alloc/release is balanced there. However, in the removal code, you have a for loop that does a release on each annotation, but there's no matching retain. Indeed, if I try this as-is, I get an exception when removeAllObjects: is invoked. Reason: NSMutableArray tries to release each object, but the memory has already been freed. If I remove the for loop, and just call removeAllObjects:, the memory is freed and deallocated. So now I'm wondering - where is the original leak you speak of?
Joe D'Andrea
Thanks. I'm confused too - because the above doesn't crash for me, and without the [annotation release] it does leak. This must be being caused by an error elsewhere somehow. I will isolate into a standalone project and re-test.
Andiih
See will harris answer above. The error was in the store location info rather than the release mechanism. My code here just bodged the earlier error. A good spot
Andiih
+2  A: 

You're not releasing mymark in storeLocationInfo:title:subtitle:index:. It looks like the problem is a typing error. The line that reads

[MyMark release];

should be

[mymark release];

Note the case difference. The first line sends release to the class, not the instance.

Will Harris
OMG you are right. Slaps self on head. Quite hard.
Andiih
A: 

I am also, working on same kind of applications. Initially I will load all locations. I have two buttons say "Show nearest location" and "show all". What I am doing is:

Show Nearest One: 1. removing all locations and adding nearest location again on map.

Show All: 1. removing nearest one from map and adding all locations.

The Problem is:

intially when map view is loading for all location "viewForAnnations" delegate function is geting called, but when I trying to add locations on button click, it is not getting called. So when we click on right accessory button, it showing different values..

Please help me.

The solution needed is "removing and re adding the annotations, with out any data lose/errors".

Shiva
Id add this as a question, not an answer
Andiih