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