我的简化版 INTULocationManager 不起作用
My cut down version of INTULocationManager does not work
我有一个使用 INTULocationManager 的 iPhone 混合应用程序,运行良好,但该软件远远超出我的需要。据我所知,我已经精简到最基本的内容,但是在尝试调用位置请求时保存的块的回调时,我显然遇到了一些问题。请有人帮我找出可能非常明显的错误。
我的 .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).
即位置管理器已设置并且 returns 一个位置,但我调用请求块的代码失败。我在调试器中注意到 self.block 在 subscribeToLocationUpdatesWithBlock 中时正确指向我的视图控制器代码,但是当代码开始调用主队列上的块时,它指向其他地方。这是因为这段代码中的 self 不再相同吗?
我为糟糕的术语道歉,我是一名 javascript 程序员,试图用 XCode 做一些可能超出我的技能范围的事情。任何人都可以提供任何帮助。
我会使用 copy
,而不是 assign
块 属性。 assign
通常用于简单的事情,例如 int
。
要缩小是块还是位置的范围,请在调用块之前为 mostRecentLocation
添加 NSLog
。
如果不是这样,请查看我关于调试的博客 post EXC_BAD_ACCESS
:
我有一个使用 INTULocationManager 的 iPhone 混合应用程序,运行良好,但该软件远远超出我的需要。据我所知,我已经精简到最基本的内容,但是在尝试调用位置请求时保存的块的回调时,我显然遇到了一些问题。请有人帮我找出可能非常明显的错误。
我的 .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).
即位置管理器已设置并且 returns 一个位置,但我调用请求块的代码失败。我在调试器中注意到 self.block 在 subscribeToLocationUpdatesWithBlock 中时正确指向我的视图控制器代码,但是当代码开始调用主队列上的块时,它指向其他地方。这是因为这段代码中的 self 不再相同吗?
我为糟糕的术语道歉,我是一名 javascript 程序员,试图用 XCode 做一些可能超出我的技能范围的事情。任何人都可以提供任何帮助。
我会使用 copy
,而不是 assign
块 属性。 assign
通常用于简单的事情,例如 int
。
要缩小是块还是位置的范围,请在调用块之前为 mostRecentLocation
添加 NSLog
。
如果不是这样,请查看我关于调试的博客 post EXC_BAD_ACCESS
: