Iphone 为什么popViewController每隔一段时间才工作

Iphone 为什么popViewController每隔一段时间才工作,iphone,cocoa-touch,uiviewcontroller,uinavigationcontroller,Iphone,Cocoa Touch,Uiviewcontroller,Uinavigationcontroller,我完全被难住了,情况如下: 我的应用程序使用核心位置框架获取用户的当前位置,然后ping我的服务器以查找附近感兴趣的位置,并将其显示为列表。没问题 为了节省电池,我在从服务器获取数据后关闭GPS服务。如果用户在使用应用程序时四处移动,并想要一个新列表,他单击导航控制器上的“刷新”,然后再次激活CLLocation服务,则会从服务器检索一批新数据并重新绘制该表 当应用程序从我的服务器抓取数据时,我加载了一个加载屏幕,屏幕上有一个旋转的地球仪,上面写着“正在加载,请稍候”,我隐藏了导航栏,这样他们就

我完全被难住了,情况如下:

我的应用程序使用核心位置框架获取用户的当前位置,然后ping我的服务器以查找附近感兴趣的位置,并将其显示为列表。没问题

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

当应用程序从我的服务器抓取数据时,我加载了一个加载屏幕,屏幕上有一个旋转的地球仪,上面写着“正在加载,请稍候”,我隐藏了导航栏,这样他们就不会点击“返回”

因此,从服务器抓取的初始数据是完美的

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

第二次点击刷新时,该功能正常工作

第三次按刷新时,它失败,如上所述

我第四次按“刷新”时,它工作正常

第五次按刷新时,它失败,如上所述

以此类推,偶数刷新成功,奇数刷新失败。我一行一行地检查了我所有的代码,似乎一切都在正常执行。实际上,我继续浏览核心指令,在大量单击“逐步浏览”之后,我发现在CFRunLoopRunSpecific中的某个点上,表视图确实显示在屏幕上,但我随后单击了“继续”,我的加载视图接管了屏幕

我完全困惑不解。请帮忙!!非常感谢您的洞察力

相关代码:

RootViewControllerMethods(这是此TableView项目的基础视图)

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

在调用updateCells时,是否可以尝试调试应用程序以查看控件的位置?应用程序似乎没有任何明显的问题

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


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

第一个想法是,在推送加载视图之前,您可能不想将startUpdatingLocation发送到CLLocationManager。通常,第一条-locationManager:didUpdateToLocation:fromLocation:消息会与缓存的GPS数据一起立即出现。只有当您处理每条消息,而不是如示例代码所示过滤GPS数据时,这才重要。但是,这不会导致您描述的情况-它会导致加载屏幕卡住

在另一种情况下,我也经历过类似的奇怪行为,在切换到其他选项卡时,我试图弹出根视图控制器,但调用没有在正确的位置进行。我相信popToRootViewController为我打了两次电话。我怀疑你的加载视图不是被推了两次就是被弹出了两次

我建议在加载ViewController时只需最少的日志记录即可实现-viewWillAppease:、-viewDidAppease:、-viewWillEveal:和-viewDidEveal:

- (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块是个好主意,但它只会阻止其他线程执行这些语句,直到第一个线程退出该块。我建议将-stopUpdatengLocation消息移动到@synchronized块中的第一条语句。这样,一旦你决定对一些新的GPS数据采取行动,你就会立即告诉CLLocationManager停止发送新数据。

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

我的解决方法是构建一个自定义加载视图,每次由于访问互联网而出现延迟时,都将屏幕翻转到该视图。我的方法使用一个布尔变量yes或no-yes切换到加载屏幕,no切换回正常视图。代码如下:

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

}

查看您的原始代码,我非常怀疑这一块:

- (void)viewDidLoad {
    ...
    lv = [[LoadingViewController alloc] initWithNibName:@"Loading" bundle:nil];
    [self.navigationController pushViewController:lv animated:YES];
    [super viewDidLoad];
 }
viewDidLoad
在每次加载NIB时都会被调用,这种情况可能会发生多次,特别是当内存不足时(考虑到您的评论,这可能只发生在设备上)。我建议您实施
-didReceiveMemoryWarning
,在调用super之后,至少打印一份日志,以便查看是否发生在您身上


上面的代码让我感到困扰的是,几乎可以肯定的是,您正在泄漏
lv
,这意味着可能会有越来越多的
加载ViewController
。你说这是一个类变量。你真的是说它是一个实例变量吗?IVAR应始终使用访问者(
self.lv
[self-lv]
而不是
lv
)。不要直接分配给他们;你几乎总是做错事(因为你可能在这里做错事)。

我在搜索完全相同的问题时遇到了这个问题,
- (void)viewDidLoad {
    ...
    lv = [[LoadingViewController alloc] initWithNibName:@"Loading" bundle:nil];
    [self.navigationController pushViewController:lv animated:YES];
    [super viewDidLoad];
 }