NSURLSession delegation: How to implement my custom SessionDelegate class accordingly?

霸气de小男生 提交于 2019-12-03 20:45:06

In Objective-C, there is an alternative to subclassing that might be what you want here: associating objects.

It works like this: you can "attach" (associate) an object to another object with a custom key and later retrieve it. So in your case, you would do something like:

#include <objc/runtime.h>

// Top level of your .m file. The type and content of this
// variable don't matter much, we need the _address_ of it.
// See the first link of this answer for details.
static char kDelegateKey = 'd';

- (void)requestDataWith:(NSString *)token
                     id:(NSString *)id
                 sender:(id<RequestFactoryDelegate>)sender
{
    NSMutableURLRequest *request = //create the request here

    NSURLSessionDataTask *dataTask = [self.defaultSession dataTaskWithRequest:request];

   // Associate the sender with the dataTask. We use "assign" here
   // to avoid retain cycles as per the delegate pattern in Obj-C.
   objc_setAssociatedObject(dataTask, &kDelegateKey, sender, OBJC_ASSOCIATION_ASSIGN);

   [dataTask resume];
}

- (void)someOtherMethodWithDataTask:(NSURLSessionDataTask *)dataTask
{
    // Read the attached delegate.
    id<RequestFactoryDelegate> delegate = objc_getAssociatedObject(dataTask, &kDelegateKey);

    // Do something with the delegate.
}

You can attach an arbitrary object to a task:

NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
id whatever = // anything at all!
[NSURLProtocol setProperty:whatever forKey:@"thing" inRequest:req];
NSURLSessionDownloadTask* task = [[self session] dataTaskWithRequest:req];

And retrieve it later (in the delegate) like this:

NSURLRequest* req = task.originalRequest;
id thing = [NSURLProtocol propertyForKey:@"thing" inRequest:req];

The value here (whatever) can be any object. It can be a completion handler callback - I've done this and it works just fine.

Here is my solution.

I just just use the unique identifier of each sessionTask object. So my delegate object contains a dictionary with blocks as values to execute on success/failure and the identifier as keys to identify the correct execution block.

In the .h file I declared the dictionary and a method to add a key/value object:

@property (nonatomic, strong) NSDictionary *completionHandlerDictionary;

- (void)addCompletionHandler:(CompletionHandlerType)handler
                     forTask:(NSString *)identifier;

And in the .m file I call the handler block.

- (void)addCompletionHandler:(CompletionHandlerType)handler
                  forTask:(NSString*)identifier
{
    if ([self.completionHandlerDictionary objectForKey:identifier]) {
        NSLog(@"Error: Got multiple handlers for a single task identifier. This should   not happen.\n");
    }

    [self.completionHandlerDictionary setObject:handler forKey:identifier];
}

- (void)callCompletionHandlerForTask:(NSString *)identifier
{
    CompletionHandlerType handler = [self.completionHandlerDictionary   objectForKey:identifier];

    if (handler) {
        [self.completionHandlerDictionary removeObjectForKey: identifier];
        NSLog(@"Calling completion handler.\n");

        handler();
    }
}

That's it, simple as it is.

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