6

Я полностью тупик, вот ситуация:Почему popViewController работает только каждый второй раз

Мое приложение использует базу Расположение Core, чтобы получить текущее местоположение пользователя, а затем пингует мой сервер на TrailBehind интересные места поблизости и отображает их как список. Нет проблем.

Чтобы сохранить батареи, я отключу службу GPS после получения моих данных с сервера. Если пользователь перемещается во время использования приложения и хочет получить новый список, он нажимает «Обновить» на контроллере навигации, а служба CLLocation снова активируется, новая партия данных извлекается с сервера, и таблица перерисовывается.

Пока приложение захватывает данные с моего сервера, я загружаю экран загрузки вращающимся глобусом, в котором говорится: «Загрузка, пожалуйста, подождите», и я скрываю панель навигации, чтобы они не ударяли «назад».

Итак, начальные данные захвата с сервера идут безупречно.

В первый раз, когда я нажимаю обновление, все коды выполняются, чтобы получить новое местоположение, снова пинговать сервер для нового списка данных и обновлять ячейки. Однако вместо того, чтобы загружать табличный вид, как он должен, он восстанавливает панель контроллера навигации для представления таблицы, но по-прежнему показывает мое загрузочное представление в главном окне. Это верно только на устройстве, все работает отлично в симуляторе.

ВТОРОЕ время, когда я нажимаю обновление, функция работает нормально.

ТРЕТЬЕ время, когда я нажимаю обновление, он терпит неудачу, как указано выше.

ЧЕТВЕРТОЕ время, когда я нахожусь, обновляется, он работает нормально.

ПЯТЫЙ раз, когда я нажимаю обновление, он терпит неудачу, как указано выше.

и т. Д. И т. Д., Даже обновляет успешные и нечетные обновления. Я перешагнул весь мой код за строкой, и все, кажется, выполняется нормально. Я действительно продолжал переходить к основным инструкциям, и после огромного количества щелчков «шаг за шагом» я обнаружил, что представление таблицы фактически отображается на экране в какой-то момент в CFRunLoopRunSpecific, но затем я нажал «продолжить», и мое загрузочное представление заняло экран.

Я абсолютно сбит с толку. Пожалуйста помоги!! Большое спасибо заранее за ваше понимание.

Video of the strange behavior:

Соответствующий код:

RootViewControllerMethods (Это базовый вид для этого проекта TableView)

- (void)viewDidLoad { 
    //Start the Current Location controller as soon as the program starts. The Controller calls delegate methods 
    //that will update the list and refresh 
    [MyCLController sharedInstance].delegate = self; 
    [[MyCLController sharedInstance].locationManager startUpdatingLocation]; 
    lv = [[LoadingViewController alloc] initWithNibName:@"Loading" bundle:nil]; 
    [self.navigationController pushViewController:lv animated:YES]; 
    [super viewDidLoad]; 
} 



- (void)updateClicked { 
    //When the location is successfully updated the UpdateCells method will stop the CL manager from updating, so when we want to update the location 
    //all we have to do is start it up again. I hope. 
    [[MyCLController sharedInstance].locationManager startUpdatingLocation]; 
    [self.navigationController pushViewController:lv animated:YES]; 
    //LV is a class object which is of type UIViewController and contains my spinning globe/loading view. 
} 



-(void)updateCells { 
    //When the Core Location controller has updated its location it calls this metod. The method sends a request for a JSON dictionary 
    //to trailbehind and stores the response in the class variable jsonArray. reloadData is then called which causes the table to 
    //re-initialize the table with the new data in jsonArray and display it on the screen. 

    [[MyCLController sharedInstance].locationManager stopUpdatingLocation]; 

    if(self.navigationController.visibleViewController != self) { 
     self.urlString = [NSString stringWithFormat:@"http://www.trailbehind.com/iphone/nodes/%@/%@/2/10",self.lat,self.lon]; 
     NSURL *jsonURL = [NSURL URLWithString:self.urlString]; 
     NSString *jsonData = [[NSString alloc] initWithContentsOfURL:jsonURL]; 
     NSLog(@"JsonData = %@ \n", jsonURL); 
     self.jsonArray = [jsonData JSONValue]; 
     [self.tableView reloadData]; 
     [self.navigationController popToRootViewControllerAnimated:YES]; 
     [jsonData release]; 
    } 
} 

CLController Методы: В основном просто отправляет все данные прямо назад к RootViewController

