1

I have implemented pull to refresh within my app which when pulled starts the location manager to get a fix on the users location then presents a modal view controller showing that location.

The problem I'm having is that the modal view controller is being presented before the users location has been obtained resulting a blank map for a few more seconds until it's obtained and updated.

I have a property that holds the users current location. Is it possible to 'hold' until that property is not nil (ie. a location has been established) before the pull to refresh calls 'showMap', perhaps if it can't locate the user after a set time it just presents an error? I tried using a 'while' loop to constantly check the currentLocation property but it didn't seem like the right thing to do and didn't work anyway.

This is my pull to refresh code which is set-up in viewDidLoad:

__typeof (&*self) __weak weakSelf = self;

[self.scrollView addPullToRefreshWithActionHandler:^ {
    int64_t delayInSeconds = 1.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [weakSelf showMap];
    });
}];

When the pull to refresh is used it calls these methods:

- (void)showMap
{
    [self.locationManager updateCurrentLocation];

    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(finishRefresh) userInfo:nil repeats:NO];

}

- (void)finishRefresh
{
    [self.scrollView.pullToRefreshController didFinishRefresh];

    [self performSegueWithIdentifier:@"showMap" sender:self];
}
4

1 回答 1

0

Abstract

To avoid map being shown prematurely, you should actually wait for the asynchronous update operation, and the cleanest pattern to do so will be delegation. Here is a nice Apple Doc on its application in Cocoa/Cocoa Touch.

Then it will work roughly like this:

  1. Pull-to-Refresh triggers location update.
  2. When location update is finished, locationManager notifies your controller and the controller presents a map.

How it can be done

I don't know the interface of your location manager class, but if it was CLLocationManager, it could have been done this way.

CLLocationManager has a delegate property. Your view controller should:

  1. conform to CLLocationManagerDelegate protocol
  2. add itself as a delegate to locationManager
  3. implement locationManager:didUpdateLocations: method — it gets called when location data has arrived and is ready for use.

The implementation of this method should look like roughly this:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 
{
    /*
     *  shouldShowMap — BOOL property of View Controller, actually optional 
     *  but allowing to filter out handling of unwanted location updates 
     *  so they will not trigger map segue every time
     */
    if (self.shouldShowMap) {
        [self performSegueWithIdentifier:@"showMap" sender:self];
        self.shouldShowMap = NO; 
    }
    // stop updating location — you need only one update, not a stream of consecutive updates
    [self.locationManager stopUpdatingLocation];
}

Your Pull-to-Refresh handler should look like this:

__typeof (&*self) __weak weakSelf = self;

[self.scrollView addPullToRefreshWithActionHandler:^ {
    self.shouldShowMap = YES;
    [weakSelf.locationManager startUpdatingLocation];
}];

Hope it helped a bit. The best way to learn (well, in most cases) is to look at how stuff is implemented in system frameworks. Think in that direction and you'll definitely come up with a solution :)

If you need clarifications, feel free to ask, I might have not explained it clearly enough.

于 2013-10-16T16:33:04.740 回答