使用MKMapView进行NSRangeException,在主线程上初始化

时间:2014-05-30 10:35:33

标签: ios objective-c mkmapview

我有一个奇怪的问题:当我在我的应用程序中更改语言时,一切似乎都没问题,但有时当我连续执行4次以上时,我有一个错误:2014年 -

05-31 18:13:46.304 MobileControl[1173:a72f] CRASH:
<MKMapView: 0x18fe7840; frame = (0 0; 0 0); transform = [0, 0, 0, 0, 0, 0]; alpha = 0; opaque = NO; layer = (null)> initWithCoder:: MKMapView must be initialized on the main thread.
2014-05-31 18:13:46.372 MobileControl[1173:a72f] Stack Trace:
(
    0   CoreFoundation                      0x2f02cfeb <redacted> + 154
    1   libobjc.A.dylib                     0x39d03ccf objc_exception_throw + 38
    2   CoreFoundation                      0x2f02cf15 <redacted> + 0
    3   MapKit                              0x301facb1 <redacted> + 1228
    4   UIKit                               0x31c5d171 <redacted> + 740
    5   UIKit                               0x31c5ce87 <redacted> + 90
    6   UIKit                               0x31bb85e1 <redacted> + 112
    7   UIKit                               0x31c5d171 <redacted> + 740
    8   UIKit                               0x31c5d111 <redacted> + 644
    9   UIKit                               0x31c5ce87 <redacted> + 90
    10  UIKit                               0x31bb7dd9 <redacted> + 888
    11  UIKit                               0x31b1062b <redacted> + 234
    12  UIKit                               0x3196cbed <redacted> + 92
    13  UIKit                               0x3184d30d <redacted> + 72
    14  UIKit                               0x318f7c01 <redacted> + 32
    15  UIKit                               0x318f7b17 <redacted> + 230
    16  UIKit                               0x318f70f3 <redacted> + 78
    17  UIKit                               0x318f6e1d <redacted> + 572
    18  UIKit                               0x318f6b8d <redacted> + 44
    19  UIKit                               0x318f6b25 <redacted> + 184
    20  UIKit                               0x31848d79 <redacted> + 380
    21  QuartzCore                          0x314c662b <redacted> + 142
    22  QuartzCore                          0x314c1e3b <redacted> + 350
    23  QuartzCore                          0x314c1ccd <redacted> + 16
    24  QuartzCore                          0x314c16df <redacted> + 230
    25  QuartzCore                          0x314c14ef <redacted> + 314
    26  QuartzCore                          0x314eea83 <redacted> + 162
    27  libsystem_pthread.dylib             0x3a32e68d <redacted> + 164
    28  libsystem_pthread.dylib             0x3a32e40b <redacted> + 86
    29  libsystem_pthread.dylib             0x3a32f17d pthread_exit + 28
    30  Foundation                          0x2f96946f <redacted> + 10
    31  Foundation                          0x2fa15a7d <redacted> + 1092
    32  libsystem_pthread.dylib             0x3a32f919 <redacted> + 140
    33  libsystem_pthread.dylib             0x3a32f88b _pthread_start + 102
    34  libsystem_pthread.dylib             0x3a32daa4 thread_start + 8
)
2014-05-31 18:13:46.378 MobileControl[1173:a72f] *** Terminating app due to uncaught exception 'NSRangeException', reason: '<MKMapView: 0x18fe7840; frame = (0 0; 0 0); transform = [0, 0, 0, 0, 0, 0]; alpha = 0; opaque = NO; layer = (null)> initWithCoder:: MKMapView must be initialized on the main thread.'
*** First throw call stack:
(0x2f02cfd3 0x39d03ccf 0x2f02cf15 0x301facb1 0x31c5d171 0x31c5ce87 0x31bb85e1 0x31c5d171 0x31c5d111 0x31c5ce87 0x31bb7dd9 0x31b1062b 0x3196cbed 0x3184d30d 0x318f7c01 0x318f7b17 0x318f70f3 0x318f6e1d 0x318f6b8d 0x318f6b25 0x31848d79 0x314c662b 0x314c1e3b 0x314c1ccd 0x314c16df 0x314c14ef 0x314eea83 0x3a32e68d 0x3a32e40b 0x3a32f17d 0x2f96946f 0x2fa15a7d 0x3a32f919 0x3a32f88b 0x3a32daa4)
libc++abi.dylib: terminating with uncaught exception of type NSException

