Got a singleton class, so called RequestManager, which shall handle requests made by different modules and background tasks of my application.
@interface RequestFactory : NSObject
- (void)requestDataWith:(NSString *)token
id:(NSString *)id
sender:(id<RequestFactoryDelegate>)sender;
...
@end
Then I got another class, so called SessionDelegate, which shall handle all the callbacks during the request.
@interface SessionDelegate : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
@property (weak, nonatomic) id <RequestFactoryDelegate> delegate;
@end
My idea is to encapsulate the functions in these classes to not overload my classes, because I need a lot of helper classes with CommonCrypto and so on.
So I set quickly coded a protocol RequestFactoryDelegate to send the received data to the sender who initiated the origin request.
- (void)requestDataWith:(NSString *)token
id:(NSString *)id
sender:(id<RequestFactoryDelegate>)sender
{
self.sessionDelegate.delegate = sender;
NSMutableURLRequest *request = //create the request here
NSURLSessionDataTask *dataTask = [self.defaultSession dataTaskWithRequest:request];
[dataTask resume];
}
Well, it works if I have an object, let us call it senderA which sends the requests, because the set delegate is always senderA itself.
The problem occurs having another object, e.g. senderB which sends requests - not even at the same time - but very shortly after senderA send.
- (void)foo
{
[requestFactory requestDataWith:token
id:id
sender:senderA]; // let's assume this takes 20s
[requestFactory requestDataWith:token
id:id
sender:senderB]; // let's assume this takes 1s
}
Because the request of senderA is still in progress, senderB sets the delegate to him and what happens is the delegate function of senderB is run twice.
<senderB>
<senderB>
Well... I really need to implement an own custom delegate (whether or not in the same class as the RequestFactory or not), but how to I handle the callback methods so I can respond properly to either senderA or senderB?
My last idea is to override the NSURLSessionTasks class and implement an own delegate property or block property or whatever.
Many thanks in advance.
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.
}