简体   繁体   English

在AppDelegate中的reloadData之后未调用cellForRowAtIndexPath

[英]cellForRowAtIndexPath not called after reloadData in AppDelegate

I've been searching for a few hours now and I haven't found any solutions for my problem despite the abundance of similar posts. 我已经搜索了几个小时,尽管有很多类似的帖子,但找不到任何解决我的问题的方法。 I'm creating an app that (at the moment to start) is continuously updating the users location using startMonitoringSignificantLocationChanges . 我正在创建一个应用程序,该应用程序(从现在开始)正在使用startMonitoringSignificantLocationChanges不断更新用户位置。 I have a custom viewcontroller LocationsViewController which is simply a tableview meant to display each location the user travels to. 我有一个自定义的viewcontroller LocationsViewController ,它只是一个表视图,用于显示用户前往的每个位置。 In my didUpdateLocations : 在我的didUpdateLocations

- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations
{
    _currentLocation = _locationManager.location;
    [_locations addObject:_currentLocation];
    [_locationsViewController.tableView reloadData];
}

And then in the numberOfRowsInSection method in the LocationsViewController, I have the code: 然后在LocationsViewController的numberOfRowsInSection方法中,我有以下代码:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    AppDelegate * delegate = [AppDelegate sharedInstance];
    NSLog(@"%lu", (unsigned long)[delegate.locations count]);
    return [delegate.locations count];
}

Now I have the LocationsViewController instantiated in the AppDelegate like so: 现在,我在AppDelegate实例化了LocationsViewController ,如下所示:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    sharedInstance              = self;
    _datahub                    = [[Datahub alloc] init];
    _locations                  = [[NSMutableArray alloc] init];
    _locationManager            = [[CLLocationManager alloc] init];
    _locationManager.delegate   = self;

    UIStoryboard * storyboard   = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

    _locationsViewController    = (LocationsViewController*) [storyboard instantiateViewControllerWithIdentifier:@"locationsViewController"];
    _timePickViewController     =  (TimePickViewController*) [storyboard instantiateViewControllerWithIdentifier:@"timePickViewController"];


    if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
        [_locationManager requestAlwaysAuthorization];
    }

    [_locationManager startMonitoringSignificantLocationChanges];
    return YES;
}

In LocationsViewController 's numberOfRowsInSection method, the count of delegate.locations is 0 when the LocationsViewController is first instantiated. LocationsViewControllernumberOfRowsInSection方法中,首次实例化LocationsViewController时, delegate.locations numberOfRowsInSection的计数为0。 However after didUpdateLocations is called, the array delegate.locations is populated with 1 location. 但是,在didUpdateLocations之后,将使用1个位置填充数组delegate.locations didUpdateLocations The reloadData method is then called and when numberOfRowsInSection is called again it returns 1. If the method returns 1 then cellForRowAtIndexPath should be called right after; 然后,调用reloadData方法,并再次调用numberOfRowsInSection时,它返回1。如果该方法返回1,则应cellForRowAtIndexPath其后调用cellForRowAtIndexPath否则,将立即调用cellForRowAtIndexPath However for some reason, it isn't getting called. 但是由于某种原因,它没有被调用。 I was wondering if anyone knew, 1. What the problem could be with my code (I don't think it has to do with any formatting or tableview setup since I used storyboards), I have my dataSource and delegate both set to self.tableView , I also tried implementing the heightForRowAtIndexPath method. 我想知道是否有人知道1.我的代码可能有什么问题(因为我使用情节提要,所以我认为它与任何格式或表格视图设置无关),我的dataSourcedelegate都设置为self.tableView ,我还尝试实现heightForRowAtIndexPath方法。 And whatever I do, I have no luck. 无论我做什么,我都没有运气。 Upon calling reloadData all of the correct methods are called except for cellForRowAtIndexPath . 调用reloadData ,将调用所有正确的方法,但cellForRowAtIndexPath除外。 Any suggestions or leads to what could be wrong would be great. 任何建议或导致错误之处的建议都会很棒。 Here's some more code if it'll help, Thanks: LocationsViewController.m 如果有帮助,这里还有更多代码,谢谢:LocationsViewController.m

@implementation LocationsViewController
//*******************************************************************************************************************************
- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.delegate            = self;
    self.tableView.dataSource          = self;


}
//*******************************************************************************************************************************
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
//*******************************************************************************************************************************
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 30.0f;
}
//*******************************************************************************************************************************
#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
//*******************************************************************************************************************************
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    AppDelegate * delegate = [AppDelegate sharedInstance];
    NSLog(@"%lu", (unsigned long)[delegate.locations count]);
    return [delegate.locations count];
}
//*******************************************************************************************************************************
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    //Cell setup
    AppDelegate * delegate = [AppDelegate sharedInstance];

    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                      reuseIdentifier:CellIdentifier];
    }

    //Edit cell
    CLGeocoder *ceo = [[CLGeocoder alloc]init];

    CLLocation * location = delegate.locations[indexPath.row];

    [ceo reverseGeocodeLocation:location
              completionHandler:^(NSArray * placemarks, NSError *error) {
                  CLPlacemark *placemark = [placemarks objectAtIndex:0];
                  //String to hold address
                  cell.textLabel.text = [NSString stringWithFormat:@"%F, %F", location.coordinate.latitude, location.coordinate.longitude];
                  cell.detailTextLabel.text = [NSString stringWithFormat:@"%@, %@", placemark.locality, placemark.administrativeArea];
              }
     ];

    return cell;
}