虽然一切都与MKMapView相关,我在主线程中做了什么。

我知道这种情况并不常见,正常的应用用户在几秒钟内没有超过4次更改语言,但它仍然给我一个错误。

更改语言:

Settings.m:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self.TableViewLanguage deselectRowAtIndexPath:indexPath animated:YES];

    switch (indexPath.row)
    {
        case kLANG_HEB:
            userLang = kHEB;
            [defaults setObject:@[@"he", @"en"] forKey:@"AppleLanguages"];
            break;
        case kLANG_ENG:
            userLang = kENG;
            [defaults setObject:@[@"en", @"he"] forKey:@"AppleLanguages"];
            break;
        case kLANG_RUS:
            userLang = kRUS;
            [defaults setObject:@[@"ru", @"en"] forKey:@"AppleLanguages"];
            break;
        case kLANG_ARAB:
            userLang = kARAB;
            [defaults setObject:@[@"ar", @"en"] forKey:@"AppleLanguages"];
            break;
        case kLANG_FRA:
            userLang = kFRA;
            [defaults setObject:@[@"fr", @"en"] forKey:@"AppleLanguages"];
    }

    [defaults setValue:userLang forKey:@"language"];
    [defaults setBool:YES forKey:ComeFromChangeLang];
    [defaults synchronize];


    if ([appDelegate.window.rootViewController isKindOfClass:[SplashScreen class]]) {
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    else {
        SplashScreen *viewController = [self.storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
        UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:viewController];

        MainMap *mapViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"MainAppScreen"];
        mapViewController.mapView.delegate = nil;

        dispatch_async(dispatch_get_main_queue(), ^{
            appDelegate.window.rootViewController = nc;
            [appDelegate.window makeKeyAndVisible];
        });
    }
}

处理地图:

MainMap.m:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    defaults = [NSUserDefaults standardUserDefaults];

    self.navigationController.navigationBarHidden = NO;

    [self initSidePanel];

    self.navigationItem.title = NSLocalizedString(@"my_location", nil);

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(popToRootViewController:)
                                                 name:kPopToRootViewController
                                               object:nil];

    if (__iOS_7_And_Heigher) {
        CGRect frame = self.btnCenterLocation.frame;
        frame.origin.y += 12;
        self.btnCenterLocation.frame = frame;
    }

    [defaults removeObjectForKey:@"TEMPORARY_MOBILE"];
    [defaults removeObjectForKey:@"userPassword"];
    [defaults setBool:NO forKey:kLogoutKey];
    [defaults synchronize];

    [SVProgressHUD dismiss];

    if ([CLLocationManager locationServicesEnabled]) {
        [self initMainMap];
    }
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if ([self.navigationController.navigationBar respondsToSelector:@selector(setBarTintColor:)]) {
        [self.navigationController.navigationBar setBarTintColor:OrangeOfficialColor];
        [self.navigationController.navigationBar setTintColor:[UIColor whiteColor]];
    } else {
        [self.navigationController.navigationBar setTintColor:OrangeOfficialColor];
    }
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    if ([CLLocationManager locationServicesEnabled]) {

        dispatch_async(dispatch_get_main_queue(), ^{
            self.mapView.mapType = [self getMapType];
        });
    }
    else {
        if (!self.alertView.isVisible) {
            if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied ||
                [CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) {
                self.alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"mobile_control_team", nil) message:NSLocalizedString(@"gps_and_wifi_text", nil) delegate:self cancelButtonTitle:NSLocalizedString(@"ok", nil) otherButtonTitles:nil];
                self.alertView.tag = kTagAlertViewNoLocation;
                [self.alertView show];
            }
        }
    }
}


