CLLocation memory issues - iphone

I've some memory issues with CLLocation.
CLLocation *annotation = [[CLLocation alloc] initWithLatitude:[[tempDict objectForKey:#"lat"] doubleValue] longitude:[[tempDict objectForKey:#"lon"]doubleValue]];
CLLocation *item2 = [[CLLocation alloc] initWithLatitude:[newLatString doubleValue] longitude:[newLongString doubleValue]];
cell.detailTextLabel.text = [NSString stringWithFormat:#"%.1f km",[item2 distanceFromLocation:annotation]/1000];
[annotation release];
[item2 release];
So I tried to do this, but I realised that you can't set the annotation's coordinate.
CLLocationCoordinate2D tempCoordinate = annotation.coordinate;
tempCoordinate.latitude = [[tempDict objectForKey:#"lat"] doubleValue];
tempCoordinate.longitude = [[tempDict objectForKey:#"lon"] doubleValue];
annotation.coordinate = tempCoordinate;
Is there a workaround this? I don't want to be alloc/initing a CLLocation everytime cellForRowAtIndexPath is called..

your resultant object is an NSString - just create a class which contains an NSString, as well as references/ivars of the intermediate data where necessary. then using an observer idiom, just update the cells when the string changes (design it so the string depends on the coordinates). you could probably make a class which takes a set of arguments at initialization (e.g. coordinates), creates an NSString during initialization, and then refer to the result if your data never changes. it really depends on what data you expect will mutate, and at what frequency.

I don't want to be alloc/initing a
CLLocation everytime
cellForRowAtIndexPath is called..
Why not? Do you know it's causing performance problems? You're releasing them right away, so they aren't taking up extra memory. CLLocation looks like a pretty lightweight class, and the Objective-C runtime is heavily optimized, so they probably alloc / init pretty quickly. Until you see scrolling / perf / memory issue, I would go with what works and is easy to maintain.
Premature optimization is the root of all evil - Donald Knuth

Related

Only the last value of NSMutableDictionary is added to NSMutableArray

I have tried my best to search for the answers to add NSMutableDictionary to NSMutableArray. Unfortunately, they all asked me to use "[allValues]" which is not what I want.
Here is the issue,
In the header file, I defined,
NSMutableArray *arData;
And in the m file,
arData = [[NSMutableArray alloc] init];
NSMutableDictionary *mutableDictionary5 = [[NSMutableDictionary alloc]init];
for (i=0;i<[[[self rssParser]rssItems]count];i++)
{
Lat = [[[[[self rssParser]rssItems]objectAtIndex:i]lat] doubleValue];
Lng = [[[[[self rssParser]rssItems]objectAtIndex:i]lng] doubleValue];
// Creates a marker in the center of the map.
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(Lat, Lng);
marker.title = [[[[self rssParser]rssItems]objectAtIndex:i]header];
[mutableDictionary5 setObject:marker.title forKey:#"title"];
[arData setValue:[mutableDictionary5 valueForKey:#"title"] forKey:#"title"];
}
The "arData" only gets the last value of [[[[self rssParser]rssItems]objectAtIndex:i]header].And I am sure mutableDictionary5 gets all the value since I have put the following at the end of the code,
NSLog(#"mutableDictionary5 values=%#",[mutableDictionary5 allValues]);
It prints all the value of the title.
I understand it shouldn't be setvalue, however, I tried to use [mutableDictionary5 allValues], "addobjects", "allkeys". They are not working. What should I do to let the NSMutableArray arData to add all values of title with "title" as the key? thanks.
Sorry for my bad English which is not my native language.
You erroneously use setValue instead of addObject.
[arData addObject:mutableDictionary5];
This will work if you alloc init a new dictionary inside the loop.
If you want to reduce the array to just titles do this after the loop:
NSArray *titleArray = [arData valueForKeyPath:#"title"];
Now you have an array containing just titles.
BTW, you could make some effort to invent better variable names. Note that by convention in Objective-C variable names start with low cap while class names are capitalized.

Memory leak when using CLLocationCoordinate2D

I am using a NSMutableArray to hold CLLocationCoordinate2D values. After testing for a few mins I found the app crashing. I found heavy memory leaks associated with both the array and CLLocationCoordinate2D values.
Here is the code:
NSMutableArray *arrayReturn = [[NSMutableArray alloc] init];
CLLocationCoordinate2D obj1 = CLLocationCoordinate2DMake(37.6085289,107.5941445);
CLLocationCoordinate2D obj2 = CLLocationCoordinate2DMake(27.1727738,78.041655);
[arrayReturn addObject:[NSValue valueWithBytes:&obj1 objCType:#encode(CLLocationCoordinate2D)]];
[arrayReturn addObject:[NSValue valueWithBytes:&obj2 objCType:#encode(CLLocationCoordinate2D)]];
return [arrayReturn autorelease];
I am creating several objects like this and adding it to the array. Even though I have tagged an autorelease at the end, I have heavy memory leaks in the array.
What am I doing wrong here?
A CLLocationCoordinate2D is a simple struct of 2 double values and not an NSObject!
You allocate the CLLocationCoordinate2D on the stack and pass pointers to that data in the NSValue objects. But the stack memory will be not available after the method returns. This is why your app crashes.
You need to convert the CLLocationCoordinate2D into NSObjects somehow.
For example like this:
NSArray* coords = [NSArray arrayWithObjects:[NSNumber numberWithDouble:obj1.latitude], [NSNumber numberWithDouble:obj1.longitude], nil];

Iphone CLLocationCoordinate2D

I am new at iphone and I have a problem.
I have this code
for (int i=0; i<2; i++) {
Datos *datos = (Datos *)[arr_datos objectAtIndex:i];
CLLocationCoordinate2D coord;
AnnotationItem *annotationItem = [[AnnotationItem alloc] init];
coord.latitude =[datos.latitud doubleValue];
coord.longitude = [datos.longitud doubleValue];
NSLog(#"coord %f",coord.longitude);
NSLog(#"coord %f",coord.latitude);
[annotationItem setCoordinate:coord];
//[annotationItem setEstacion:estacion];
[mapView_ addAnnotation:annotationItem];
[annotationItem release];
}
The problem that it doesn't done anything
But if i change the coord.latitude=40.444 and coord.longitude=-3.700;
this gives me what I want, but I don't want this, because I have an array with many latitudes and longitudes. Can anyone help me with this? when i put coord.longitude=[datos.longitude floatValue];, it doesn't work?
I'm using Xcode 3.2.2
Thanks and forgive me english.
The problem is that i had change the values, I was putting wrong values. Only I have to do is change the
coord.latitude =[datos.longitud doubleValue];
coord.longitude = [datos.latitud doubleValue];
thank everyone for your time.
It seems like Datos is an object you defined since i couldn't find it in the SDK. Given that it could be a few different things:
Either that arr_datos does not have the correct (or any) data inside of it
It could be that the Datos object is incorrectly handling data passed into it and not storing it correctly.
Place a breakpoint in Xcode and verify that arr_datos has the information you think inside of it and that the datos object is correctly storing information.
CLLocationCoordinate2D is not an object so declare it like:
CLLocationCoordinate2D coord;
BTW, you should be getting warnings about CLLocationCoordinate2D *coord - can you check your compiler logs?
[suggestion1]
NSLog(#"datos.lon %#", datos.longitud);
NSLog(#"datos.lat %#", datos.latitud);
[/suggestion1]
[suggestion2]
Note too that you can iterate through all of your datos_arr with the following:
for(Datos *datos in datos_arry) {
NSLog(.....);
}
[/suggestion2]

EXC_BAD_ACCESS signal received

I am getting a EXC_BAD_ACCESS signal when calling the following line:
self.distance = [NSNumber numberWithDouble:[currentLocation distanceFromLocation: self.location]];
This is only happening in iOS 3.2 for iPad,
I know this is a memory issue but i can't seem to see what is wrong with the above line?
edit: here is the full method:
-(void)updateDistance:(CLLocation *)currentLocation {
self.distance = [NSNumber numberWithDouble:[currentLocation distanceFromLocation:self.location]];
placeWrapper.distance = self.distance;
}
which is called like so:
[place updateDistance:self.currentLocation];
self.currentLocation is created here:
CLLocation *location = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude];
self.currentLocation = location;
[location release];
Another edit :)
here is the stack trace: http://pastie.org/1222992
Run your code with NSZombieEnabled set. This should tell you if you are over releasing or under retaining somewhere.
It's difficult to say without demonstrating where/how you're creating "currentLocation", "location", or possibly even "self". I'm guessing either currentLocation or self.location are not properly retained on creation/setting.
You need to retain something...
[currentLocation retain]
or
[self.location retain];
but you have to do it further up the code. Something's getting "forgotten" or goes "out of scope" so try those retains.
DON'T FORGET TO RELEASE WHATEVER IT IS THAT YOU'RE RETAINING.

Class initialization breaking application

I've recently created a new class for my iPhone application which will hold information read from a text file containing the street address and GPS points of points of interest.
The issue though is that whenever I add code to initialize the class my application loads up and the instantly quits with no errors in the console. When I remove it, everything is fine. I simply cannot see anything wrong with the code.
Here is the constructor:
#import "GPSCoordinate.h"
#implementation GPSCoordinate
-(GPSCoordinate*) initWithData:(NSString *)rawData size:(int)size
{
self = [super init];
location = [NSMutableArray arrayWithCapacity:size];
coordinates = [NSMutableArray arrayWithCapacity:(int)size];
NSArray *tokens = [rawData componentsSeparatedByString:#"#"];
for (int i = 0; i < size - 1; i++) {
//Sub tokens
NSString *line = [tokens objectAtIndex:i];
NSArray *lineTokens = [line componentsSeparatedByString:#":"];
//Store address
[location addObject:[lineTokens objectAtIndex:0]];
//Store GPS coords
NSString *coords = [lineTokens objectAtIndex:1];
coords = [[coords stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:#""]
stringByReplacingCharactersInRange:NSMakeRange([coords length]-2, 1) withString:#""];
NSArray *coordsTokens = [coords componentsSeparatedByString:#" "];
CLLocationCoordinate2D coord;
coord.latitude = [[coordsTokens objectAtIndex:0] doubleValue];
coord.longitude =[[coordsTokens objectAtIndex:1] doubleValue];
[coordinates addObject:coords];
[line release];
[lineTokens release];
[coords release];
[coordsTokens release];
}
return self;
}
#end
Here is the call I make to it in another class:
self.gps = [[GPSCoordinate alloc] initWithData:gpsRawData size:[[gpsRawData componentsSeparatedByString:#"#"] count]];
Where am I going wrong with this?
I see a number of problems.
You're not checking the return value of [super init].
You're storing autoreleased arrays in what are presumably ivars (location and coordinates).
You're passing a separate size parameter which is calculated from the rawData outside of the call, but -initWithData: makes the exact same calculation inside the method. The size: parameter seems completely superfluous here.
You're skipping the last token entirely. You should take that for loop and make the condition simply i < size. Alternately if you're targetting iOS 4.0 or above you can turn the entire loop into
[tokens enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
NSString *line = obj;
// rest of loop body
}];
Since you don't seem to need the index inside the loop, you could also just use a for-in loop (this will work on pre-4.0 iOS devices):
for (NSString *line in tokens) {
// body of loop
}
You're not checking that your data is valid. If a line contains "foo", your program will crash when it tries to access [lineTokens objectAtIndex:1]. Similarly it'll crash if you have the string "foo:" as it tries to remove the first character of the coordinates variable. In fact anything less than 2 characters after the colon will crash. It'll also crash if there's no spaces after the colon.
And finally, all those calls to -release at the end will crash. All 4 of those objects are autoreleased objects, so by calling -release on them now you're simply guaranteeing that the app will crash when the autorelease pool is drained.
You're also storing coords (e.g. the string) in your coordinates array. Presumably you meant to store coord, though you'll need to wrap it in an NSValue in order to store it in an NSArray.
I see several issues.
1) Most fundamentally, you are releasing a lot of objects that you didn't allocate. For example:
NSString *line = [tokens objectAtIndex:i];
....
[line release];
is incorrect. Review the Cocoa Memory Management Rules.
2) Why are you doing [[gpsRawData componentsSeparatedByString:#"#"] count to pass the size to
your initWithData:size: method, when you're just going to have to repeat the -componentsSeparatedByString: call inside your method. Passing a separate "size" doesn't gain you anything, involves a redundant parse of the input, and opens up more possible bugs (what if the caller passes in a "size" that doesn't match the number of "#"s in the input - you aren't handling that error condition).
3) I also see that you are assigning latitude/longitude to CLLocationCoordinate2D coord; but not doing anything with it. Is that deliberate?