我正在尝试创建一个NSURLConnection的子类,它已经预先实现了一个委托方法.
我目前的方法是使用一个“代理”委托,它具有预填充此方法并调用其他方法,如下所示:
-(BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection{
if ([self.delegate respondsToSelector:@selector(connectionShouldUseCredentialStorage:)]) {
return [self.delegate connectionShouldUseCredentialStorage:connection];
}
else{
return NULL;
}
}
delegate是实际用户定义的委托.这会导致某种问题,因为在某些情况下返回NULL会导致操作停止.
这样做的正确方法是什么?
我的类最终应该有一个预先配置的方法调用,其他东西应该由dev实现.
编辑:另一个补充什么是void委托方法的正确方法?
Edit2:另一个要求是子类应该像它的父类一样工作,但它必须预先实现一个委托方法.因此开发人员还可以实现NSURLConnection的另一个委托.无法看到如何使用自定义协议
解决方法
你可以做的是编写一个实现respondsToSelector:的nsproxy子类.像这样的东西:
URLConnectionProxyDelegate.h:
#import <Foundation/Foundation.h> @interface URLConnectionProxyDelegate : nsproxy <NSURLConnectionDelegate> - (instancetype)initWithDelegate:(id<NSURLConnectionDelegate>)delegate; @end
URLConnectionProxyDelegate.m:
#import "URLConnectionProxyDelegate.h"
@implementation URLConnectionProxyDelegate
{
__weak id<NSURLConnectionDelegate> _realDelegate;
}
#pragma mark - Object Lifecycle
- (instancetype)initWithDelegate:(id<NSURLConnectionDelegate>)delegate
{
if (self) {
_realDelegate = delegate;
}
return self;
}
#pragma mark - nsproxy Overrides
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [(id)_realDelegate methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
invocation.target = _realDelegate;
[invocation invoke];
}
#pragma mark - NSObject Protocol Methods
- (BOOL)respondsToSelector:(SEL)sel
{
// replace @selector(connection:didFailWithError:) with your actual pre-implemented method's selector
if (sel == @selector(connection:didFailWithError:)) {
return YES;
}
return [_realDelegate respondsToSelector:sel];
}
#pragma mark - NSURLConnectionDelegate Methods
// Since I don't kNow which method your pre-implemented method is,// I just chose connection:didFailWithError: as an example. Replace this
// with your actual pre-implemented method.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"Connection Failed: This gets called only when the proxy delegate is used");
}
@end
然后在你的视图控制器类中使用这个类,你可以这样做:
SomeViewController.m:
#import "SomeViewController.h"
#import "URLConnectionProxyDelegate.h"
@interface SomeViewController () <NSURLConnectionDelegate>
@end
@implementation SomeViewController
#pragma mark - Button actions
- (IBAction)testSuccessURLWithnormalDelegate:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://example.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Using self as the delegate
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (IBAction)testFailURLWithnormalDelegate:(id)sender
{
NSURL *url = [NSURL URLWithString:@"not a real url"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Using self as the delegate
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (IBAction)testSuccessURLWithProxyDelegate:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://example.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Using a proxy delegate,with self as the real delegate
URLConnectionProxyDelegate *proxy = [[URLConnectionProxyDelegate alloc] initWithDelegate:self];
[NSURLConnection connectionWithRequest:request delegate:proxy];
}
- (IBAction)testFailURLWithProxyDelegate:(id)sender
{
NSURL *url = [NSURL URLWithString:@"not a real url"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Using a proxy delegate,with self as the real delegate
URLConnectionProxyDelegate *proxy = [[URLConnectionProxyDelegate alloc] initWithDelegate:self];
[NSURLConnection connectionWithRequest:request delegate:proxy];
}
#pragma mark - NSURLConnectionDelegate Methods
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"Connection Failed: This gets called only when the view controller is used as the delegate");
}
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
{
NSLog(@"Connection success: This gets called when the view controller OR the proxy delegate is used as the delegate");
return YES;
}
@end
关于这一切的重要注意事项是URLConnectionProxyDelegate重写respondsToSelector:并将其传递给它的_realDelegate对象而不是调用super,如果选择器是你的“预实现”方法的选择器,它也总是返回YES.这意味着您甚至不必在NSURLConnectionDelegate协议中实现任何其他方法 – 您只需要实现“预先实现”的方法.
你甚至可以有几个预先实现的方法.只需在代理类的respondsToSelector中为选择器添加更多检查即可轻松完成:
[...]
if (sel == @selector(connection:didFailWithError:)) {
return YES;
}
if (sel == @selector(connectionShouldUseCredentialStorage:)) {
return YES;
}
[...]
…然后只是确保在代理类中实现所有这些方法,当然:
[...]
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"pre-implemented connection:didFailWithError:");
}
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
{
NSLog(@"pre-implemented connectionShouldUseCredentialStorage:");
return YES;
}
[...]
希望这是有道理的,对你有所帮助.