- (void)initMainMap
{
    dispatch_async(dispatch_get_main_queue(), ^{
        self.mapView.delegate = self;
        self.mapView.mapType = [self getMapType];
        self.mapView.userInteractionEnabled = YES;
        self.mapView.userTrackingMode = MKUserTrackingModeFollow;
        self.mapView.showsUserLocation = YES;

        [self centerCurrentLocation:self.mapView.userLocation];
    });

    [[SplashScreen sharedScreen] restartService];
}

#pragma mark -
#pragma mark - MKMapView Delegate
/****************************************************************************/
/*                              MKMapView Delegate                          */
/****************************************************************************/

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    @try {
        if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) {
            return;
        }
        if (userLocation.location == nil) {
            return;
        }

        // Work around a bug in MapKit where user location is not initially zoomed to.
        if (userLocation.coordinate.latitude != 0.0 && userLocation.coordinate.longitude != 0.0) {
            MKCoordinateRegion userRegion = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 1500.0, 1500.0);

            dispatch_async(dispatch_get_main_queue(), ^{
                [mapView setRegion:userRegion animated:YES];
            });
        }
    }
    @catch (NSException *exception) {
        NSLog(@"%s, exception.reason: %@", __PRETTY_FUNCTION__, exception.reason);
    }
}

- (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error
{
    NSLog(@"%s, %@", __PRETTY_FUNCTION__, error.localizedDescription);
}

- (void)gotoLocation
{
    MKCoordinateRegion newRegion;
    newRegion.center.latitude = _locationManager.location.coordinate.latitude;
    newRegion.center.longitude = _locationManager.location.coordinate.longitude;
    newRegion.span.latitudeDelta = 0.112872;
    newRegion.span.longitudeDelta = 0.109863;

    dispatch_async(dispatch_get_main_queue(), ^{
        [self.mapView setRegion:newRegion animated:YES];
    });
}

- (MKMapType)getMapType
{
    NSLog(@"%s, [defaults integerForKey:@\"map_mode\"]: %ld", __PRETTY_FUNCTION__, (long)[defaults integerForKey:@"map_mode"]);

    switch ([defaults integerForKey:@"map_mode"]) {
        case 0:
        case 1:
            return MKMapTypeStandard;
        case 2:
            return MKMapTypeSatellite;
        case 3:
            return MKMapTypeHybrid;
        default:
            return MKMapTypeStandard;
    }
}

enter image description here

我似乎无法找到我的问题,我只是在主线程中触摸MKMapView但我仍然会收到此错误,不知道吗?

编辑1:

  • 更新了MainMap.m代码。
  • 添加了后台位置的代码。

SplashScreen.m:

- (void)restartService
{
    self.locationTracker = [[LocationTracker alloc]init];
    [self.locationTracker performSelectorOnMainThread:@selector(startService) withObject:nil waitUntilDone:NO];
}

LocationTracker.m:

- (void)startService
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    if (![CLLocationManager locationServicesEnabled]) { // Location services disabled
        NSLog(@"locationServices not enabled.");

        if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied ||
            [CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) { // User choosed not to use location
            NSLog(@"locationServices not authorized.");

            dispatch_async(dispatch_get_main_queue(), ^{
                UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"mobile_control_team", nil)
                                                                    message:NSLocalizedString(@"gps_and_wifi_text", nil)
                                                                   delegate:self
                                                          cancelButtonTitle:NSLocalizedString(@"ok", nil)
                                                          otherButtonTitles:nil];
                [alertView show];
            });
        }

        return;
    }

    if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) {
        NSLog(@"user not authorized to use locationServices.");
        [self performSelector:@selector(startService) withObject:nil afterDelay:30];
    }

    if ([defaults integerForKey:@"userID"] <= 0) {
        NSLog(@"Incorrect userID: %li", (long)[defaults integerForKey:@"userID"]);
        return;
    }

    [MobileControlHandler clearMyInfoData];

    _isFiveMinutesTimer = NO;
    _fiveMinutesTimer = 0;
    _serviceWillStop = NO;

    _operationQueue = [NSOperationQueue new];
    _internetOpsQueue = [NSOperationQueue new];

    [_operationQueue addObserver:self
                      forKeyPath:@"operationCount"
                         options:0
                         context:NULL];

    [_internetOpsQueue addObserver:self
                        forKeyPath:@"operationCount"
                           options:0
                           context:nil];

    self.isSameLocation = NO;
    self.measuredLocations = [[NSMutableArray alloc] init];

    ///
    [self startLocationTracking];
    ///

    if ([CLLocationManager locationServicesEnabled]) {
        [self performSelector:@selector(startServiceListener) withObject:nil afterDelay:3];
        [self startTimerCounter];
    }
}

