在我的viewController
中,我有一个定时器,每隔20秒触发一次,并调用位置更新。然后,当位置更新时,我通过performSelectorOnMainThread
调用方法。出于某种原因,即使我已经包含waitUntilDone:NO
,我的用户界面也会在执行检查时保持锁定状态。有谁知道如何改善这一点,以便屏幕不会每20秒冻结一次?谢谢!
-(void)viewDidLoad {
NSTimer* myTimer = [NSTimer scheduledTimerWithTimeInterval: 20.0 target: self
selector: @selector(callAfterSixtySecond:) userInfo: nil repeats: YES];
//other code
}
-(void) callAfterSixtySecond:(NSTimer*) t {
locationManagerProfile.delegate = self;
locationManagerProfile.desiredAccuracy = kCLLocationAccuracyBest;
[locationManagerProfile startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
[self performSelectorOnMainThread:@selector(buttonUpdate) withObject:nil
waitUntilDone:NO];
}
}
最后,我的界面使用以下方法更新:
-(void) buttonUpdate {
[locationManagerProfile stopUpdatingLocation];
NSString *userLatitude =[(PDCAppDelegate *)[UIApplication sharedApplication].delegate
getUserLatitude];
NSString *userLongitude =[(PDCAppDelegate *)[UIApplication sharedApplication].delegate
getUserLongitude];
NSString *placeLatitude = [[NSUserDefaults standardUserDefaults]
stringForKey:@"savedLatitude"];
NSString *placeLongitude = [[NSUserDefaults standardUserDefaults]
stringForKey:@"savedLongitude"];
NSString *distanceURL = [NSString stringWithFormat:@"http://www.website.com/page.php?
lat1=%@&lon1=%@&lat2=%@&lon2=%@",userLatitude, userLongitude, placeLatitude,
placeLongitude];
NSData *distanceURLResult = [NSData dataWithContentsOfURL:[NSURL
URLWithString:distanceURL]];
NSString *distanceInFeet = [[NSString alloc] initWithData:distanceURLResult
encoding:NSUTF8StringEncoding];
if ([distanceInFeet isEqualToString:@"1"]) {
UIBarButtonItem *btnGo = [[UIBarButtonItem alloc] initWithTitle:@"Button A"
style:UIBarButtonItemStyleBordered target:self action:@selector(actionA)];
self.navigationItem.rightBarButtonItem = btnGo;
[self.navigationItem.rightBarButtonItem setTintColor:[UIColor
colorWithRed:44.0/255.0 green:160.0/255.0 blue:65.0/255.0 alpha:1.0]];
UIBarButtonItem *btnGoTwo = [[UIBarButtonItem alloc] initWithTitle:@"Button B"
style:UIBarButtonItemStyleBordered target:self action:@selector(actionB)];
self.navigationItem.rightBarButtonItem = btnGoTwo;
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:btnGo,
btnGoTwo, nil];
}
if ([distanceInFeet isEqualToString:@"0"]) {
UIBarButtonItem *btnGo = [[UIBarButtonItem alloc] initWithTitle:@"Button C"
style:UIBarButtonItemStyleBordered target:self action:@selector(actionC)];
self.navigationItem.rightBarButtonItem = btnGo;
[self.navigationItem.rightBarButtonItem setTintColor:[UIColor
colorWithRed:44.0/255.0 green:160.0/255.0 blue:65.0/255.0 alpha:1.0]];
UIBarButtonItem *btnGoTwo = [[UIBarButtonItem alloc] initWithTitle:@"Button B"
style:UIBarButtonItemStyleBordered target:self action:@selector(actionB)];
self.navigationItem.rightBarButtonItem = btnGoTwo;
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:btnGo,
btnGoTwo, nil];
}
}
答案 0 :(得分:4)
似乎您在主线程上使用dataWithContentsOfURL:
从URL获取一些数据。
看起来它会导致冻结。
尝试将其移出,这样当您想要在UI中显示的数据准备就绪时,您只需调用主线程。
答案 1 :(得分:3)
viewDidLoad ,你在这里添加定时器,以便在主线程上调用选择器。你不是在后台。有许多方法可以使方法同时执行,例如,您可以在其中调用 dispatch_async :
-(void) callAfterSixtySecond:(NSTimer*) t {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ^{
locationManagerProfile.delegate = self;
locationManagerProfile.desiredAccuracy = kCLLocationAccuracyBest;
[locationManagerProfile startUpdatingLocation];
});
}
或者异步添加计时器:
-(void)viewDidLoad {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ^{
NSTimer* myTimer = [NSTimer scheduledTimerWithTimeInterval: 20.0 target: self
selector: @selector(callAfterSixtySecond:) userInfo: nil repeats: YES];
});
//other code
}
答案 2 :(得分:3)
CLLocationManager
的想法是,当您的应用对该位置感兴趣时,您可以创建,配置和启动它。然后,根据您设置的配置,只要位置发生变化,它就会回叫(locationManager:didUpdateToLocation:fromLocation:
或更好,如果可以,locationManager:didUpdateLocations:
)。反复启动和停止位置管理器效率低下,不太可能为您提供准确的位置信息。
一旦你解决了,你可能会没事。
之后,你需要刷新线程,因为计时器将在主线程上触发,因此切换回主线程并没有真正改变任何东西(只是增加了一个短暂的延迟)。
另外,不要写这么多代码。特别是如果它是一遍又一遍的相同代码。例如,如果您想从用户默认值中获取多个内容,请不要这样做:
[[NSUserDefaults standardUserDefaults] stringForKey:@"savedLatitude"]
[[NSUserDefaults standardUserDefaults] stringForKey:@"savedLongitude"]
更好:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]
[defaults stringForKey:@"savedLatitude"]
[defaults stringForKey:@"savedLongitude"]
(用户默认值只是一个示例,这适用于您无缘无故多次进行的任何方法调用...)
每次都是一个很小的收获,但它们都会增加(运行成本和可读性/维护)。
答案 3 :(得分:2)
当调用计时器回调时,您处于主线程中。然后,当您使用“performSelectorOnMainThread”调用buttonUpdate方法时,您只需在主运行循环中对此消息进行排队并继续执行。然后,当执行buttonUpdate时,由于同步网络调用“dataWithContentsOfURL”在主线程内运行,它会阻止UI。 解决问题的最佳方法是立即调用“buttonUpdate”(不要使用performSelectorOnMainThread,因为您已经在主线程中)并从GCD异步或NSOperationQueue中调用initWithURL。在等待数据更新时,您可以在按钮中显示“更新消息”,一旦异步块或并发NSOperation终止,您最终可以将按钮更新到最终状态(不要忘记更新主线程。)