AppDelegate.m AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    sharedInstance              = self;
    _datahub                    = [[Datahub alloc] init];
    _locations                  = [[NSMutableArray alloc] init];
    _locationManager            = [[CLLocationManager alloc] init];
    _locationManager.delegate   = self;

    UIStoryboard * storyboard   = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

    _locationsViewController    = (LocationsViewController*) [storyboard instantiateViewControllerWithIdentifier:@"locationsViewController"];
    _timePickViewController     =  (TimePickViewController*) [storyboard instantiateViewControllerWithIdentifier:@"timePickViewController"];


    if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
        [_locationManager requestAlwaysAuthorization];
    }

    [_locationManager startMonitoringSignificantLocationChanges];
    return YES;
}
//*******************************************************************************************************************************
- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations
{
    _currentLocation = _locationManager.location;
    [_locations addObject:_currentLocation];
    [_locationsViewController.tableView reloadData];
}

@rdelmar's comment is the core of the problem. @rdelmar的评论是问题的核心。 In your app delegate you're instantiating a LocationsViewController and then never doing anything with it. 在您的应用程序委托中,您要实例化LocationsViewController,然后再对其执行任何操作。 That view controller will never appear on the screen, and will never do anything. 该视图控制器将永远不会出现在屏幕上,也永远不会做任何事情。

In general it's bad to make the app delegate manage anything other than initial setup and handling app delegate methods. 通常,让应用程序委托管理除初始设置和处理应用程序委托方法以外的任何事情都是很糟糕的。 You should either make your view controller create a location manager object or set up a separate location services object to do that. 您应该使视图控制器创建一个位置管理器对象,或者设置一个单独的位置服务对象来执行此操作。

It's also a very bad idea to reach into a view controller and manipulate it's view objects directly. 直接进入视图控制器并直接操纵其视图对象也是一个非常糟糕的主意。 If you need a view controller to update one of it's views then you should add a method that the outside object calls, and that method would change the view as needed. 如果您需要一个视图控制器来更新其中一个视图,则应添加一个外部对象调用的方法,该方法将根据需要更改视图。

Making the view controller manage the location manager itself is by far the simplest solution, although it's got limitations. 尽管有局限性,但使视图控制器管理位置管理器本身是最简单的解决方案。 That approach really only works well if only that view controller cares about location services. 仅当该视图控制器关心位置服务时,该方法才有效。

If you have other objects (view controllers, etc) in your app that care about location information you should create a separate object for managing location updates. 如果您的应用中还有其他关心位置信息的对象(视图控制器等),则应创建一个单独的对象来管理位置更新。 In that case you should set it up with a delegate, or give it a location update block to call when updates are available. 在这种情况下,您应该为它设置一个委托,或者给它一个位置更新块,以便在有可用更新时调用。 If you want multiple view controllers in your app to be notified at the same time you might want to use the notification manager to send out custom location update notifacations. 如果您希望同时通知应用程序中的多个视图控制器,则可能要使用通知管理器发出自定义位置更新通知。

You might want to make your location services object a singleton. 您可能希望使位置服务对象成为单例对象。 That way your view controller(s) can fetch the single instance of the location services object and set themselves as deleate/set their handler block as the active handler block when they are frontmost. 这样,您的视图控制器就可以获取位置服务对象的单个实例,并将其设置为deleate /将它们的处理程序块设置为最前面的活动处理程序块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM