UI тіпті performSelectorOnMainThread және waitUntilDone: NO дегідей құлыптайды

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

7 жауаптар

Негізгі өңде болған кезде dataWithContentsOfURL: арқылы URL мекен-жайынан кейбір деректерді алдық.

Бұл мұздатуға жауапты болар еді.

Бұл интерфейсті жылжытуға тырысыңыз, сондықтан UI-де ұсынғыңыз келетін деректер дайын болғанда негізгі ағынға қоңырау шалыңыз.

4
қосылды

viewDidLoad gets called on the main thread, you're adding the timer here so the selector is called on the main thread. You aren't in background. There are many ways to make the method execute concurrently, for example you can call dispatch_async inside it:

-(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
}
3
қосылды
Сіз бұл қатені қандай қатеге ұшыратасыз?
қосылды автор Ramy Al Zuhouri, көзі
рахмет! Қате (^) (void) парамперге сәйкес келмейтін түрдегі 'unsigned long' ішінен өтетінін айтады. мұны қалайша түзетуге болатын кез келген идея?
қосылды автор user2492064, көзі

viewDidLoad gets called on the main thread, you're adding the timer here so the selector is called on the main thread. You aren't in background. There are many ways to make the method execute concurrently, for example you can call dispatch_async inside it:

-(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
}
3
қосылды
Сіз бұл қатені қандай қатеге ұшыратасыз?
қосылды автор Ramy Al Zuhouri, көзі
рахмет! Қате (^) (void) парамперге сәйкес келмейтін түрдегі 'unsigned long' ішінен өтетінін айтады. мұны қалайша түзетуге болатын кез келген идея?
қосылды автор user2492064, көзі

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
қосылды
Шон Лазастилден алынған жауап-ақ тамаша мәселе және бұл мәселеге өз үлесін қосады.
қосылды автор Wain, көзі
@BillBurgess [NSUserDefaults standardDefaults] мысал бола алмайды, бірақ жалпы ереже ретінде әдіс жарамды, себебі ол аксессуардың әдісін өңдеуге жұмсалатын шығынды болдырмайды.
қосылды автор Wain, көзі
[NSUserDefaults standardDefaults] көмегімен немесе оны айнымалыға тағайындау бірдей жады мекенжайына ие болады және жад стекке ештеңеге тұрмайды, ол тек жеке басымдылыққа айналады. Қосымша кодтар жолдарын немесе сәл ұзын сызықтарды алғыңыз келе ме?
қосылды автор Bill Burgess, көзі

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
қосылды
Шон Лазастилден алынған жауап-ақ тамаша мәселе және бұл мәселеге өз үлесін қосады.
қосылды автор Wain, көзі
@BillBurgess [NSUserDefaults standardDefaults] мысал бола алмайды, бірақ жалпы ереже ретінде әдіс жарамды, себебі ол аксессуардың әдісін өңдеуге жұмсалатын шығынды болдырмайды.
қосылды автор Wain, көзі
[NSUserDefaults standardDefaults] көмегімен немесе оны айнымалыға тағайындау бірдей жады мекенжайына ие болады және жад стекке ештеңеге тұрмайды, ол тек жеке басымдылыққа айналады. Қосымша кодтар жолдарын немесе сәл ұзын сызықтарды алғыңыз келе ме?
қосылды автор Bill Burgess, көзі

Таймерді кері шақыруды шақырғанда, сіз басты ағынмен жұмыс жасайсыз. Содан кейін «executionSelectorOnMainThread» көмегімен «buttonUpdate» әдісін шақырғанда, сіз бұл хабарды негізгі іске қосу циклінде кезекке қоюға және орындауды жалғастыруға болады. Содан кейін батырманың Update орындалатын уақыты болғанда, ол негізгі деректерді «dataWithContentsOfURL» синхронды желілік шақыруының арқасында іске қосады. Мәселеңізді түзетудің ең жақсы жолы - «immediate түймесі» дереу қоңырау шалыңыз (атқаратын қызметім орындаушыныOnMainThread қолданбаңыз, себебі сіз басты тақырыпта болғанда) және initWithURL-ді GCD асинкасына немесе NSOperationQueue-ке шақырыңыз. Деректердің жаңартылуын күтіп тұрғанда, түймені «жаңарту туралы хабарды» көрсетуіңізге болады және сіздің синхрондалған блоктың немесе бір мезгілде NSOperation аяқталғаннан кейін, сіз түпнұсқасын соңғы күйіне дейін жаңарта аласыз (жаңартуды ұмытпаңыз негізгі ағын).

2
қосылды

Таймерді кері шақыруды шақырғанда, сіз басты ағынмен жұмыс жасайсыз. Содан кейін «executionSelectorOnMainThread» көмегімен «buttonUpdate» әдісін шақырғанда, сіз бұл хабарды негізгі іске қосу циклінде кезекке қоюға және орындауды жалғастыруға болады. Содан кейін батырманың Update орындалатын уақыты болғанда, ол негізгі деректерді «dataWithContentsOfURL» синхронды желілік шақыруының арқасында іске қосады. Мәселеңізді түзетудің ең жақсы жолы - «immediate түймесі» дереу қоңырау шалыңыз (атқаратын қызметім орындаушыныOnMainThread қолданбаңыз, себебі сіз басты тақырыпта болғанда) және initWithURL-ді GCD асинкасына немесе NSOperationQueue-ке шақырыңыз. Деректердің жаңартылуын күтіп тұрғанда, түймені «жаңарту туралы хабарды» көрсетуіңізге болады және сіздің синхрондалған блоктың немесе бір мезгілде NSOperation аяқталғаннан кейін, сіз түпнұсқасын соңғы күйіне дейін жаңарта аласыз (жаңартуды ұмытпаңыз негізгі ағын).

2
қосылды