4

我有以下类,它异步发出 HTTP 发布请求以避免主 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"];

所以,这就是我的理解:

  1. doLookup在异步连接上执行请求。
  2. 当数据已完全加载时,它将调用connectionDidFinishLoading
  3. 数据加载完成后,我将从响应数据构建一个对象,并将其发送回调用控制器

我怎样才能让调用控制器监听这个?我是否需要在 ViewController 中实现自己的回调方法来监听调用,然后停止微调器并根据内容更新 UI myObj

我希望有一个我忽略的非常简单的方法......

谢谢

4

3 回答 3

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 方法。

于 2012-05-31T15:00:33.793 回答
4

您有几种方法可以ViewController在数据存在时通知您:

  1. ViewController在和之间定义一个委托协议DataFeeder,以便后者在 中向前者发送消息connectionDidFinishLoading:

  2. 使用NSNotificationCenterso 解耦:将自己作为观察者添加到默认通知中心DataFeederViewControllerViewController

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataIsThere:) name:kMyNetworkNotificationDataIsThere object:nil];
    

DataFeeder正确的时间发送通知:

     [[NSNotificationCenter defaultCenter] postNotificationName:kMyNetworkNotificationDataIsThere object:self];
  1. makeViewController实现委托方法NSURLConnection并处理响应本身(这需要将其作为参数传递给DataFeeder构造函数)。
于 2012-05-31T15:04:02.397 回答
2

一个很好的方法是使用块。您的doLookup:方法可以接受一个块对象,并且您可以在连接完成时调用它。

由于您可能希望能够使用不同的完成块执行多个查找,因此您需要将传入的块与适当的 NSURLConnection 相关联。

为此,您可以使用具有属性的NSURLConnection子类completionBlock,或使用与 Objective-C 关联的对象(通过使用objc_setAssociatedObjectandobjc_getAssociatedObject函数)将块附加到连接对象。

当方法中的一切准备就绪connectionDidFinishLoading:并且您已经准备好最终响应对象时,您从NSURLConnection对象中获取块并调用它,将最终数据传递给它。

因此,您最终希望您的客户端代码如下所示:

[feeder doLookup:@"Something" completionBlock:(FetchedData *data, NSError *error) {
    if (error) {
        // ...
        return;
    }

    // access the returned data
}];

我希望这对你来说已经足够详细了。

于 2012-05-31T15:07:00.633 回答