6

我完全难倒,这里的情况:为什么popViewController只工作每个其他时间

我的应用程序使用核心定位框架来获取用户的当前位置,然后在TrailBehind坪我服务器有趣的地方附近并将它们显示为一个列表。没问题。

为了节约电池,我从服务器获取数据后关闭了GPS服务。如果用户在使用应用程序时四处移动并想要一个新列表,他会在导航控制器上单击“刷新”,然后再次激活CLLocation服务,从服务器检索新的一批数据并重新绘制表格。

当应用程序从我的服务器获取数据时,我加载了一个旋转地球仪的加载屏幕,其中显示“正在加载,请稍候”,我隐藏了导航栏,因此它们不会“回”。

因此,从服务器获取的初始数据完美无瑕。

第一次刷新所有代码执行以获取新位置时,再次ping服务器以获取新数据列表并更新单元格。但是,应该不是像加载表格视图一样,而是为表格视图恢复导航控制器栏,但仍然在主窗口中显示我的加载视图。这只在设备上才是真实的,在模拟器中一切正常。

第二次我点击刷新功能正常工作。

第三次我刷新它失败,如上所述。

第四次点击刷新它正常工作。

第五次我刷新它失败,如上所述。

等等,甚至刷新成功,奇怪的刷新失败。我一行一行地遍历所有的代码,一切似乎都正常执行。我实际上继续介绍了核心指令,经过大量点击“逐步”后,我发现表格视图实际上在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 2009-05-04 03:28:44

+0

如果你离开应用程序是否会出现弹出窗口?看起来你不会离开应用足够的时间来获得视频中的GPS修复。 尝试在locationManager方法中设置断点。 – 2009-05-04 07:40:44

回答

0

您可以尝试调试应用程序以查看调用updateCells时控件的位置?似乎没有什么明显错误的应用程序。

确保当您处于LoadingViewController类中时没有内存警告。如果存在内存警告并且您的RootViewController的视图正在释放,那么当您弹出RootViewController时,将再次调用viewDidLoad。

在viewDidLoad和updateCells中保留断点。你确定你没有在其他地方调用过LoadingViewController吗?

1

第一个想法是,在推送加载视图之前,您可能不想将startUpdatingLocation发送到CLLocationManager。通常,第一个-locationManager:didUpdateToLocation:fromLocation:消息将随着缓存的GPS数据立即出现。如果您按照每条消息采取行动并且不按照示例代码中所示过滤GPS数据,则这一点很重要。但是,这不会导致您描述的情况 - 这会导致加载屏幕卡住。

我在不同的情况下遇到了类似的奇怪行为,我试图在切换到不同的选项卡时弹出到根视图控制器,并且调用未在正确的位置进行。我相信popToRootViewController被我两次调用。我的怀疑是你的加载视图要么被推两次或弹出两次。

我推荐实现-viewWillAppear:,-viewDidAppear:,-viewWillDisappear:和-viewDidDisappear:在您的LoadingViewController中使用最少的日志记录。

- (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消息移动到该@synchronized块中的第一条语句。这样,一旦你决定采取一些新的GPS数据,你立即告诉CLLocationManager停止发送新的数据。

0

所以,我从来没有得到这个工作。我只在每次以编程方式调用popViewController而不是允许导航控制器上的默认后退按钮执行弹出操作时,才在设备上观察此行为。

我的解决方法是建立一个自定义加载视图,并在每次因访问互联网而延迟时将屏幕翻转到该视图。我的方法采用了一个布尔变量是或否 - 是切换到加载屏幕,并没有切换回普通视图。下面的代码:

- (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,并且在调用super之后,至少打印一个日志,以便看看它是否发生在你身上。

上面的代码让我困扰的事情是,你几乎肯定泄漏lv,这意味着可能有越来越多的LoadingViewControllers四处奔波。你说这是一个类变量。你真的认为这是一个实例变量吗? ivars应始终使用访问器(self.lv[self lv]而不是lv)。不要直接分配给他们;你几乎总是会犯错误的(因为你很可能在这里)。

0

我碰到这个当搜寻完全相同的问题,因此,虽然我敢肯定,你已经解决了你的问题现在,我想我会后我万一有人解决方案跨越它在其他运行...

这个错误似乎当你分配两个IBActions在界面生成器相同的UIButton被引起的。事实证明,我用来将视图控制器推入堆栈的按钮被分配给两个IBAction,并且每个按钮都将一个不同的控制器推到navigationController的堆栈上(尽管最终只会看到其中的一个 - 也许是最后一个一个被称为)。因此,无论如何,按下最上面的视图上的后退按钮并不会真正消除它(或者它可能会解散第二个看不见的控制器),并且您必须按两次才能恢复。

无论如何,请检查您的按钮,并确保他们只分配到一个IBAction为。这为我修好了。

相关问题