我正在App Delegate类中异步下载JSON提要。现在数据需要一段时间才能加载,因此我的表视图最初显示为空,然后在几秒后填充。因此,我想要:
1-找出导致此延迟的原因。因此,请保留应用程序中的所有活动:didFinishLaunchingWithOptions方法,并仅在加载完所有内容后加载VC。
OR
2-显示活动指示器,直到表格填充数据。
现在在第一个场景中,我很确定我在错误的时间推送视图控制器。我尝试过玩它,但似乎这是我的应用程序构建和运行的唯一方式。
在第二个场景中,我想知道哪个“连接”方法首先被调用,哪个最后被调用。因此,我将能够在第一种方法启动活动指示器视图,并在最后一种方法结束时释放。
以下是我的代码。任何建议/帮助非常感谢。谢谢你的阅读。
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Error"
message:@"Please check your network connection and relaunch the application"
delegate:self
cancelButtonTitle:@"Dismiss"
otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if ([responseString isEqualToString:@"Unable to find specified resource."]) {
NSLog(@"Unable to find specified resource.n");
}
else {
ListingsViewController *listingsViewController = [[ListingsViewController alloc] initWithNibName:@"ListingsViewController" bundle:nil];
listingsViewController.jsonData = responseString;
[self.navigationController pushViewController:listingsViewController animated:NO];
[self.navigationController setViewControllers:[NSArray arrayWithObject:listingsViewController] animated:NO];
[listingsViewController release];
}
[connection release];
[responseData release];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Start the HTTP request
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:@"http://www.shoofeetv.com/iphonexml/view/all_channels.json"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
// Display the navigation controller
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
答案 0 :(得分:2)
使用选项2.尽管在数据加载之前UI可能没有用,但是尽可能快地显示内容是一种很好的UI设计。至少会让应用程序的用户感觉到某些事情正在发生。
在didFinishLaunchingWithOptions中弹出UI,显示活动指示符,并在connectionDidFinishLoading中隐藏并销毁活动指示器。
我还建议将所有异步http请求逻辑包装到另一个类中,让它接受委托,然后例如你可以调用:
{
// Show activity indicator
[httpClient get:@"www.example.com/json" withDelegate:self];
}
-(void)httpClientSuccessful:(NSData*)response
{
// hide activity indicator
}
答案 1 :(得分:2)
选项2肯定是正确的方法。在网络操作完成之前,您永远不应阻止UI。如果您的接收效果不佳,则不需要几秒钟无响应的应用。用户将杀死它。
NSURLConnection
委托方法的调用顺序为didReceiveResponse
,didReceiveData
(可能多次),connectionDidFinishLoading
。 didFailWithError
可以随时调用。
我已经成功使用了一个模式,我立即创建并显示表视图。只要数据尚未加载,我就会显示一个带有活动指示器的单个表格单元格和一个“正在加载数据...”的文本。
<强>更新强>
这是一些代码(只是必不可少的部分)。主要思想是管理当前状态,无论是未加载,加载,失败还是就绪:
@interface MyViewController : UITableViewController<NSURLConnectionDelegate>
{
NSInteger state;
NSURLConnection* connection;
MyData* data;
}
...
@end
@implementation MyViewController
typedef enum LoadingState {
eNotLoaded,
eLoading,
eFailed,
eReady
} LoadingState;
- (void) viewWillAppear: (BOOL) animated
{
[super viewWillAppear: animated];
// Start loading the data when the table view appears for the first time
if (state == eNotLoaded) {
NSURLRequest request = // create the request
connection = [NSURLConnection initWithRequest:request delegate:self];
[request release];
state = eLoading;
}
}
- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data
{
// record and process the received data
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
// parse the received data and store it into 'data'
[connection release];
connection = nil;
// state changed; redisplay the table view
state = eReady;
[[self tableView] reloadData];
}
- (NSInteger) tableView: (UITableView*) tableView numberOfRowsInSection: (NSInteger) section
{
if (state == eReady) {
return [data numberOfRows];
} else {
return 1;
}
}
- (UITableViewCell*) tableView: (UITableView*) tableView cellForRowAtIndexPath: (NSIndexPath*) indexPath
{
static NSString* DefaultCellIdentifier = @"Default";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier: DefaultCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: DefaultCellIdentifier] autorelease];
}
if (state == eReady) {
cell.textLabel.text = [data labelAtRow: indexPath.row];
if (state == eLoading) {
cell.textLabel.text = @"Loading...";
} else {
cell.textLabel.text = @"Failed";
}
return cell;
}
答案 2 :(得分:0)
我使用了NSURLConnection
类方法sendAsynchronousRequest:queue:completionHandler:,这非常有用且直截了当。
它允许我发送一个块作为回调来分析指定请求的错误或成功:
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url]
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
[self parseData:data];
} else {
NSLog(@"ERROR %@", error);
}
}
];
这样我可以在调用方法之前激活活动指示器,并在检索到数据后将其删除,同时我可以处理错误。
我希望这会有所帮助;)