如何在异步获取JSON数据时显示UIActivityIndi​​catorView以在UITableView中填充?

时间:2014-09-14 19:08:27

标签: ios objective-c json uitableview asynchronous

我正在调用一个GET API,它接受一个字符串关键字并返回JSON数据,我解析并在我的UITableView中显示

当API返回数据时,我正在显示UIActivityIndi​​catorView,这很好用。 但是,一旦收到数据,UIActivityIndi​​catorView就会按预期消失,但数据不会显示在UITableView中,但如果我触摸屏幕上的任何地方,数据将在UI TableView中显示。

这是我的代码:

-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    [indicator startAnimating];
    indicator.hidesWhenStopped = YES;

    dispatch_queue_t queue = dispatch_queue_create("ID", NULL);
    dispatch_async(queue, ^{
        NSString *searchText=searchBar.text;
        NSString *trimmedString = [searchText stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
        if (trimmedString.length==0) {
            isFilter=NO;

            UIAlertView *noConn = [[UIAlertView alloc] initWithTitle:@"ERROR" message:@"Please enter something in search bar" delegate:self cancelButtonTitle:nil otherButtonTitles:@"ok", nil];
            [noConn show];
        } else {
            NSString *searchNew = [trimmedString stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
            isFilter=YES;
            @try {
                [label removeFromSuperview];
                _Title1 = [[NSMutableArray alloc] init];
                _Author1 = [[NSMutableArray alloc] init];
                _Images1 = [[NSMutableArray alloc] init];
                _Details1 = [[NSMutableArray alloc] init];
                _link1 = [[NSMutableArray alloc] init];
                _Date1 = [[NSMutableArray alloc] init];
                NSString* myURLString = [NSString stringWithFormat:@"www.example.com=%@", searchNew];
                NSURL *url = [NSURL URLWithString:myURLString];

                NSData* data = [NSData dataWithContentsOfURL:url];

                if ((unsigned long)data.length > 3) {
                    NSArray *ys_avatars = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
                    if(ys_avatars) {
                        for (int j=0;j<ys_avatars.count;j++) {
                            if( ys_avatars[j][@"title"]==[NSNull null] ) {
                                [_Title1 addObject: @""];
                            } else {
                                [_Title1 addObject:ys_avatars[j][@"title"]];
                            }

                            if( ys_avatars[j][@"author"]==[NSNull null] ) {
                                [_Author1 addObject: @""];
                            }

                            [_Author1 addObject: ys_avatars[j][@"author"]];

                            if( ys_avatars[j][@"featured_img"]==[NSNull null] ) {
                                [_Images1 addObject: @""];
                            } else {
                                [_Images1 addObject: ys_avatars[j][@"featured_img"]];

                            }

                            if( ys_avatars[j][@"content"]==[NSNull null] ) {
                                [_Details1 addObject: @""];
                            } else {
                                [_Details1 addObject:ys_avatars[j][@"content"]];
                            }

                            if( ys_avatars[j][@"permalink"]==[NSNull null] ) {
                                [_link1 addObject: @""];
                            } else {
                                [_link1 addObject:ys_avatars[j][@"permalink"]];
                            }

                            if( ys_avatars[j][@"date"]==[NSNull null] ) {
                                [_Date1 addObject: @""];
                            } else {
                                NSString *newStr=[ys_avatars[j][@"date"] substringToIndex:[ys_avatars[j][@"date"] length]-3];
                                [_Date1 addObject:newStr];
                            }
                        }
                    } else {
                        NSLog(@"error");
                    }
                    [self.myTableView reloadData];
                } else {
                    if(IDIOM == IPAD){
                        [self.myTableView reloadData];

                        self.tableView.separatorColor = [UIColor colorWithRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:1.0];

                        label = [[UILabel alloc] initWithFrame:CGRectMake(150, 200, 200, 100)];
                        label.text=@"No Article Found";
                        label.backgroundColor = [UIColor clearColor];
                        [self.view addSubview:label];
                    } else {
                        [self.myTableView reloadData];
                        self.tableView.separatorColor = [UIColor colorWithRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:1.0];
                        label = [[UILabel alloc] initWithFrame:CGRectMake(90, 100, 200, 100)];
                        label.text=@"No Article Found";
                        label.backgroundColor = [UIColor clearColor];
                        [self.view addSubview:label];
                    }
                }
            }
            @catch (NSException *exception) { }
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            [indicator performSelectorOnMainThread:@selector(stopAnimating) withObject:nil waitUntilDone:YES];
        });
    });

    [self.mySearchBar resignFirstResponder];
}

2 个答案:

答案 0 :(得分:4)

您的基本问题是您正在尝试从后台线程更新UI。 所有UI更新必须在主线程/队列上完成。

通常最简单的方法是使用:

dispatch_async(dispatch_get_main_queue(), ^{
    // code to run on the main queue
});

我实际上看到你在此处停止UIActiviteIndicatorView时正在使用它:

dispatch_async(dispatch_get_main_queue(), ^{
    [indicator performSelectorOnMainThread:@selector(stopAnimating) withObject:nil waitUntilDone:YES];
});

但是,在这种情况下,您实际上已将stopAnimating方法分派到主队列两次。你真的需要这个:

dispatch_async(dispatch_get_main_queue(), ^{
    [indicator stopAnimating];
});

至于你的表没有更新,因为你需要将所有reloadData个电话调度到主队列。

