I have question regarding memory usage of ios. I have implemented code as shown below and run it on the device about 10 min and it stopped and gave me warning "Received memory warning". I wonder why I am getting this warning.
NSArray *ants = [mapView overlays];
for(bb = 0; bb < [polygonArray count]; bb++){
int attr=[[idArray objectAtIndex:bb]floatValue];
coords = malloc(sizeof(CLLocationCoordinate2D) * [[polygonArray objectAtIndex:bb] count]);
for (int a = 0;a < [[polygonArray objectAtIndex:bb] count]; a++){
coords[a].latitude = [[[[polygonArray objectAtIndex:bb]objectAtIndex:a]objectAtIndex:0]doubleValue];
coords[a].longitude = [[[[polygonArray objectAtIndex:bb]objectAtIndex:a]objectAtIndex:1]doubleValue];
}
polygon = [[MKPolygon alloc]init];
polygon = [MKPolygon polygonWithCoordinates:coords count:[[polygonArray objectAtIndex:bb]count]];
//free(coords);
[previousPolygons addObject:polygon];
}
[mapView addOverlay:polygon];
}
}
[mapView removeOverlays:ants];
You seem to have more closing brackets that you have opening ones so there may be more at play than you've shown us, but I've shown what I think will improve your code below
NSArray *ants = [mapView overlays];
for(bb = 0; bb < [polygonArray count]; bb++){
int attr=[[idArray objectAtIndex:bb]floatValue];
coords = malloc(sizeof(CLLocationCoordinate2D) * [[polygonArray objectAtIndex:bb] count]);
for (int a = 0;a < [[polygonArray objectAtIndex:bb] count]; a++){
coords[a].latitude = [[[[polygonArray objectAtIndex:bb]objectAtIndex:a]objectAtIndex:0]doubleValue];
coords[a].longitude = [[[[polygonArray objectAtIndex:bb]objectAtIndex:a]objectAtIndex:1]doubleValue];
}
//Remove the next line because polygonWIthCoordinates creates one for you
//polygon = [[MKPolygon alloc]init];
polygon = [MKPolygon polygonWithCoordinates:coords count:[[polygonArray objectAtIndex:bb]count]];
//reinstate this line
free(coords);
[previousPolygons addObject:polygon];
}
//This is outside the for-loop so you'll only be adding the last polygon
[mapView addOverlay:polygon];
}
}
[mapView removeOverlays:ants];
Related
I am trying to remove existing all markers from google maps, we can do by map.clear but I don't want to remove everything(Polyline, polygons) on map, I just want to remove only markers
I am creating markers based on array count
-(void)annotationCreationForCoordinatesOfArray:(NSMutableArray *)array
{
for (int i=0; i<array.count; i++)
{
CLLocationCoordinate2D position = CLLocationCoordinate2DMake([[[array objectAtIndex:i] objectForKey:#"latitude"] doubleValue], [[[array objectAtIndex:i] objectForKey:#"longitude"] doubleValue]);
mark = [GMSMarker markerWithPosition:position];
NSString *annoNumber = [NSString stringWithFormat:#"%i",i];
mark.title = annoNumber;
mark.map = _mapView;
mark.tracksViewChanges = YES;
mark.draggable = YES;
mark.icon = [UIImage imageNamed:#"Mappin.png"];
}
}
Try this code its work for me.
Create global array
NSMutableArray *removalMarkerArray;
Now add all marker in global array
removalMarkerArray=[[NSMutableArray alloc]init];
-(void)annotationCreationForCoordinatesOfArray:(NSMutableArray *)array{
for (int i=0; i<array.count; i++){
CLLocationCoordinate2D position = CLLocationCoordinate2DMake([[[array objectAtIndex:i] objectForKey:#"latitude"] doubleValue], [[[array objectAtIndex:i] objectForKey:#"longitude"] doubleValue]);
mark = [GMSMarker markerWithPosition:position];
NSString *annoNumber = [NSString stringWithFormat:#"%i",i];
mark.title = annoNumber;
mark.map = _mapView;
mark.tracksViewChanges = YES;
mark.draggable = YES;
mark.icon = [UIImage imageNamed:#"Mappin.png"];
[removalMarkerArray addObject:mark];
}
}
Then where you want to clear all marker
for (GMSMarker *marker in removalMarkerArray ){
marker.map = nil;
}
I am trying the GMSPolygon *polygon = [GMSPolygon polygonWithPath:rect]; method to draw a polygon of the tapped coordinates by the user. Here's how I store the clicked coordinates:
// array made of clicked coordinates
NSMutableArray *latitudeTappedCoordinates = [NSMutableArray array];
NSMutableArray *longitudeTappedCoordinates = [NSMutableArray array];
NSUInteger numberOfLongitudeCoordinates = [longitudeTappedCoordinates count];
NSUInteger numberOfLatitudeCoordinates = [latitudeTappedCoordinates count];
for (int i = 2; i < numberOfLatitudeCoordinates; i++) {
[latitudeTappedCoordinates addObject:[NSNumber numberWithInt:coordinate.latitude]];
}
for (int i = 2; i < numberOfLongitudeCoordinates; i++) {
[longitudeTappedCoordinates addObject:[NSNumber numberWithInt:coordinate.longitude]];
}
After this, I have the following:
// polygon
GMSMutablePath *rect = [GMSMutablePath path];
[rect addCoordinate:CLLocationCoordinate2DMake(coordinate.latitude,coordinate.longitude)];
GMSPolygon *polygon = [GMSPolygon polygonWithPath:rect];
As you can see, the line
[rect addCoordinate:CLLocationCoordinate2DMake(coordinate.latitude,coordinate.longitude)];
only takes in a single attribute. I want it to take in all the values in the arrays init above, so it can draw the polygon. How can I do that?
First store float values not int values in array.
then
Add in interface
NSMutableArray *latitudeTappedCoordinates;
NSMutableArray *longitudeTappedCoordinates;
You can do like this :
// Create a rectangular path
GMSMutablePath *rect = [GMSMutablePath path];
CLLocationCoordinate2D event;
for (int i = 0; i <= [longitudeTappedCoordinates count]-1; i++) {
event.latitude = [[latitudeTappedCoordinates objectAtIndex:i] floatValue];
event.longitude = [[longitudeTappedCoordinates objectAtIndex:i] floatValue];
[rect addCoordinate:event];
}
GMSPolygon *polygon = [GMSPolygon polygonWithPath:rect];
polygon.fillColor = [UIColor colorWithRed:0.25 green:0 blue:0 alpha:0.05];
polygon.strokeColor = [UIColor blackColor];
polygon.strokeWidth = 2;
polygon.map = mapView;
I have create a PolyLine in MapView. I tried to many times but did not draw. Ones a draw polyLine but that case run only simulator, I run in device and crash my app. and I already post my question here
I tried to many times and using lots of tutorials, please suggest any other tutorial.
I want to create a PolyLine in MapView using google direction URL. Starting point is my device location and end point is any lat long. so both points in centre draw a polyLine. That means create a root map starting point to end point draw a PolyLine.
Please help, Thank you
you can use google api for this
http://maps.googleapis.com/maps/api/directions/json?origin
in this api you have to pass lat log of your locations like this methode
-(NSArray*) calculateRoutes
{
NSString *baseUrl = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=true",currentlatitude,currentlongitude,destination lat,destination log];
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:baseUrl]];
if (data) {
NSDictionary *direction_dictionary=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (direction_dictionary) {
if ([[direction_dictionary valueForKey:#"status"] isEqualToString:#"OK"]) {
NSArray *routes_array=[direction_dictionary valueForKey:#"routes"];
if (routes_array) {
NSString *poinstEncoded_String=[[[routes_array firstObject] valueForKey:#"overview_polyline"] valueForKey:#"points"];
routes = [self decodePolyLine:[poinstEncoded_String mutableCopy]];
NSInteger numberOfSteps = routes.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++)
{
CLLocation *location = [routes objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
dispatch_async(dispatch_get_main_queue(), ^{
[self.MapVw addOverlay:polyLine];
// add polyline here to your mapview
});
}
}
}
}
}
-(NSMutableArray *)decodePolyLine: (NSMutableString *)encoded
{
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\" options:NSLiteralSearch range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len)
{
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
After getting response (Full example http://way2ios.com/development/ios-development-2/iphone-2/draw-polygon-mkmapview-stylus/):
– (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay
{
MKPolygonView *polygonView = [[MKPolygonView alloc] initWithPolygon:overlay];
polygonView.lineWidth = 5;
polygonView.strokeColor = [UIColor redColor];
polygonView.fillColor = [UIColor colorWithRed:0 green:191 blue:255 alpha:0.5];
mapView.userInteractionEnabled = YES;
return polygonView;
}
Check these also :
https://github.com/kadirpekel/MapWithRoutes and https://github.com/versluis/MapViewLines
I am using google map ios sdk, My problem is i have to get coordinates for every 1000 meter on a poly line in map. now i am able to get number of location in given path and able to accesses them using the following code snip.
-(NSMutableArray*)getCoordinates {
pathCoordinatesArray = [[NSMutableArray alloc]init];
GMSMutablePath *path = [VTDirectionManager getPath];
NSLog(#"count %d",path.count);
for (int i=0 ; i<path.count; i++) {
if (i+1 > path.count) {
return pathCoordinatesArray;
}
for (int j = i+1; j<path.count; j++) {
CLLocationCoordinate2D sourceCoordinate = [path coordinateAtIndex:i];
CLLocation *sourceLocation = [[CLLocation alloc]initWithLatitude:sourceCoordinate.latitude longitude:sourceCoordinate.longitude];
CLLocationCoordinate2D destinationCoordinate = [path coordinateAtIndex:j];
CLLocation *destinationLocation = [[CLLocation alloc]initWithLatitude:destinationCoordinate.latitude longitude:destinationCoordinate.longitude];
BOOL check ;
check = [self checkDistanceForSource:sourceLocation andDestination:destinationLocation];
//jump to next 1000 distance position
if (check) {
i = j;
}
}
}
return pathCoordinatesArray;
}
-(BOOL)checkDistanceForSource:(CLLocation*)source andDestination:(CLLocation*)destination {
CLLocationDistance distance = [source distanceFromLocation:destination];
if (distance > 1000) {
CLLocation *location = [[CLLocation alloc] initWithLatitude:destination.coordinate.latitude longitude:destination.coordinate.longitude];
[pathCoordinatesArray addObject:location];
return YES;
}
return NO;
}
Suppose if i have 5000 meter distance path , then i have to get 5 coordinates ,each at 1000 meters position sequentially.
i think it is wrong code . Suggest me with optimized code
see the image each points are 1000 metered distance .
Please change your loop code like this
for (int i=0 ; i<path.count; i++) {
if (pathCoordinatesArray.count == 0) {
CLLocationCoordinate2D temp2d = [path coordinateAtIndex:i];
CLLocation *tempLoc = [[CLLocation alloc]initWithLatitude:temp2d.latitude longitude:temp2d.longitude];
[pathCoordinatesArray addObject:tempLoc];
}
CLLocationCoordinate2D destinationCoordinate = [path coordinateAtIndex:i];
CLLocation *destinationLocation = [[CLLocation alloc]initWithLatitude:destinationCoordinate.latitude longitude:destinationCoordinate.longitude];
[self checkDistanceForSource:[pathCoordinatesArray lastObject] andDestination:destinationLocation];
}
}
Basically, I want to draw a Polyline with this code. As you can see, I have the Overlay method ready, I only need to know how to call MKPolyline in the (void)viewDidLoad
[UPDATE] OK so I managed to draw Polylines. However, the lines don't make sense, they connect some pins with no order and then 4 of the pins release a line directed to the north west of the map, I need to know how to make it line one pin to another in an ordered manner.
- (void)viewDidLoad {
[super viewDidLoad];
NSString *csvFilePath = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"csv"];
NSString *dataStr = [NSString stringWithContentsOfFile:csvFilePath encoding:NSUTF8StringEncoding error:nil];
NSArray* allLinedStrings = [dataStr componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
MKMapPoint northEastPoint;
MKMapPoint southWestPoint;
MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * allLinedStrings.count);
for(int idx = 0; idx < allLinedStrings.count; idx++)
{
NSString* currentPointString = [allLinedStrings objectAtIndex:idx];
NSArray* infos = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#","]];
if ([infos count] > 1)
{
NSString * latitude = [infos objectAtIndex:1];
NSString * longitude = [infos objectAtIndex:2];
NSString * Description =[infos objectAtIndex:3];
NSString * address = [infos objectAtIndex:4];
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude.doubleValue;
coordinate.longitude = longitude.doubleValue;
Location *annotation = [[Location alloc] initWithName:Description address:address coordinate:coordinate] ;
[mapview addAnnotation:annotation];
MKMapPoint point = MKMapPointForCoordinate(coordinate);
//
// adjust the bounding box
//
// if it is the first point, just use them, since we have nothing to compare to yet.
if (idx == 0) {
northEastPoint = point;
southWestPoint = point;
}
else
{
if (point.x > northEastPoint.x)
northEastPoint.x = point.x;
if(point.y > northEastPoint.y)
northEastPoint.y = point.y;
if (point.x < southWestPoint.x)
southWestPoint.x = point.x;
if (point.y < southWestPoint.y)
southWestPoint.y = point.y;
}
pointArr[idx] = point;
}
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:allLinedStrings.count];
_routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);
[self.mapview addOverlay:self.routeLine];
}
}
}
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView
rendererForOverlay:(id < MKOverlay >)overlay
{
MKPolylineRenderer *renderer =
[[MKPolylineRenderer alloc] initWithPolyline:overlay];
renderer.strokeColor = [[UIColor orangeColor] colorWithAlphaComponent:1];
renderer.lineWidth = 6.0;
renderer.lineDashPattern = #[#2, #10];
renderer.alpha = 0.5;
return renderer;
}
Also, my csv file if its of any help
01,51.751782,-0.238992, Location 1, 1st Stop
02,51.815020,-0.200418, Location 2, 2nd Stop
03,51.755462,-0.340392, Location 3, 3rd Stop
04,51.660507,-0.389374, Location 4, 4th Stop
05,51.798323,-0.081622, Location 5, 5th Stop
An overlay is being added as each coordinate is added to the C array (before all the rest of the coordinates in the array are set). This causes the lines going to the northwest. Create and add the overlay after the loop.
Here's a summary of the current code with just the relevant parts pointed out:
MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * allLinedStrings.count);
for(int idx = 0; idx < allLinedStrings.count; idx++)
{
//some code that gets "infos" (current coordinate's data)...
if ([infos count] > 1)
{
//some code that creates and adds an annotation...
MKMapPoint point = MKMapPointForCoordinate(coordinate);
//some code that calculates the "bounding box" (irrelevant)...
pointArr[idx] = point;
}
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:allLinedStrings.count];
//_routeRect = ... (irrelevant)
[self.mapview addOverlay:self.routeLine];
} //end of for-loop
Notice that the addOverlay call is inside the for-loop which means a polyline overlay is added for each coordinate.
But at each iteration, the pointArr array has not been fully populated yet:
When pointArr[0] is set to location 1, pointArr[1] to pointArr[4] are not set yet and contain either zero or random values.
When pointArr[1] is set to location 2, pointArr[2] to pointArr[4] are not set yet and contain either zero or random values, etc...
With the pointArr partially set like this at each coordinate/iteration, the polyline is being added resulting in the random lines going into the northwest.
Instead, create and add the polyline overlay once and after the for-loop and after pointArr is fully populated:
MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * allLinedStrings.count);
for(int idx = 0; idx < allLinedStrings.count; idx++)
{
//some code that gets "infos" (current coordinate's data)...
if ([infos count] > 1)
{
//some code that creates and adds an annotation...
MKMapPoint point = MKMapPointForCoordinate(coordinate);
//some code that calculates the "bounding box" (irrelevant)...
pointArr[idx] = point;
}
//_routeRect = ... (irrelevant)
} //end of for-loop
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:allLinedStrings.count];
[self.mapview addOverlay:self.routeLine];
A few other points:
This malloc is technically wrong:
MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * allLinedStrings.count);
It's defining an array of MKMapPoint structs but using the size of CLLocationCoordinate2D structs. Since you are intending to add MKMapPoint structs, you should use that struct's size instead:
MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * allLinedStrings.count);
The reason it still "works" the wrong way is because MKMapPoint and CLLocationCoordinate2D happen to be the same size.
You are allocating the C array with malloc but not freeing the memory. After pointArr is no longer needed, you should call free:
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:allLinedStrings.count];
[self.mapview addOverlay:self.routeLine];
free(pointArr);
Just FYI: Since you have CLLocationCoordinate2D coordinate values to begin with, you can just create the polyline using polylineWithCoordinates and save the trouble of converting them to MKMapPoints.
The bounding box calculation seems more complex than necessary. It's simpler to initialize the MKMapRect to MKMapRectNull and then add each annotation's MKMapPoint to it using MKMapRectUnion. See this answer for an example. Even simpler than that is to just call [self.mapview showAnnotations:self.mapview.annotations animated:YES]; after all the annotations are added.