0

My app is MapKit based, where multiple users can be tracked. Now using our web services, I am displaying my location on the map plus other users' last, let's say 10 locations. If a user updates their location, it is sent through the web service and displayed on the maps via call back. I am able to track other users in real time but don't know how to use Threading here. My UI is blocking at times and also crashing sometimes due to memory issue.

In my connectionDidFinishLoading method, I am parsing JSON data and then creating annotations and overlay:

-(void) connectionDidFinishLoading: (NSURLConnection *) connection
{

[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

NSArray *trackingDict = [NSJSONSerialization JSONObjectWithData:empJsonData options:kNilOptions error:nil];
NSLog(@"Json Dictionary = %@", trackingDict);
NSLog(@"COUNT = %i",trackingDict.count);

if ([trackingDict count] >= 2) {
    for (trackUsersCount = 0; trackUsersCount< trackingDict.count; trackUsersCount++) {
        NSLog(@"trackUsersCount %i", trackUsersCount);

        NSMutableArray *latlongArray = [[NSMutableArray alloc]init];
        latlongArray = [[trackingDict objectAtIndex:trackUsersCount]objectForKey:@"latlong"];

        [userLongitudeArray removeAllObjects];
        [userLatitudeArray removeAllObjects];

        for (int i = 0; i<latlongArray.count; i++) {
            NSLog(@"COunt - > %@", [[latlongArray objectAtIndex:i]objectForKey:@"lat"]);
            NSLog(@"COunt - > %@", [[latlongArray objectAtIndex:i]objectForKey:@"long"]);
            [userLatitudeArray addObject:[[latlongArray objectAtIndex:i]objectForKey:@"lat"]];
            [userLongitudeArray addObject:[[latlongArray objectAtIndex:i]objectForKey:@"long"]];

        }

        // ProfilePIC URL
        profilePicURLString = [[trackingDict objectAtIndex:trackUsersCount]objectForKey:@"user_profilePicture"];

NSString *name = [[trackingDict objectAtIndex:trackUsersCount]objectForKey:@"user_firstName"];
        [userNameArray addObject:name];
        [profilePicURLStringArray addObject:profilePicURLString];

        for (int i = 0; i<userLatitudeArray.count; i++) {
            CLLocationCoordinate2D userLocation;
            userLocation.latitude = [[userLatitudeArray objectAtIndex:i]doubleValue];
            userLocation.longitude = [[userLongitudeArray objectAtIndex:i] doubleValue];
            Annotation *Anno = [[Annotation alloc]init];

            Anno.coordinate = userLocation;
            Anno.title = name;
            Anno.userProfileImageString = profilePicURLString;
            [mapView addAnnotation:Anno];
        }

        NSLog(@"ARRAY for longitude %@", userLongitudeArray);
        NSLog(@"ARRAY for latitude %@", userLatitudeArray);
        int i;
        for (i = 0; i<userLatitudeArray.count; i++) {
            CLLocationCoordinate2D userLocation;
            userLocation.latitude = [[userLatitudeArray objectAtIndex:i]doubleValue];
            userLocation.longitude = [[userLongitudeArray objectAtIndex:i] doubleValue];
            MKMapPoint * pointsArray = malloc(sizeof(CLLocationCoordinate2D)*userLongitudeArray.count);
            pointsArray[i] = MKMapPointForCoordinate(userLocation);
            polyline = [MKPolyline polylineWithPoints:pointsArray count:i];
            free(pointsArray);
        }
         [mapView addOverlay:polyline];
         }
}

[mapView reloadInputViews];

}

}

The web service is called after every 20 seconds, I know I can user GCD here or other threading approach but at the time-interval when web service is called via background thread, the annotations and overlays are not displayed not the map.

Any help is much appreciated!

Samapple007
  • 355
  • 4
  • 15
  • It's OK to use background thread to modify the data (model) but you really shouldn't modify the UI from the background thread. – Rok Jarc Jan 29 '13 at 09:26
  • Thanks @rokjarc for response. I really need to know how will I deal with threading in my situation. Any sample snippet would be very helpful. – Samapple007 Jan 29 '13 at 09:31

1 Answers1

0

I don't think there's an quick & easy fix for this. One approach would be to separate the code that collects (modifies) the data from the code that updates the view.

Set the code that is dealing with UI into a separate method, updateUI for example.

From here on you have couple of choices. You could try this for example:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
   //perform the data collection, calculations... 
   //here is where the model in MVC gets modified
   //
   [self performSelectorOnMainThread: @selector(updateUI) withObject:nil waitUntilDone: NO];
}

-(void)updateUI
{
   //do the UI updates (like adding overlays etc...) here 
}

You could also store all the data needed to update the UI to a kind of object and pass it as withObject: parameter.

Rok Jarc
  • 18,765
  • 9
  • 69
  • 124
  • OK thanks, I will try, just one question related to your last answer, that if I deal with UI in separate method (like you've written) will the `connectionDidFinishLoading` method not block my UI? Because the data is still arriving in this method. – Samapple007 Jan 30 '13 at 04:04
  • Just found a great answer that could help you out completely: http://stackoverflow.com/a/1730053/653513 It deals with downloading the image but basically it's the same thing. – Rok Jarc Jan 30 '13 at 08:35