2016-02-18 2 views
0

У меня есть гибридное приложение iPhone, использующее INTULocationManager, который работает хорошо, но программное обеспечение намного больше, чем мне нужно. Насколько я могу судить об основных принципах, но я, очевидно, получил что-то не так, когда пытался вызвать обратный вызов для блока, сохраненного при запросе местоположения. Пожалуйста, кто-нибудь может заметить, вероятно, довольно очевидную ошибку для меня.Моя сокращенная версия INTULocationManager не работает

Мой .h файл для этого

#import <Foundation/Foundation.h> 
#import <CoreLocation/CoreLocation.h> 

typedef void(^SBLocationRequestBlock)(CLLocation *currentLocation); 

@interface SBLocationManager : NSObject 

// Returns the singleton instance of this class. 

+ (instancetype)sharedInstance; 

// Creates a subscription for location updates 

- (void)subscribeToLocationUpdatesWithBlock:(SBLocationRequestBlock)block; 

// Set the minimum distance between two successive location returns 

- (void)setDistanceFilter:(double)distance; 

@end 

Мой файл .m выглядит следующим образом

#import "SBLocationManager.h" 
#import "SBLocationManager+Internal.h" 

@interface SBLocationManager() <CLLocationManagerDelegate> 

// The instance of CLLocationManager encapsulated by this class. 
@property (nonatomic, strong) CLLocationManager *locationManager; 
// Whether or not the CLLocationManager is currently sending location updates. 
@property (nonatomic, assign) BOOL isUpdatingLocation ; 
//Whether an error occurred during the last location update. 
@property (nonatomic, assign) BOOL updateFailed; 
// the code to be called when a location is available 
@property (nonatomic, assign) SBLocationRequestBlock block; 
@end 


@implementation SBLocationManager 

static id _sharedInstance; 

// Create instance of this class. 

- (instancetype)init 
    { 
    //self = [super init]; 
    if (self) { 
     _locationManager = [[CLLocationManager alloc] init]; 
     _locationManager.delegate = self; 
     _locationManager.pausesLocationUpdatesAutomatically = NO; // to keep it going in background mode 

#ifdef __IPHONE_8_4 
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_8_4 
     /* iOS 9 requires setting allowsBackgroundLocationUpdates to YES in order to receive background location updates. 
     We only set it to YES if the location background mode is enabled for this app, as the documentation suggests it is a 
     fatal programmer error otherwise. */ 
     NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; 
     if ([backgroundModes containsObject:@"location"]) { 
      if ([_locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { 
       [_locationManager setAllowsBackgroundLocationUpdates:YES]; 
      } 
     } 
#endif /* __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_8_4 */ 
#endif /* __IPHONE_8_4 */ 

    } 
    self.isUpdatingLocation = NO ; 
    return self; 
} 

+ (instancetype)sharedInstance 
    { 
    static dispatch_once_t _onceToken; 
    dispatch_once(&_onceToken, ^{ 
     _sharedInstance = [[self alloc] init]; 
    }); 
    return _sharedInstance; 
    } 

- (void)subscribeToLocationUpdatesWithBlock:(SBLocationRequestBlock)block 
    { 
    self.block = block; 
    [self requestAuthorizationIfNeeded]; 
    [self.locationManager startUpdatingLocation]; 
    self.isUpdatingLocation = YES; 
    } 

- (void)setDistanceFilter:(double)distance 
    { 
    self.locationManager.distanceFilter = distance ; 
    self.locationManager.desiredAccuracy = distance ; 
    } 


#pragma mark Internal methods 


//Requests permission to use location services on devices with iOS 8+. 

- (void)requestAuthorizationIfNeeded 
{ 
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1 
    // As of iOS 8, apps must explicitly request location services permissions 
    // SBLocationManager supports both levels, "Always" and "When In Use". 
    // SBLocationManager determines which level of permissions to request based 
    // which description key is present in your app's Info.plist 
    // If you provide values for both description keys, the more permissive "Always 
    // level is requested. 
    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1 && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) { 
     BOOL hasAlwaysKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil; 
     BOOL hasWhenInUseKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil; 
     if (hasAlwaysKey) { 
      [self.locationManager requestAlwaysAuthorization]; 
     } else if (hasWhenInUseKey) { 
      [self.locationManager requestWhenInUseAuthorization]; 
     } else { 
      // At least one of the keys NSLocationAlwaysUsageDescription 
      // NSLocationWhenInUseUsageDescription MUST be present in the Info.plis 
      // file to use location services on iOS 8+. 
      NSAssert(hasAlwaysKey || hasWhenInUseKey, @"To use location services in iOS 8+, your Info.plist must provide a value for either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription."); 
     } 
    } 
#endif /* __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1 */ 
} 


#pragma mark CLLocationManagerDelegate methods 

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 
    { 
    self.updateFailed = NO; 

    CLLocation *mostRecentLocation = [locations lastObject]; 

    dispatch_async(dispatch_get_main_queue(), ^{ 
      if (self.block) { 
       self.block(mostRecentLocation); 
      } 
     }); 
} 

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error 
     { 
    self.updateFailed = YES; 
     } 

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status 
     { 
     } 

@end 

Я призываю запрос следующим образом:

- (void)requestLocationUpdates:(double)distanceValue 
{ 
    SBLocationManager *locMgr = [SBLocationManager sharedInstance]; 
    [locMgr subscribeToLocationUpdatesWithBlock:^(CLLocation *currentLocation) { 

    NSLog (@"New Location:\n%@", currentLocation); 
    NSString *javascriptString = [NSString stringWithFormat:@"UpdateOwnLocation('%.6f','%.6f','%.6f');", currentLocation.coordinate.latitude, currentLocation.coordinate.longitude, currentLocation.horizontalAccuracy]; 

    [webView stringByEvaluatingJavaScriptFromString:javascriptString]; 

    }]; 
    [locMgr setDistanceFilter:distanceValue]; 
} 

- (void) changeLocationUpdates:(double)distanceValue 
{ 
    SBLocationManager *locMgr = [SBLocationManager sharedInstance]; 
    [locMgr setDistanceFilter:distanceValue]; 
} 

Однако, когда я бегу это (в симуляторе) я получаю

EXC_BAD_ACCESS в строке self.block (mostRecentLocation).

т. Е. Диспетчер местоположений настроен и возвращает местоположение, но мой код для вызова запрашивающего блока выходит из строя. Я заметил в отладчике, что self.block правильно указывает на код моего контроллера представления, когда в subscribeToLocationUpdatesWithBlock, но к тому времени, когда код получает вызов блока в главной очереди, он указывает где-то в другом месте. Это потому, что я больше не то же самое в этом бите кода.

Приносим извинения за неправильную терминологию, я программист javascript, пытающийся что-то сделать с XCode, который, вероятно, выходит за рамки моих навыков. Любая помощь, которую любой может предоставить, будет прекрасной.

ответ

0

Я бы использовал copy, а не assign для блока собственности. assign для простых вещей, таких как int обычно.

Чтобы сузить, если это блок или местоположение, добавьте NSLog для mostRecentLocation перед вызовом блока.

Если это не его, проверить мой блог на отладку EXC_BAD_ACCESS:

http://loufranco.com/blog/understanding-exc_bad_access

+0

копия сделал трюк. Я очень благодарен. –

Смежные вопросы