0

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];
    }       
}
4

4 に答える 4

4

dataWithContentsOfURL:メイン スレッドで while を使用して URL からデータを取得しているようです。

それが凍結の原因のようです。

UI に表示するデータの準備ができたときにのみメイン スレッドを呼び出すように、それを移動してみてください。

于 2013-06-23T12:01:37.627 に答える
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"]

(ユーザーのデフォルトは単なる例です。これは、理由もなく複数回行っているメソッド呼び出しに適用されます...)

毎回わずかな利益ですが、すべてが加算されます (実行時のコストと読みやすさ/メンテナンスの両方)。

于 2013-06-23T12:00:15.243 に答える
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
}
于 2013-06-23T11:56:56.103 に答える