我正在尝试创建一个NSURLConnection的子类,它已经预先实现了一个委托方法.
我目前的方法是使用一个“代理”委托,它具有预填充此方法并调用其他方法,如下所示:
-(BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection{ if ([self.delegate respondsToSelector:@selector(connectionShouldUseCredentialStorage:)]) { return [self.delegate connectionShouldUseCredentialStorage:connection]; } else{ return NULL; }
}
delegate是实际用户定义的委托.这会导致某种问题,因为在某些情况下返回NULL会导致操作停止.
这样做的正确方法是什么?
我的类最终应该有一个预先配置的方法调用,其他东西应该由dev实现.
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; } [...]
希望这是有道理的,对你有所帮助.