// Called when the location is updated 
- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
      fromLocation:(CLLocation *)oldLocation 
{ 
    NSLog(@"New Location: %@ \n", newLocation); 
    NSLog(@"Old Location: %@ \n", oldLocation); 
    @synchronized(self) { 
     NSNumber *lat = [[[NSNumber alloc] init] autorelease]; 
     NSNumber *lon = [[[NSNumber alloc] init] autorelease]; 
     lat = [NSNumber numberWithFloat:newLocation.coordinate.latitude]; 
     lon = [NSNumber numberWithFloat:newLocation.coordinate.longitude]; 
     [self.delegate noteLat:lat]; 
     [self.delegate noteLon:lon]; 
     [self.delegate noteNewLocation:newLocation]; 
     [self.delegate updateCells]; 
    } 
} 
+0

Вы прошли через эти методы в отладчике? Запустите на нем инструменты, чтобы узнать, что вы хотите создать или удалить объект? Извините, если я оскорбляю ваш интеллект, но так как я не вижу проблемы из-за быстрого взгляда, следующая вещь, которую я бы сделал, это начать шаг ... – mikeh

+0

Появляется ли поп, если вы покидаете приложение? Похоже, вы не оставляете приложение достаточно времени, чтобы получить исправление GPS в видео. Попробуйте установить контрольные точки в методах locationManager. –

ответ

0

Можете ли вы попробовать и отладить ваше приложение, чтобы узнать, куда идет управление при вызове updateCells? Кажется, что ничего не похоже на приложение.

Убедитесь, что предупреждения о сохранении памяти отсутствуют, пока вы находитесь в классе LoadViewController. Если есть предупреждение о сохранении памяти, и ваше представление RootViewController освобождается, тогда viewDidLoad будет вызван снова, когда вы поместите его в RootViewController.

Сохранять контрольные точки в представленииDidLoad и updateCells. Вы уверены, что не вызываете LoadingViewController где-нибудь еще?

+0

Я поставил точки останова в обеих этих функциях, и viewDidLoad не вызывается при загрузке экрана загрузки. Также никто из моих функций didRecieveMemoryError не вызывается. После того, как updateCells называется элементом управления, возвращается в основной стек, и я думаю, что что-то там может быть возиться со мной. –

1

Первой мыслью является то, что вы не захотите отправить startUpdatingLocation в CLLocationManager до тех пор, пока вы не подтолкнете свое загрузочное представление. Зачастую первое сообщение-locationManager: didUpdateToLocation: fromLocation: будет отображаться мгновенно с кэшированными данными GPS. Это имеет значение только в том случае, если вы действуете на каждое сообщение и не фильтруете данные GPS, как показано в вашем примере кода здесь. Однако это не повлияет на ситуацию, о которой вы описали, это заставит экран загрузки застрять.

Я столкнулся с таким же странным поведением, как это, в другой ситуации, когда я пытался вытащить контроллер корневого представления при переключении на другую вкладку, и вызов не был сделан в правильном месте. Я считаю, что popToRootViewController вызывался дважды для меня. Мое подозрение состоит в том, что ваше загрузочное представление либо выталкивается дважды, либо дважды выворачивается.

Я рекомендую внедрить -viewWillAppear :, -viewDidAppear :, -viewWillDisappear: and -viewDidDisappear: с минимальным протоколированием в вашем LoadViewController.

- (void)viewWillAppear:(BOOL)animated { 
    NSLog(@"[%@ viewWillAppear:%d]", [self class], animated); 
    [super viewWillAppear:animated]; 
} 

- (void)viewDidAppear:(BOOL)animated { 
    NSLog(@"[%@ viewDidAppear:%d]", [self class], animated); 
    [super viewDidAppear:animated]; 
} 

- (void)viewWillDisappear:(BOOL)animated { 
    NSLog(@"[%@ viewWillDisappear:%d]", [self class], animated); 
    [super viewWillDisappear:animated]; 
} 

- (void)viewDidDisappear:(BOOL)animated { 
    NSLog(@"[%@ viewDidDisappear:%d]", [self class], animated); 
    [super viewDidDisappear:animated]; 
} 

Затем запустите тест на устройстве, чтобы убедиться, что они всегда посылают в ваш контроллер представления и как часто. Вы можете добавить некоторые записи в -updateClicked, чтобы выявить двойные нажатия.

