У меня есть гибридное приложение 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, который, вероятно, выходит за рамки моих навыков. Любая помощь, которую любой может предоставить, будет прекрасной.
копия сделал трюк. Я очень благодарен. –