NSURLSession委托:如何相应地实现我的自定义SessionDelegate类?

Kun*_*uno 3 delegation objective-c nsurlrequest ios7 nsurlsession

有一个单例类,所谓的RequestManager,它将处理由我的应用程序的不同模块和后台任务发出的请求.

@interface RequestFactory : NSObject

- (void)requestDataWith:(NSString *)token
                     id:(NSString *)id
                 sender:(id<RequestFactoryDelegate>)sender;
...

@end
Run Code Online (Sandbox Code Playgroud)

然后我得到另一个类,所谓的SessionDelegate,它将处理请求期间的所有回调.

@interface SessionDelegate : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>

@property (weak, nonatomic) id <RequestFactoryDelegate> delegate;

@end
Run Code Online (Sandbox Code Playgroud)

我的想法是将函数封装在这些类中以不重载我的类,因为我需要很多带有CommonCrypto的辅助类等等.

因此,我快速编写了一个协议RequestFactoryDe​​legate,将接收到的数据发送给发起原始请求的发送方.

- (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];
}
Run Code Online (Sandbox Code Playgroud)

好吧,如果我有一个对象,它可以工作,我们称之为senderA发送请求,因为set delegate总是senderA本身.

问题出现了另一个对象,例如senderB发送请求 - 甚至不是在同一时间 - 但在senderA发送后不久.

- (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
 }
Run Code Online (Sandbox Code Playgroud)

因为senderA的请求仍在进行中,所以senderB将委托设置给他,发生的事情是senderB的委托函数运行两次.

 <senderB>
 <senderB>
Run Code Online (Sandbox Code Playgroud)

好吧......我真的需要实现一个自己的自定义委托(无论是否与RequestFactory在同一个类中),但是如何处理回调方法以便我能正确响应senderA或senderB?

我的最后一个想法是覆盖NSURLSessionTasks类并实现自己的委托属性或块属性或其他.

提前谢谢了.

mat*_*att 10

您可以将任意对象附加到任务:

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

并稍后(在委托中)检索它,如下所示:

NSURLRequest* req = task.originalRequest;
id thing = [NSURLProtocol propertyForKey:@"thing" inRequest:req];
Run Code Online (Sandbox Code Playgroud)

here(whatever)的值可以是任何对象.它可以是一个完成处理程序回调 - 我已经完成了它并且它工作得很好.

  • 好.顺便说一句,我刚刚确认,当应用重新连接会话时,不会记住额外的属性. (2认同)

Dar*_*ust 5

在Objective-C中,有一种子类化的替代方法可能就是你想要的:关联对象.

它的工作方式如下:您可以使用自定义键将对象"附加"(关联)到另一个对象,然后再检索它.所以在你的情况下,你会做类似的事情:

#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.
}
Run Code Online (Sandbox Code Playgroud)