无法填充UITableView,源数组有效

时间:2012-08-18 21:35:07

标签: ios objective-c multithreading uitableview grand-central-dispatch

我不能让我的表视图显示我的数据,该数组由NSLog输出有有效数据。我在tableView:cellForRowAtIndexPath:的开头放了一个断点,它永远不会到达那里。有什么想法吗?

#import "ViewController.h"
#import "Ride.h"

@interface ViewController ()
@property (nonatomic, strong) NSMutableData *responseData;
@end

@implementation ViewController

@synthesize rideIds = _rideIds;
@synthesize rideNames = _rideNames;

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"viewdidload");

    self.responseData = [NSMutableData data];


    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    // http://www.strava.com/api/v1/segments/229781/efforts?best=true

    // Efforts on segment by athlete limited by startDate and endDate
    //NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.strava.com/api/v1/segments/229781/efforts?athleteId=11673&startDate=2012-02-01&endDate=2012-02-28"]];

    //Leader Board on Segment all Athletes
    //NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.strava.com/api/v1/segments/229781/efforts?best=true"]];

    //Rides by Athlete
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.strava.com/api/v1/rides?athleteId=10273"]];


    //Twitter Example
    //NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://api.twitter.com/1/trends"]];


    //Efforts by Ride
    //NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.strava.com/api/v1/rides/77563/efforts"]];

    //Effort Detail
    //NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.strava.com/api/v1/efforts/688432"]];


    //Google API Call
    //NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://maps.googleapis.com/maps/api/place/search/json?location=-33.8670522,151.1957362&radius=500&types=food&name=harbour&sensor=false&key=AIzaSyAbgGH36jnyow0MbJNP4g6INkMXqgKFfHk"]];

/*    dispatch_async(dispatch_get_main_queue(),^ {
        NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    } ); */

        NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

    if(theConnection){
        self.rideIds = [[NSMutableArray alloc]init];
        self.rideNames  = [[NSMutableArray alloc] init];
    } else {
        NSLog(@"No Connection");
        }





}


//Delegate methods for the NSURLConnection

//In order to download the contents of a URL, an application needs to provide a delegate object that, at a minimum, implements the following delegate methods: connection:didReceiveResponse:, connection:didReceiveData:, connection:didFailWithError: and connectionDidFinishLoading:.

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

    NSLog(@"didReceiveResponse");

    //This message can be sent due to server redirects, or in rare cases multi-part MIME documents.
    //Each time the delegate receives the connection:didReceiveResponse: message, it should reset any progress indication and discard all previously received data.

    [self.responseData setLength:0];
}


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    [self.responseData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {

    NSLog(@"didFailWithError");
    NSString *errorDescription = [error description];
//    NSLog([NSString stringWithFormat:@"Connection failed: %@", errorDescription]);
    NSLog(@"Connection failed: %@", errorDescription);
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    NSLog(@"connectionDidFinishLoading");
    NSLog(@"Succeeded! Received %d bytes of data",[self.responseData length]);

    // convert to JSON
    NSError *myError = nil;
    //NSDictionary *jsonRes = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:&myError];

    NSDictionary *jsonResult = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:&myError];
    NSDictionary *jsonRides =[jsonResult objectForKey:@"rides"];


    // Show all values coming out of "rides" key
    // Store ride id's and names on arrays for later display on tableview
    for (NSDictionary *rides in jsonRides) {

        [self.rideIds addObject:[rides objectForKey:@"id"]];
        NSLog(@"id = %@", [rides objectForKey:@"id"]);
        //NSLog(@"%@",self.rideIds);

        [self.rideNames addObject:[rides objectForKey:@"name"]];
        NSLog(@"name = %@", [rides objectForKey:@"name"]);
        //NSLog(@"%@",self.rideNames);
    }
        NSLog(@"%@",self.rideIds);
        NSLog(@"%@",self.rideNames);

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    // Show all values coming out of NSKSONSerialization
    for(id key in jsonResult) {

        id value = [jsonResult objectForKey:key];

        NSString *keyAsString = (NSString *)key;
        NSString *valueAsString = (NSString *)value;

        NSLog(@"key: %@", keyAsString);
        NSLog(@"value: %@", valueAsString);
    }

    // extract specific value...
    // NSArray *results = [res objectForKey:@"results"];
    /*NSArray *results = [res objectForKey:@"rides"];
    for (NSDictionary *result in results) {
        NSData *athleteData = [result objectForKey:@"name"];
        NSLog(@"Ride name: %@", athleteData);
    }*/


/*    dispatch_async(dispatch_get_main_queue(),^ {
        [self.rideTableView reloadData];
    } ); */

    [self.rideTableView reloadData];


}



- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    NSLog(@"tableView:numberOfRowsInSection: ");

    //return self.rideIds.count;
    NSLog(@"%u",self.rideNames.count);
    return 3;
}


- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"tableView:cellForRowAtIndexPath: ");


    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if( nil == cell ) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    cell.textLabel.text= [self.rideNames objectAtIndex:indexPath.row];
    return cell;
}


- (void)tableView:(UITableView *)tv
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tv deselectRowAtIndexPath:indexPath animated:YES];
}



@end

NSLog内容:

2012-08-18 18:47:29.497 WebServiceCall[10387:c07] viewdidload
2012-08-18 18:47:29.503 WebServiceCall[10387:c07] tableView:numberOfRowsInSection: 
2012-08-18 18:47:29.503 WebServiceCall[10387:c07] 0
2012-08-18 18:47:29.504 WebServiceCall[10387:c07] tableView:cellForRowAtIndexPath: 
2012-08-18 18:47:29.506 WebServiceCall[10387:c07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(0x14b6022 0xeb6cd6 0x14a2d88 0x395d 0xb3c54 0xb43ce 0x9fcbd 0xae6f1 0x57d42 0x14b7e42 0x1d87679 0x1d91579 0x1d164f7 0x1d183f6 0x1da5160 0x17e84 0x18767 0x27183 0x27c38 0x1b634 0x13a0ef5 0x148a195 0x13eeff2 0x13ed8da 0x13ecd84 0x13ecc9b 0x17c65 0x19626 0x22fd 0x2265 0x1)
terminate called throwing an exception(lldb)  

更新:似乎在通过viewDidLoad后,它跳转到tableview:numberOfRowsInSection方法,跳过所有4种方法来处理NSURLConnection(我更新了我的数组)。

我的视图控制器既是我的NSURLConnection又是tableView的代表。它似乎首先运行tableView方法。有关如何使其首先运行NSURLConnection方法的任何建议吗?

2 个答案:

答案 0 :(得分:0)

tableView:numberOfSectionsInTableView:在哪里?也许这会返回 0 ,但如果未设置则默认为 1 ;您还需要在tableView上设置delegatedataSource

答案 1 :(得分:0)

您可以尝试两件事 - 首先,在您的numberOfRowsInSection方法中记录self.rideIds.count以确保它不返回0.其次,在您的connectionDidFinishLoading方法结束时,输入[tableView reloadData](或者其他表视图的出口是),它应该解决在连接完成之前调用表视图方法的问题。

编辑后:错误“ - [__ NSArrayM objectAtIndex:]:索引0超出空数组的边界”是由numberOfRowsInSection方法中的“返回3”引起的。当应用程序启动时,表视图将尝试在连接返回任何结果之前填充自身,因此numberOfRowsInSection应该在第一次返回0时返回0,如果您放回返回self.rideIds.count行,它将执行此操作。如果在连接委托方法结束时执行reloadData,那么将填充数组并且表视图应该正常工作。