我似乎无法找到关于这个问题的任何信息,所以我想我会问社区。 p>
基本上,我有一个UITableView,我想显示一个活动指示器,同时从我的服务器加载数据。
以下是我正在尝试做的一些示例代码(我正在使用ASIHttpRequest)。
//self.listData = [[NSArray alloc] initWithObjects:@"Red", @"Green", @"Blue", @"Indigo", @"Violet", nil]; //this works
NSString *urlStr=[[NSString alloc] initWithFormat:@"http://www.google.com"]; //some slow request
NSURL *url=[NSURL URLWithString:urlStr];
__block ASIHTTPRequest *request=[ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request setCompletionBlock:^{
self.listData = [[NSArray alloc] initWithObjects:@"Red", @"Green", @"Blue", @"Indigo", @"Violet", nil]; //this doesn't work...
[table reloadData];
}];
[request setFailedBlock:^{
}];
[request startAsynchronous];
对google.com的虚拟请求什么都不做 - 它只会造成延迟,在回复中我希望通过我自己网站的一些JSON响应来重新填充表格。
但是当我尝试用颜色填充表格时,没有任何反应!我只是得到一张空白的表...如果我取消注释上面的行,它工作正常,它只是在http响应中,对我来说不起作用。
任何建议都非常感谢。
我做了一个[self.tableView reloadData];
现在它有效......
答案 0 :(得分:64)
NSURLConnection
并不难使用,并且会产生更好,更高效的代码。UITableView
提供信息。我再次推荐Core Data。我建议回顾一下MVC是如何工作的,你是设计的短路,这是核心问题。
这里有更详细的说明。首先,您希望数据检索是异步的。最容易和最可重用的方法是构建一个简单的NSOperation子类。
@class CIMGFSimpleDownloadOperation;
@protocol CIMGFSimpleDownloadDelegate <NSObject>
- (void)operation:(CIMGFSimpleDownloadOperation*)operation didCompleteWithData:(NSData*)data;
- (void)operation:(CIMGFSimpleDownloadOperation*)operation didFailWithError:(NSError*)error;
@end
@interface CIMGFSimpleDownloadOperation : NSOperation
@property (nonatomic, assign) NSInteger statusCode;
- (id)initWithURLRequest:(NSURLRequest*)request andDelegate:(id<CIMGFSimpleDownloadDelegate>)delegate;
@end
此子类是从URL下载内容的最基本方法。使用NSURLRequest
和委托构造它。它将回调成功或失败。实施只是稍长一点。
#import "CIMGFSimpleDownloadOperation.h"
@interface CIMGFSimpleDownloadOperation()
@property (nonatomic, retain) NSURLRequest *request;
@property (nonatomic, retain) NSMutableData *data;
@property (nonatomic, assign) id<CIMGFSimpleDownloadDelegate> delegate;
@end
@implementation CIMGFSimpleDownloadOperation
- (id)initWithURLRequest:(NSURLRequest*)request andDelegate:(id<CIMGFSimpleDownloadDelegate>)delegate
{
if (!(self = [super init])) return nil;
[self setDelegate:delegate];
[self setRequest:request];
return self;
}
- (void)dealloc
{
[self setDelegate:nil];
[self setRequest:nil];
[self setData:nil];
[super dealloc];
}
- (void)main
{
[NSURLConnection connectionWithRequest:[self request] delegate:self];
CFRunLoopRun();
}
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSHTTPURLResponse*)resp
{
[self setStatusCode:[resp statusCode]];
[self setData:[NSMutableData data]];
}
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)newData
{
[[self data] appendData:newData];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
[[self delegate] operation:self didCompleteWithData:[self data]];
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{
[[self delegate] operation:self didFailWithError:error];
CFRunLoopStop(CFRunLoopGetCurrent());
}
@synthesize delegate;
@synthesize request;
@synthesize data;
@synthesize statusCode;
@end
现在这个类非常可重用。您可以根据需要添加NSURLConnection的其他委托方法。 NSURLConnection
可以处理重定向,身份验证等。我强烈建议您查看其文档。
从此处,您可以从CIMGFSimpleDownloadOperation
或应用程序的其他部分中分离UITableViewController
。在本演示中,我们将在UITableViewController
中进行演示。根据您的应用需求,您可以在任何有意义的地方启动数据下载。对于这个例子,我们将在视图出现时将其踢开。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSURLRequest *request = ...;
CIMGFSimpleDownloadOperation *op = [[CIMGFSimpleDownloadOperation alloc] initWithURLRequest:request andDelegate:self];
[[NSOperationQueue mainQueue] addOperation:op];
[self setDownloadOperation:op]; //Hold onto a reference in case we want to cancel it
[op release], op = nil;
}
现在,当视图出现时,将进行异步调用并下载URL的内容。在此代码中将通过或失败。失败第一:
- (void)operation:(CIMGFSimpleDownloadOperation*)operation didFailWithError:(NSError*)error;
{
[self setDownloadOperation:nil];
NSLog(@"Failure to download: %@\n%@", [error localizedDescription], [error userInfo]);
}
成功后我们需要解析回来的数据。
- (void)operation:(CIMGFSimpleDownloadOperation*)operation didCompleteWithData:(NSData*)data;
{
[self setDownloadOperation:nil];
NSLog(@"Download complete");
//1. Massage the data into whatever we want, Core Data, an array, whatever
//2. Update the UITableViewDataSource with the new data
//Note: We MIGHT be on a background thread here.
if ([NSThread isMainThread]) {
[[self tableView] reloadData];
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
[[self tableView] reloadData];
});
}
}
完成了。您可以编写更多代码行,但它会替换使用ASI导入的13K +代码行,从而生成更小,更精简,更快的应用程序。更重要的是,它是一个你理解每一行代码的应用程序。
答案 1 :(得分:12)
这是问题
request setCompletionBlock:^{
self.listData = [[NSArray alloc] initWithObjects:@"Red", @"Green", @"Blue", @"Indigo", @"Violet", nil]; //this doesn't work...
[table performSelectorOnMainThread:@selector(reloadTable) withObject:nil waitUntilDone:NO];
}];
需要在主线程上完成重装表。
答案 2 :(得分:0)
我尝试过NWCoder的解决方案,但它没有用,因为它调用了错误的方法。这是我用的。
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];