+ (void)stopService
{
    [LocationTracker sharedLocationManager].delegate = nil;

    CFRunLoopStop(CFRunLoopGetCurrent());
    [self cancelPreviousPerformRequestsWithTarget:self selector:@selector(startServiceListener) object:nil];
}

- (void)startTimerCounter
{
    timerTask = [[NSTimerTask alloc] init];
    [timerTask scheduleTimerTaskInterval:TimerTaskIntervalMinutes timeValue:1 usingBlock:^{
        [self timerTaskInterval];
    }];
}

- (void)timerTaskInterval
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    if (isStandingOperation == true) {
        if (userCycleFiveTimes < 5) {
            userCycleFiveTimes++;
            isStandingOperation = true;
            [self startServiceListener];
        }
        else if (userCycleFiveTimes == 5) {
            counter = 0;
            userCycleFiveTimes = 0;
            isStandingOperation = false;
        }
    }
    else if (isStandingOperation == false) {
        counter++;

        if (counter == 1 || counter == 2 || counter == 4) {
            [self startServiceListener];
        }
        else if (counter == 8) {
            counter = 0;
            eightHowManyTimesCounter++;
            [self startServiceListener];
        }
    }

    if (eightHowManyTimesCounter == 2) {
        eightHowManyTimesCounter = 0;
        [self saveLocation];
    }

    [timerTask scheduleTimerTaskInterval:TimerTaskIntervalMinutes timeValue:1 usingBlock:^{
        [self timerTaskInterval];
    }];
}

- (void)startServiceListener
{
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"locationServices not enabled.");
        return;
    }

    if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) {
        NSLog(@"user not authorized to use locationServices.");
        return;
    }

    if (measuredLocations.count > 2) {
        NSInteger lastObjectIndex = measuredLocations.count - 1;
        NSInteger oneBeforeLastObjectIndex = lastObjectIndex - 1;
        CLLocation *locLast = measuredLocations[lastObjectIndex];
        CLLocation *locBeforeLast = measuredLocations[oneBeforeLastObjectIndex];

        if (locLast.coordinate.latitude == locBeforeLast.coordinate.latitude &&
            locLast.coordinate.longitude == locBeforeLast.coordinate.longitude) {
            NSLog(@"----------SAME ADDRESS!----------");
            self.isSameLocation = YES;
            if (self.measuredLocations.count >= 20) {
                self.measuredLocations = [[NSMutableArray alloc] init];
                self.isSameLocation = NO;
            }
        }
        else {
            self.isSameLocation = NO;
        }
    }


    if (!self.isSameLocation) {
        // NSLog(@"Different location.");
        [self saveLocation];
    }
    else {
        NSLog(@"Same location.");
    }

    [self performGetCloud];

    // GetCloud only if we don't have token (Apple push notification unique id per device)
    /*if ([defaults boolForKey:IS_TOKEN_OK] == NO || [UIDevice currentDevice].systemVersion.floatValue < 7.1) {
        [self performGetCloud];
    }*/
}

0 个答案:

没有答案