我有以下类异步发出HTTP post请求以避免主UI线程出现问题:
@implementation DataFeeder
-(void) doLookup:(NSString *)inputValue
{
NSString *myRequestString = [NSString stringWithFormat:@"val=%@", inputValue];
NSMutableData *myRequestData = [ NSMutableData dataWithBytes: [ myRequestString UTF8String ] length: [ myRequestString length ] ];
NSURL * myUrl = [NSURL URLWithString: @"http://mywebsite/results.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myUrl];
[request setHTTPMethod: @"POST"];
[request setHTTPBody: myRequestData];
[request setTimeoutInterval:10.0];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// Show error message
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Use responseData
// Got all my response data here, so build up an object ready to send back
}
@end
我正在使用以下代码行从我的ViewController
调用上述内容:
MyObject * myObj = [feeder doLookup:@"SomeStaticStringForNow"];
所以,这就是我理解的方式:
doLookup
将在异步上执行请求
连接。connectionDidFinishLoading
如何让呼叫控制器听取此消息?我是否需要在ViewController中实现我自己的回调方法,该方法将监听调用,然后停止微调器并根据myObj
的内容更新UI?
我希望这是一个我忽略的简单方法......
由于
答案 0 :(得分:6)
是的,您应该使用委托模式实现回调。也就是说,在我看来,这是最简单,最标准的方法。还有其他方法,您可以在其他回复中看到。
在DataFeeder.h
文件中:
@protocol DataFeederDelegate
- (void)dataReady:(NSData*)data;
@end
@interface DataFeeder : NSObject {
id delegate_;
}
- (id)initWithDelegate:(id<DataFeederDelegate>)delegate;
@end
在DataFeeder.m
:
@implementation DataFeeder
- (id)initWithDelegate:(id<DataFeederDelegate>)delegate {
self = [super init];
if(self) {
delegate_ = delegate;
}
return self;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[delegate_ dataReady:responseData];
}
@end
您将实例化一个DataFeeder对象:
DataFeeder *dataFeeder = [[DataFeeder alloc] initWithDelegate:self];
当然,调用视图控制器必须实现DataFeederDelegate方法。
答案 1 :(得分:4)
有数种方法可以在数据出现时通知ViewController
:
在ViewController
和DataFeeder
之间定义委托协议,以便后者在connectionDidFinishLoading:
中向前者发送消息;
使用NSNotificationCenter
,以便将DataFeeder
和ViewController
分离:ViewController
将自己添加为默认通知中心的观察者:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataIsThere:) name:kMyNetworkNotificationDataIsThere object:nil];
DataFeeder
在正确的时间发送通知:
[[NSNotificationCenter defaultCenter] postNotificationName:kMyNetworkNotificationDataIsThere object:self];
ViewController
实现NSURLConnection
的委托方法并自行处理响应(这需要将其作为参数传递给DataFeeder
构造函数)。答案 2 :(得分:2)
一个很好的方法是使用块。您的doLookup:
方法可以接受块对象,您可以在连接完成时调用它。
由于您可能希望能够使用不同的完成块执行多次查找,因此需要将传入的块与相应的NSURLConnection相关联。
要执行此操作,您可以使用带有NSURLConnection
属性的completionBlock
子类,也可以使用Objective-C关联对象(使用objc_setAssociatedObject
和objc_getAssociatedObject
函数)将块附加到连接对象。
当connectionDidFinishLoading:
方法中的所有内容都准备好并且您已准备好最终响应对象时,您从NSURLConnection
对象中获取块并调用它,并将最终数据传递给它。
所以你最终希望你的客户端代码看起来像这样:
[feeder doLookup:@"Something" completionBlock:(FetchedData *data, NSError *error) {
if (error) {
// ...
return;
}
// access the returned data
}];
我希望这对你来说足够详细。