Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/43.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 即使使用performSelectorOnMainThread和waitUntilDone,UI也会锁定:否_Iphone_Ios_Objective C - Fatal编程技术网

Iphone 即使使用performSelectorOnMainThread和waitUntilDone,UI也会锁定:否

Iphone 即使使用performSelectorOnMainThread和waitUntilDone,UI也会锁定:否,iphone,ios,objective-c,Iphone,Ios,Objective C,在我的viewController中,我有一个计时器,它每20秒触发一次并调用位置更新。然后,当更新位置时,我通过performselectornmainthread调用一个方法。出于某种原因,即使我包含了waitUntilDone:NO,但在执行检查时,我的用户界面一直处于锁定状态。有人知道我如何改进这一点,使屏幕不会每20秒冻结一次吗?谢谢大家! -(void)viewDidLoad { NSTimer* myTimer = [NSTimer scheduledTimerWithT

在我的viewController中,我有一个计时器,它每20秒触发一次并调用位置更新。然后,当更新位置时,我通过performselectornmainthread调用一个方法。出于某种原因,即使我包含了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];   
    }
}
最后,我的界面用以下方法更新:

viewDidLoad在主线程上被调用,您在这里添加了计时器,因此选择器在主线程上被调用。你不在幕后。有许多方法可以使该方法并发执行,例如,您可以在其中调用dispatch\u 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
}
CLLocationManager的理念是,当你的应用对位置感兴趣时,你可以创建、配置并启动它一次。然后,根据您设置的配置,每当位置发生更改时,它将回调locationManager:didUpdateToLocation:fromLocation:或locationManager:didUpdateLocations:更好。反复启动和停止location manager效率低下,不可能获得准确的位置信息

一旦你下定决心,你可能就没事了

在那之后,您需要重新开始线程,因为计时器将在主线程上启动,所以切换回主线程并不会真正改变任何事情,只会增加一个短暂的延迟

另外,不要写太多代码。特别是如果它是相同的代码一遍又一遍。例如,如果您想从用户默认设置中获取多个内容,请不要执行以下操作:

[[NSUserDefaults standardUserDefaults] stringForKey:@"savedLatitude"]
[[NSUserDefaults standardUserDefaults] stringForKey:@"savedLongitude"]
更好的做法是:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]
[defaults stringForKey:@"savedLatitude"]
[defaults stringForKey:@"savedLongitude"]
用户默认值只是一个例子,这适用于您多次无故进行的任何方法调用


每次都是一个小小的收益,但这都会增加运行时成本和可读性/维护。

在主线程上,您似乎正在使用dataWithContentsOfURL:从URL获取一些数据

看来是它造成了这次冻结


尝试将其移出,以便仅在您希望在UI中显示的数据就绪时调用主线程。

调用计时器回调时,您位于主线程中。然后,当您使用performSelectorOnMainThread调用buttonUpdate方法时,只需在主运行循环中将此消息排队,然后继续执行。然后,当执行buttonUpdate时,由于同步网络调用dataWithContentsOfURL在主线程内运行,它会阻塞UI。
解决问题的最佳方法是立即调用buttonUpdate。不要使用performSelectorOnMainThread,因为您已经在主线程中,并从GCD async或NSOperationQueue中调用initWithURL。在等待数据更新时,您可以在按钮中显示更新消息,一旦异步块或并发NSO操作终止,您可以最终将按钮更新到其最终状态。不要忘记在主线程上进行更新。

塞恩·拉巴斯蒂尔的回答也是一个很好的观点,将有助于解决问题问题。使用[NSUserDefaults standardDefaults]或将其分配给变量将具有相同的内存地址,并且不会对内存堆栈造成任何损失,这只是个人的首选。您想要额外的代码行还是稍长一点的代码行。@Billburges[NSUserDefaults standardDefaults]可能不是最好的例子,但一般来说,这种方法是有效的,因为它将避免访问器方法所做的任何处理的成本。谢谢!我收到一个错误,该错误表示将void^void传递给不兼容类型“unsigned long”的参数。有没有办法解决这个问题?
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]
[defaults stringForKey:@"savedLatitude"]
[defaults stringForKey:@"savedLongitude"]