How do you return from an asynchronous NSURLConnection to the calling class?

强颜欢笑 提交于 2019-12-04 11:05:43

Yeah, you should implement your callback using the delegate pattern. That is, in my opinion, the easiest and most standard way to do it. There are other ways, as you can see in the other responses.

In your DataFeeder.h file:

@protocol DataFeederDelegate
 - (void)dataReady:(NSData*)data;
@end

@interface DataFeeder : NSObject {
 id delegate_;
}
- (id)initWithDelegate:(id<DataFeederDelegate>)delegate;
@end

In your 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

You would instantiate a DataFeeder object like this:

DataFeeder *dataFeeder = [[DataFeeder alloc] initWithDelegate:self];

Of course, the calling view controller has to implement the DataFeederDelegate methods.

You have several approaches to getting you ViewController notified when the data is there:

  1. define a delegate protocol between the ViewController and the DataFeeder, so that the latter sends a message to the former in connectionDidFinishLoading:;

  2. use NSNotificationCenter so to decouple DataFeeder and ViewController: ViewController adds itself as an observer to the default notification center:

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

while DataFeeder send the notification at the right time:

     [[NSNotificationCenter defaultCenter] postNotificationName:kMyNetworkNotificationDataIsThere object:self];
  1. make ViewController implement the delegate methods for NSURLConnection and handle the response itself (this will require passing it as a parameter to DataFeeder constructor).

A nice way to do this would be using blocks. Your doLookup: method could accept a block object, and you can invoke that when the connection finishes.

Since you probably want to be able to perform multiple lookups with different completion blocks, you need to associate the passed in block with the appropriate NSURLConnection.

To do this ou can either use an NSURLConnection subclass with a completionBlock property, or use objective-C associated objects (by using the objc_setAssociatedObject and objc_getAssociatedObject functions) to attach the block to the connection object.

When everything is ready in the connectionDidFinishLoading: method and you've prepared the final response object, you grab the block from the NSURLConnection object and invoke it, passing it the final data.

So you eventually want your client code to look like this:

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

    // access the returned data
}];

I hope this was enough detail for you.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!