Другая мысль, в то время как ваш @synchronized блок является хорошей идеей, он будет удерживать другие потоки от выполнения этих операторов до тех пор, пока первый поток не выйдет из блока. Я предлагаю перенести сообщение -stopUpdatingLocation в первый оператор внутри этого синхронизированного блока. Таким образом, как только вы решите действовать с использованием некоторых новых данных GPS, вы сразу же сообщите CLLocationManager прекратить отправку новых данных.

0

Итак, я никогда не получал это от работы. Я наблюдаю это поведение на устройстве только каждый раз, когда я вызываю popViewController программно, вместо того, чтобы разрешить кнопку возврата по умолчанию на навигационном контроллере делать всплывающие окна.

Мое обходное решение состояло в том, чтобы создать пользовательский режим загрузки и перевернуть экран в это представление каждый раз, когда будет задержка из-за доступа к Интернету. Мой метод принимает логическую переменную yes или no - yes переключается на экран загрузки и не переключается обратно в обычный режим. Вот код:

- (void)switchViewsToLoading:(BOOL)loading { 
// Start the Animation Block 
CGContextRef context = UIGraphicsGetCurrentContext(); 
[UIView beginAnimations:nil context:context]; 
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromLeft forView:self.tableView cache:YES]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:.75]; 

// Animations 
if(loading) { 
    if (lv == nil) { lv = [[LoadingViewController alloc] initWithNibName:@"Loading" bundle:nil]; } 
    [self.view addSubview:lv.view]; 
    [self.view sendSubviewToBack:self.tableView]; 
    self.title = @"TrailBehind"; 
} 
else { 
    [lv.view removeFromSuperview]; 

} 
// Commit Animation Block 
[UIView commitAnimations]; 
//It looks kind of dumb to animate the nav bar buttons, so set those here 
if(loading) { 
    self.navigationItem.rightBarButtonItem = nil; 
    self.navigationItem.leftBarButtonItem = nil; 
    self.title = @"TrailBehind"; 
} 
else { 
    UIBarButtonItem *feedback = [[UIBarButtonItem alloc] initWithTitle:@"Feedback" style:UIBarButtonItemStylePlain target:self action:@selector(feedbackClicked)]; 
    self.navigationItem.rightBarButtonItem = feedback; 
    UIBarButtonItem *update = [[UIBarButtonItem alloc] initWithTitle:@"Move Me" style:UIBarButtonItemStylePlain target:self action:@selector(updateClicked)]; 
    self.navigationItem.leftBarButtonItem = update; 
    [feedback release]; 
    [update release]; 
} 

}

0

Глядя на ваш исходный код, я подозреваю, что этот блок очень много:

- (void)viewDidLoad { 
    ... 
    lv = [[LoadingViewController alloc] initWithNibName:@"Loading" bundle:nil]; 
    [self.navigationController pushViewController:lv animated:YES]; 
    [super viewDidLoad]; 
} 

viewDidLoad называется каждый раз СИБ загружается, что может произойти многократный раз, особенно если вы работаете с низким объемом памяти (что кажется вероятным, учитывая ваше замечание, что это происходит только на устройстве). Я рекомендую вам реализовать -didReciveMemoryWarning, а после вызова супер, по крайней мере, распечатайте журнал, чтобы вы могли видеть, происходит ли это с вами.

Вещь, которая беспокоит меня по поводу приведенного выше кода, заключается в том, что вы почти наверняка просачиваетесь lv, а это значит, что все большее число LoadingViewControllers работает. Вы говорите, что это переменная класса. Вы действительно имеете в виду, что это переменная экземпляра? ivars всегда должны использовать аксессоры (self.lv или [self lv], а не lv). Не назначайте им прямо; вы почти всегда будете ошибаться (как вы, вероятно, здесь).

0

Я столкнулся с этим во время поиска той же самой проблемы, поэтому, хотя я уверен, что вы уже решили свою проблему, я решил, что опубликую свое решение, если кто-то еще столкнется с ним ...

Эта ошибка, кажется, вызвана, когда вы назначаете два IBActions одному и тому же UIButton в построителе интерфейса. Оказалось, что кнопка, которую я использовал, чтобы направить контроллер представления в стек, была назначена двум IBActions, и каждый из них нажимал другой контроллер на стек навигационного контроллера (хотя вы только закончите видеть один из них - возможно, последний один из которых называется). Так или иначе, нажатие кнопки «Назад» на верхнем экране не отменяет его (или, возможно, это отклоняет второй, невидимый контроллер), и вам нужно нажать дважды, чтобы вернуться.

В любом случае, проверьте свои кнопки и убедитесь, что они привязаны только к одному IBAction. Это исправило это для меня.

Смежные вопросы