您的代码中有很多地方需要调度回主队列,但不是将dispatch_async中的所有内容包装到主队列中,而是更简单的方法。我看到你在实际做一些应该在后台线程上做的事情的唯一地方是这一行:

NSData* data = [NSData dataWithContentsOfURL:url];

这意味着你可以在方法开头摆脱dispatch_async(queue, ^{...});,而只是在你致电[NSData dataWithContentsOfUrl:url]之前做到这一点。然后,dispatch_async立即返回主队列。

像这样:

-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    [indicator startAnimating];
    indicator.hidesWhenStopped = YES;

    NSString *searchText=searchBar.text;
    NSString *trimmedString = [searchText stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
    if (trimmedString.length==0) {
        isFilter=NO;

        UIAlertView *noConn = [[UIAlertView alloc] initWithTitle:@"ERROR" message:@"Please enter something in search bar" delegate:self cancelButtonTitle:nil otherButtonTitles:@"ok", nil];
        [noConn show];
    } else {
        NSString *searchNew = [trimmedString stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
        isFilter=YES;
        @try {
            [label removeFromSuperview];
            _Title1 = [[NSMutableArray alloc] init];
            _Author1 = [[NSMutableArray alloc] init];
            _Images1 = [[NSMutableArray alloc] init];
            _Details1 = [[NSMutableArray alloc] init];
            _link1 = [[NSMutableArray alloc] init];
            _Date1 = [[NSMutableArray alloc] init];
            NSString* myURLString = [NSString stringWithFormat:@"www.example.com=%@", searchNew];
            NSURL *url = [NSURL URLWithString:myURLString];

            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                NSData* data = [NSData dataWithContentsOfURL:url];

                dispatch_async(dispatch_get_main_queue(), ^{
                    if ((unsigned long)data.length > 3) {
                        NSArray *ys_avatars = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
                        if(ys_avatars) {
                            for (int j=0;j<ys_avatars.count;j++) {
                                if( ys_avatars[j][@"title"]==[NSNull null] ) {
                                    [_Title1 addObject: @""];
                                } else {
                                    [_Title1 addObject:ys_avatars[j][@"title"]];
                                }

                                if( ys_avatars[j][@"author"]==[NSNull null] ) {
                                    [_Author1 addObject: @""];
                                }

                                [_Author1 addObject: ys_avatars[j][@"author"]];

                                if( ys_avatars[j][@"featured_img"]==[NSNull null] ) {
                                    [_Images1 addObject: @""];
                                } else {
                                    [_Images1 addObject: ys_avatars[j][@"featured_img"]];

                                }

                                if( ys_avatars[j][@"content"]==[NSNull null] ) {
                                    [_Details1 addObject: @""];
                                } else {
                                    [_Details1 addObject:ys_avatars[j][@"content"]];
                                }

                                if( ys_avatars[j][@"permalink"]==[NSNull null] ) {
                                    [_link1 addObject: @""];
                                } else {
                                    [_link1 addObject:ys_avatars[j][@"permalink"]];
                                }

                                if( ys_avatars[j][@"date"]==[NSNull null] ) {
                                    [_Date1 addObject: @""];
                                } else {
                                    NSString *newStr=[ys_avatars[j][@"date"] substringToIndex:[ys_avatars[j][@"date"] length]-3];
                                    [_Date1 addObject:newStr];
                                }
                            }
                        } else {
                            NSLog(@"error");
                        }
                        [self.myTableView reloadData];
                    } else {
                        if(IDIOM == IPAD){
                            [self.myTableView reloadData];

                            self.tableView.separatorColor = [UIColor colorWithRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:1.0];

                            label = [[UILabel alloc] initWithFrame:CGRectMake(150, 200, 200, 100)];
                            label.text=@"No Article Found";
                            label.backgroundColor = [UIColor clearColor];
                            [self.view addSubview:label];
                        } else {
                            [self.myTableView reloadData];
                            self.tableView.separatorColor = [UIColor colorWithRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:1.0];
                            label = [[UILabel alloc] initWithFrame:CGRectMake(90, 100, 200, 100)];
                            label.text=@"No Article Found";
                            label.backgroundColor = [UIColor clearColor];
                            [self.view addSubview:label];
                        }
                    }

                    [indicator stopAnimating];
                });
            });
        }
        @catch (NSException *exception) { }
    }

    [self.mySearchBar resignFirstResponder];
}

注意:你在这个方法中做了很多。我建议将其拆分为多种方法,以使您的代码更具可读性和可维护性。

答案 1 :(得分:2)

尝试使用可以省去很多麻烦的NSURLConnection并使您的网址请求更易于管理

@interface myTableView : UITableViewController<NSURLConnectionDelegate>{
     NSMutableData *_responseData;
}

然后使用委托方法解析收到的数据,停止指标查看,并重新加载您的tableview

#pragma mark NSURLConnection Delegate Methods

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    // A response has been received, this is where we initialize the instance var you created
    // so that we can append data to it in the didReceiveData method
    // Furthermore, this method is called each time there is a redirect so reinitializing it
    // also serves to clear it
    _responseData = [[NSMutableData alloc] init];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    // Append the new data to the instance variable you declared
    [_responseData appendData:data];
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse*)cachedResponse {
    // Return nil to indicate not necessary to store a cached response for this connection 
    return nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // The request is complete and data has been received
    // You can parse the stuff in your instance variable now

}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    // The request has failed for some reason!
    // Check the error var
}

并随时随地提出您的网址请求

// Create the request.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://google.com"]];

// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];

source