I have a function which prepares data for my UITableView:
- (void) SearchFromMyPosition {
TitleLabelSort = [[NSMutableArray alloc] init];
DistanceLabelSort = [[NSMutableArray alloc] init];
TagValueSort = [[NSMutableArray alloc] init];
DistanceUnitSort = [[NSMutableArray alloc] init];
LatArraySort = [[NSMutableArray alloc] init];
LngArraySort = [[NSMutableArray alloc] init];
// loading
[activityIndicatorObject startAnimating];
NSNumber *latNr1 = [[NSUserDefaults standardUserDefaults] valueForKey:#"api_lat"];
NSNumber *lngNr1 = [[NSUserDefaults standardUserDefaults] valueForKey:#"api_lng"];
double lat1 = [latNr1 doubleValue];
double lng1 = [lngNr1 doubleValue];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSArray *array = [APIConnection GetDataFromUrlAuth];
dispatch_async(dispatch_get_main_queue(), ^{
for (NSString *item in array) {
NSArray *coords = [[[array valueForKey:item] valueForKey:#"location"] componentsSeparatedByString:#"|"];
double lat2 = [[coords objectAtIndex:0] doubleValue];
double lng2 = [[coords objectAtIndex:1] doubleValue];
CLLocation *oldLocation = [[CLLocation alloc] initWithLatitude:lat1 longitude:lng1];
CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:lat2 longitude:lng2];
CLLocationDistance meters = [newLocation distanceFromLocation:oldLocation];
[LatArraySort addObject:[NSString stringWithFormat:#"%f",lat2]];
[LngArraySort addObject:[NSString stringWithFormat:#"%f",lng2]];
[TitleLabelSort addObject:[[array valueForKey:item] valueForKey:#"name"]];
[DistanceLabelSort addObject:[NSString stringWithFormat:#"%f",meters]];
[TagValueSort addObject:item];
[self.myTableView reloadData];
[activityIndicatorObject stopAnimating];
}
});
});
}
This works but I need to sort results by DistanceLabelSort
For sorting CoreData results I use below function and works fine:
- (void) SetTableData {
TitleLabel = [[NSMutableArray alloc] init];
DistanceLabel = [[NSMutableArray alloc] init];
TagValue = [[NSMutableArray alloc] init];
DistanceUnit = [[NSMutableArray alloc] init];
LatArray = [[NSMutableArray alloc] init];
LngArray = [[NSMutableArray alloc] init];
// sorting
NSArray *sortedArray = [DistanceLabelSort sortedArrayUsingComparator:^(NSString *str1, NSString *str2) {
return [str1 compare:str2 options:NSNumericSearch];
}];
NSString *sortIdentStr = [[NSString alloc] init];
unsigned long sortIdent;
NSMutableArray *arrayUnit = [[NSMutableArray alloc] init];
for (int i = 0; i < sortedArray.count; i++) {
sortIdentStr = [sortedArray objectAtIndex:i];
sortIdent = [DistanceLabel indexOfObject:sortIdentStr];
arrayUnit = [self unitStr:sortIdentStr];
[TitleLabel addObject:[TitleLabelSort objectAtIndex:sortIdent]];
[TagValue addObject:[TagValueSort objectAtIndex:sortIdent]];
[LatArray addObject:[LatArraySort objectAtIndex:sortIdent]];
[LngArray addObject:[LngArraySort objectAtIndex:sortIdent]];
[DistanceLabel addObject:[arrayUnit objectAtIndex:0]];
[DistanceUnit addObject:[arrayUnit objectAtIndex:1]];
[self.myTableView reloadData];
[activityIndicatorObject stopAnimating];
}
}
But if I try use this for sorting data from external api function SetTableData is done before I get results from external api.
Finally I found solution and maybe this will be helpful for others:
I added function which checks if the task is done:
- (void)SearchFromMyPositionWithSuccess:(void (^)(void))successHandler failure:(void (^)(void))failureHandler {
TitleLabelSort = [[NSMutableArray alloc] init];
DistanceLabelSort = [[NSMutableArray alloc] init];
TagValueSort = [[NSMutableArray alloc] init];
DistanceUnitSort = [[NSMutableArray alloc] init];
LatArraySort = [[NSMutableArray alloc] init];
LngArraySort = [[NSMutableArray alloc] init];
// loading
[activityIndicatorObject startAnimating];
NSNumber *latNr1 = [[NSUserDefaults standardUserDefaults] valueForKey:#"api_lat"];
NSNumber *lngNr1 = [[NSUserDefaults standardUserDefaults] valueForKey:#"api_lng"];
double lat1 = [latNr1 doubleValue];
double lng1 = [lngNr1 doubleValue];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSArray *array = [APIConnection GetDataFromUrlAuth];
dispatch_async(dispatch_get_main_queue(), ^{
int i = 0;
for (NSString *item in array) {
i++;
NSArray *coords = [[[array valueForKey:item] valueForKey:#"location"] componentsSeparatedByString:#"|"];
double lat2 = [[coords objectAtIndex:0] doubleValue];
double lng2 = [[coords objectAtIndex:1] doubleValue];
CLLocation *oldLocation = [[CLLocation alloc] initWithLatitude:lat1 longitude:lng1];
CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:lat2 longitude:lng2];
CLLocationDistance meters = [newLocation distanceFromLocation:oldLocation];
[LatArraySort addObject:[NSString stringWithFormat:#"%f",lat2]];
[LngArraySort addObject:[NSString stringWithFormat:#"%f",lng2]];
[TitleLabelSort addObject:[[array valueForKey:item] valueForKey:#"name"]];
[DistanceLabelSort addObject:[NSString stringWithFormat:#"%f",meters]];
[TagValueSort addObject:item];
if (i == array.count) {
successHandler();
}
[activityIndicatorObject stopAnimating];
}
});
});
}
And wait for success in this function:
-(void) SearchFromMyPosition {
[self SearchFromMyPositionWithSuccess: ^{
[self SetTableData];
NSLog(#"success");
} failure:^{
NSLog(#"failure");
}];
}
This solves my case :)
Related
I am inserting some annotations that are coming from a json server, but I wanted to check if the annotation is already on the map, if so, does not add it again. For they are being added on each other , have someone help me solve this problem?
my code:
// adiciona produtos ao mapa
- (void)adicionaAnnotationsNoMapa:(id)objetos{
NSMutableArray *annotationsPins = [[NSMutableArray alloc] init];
for (NSDictionary *annotationDeProdutos in objetos) {
CLLocationCoordinate2D location;
AnnotationMap *myAnn;
myAnn = [[AnnotationMap alloc] init];
location.latitude = [[annotationDeProdutos objectForKey:#"latitude"] floatValue];
location.longitude = [[annotationDeProdutos objectForKey:#"longitude"] floatValue];
myAnn.coordinate = location;
myAnn.title = [annotationDeProdutos objectForKey:#"name"];
myAnn.subtitle = [NSString stringWithFormat:#"R$ %#",[annotationDeProdutos objectForKey:#"price"]];
myAnn.categoria = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id_categoria"]];
myAnn.idProduto = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id"]];
[annotationsPins addObject:myAnn];
}
[self.mapView addAnnotations:annotationsPins];
}
You can iterate through annotations already on MkMapView and see if they are already there:
NSArray * annotations = [self.mapView.annotations copy];
for (NSDictionary *annotationDeProdutos in objetos)
{
// Check if annotation in annotations are duplicate of annotationDeProdutos.
// You can match using name.
}
Or the other way if you only want to show annotations from single server call:
[self.mapView removeAnnotations: self.mapView.annotations];
// Now add from JSON response.
You can do this for each of your annotations:
if(![self.mapView.annotations containsObject: myAnn]) {
[self.mapView addAnnotations: myAnn];
}
I solved the problem with this code :
// adiciona produtos ao mapa
- (void)adicionaAnnotationsNoMapa:(id)objetos{
NSMutableArray *annotationsPins = [[NSMutableArray alloc] init];
for (NSDictionary *annotationDeProdutos in objetos) {
CLLocationCoordinate2D location;
AnnotationMap *myAnn;
myAnn = [[AnnotationMap alloc] init];
location.latitude = [[annotationDeProdutos objectForKey:#"latitude"] floatValue];
location.longitude = [[annotationDeProdutos objectForKey:#"longitude"] floatValue];
myAnn.coordinate = location;
myAnn.title = [annotationDeProdutos objectForKey:#"name"];
myAnn.subtitle = [NSString stringWithFormat:#"R$ %#",[annotationDeProdutos objectForKey:#"price"]];
myAnn.categoria = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id_categoria"]];
myAnn.idProduto = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id"]];
if (self.mapView.annotations.count <1) {
[annotationsPins addObject:myAnn];
} else {
__block NSInteger foundIndex = NSNotFound;
[annotationsPins enumerateObjectsUsingBlock:^(AnnotationMap *annotation, NSUInteger idx, BOOL *stop) {
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
if ([loc1 distanceFromLocation:loc2] <= 1.0f) {
foundIndex = idx;
*stop = YES;
}
}];
if (foundIndex != NSNotFound) {
[annotationsPins addObject:myAnn];
}
}
}
[self.mapView addAnnotations:annotationsPins];
}
I am creating a table with multiple columns. In the left column I want to get the indicator name which is stored in a database and I have to check that the indicator id in database and in json (API) matches and then display the name in that column. I have tried some code
In view load method I take values from database and store it in an array
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
indicatorName = [[NSMutableArray alloc] init];
NSString *path = appDelegate.databasePath;
FMDatabase *db = [[FMDatabase alloc] initWithPath:path];
[db open];
NSString *sql = [NSString stringWithFormat:#"SELECT * FROM Topic AS t INNER JOIN TopicIndicators AS ti ON t.Id = ti.TopicId INNER JOIN Indicators AS i ON ti.IndicatorID = i.Id"];// WHERE t.Id = %ld", (long)self.Tid];
FMResultSet *fresult = [db executeQuery:sql];
while ([fresult next])
{
TopicModel *topicModel = [[TopicModel alloc]init];
topicModel.TId = [fresult intForColumn:#"Id"];
topicModel.TTopicType = [fresult stringForColumn:#"TopicType"];
topicModel.TCode = [fresult stringForColumn:#"Code"];
topicModel.TName = [fresult stringForColumn:#"Name"];
topicModel.IId = [fresult intForColumn:#"Id"];
topicModel.ICodeId = [fresult stringForColumn:#"CodeId"];
topicModel.IName = [fresult stringForColumn:#"Name"];
topicModel.INotes = [fresult stringForColumn:#"Notes"];
topicModel.TIId = [fresult intForColumn:#"Id"];
topicModel.TITopicId = [fresult intForColumn:#"TopicId"];
topicModel.TIIndicatorID = [fresult intForColumn:#"IndicatorId"];
[indicatorName addObject:topicModel];
}
[db close];
mainTableData = [[NSMutableArray alloc] init];
[self callPages];
self.title = NSLocalizedString(#"Compare By", nil);
XCMultiTableView *tableView = [[XCMultiTableView alloc] initWithFrame:CGRectInset(self.view.bounds, 5.0f, 5.0f)];
tableView.leftHeaderEnable = YES;
tableView.datasource = self;
[self.view addSubview:tableView];
}
In request finished method I am taking values from json and assigning the values in appropriate columns.
-(void) requestFinished: (ASIHTTPRequest *) request
{
NSString *theJSON = [request responseString];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSMutableArray *jsonDictionary = [parser objectWithString:theJSON error:nil];
headData = [[NSMutableArray alloc] init];
NSMutableArray *head = [[NSMutableArray alloc] init];
leftTableData = [[NSMutableArray alloc] init];
NSMutableArray *left = [[NSMutableArray alloc] init];
rightTableData = [[NSMutableArray alloc]init];
for (NSMutableArray *dictionary in jsonDictionary)
{
Model *model = [[Model alloc]init];
model.cid = [[dictionary valueForKey:#"cid"]intValue];
model.iid = [[dictionary valueForKey:#"iid"]intValue];
model.yr = [[dictionary valueForKey:#"yr"]intValue];
model.val = [dictionary valueForKey:#"val"];
[head addObject:[NSString stringWithFormat:#"%ld", model.yr]];
[left addObject:[NSString stringWithFormat:#"%ld", model.iid]];
[mainTableData addObject:model];
}
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:head];
headData = [[orderedSet array] mutableCopy];
NSOrderedSet *orderedSet1 = [NSOrderedSet orderedSetWithArray:left];
NSMutableArray *arrLeft = [[orderedSet1 array] mutableCopy];
//remove duplicate enteries from header array
[leftTableData addObject:arrLeft];
NSMutableArray *right = [[NSMutableArray alloc]init];
for (int i = 0; i < arrLeft.count; i++)
{
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int j = 0; j < headData.count; j++)
{
/* NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.iid == %ld", [[arrLeft objectAtIndex:i] intValue]];
NSArray *filteredArray = [mainTableData filteredArrayUsingPredicate:predicate];*/
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.iid == %ld AND SELF.yr == %ld", [[arrLeft objectAtIndex:i] intValue], [[headData objectAtIndex:j] intValue]];
NSArray *filteredArray = [mainTableData filteredArrayUsingPredicate:predicate];
NSMutableArray *newArray = [[NSMutableArray alloc] init];
TopicModel *topicModel = [[TopicModel alloc]init];
for (int k = 0; k < arrLeft.count; k++)
{
if (topicModel.IId == arrLeft[k])
{
[newArray addObject:[NSString stringWithFormat:#"%#",topicModel.IName]];
}
}
if([filteredArray count]>0)
{
Model *model = [filteredArray objectAtIndex:0];
[array addObject:model.val];
}
}
[right addObject:array];
}
[rightTableData addObject:right];
}
I am using FMDB, ASIHTTPRequest, SBJSON, XCMultisortTableView.
Please do help.
Well you are creating new TopicModel object which is empty! You need to use the one which you set in your viewDidLoad: method.
for (int k = 0; k < arrLeft.count; k++) {
if ([(TopicModel *)indicatorName[k] IId] == [arrLeft[k] integerValue]) {
[newArray addObject:[NSString stringWithFormat:#"%#",[(TopicModel *)indicatorName[k] IName]];
}
}
Now I loop through one Array at once and calculate distance like this:
- (void)calculateDistance
{
ann = [dict objectForKey:#"Blue"];
for(int i = 0; i < [ann count]; i++) {
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:#"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:0] doubleValue];
// Calculating distance
CLLocation *pinLocation = [[CLLocation alloc]
initWithLatitude:realLatitude
longitude:realLongitude];
CLLocation *userLocation = [[CLLocation alloc]
initWithLatitude:mapView.userLocation.coordinate.latitude
longitude:mapView.userLocation.coordinate.longitude];
CLLocationDistance distance = [pinLocation distanceFromLocation:userLocation];
// Adding distance to dictionaries
if (distance > 1000) {
NSString *dist = [NSString stringWithFormat:#"%.2f km.", distance/1000];
NSMutableDictionary *inDict = [[NSMutableDictionary alloc] init];
inDict = [ann objectAtIndex:i];
[inDict setValue:dist forKey:#"Distance"];
}
else{
NSString *dist = [NSString stringWithFormat:#"%4.0f m.", distance];
NSMutableDictionary *inDict = [[NSMutableDictionary alloc] init];
inDict = [ann objectAtIndex:i];
[inDict setValue:dist forKey:#"Distance"];
}
}
}
My data structure is:
How to loop through all Array's at once? I have Array which contains all my Array's named "resultArray", but this code doesn't work:
ann = [dict objectForKey:resultArray];
NSLog(#"%#", resultArray);
2013-05-05 10:57:03.643 testApp[5708:907] (
Black,
Green,
Orange,
Blue,
Darkblue
)
I guess you want to enumerate through the keys stored in resultArray and calculate the distance and add that calculated values to it.
- (void)calculateDistance
{
//Enumerates through resultArray
for (NSString *key in resultArray) {
//ann array is considered as an instance of NSMutableArray
ann = dict[key];
for(int i = 0; i < [ann count]; i++) {
NSMutableDictionary *inDict = [ann[i] mutableCopy];
NSString *coordinates = inDict[#"Coordinates"];
NSArray *coordinateComponents = [coordinates componentsSeparatedByString:#","];
double realLatitude = [coordinateComponents[1] doubleValue];
double realLongitude = [coordinateComponents[0] doubleValue];
// Calculating distance
CLLocation *pinLocation = [[CLLocation alloc] initWithLatitude:realLatitude
longitude:realLongitude];
CLLocation *userLocation = [[CLLocation alloc]
initWithLatitude:mapView.userLocation.coordinate.latitude
longitude:mapView.userLocation.coordinate.longitude];
CLLocationDistance distance = [pinLocation distanceFromLocation:userLocation];
// Adding distance to dictionaries
if (distance > 1000) {
NSString *dist = [NSString stringWithFormat:#"%.2f km.", distance/1000];
[inDict setValue:dist forKey:#"Distance"];
}
else{
NSString *dist = [NSString stringWithFormat:#"%4.0f m.", distance];
[inDict setValue:dist forKey:#"Distance"];
}
//Inserting the modified values to the main array
[ann replaceObjectAtIndex:i withObject:inDict];
}
}
}
ann = [dict objectForKey:resultArray];
for(NSArray *colourArray in ann)
{
for(NSDictionary *itemDictionary in colourArray)
{
NSLog(#"Coordinates = %#",[itemDictionary objectForKey:#"Coordinates"]);
NSLog(#"Name = %#",[itemDictionary objectForKey:#"Name"]);
NSLog(#"Address = %#",[itemDictionary objectForKey:#"Address"]);
}
}
Hope it will help you .
EDIT: I USE ARC IN PROJECT
I load annotations from plist like this:
[NSThread detachNewThreadSelector:#selector(loadPList) toTarget:self withObject:nil];
...
- (void) loadPList
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:#"test.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; // memory leak here
NSMutableArray *annotations = [[NSMutableArray alloc]init];
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
[ annotationsToRemove removeObject:mapView.userLocation ] ;
[ mapView removeAnnotations:annotationsToRemove ] ;
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blackKey"])
{
NSArray *ann = [dict objectForKey:#"Black"];
for(int i = 0; i < [ann count]; i++) {
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:#"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:#"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:#"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:#"Icon"];
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
}
}
});
}
All loads fine, but Memory leak tool shows me an leak.
You need to put the #autoreleasepool at the start of your method - with that dictionaryWithContentsOfFile: call outside of it, you're creating an autoreleased object without a pool, so it'll leak. Per the threading programming guide:
If your application uses the managed memory model, creating an
autorelease pool should be the first thing you do in your thread entry
routine. Similarly, destroying this autorelease pool should be the
last thing you do in your thread.
Also, can I ask why you to use NSThread for loading the plist rather than a dispatch_async()using a global queue? I don't often see dispatch_async() nested inside a thread detachment, so just curious.
EDIT:
To fix your memory leak, without disturbing your thread / GCD hybrid, call your method like this:
[NSThread detachNewThreadSelector:#selector(loadPList) toTarget:self withObject:nil];
And implement it like this:
- (void) loadPList
{
#autoreleasepool {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:#"test.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; // memory leak here
NSMutableArray *annotations = [[NSMutableArray alloc]init];
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
[ annotationsToRemove removeObject:mapView.userLocation ] ;
[ mapView removeAnnotations:annotationsToRemove ] ;
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blackKey"])
{
NSArray *ann = [dict objectForKey:#"Black"];
for(int i = 0; i < [ann count]; i++)
{
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:#"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:#"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:#"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:#"Icon"];
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
}
}
}
);
}
}
If nothing else, you need an autorelease pool. To quote from the documentation for detachNewThreadSelector, "the method aSelector is responsible for setting up an autorelease pool for the newly detached thread and freeing that pool before it exits."
Personally, I'd probably just invoke loadPlist via GCD rather than detachNewThreadSelector, and then you don't need to worry about an autorelease pool:
dispatch_async(get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self loadPlist];
});
NSMutableArray *annotations = [[NSMutableArray alloc]init]; // Never released
NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ; // Never released
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init]; // Never released
Your method should look like this:
- (void) loadPList {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:#"test.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; // memory leak here
NSMutableArray *annotations = [[[NSMutableArray alloc] init] autorelease];
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray * annotationsToRemove = [[mapView.annotations mutableCopy] autorelease];
[annotationsToRemove removeObject:mapView.userLocation] ;
[mapView removeAnnotations:annotationsToRemove] ;
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blackKey"])
{
NSArray *ann = [dict objectForKey:#"Black"];
for(int i = 0; i < [ann count]; i++) {
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:#"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[[MyAnnotation alloc] init] autorelease];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:#"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:#"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:#"Icon"];
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
}
}
});
}
Why am I unable to remove my annotations from mapview?
My code:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self becomeFirstResponder];
NSMutableArray *annotations = [[NSMutableArray alloc]init];
NSString *path = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blackKey"])
{
NSLog(#"Black is on");
NSArray *ann = [dict objectForKey:#"Category1"];
for(int i = 0; i < [ann count]; i++) {
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:#"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:#"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:#"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:#"Icon"];
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blackKey"])
{
NSLog(#"Black is on");
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
} else
{
NSLog(#"Black is off");
[self.mapView removeAnnotation:myAnnotation];
}
}
}
else
{
//Do nothing
}
}
[self.mapView removeAnnotation:myAnnotation]; does not work for me
There is nothing to remove. You create the annotation, and then based off the check for blackKey, you EITHER add or remove it. But when you remove it, you never added it prior to that.