NSURLsession &JSON 导致加载 table 视图的延迟很长

NSURLsession &JSON causing very long delay in loading table view

我的 table 视图有问题,加载时间很长(有时大约 20 秒以上)。首先,这与我们的服务器或互联网连接无关,我已经检查过通过另一个系统获取数据并且它运​​行良好。 请在我的 ViewDidLoad 中找到下面的代码,您会注意到有一个 NSLOG 打印出 dataArray 的内容。为了尝试找出问题所在,我在我的 table 视图控制器中设置了两个断点,一个在 NSLOG 之后的行,另一个在 cellForRowAtIndexPath 的开头。当我 运行 它到达第一个断点时,它几乎立即显示正确的 dataArray 信息,没有延迟,即它已经非常快速地检索到 JSON 数据。 我停止程序并再次 运行 它,这次我在第一个断点停止后立即单击继续,它需要 20+ 秒,然后到达第二个断点(我只加载 3 个单元格,所以觉得这有点过分)。 我对此很陌生,所以很可能会犯一些新手错误。 无论哪种方式,我们都将不胜感激。

谢谢

//  Set up the session configuration
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];

    [[session dataTaskWithURL:[NSURL URLWithString:teacherUrl]
            completionHandler:^(NSData *data,
                                NSURLResponse *response,
                                NSError *error) {

                if (!error) {
                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
                    if (httpResponse.statusCode == 200){

                        NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers|NSJSONReadingAllowFragments error:&error];

                        // move serialised JSON into Array (as the data contained is in array)
                        dataArray=(NSArray*)[jsonData copy];
                    NSLog(@"datarr == %@", dataArray);
                        [self.tableView reloadData];



                    }
                }
            }



      ]resume];

    }


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    // Return the number of sections.
    return 1;
}

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

    // Return the number of rows in the section.


    return [dataArray count];

 }


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"teacherCell" forIndexPath:indexPath];


// Load and display name
    UILabel *nameLabel = (UILabel *)[cell viewWithTag:100];
    nameLabel.text = [dataArray[indexPath.row] valueForKeyPath: @"firstName"];

// Load and display address
    UILabel *addressLabel = (UILabel *)[cell viewWithTag:101];
    NSString *city = [dataArray[indexPath.row] valueForKeyPath: @"address.city"];
    addressLabel.text = [NSString stringWithFormat:@"%@", city];

// Load and display rating star images
    NSNumber *rating = [dataArray[indexPath.row] valueForKeyPath: @"rating"];
    UIImageView *ratingImageView = (UIImageView *)[cell viewWithTag:102];
    ratingImageView.image = [self imageForRating:rating];

// Load and display subjects
    UILabel *subjectLabel = (UILabel *)[cell viewWithTag:103];
    NSArray *arr = [dataArray [indexPath.row] valueForKeyPath:@"subjects"];
    NSString * subject1String = [arr[0] valueForKeyPath: @"name"];
    NSString * subject2String = @" ";
    NSString * dots = @" ";
    if (arr.count >1) {
        subject2String = [arr[1] valueForKeyPath: @"name"];
        if (arr.count >2) {
            dots = @"...";
        }
    }

   subjectLabel.text = [NSString stringWithFormat:@"%@ %@ %@", subject1String, subject2String, dots];

// Load and display review
    UILabel *reviewLabel = (UILabel *)[cell viewWithTag:104];
    reviewLabel.text = [dataArray[indexPath.row] valueForKeyPath: @"hotReview"];

// Load and display Number of lessons
//    UILabel *noOfLessonsLabel = (UILabel *)[cell viewWithTag:105];
//    noOfLessonsLabel.text = [dataArray[indexPath.row] valueForKeyPath: @"lessons"];

// Load and display distance
    UILabel *distanceLabel = (UILabel *)[cell viewWithTag:106];
    //distanceLabel.text = [dataArray[indexPath.row] valueForKeyPath: @"firstName"];
    distanceLabel.text = @"1.5km";


// Load and display photo using SDWEBImage
    UIImageView *photoImageView = (UIImageView *)[cell viewWithTag:120];

    NSString *urlPhotoId = [dataArray [indexPath.row]valueForKeyPath:@"picture.id"];
    NSString *urlPhoto = [NSString stringWithFormat:@"http://soon.nextdoorteacher.com/img/profiles/%@.jpg", urlPhotoId];

    [photoImageView sd_setImageWithURL:[NSURL URLWithString:urlPhoto] placeholderImage:[UIImage imageNamed:@"mortarboard2"]];

    return cell;
}


- (UIImage *)imageForRating:(NSNumber*)rating
{

    if (rating.floatValue >=1 && rating.floatValue <2) {
        return [UIImage imageNamed:@"1starimage"];
    }else if (rating.floatValue  >=2 && rating.floatValue <3){
        return [UIImage imageNamed:@"2starimage"];
    }else if (rating.floatValue >=3 && rating.floatValue <4){
        return [UIImage imageNamed:@"3starimage"];
    }else if (rating.floatValue >=4 && rating.floatValue <5){
        return [UIImage imageNamed:@"4starimage"];
    }else if (rating.floatValue >=5){
        return [UIImage imageNamed:@"5starimage"];
    }else{
        return nil;
    }
}

您正在发出同步请求,这就是您的 UI 被阻止的原因。

或者您为此使用块,GCD or use AFNetworking。它是用于获取和发布数据的简单库。

这是发出请求的代码:

AFHTTPRequestOperationManager *manager =    [AFHTTPRequestOperationManager manager];
[manager GET:@"http://example.com/resources.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];

在主线程上重新加载 table 数据

dispatch_async(dispatch_get_main_queue(), ^{
 [tableView reloadData];
  });

啊,@rmaddy 是对的(通常 ;)这些完成处理程序不能保证在主线程上。我通常使用 NSURLConnection 方法 sendAsynchronousRequest:queue:completionHandler: 它允许您传入 mainQueue 以保证完成块将 运行 在主线程上。如果您不想添加 GCD,您可能想切换到那个。 RahulMishra 添加的 'To reload table data on main thread' 编辑应该可以工作,但作为替代方案,您可以使用 NSURLConnection 重写该方法,如下所示:

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:teacherUrl];
[NSURLConnection
      sendAsynchronousRequest:request
                        queue:[NSOperationQueue mainQueue]
            completionHandler:^(NSURLResponse *response,
                                NSData *data,
                                NSError *connectionError) {
                if (!connectionError) {
                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
                    if (httpResponse.statusCode == 200){

                        NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers|NSJSONReadingAllowFragments error:&error];

                        // move serialised JSON into Array (as the data contained is in array)
                        dataArray=(NSArray*)[jsonData copy];
                    NSLog(@"datarr == %@", dataArray);
                        [self.tableView reloadData];
                    }
                }
            }
    }