我有一个对象,它定义了一组协议和委托方法
另一个对象以通常的模式委托模式
响应它们 @interface object
@property (nonatomic,weak) id <myProtocol> delegate;
@end
object.delegate = someObject;
@interface someObject <object delegate>
// some object delegate methods and their implementation
@end
在许多情况下 - 我想改变特定委托方法的行为(协议的实现)
在基于块的语法中,我可以根据我的考虑轻松地为委托对象分配一个新的“块”。
但是在标准委托模式中,这是不可能的。 解决问题的一种方法是 创建一个大的调度表(在回答代理中的“if”或“switch”语句) - 但这会很难理解代码。
写一些像
这样的东西要容易得多//standard case
theObject.delegate.blockForMethodOne = ^{the usual code to run} // perhaps how to update a UITableView
if (some condition happened) //something was selected something for instance
{
theObject.delegate.blockForMethodOne = ^ { some code to run in that case }
}
没有这种语法,我们需要编写类似的东西
-(void)methodOne
{
if (standard case)
{
//standard code
}
else if (self.someConditionHappended) // awkward variable in the object to track changes
{
// the code in this case
}
// and so on
}
I've seen answers但他们还不够好。
可以动态生成选择器和块的东西会更好(代理委托)
知道怎么创建这个吗?
修改
基于一些博客,我创建了这个示例类,它将回答任何委托方法并转发它们
@interface DelegateManager : NSObject
@property (nonatomic,weak) id proxiedObject;
@property (nonatomic) BOOL justResponded;
@property (nonatomic) BOOL logOnNoResponse;
-(id)init;
-(void)forwardInvocation:(NSInvocation*)invocation;
-(id)proxiedObject;
-(void)setProxiedObject:(id)proxied;
-(BOOL)justResponded;
-(void)setLogOnNoResponse:(BOOL)log;
-(BOOL)logOnNoResponse;
@end
@interface NSMethodSignature (objctypes)
+(NSMethodSignature*)signatureWithObjCTypes:(const char*)types;
@end
@implementation DelegateManager
-(id)init
{
self = [super init];
if (self)
{
self.proxiedObject = nil;
self.justResponded = NO;
self.logOnNoResponse = NO;
}
return self;
}
-(NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
NSMethodSignature *sig;
sig=[[self.proxiedObject class] instanceMethodSignatureForSelector:selector];
if(sig==nil)
{
// sig=[NSMethodSignature signatureWithObjCTypes:"@^v^c"];
sig = [[NSObject class] instanceMethodSignatureForSelector: @selector(init)];
}
self.justResponded=NO;
return sig;
}
-(void)forwardInvocation:(NSInvocation*)invocation
{
if(self.proxiedObject==nil)
{
if(self.logOnNoResponse)
NSLog(@"Warning: proxiedObject is nil! This is a debugging message!");
return;
}
if([self.proxiedObject respondsToSelector:[invocation selector]])
{
[invocation invokeWithTarget:self.proxiedObject];
self.justResponded=YES;
}
else if(self.logOnNoResponse)
{
NSLog(@"Object \"%@\" failed to respond to delegate message \"%@\"! This is a debugging message.",[[self proxiedObject] class],NSStringFromSelector([invocation selector]));
}
return;
}
@end
此代码的工作原理如下
myobject.delegate = self.delegateManager; // always sets itself to this internal "proxy" for the delegate
-(void)setDelegate(id<myProtocol>)delegate
{
[self.delegateManager setProxiedObject:delegate];
}
消息总是发送给代理,代理会尝试将它们传递给
myObject的:
[self.delegateManager callADelegateMethod:self];
delegateManager负责传递消息
似乎可以通过做类似
的事情来扩展这一点if (something happened in my object)
{
// replace the implementation of the selector my delegate supplies
[self.myObject.delegateManager setBlock:someBlock forSelector:the selector of the delegate];
}
在delegateManager中
-(void)setBlock:(someBlock)block forSelector:(selector)aSelector
{
[self.dictionary setObject:block forKey:aSelector];
}
-(void)forwardInvocation:(NSInvocation*)invocation
{
//check if there is an entrance of a block for the particular invocation
}
问题是如何创建一个对此查找有用的密钥?
答案 0 :(得分:0)
如果你想要那样的东西:
theObject.delegate.blockForMethodOne = ^{the usual code to run}
if (some condition happened)
{
theObject.delegate.blockForMethodOne = ^ { some code to run in that case }
}
几乎没有问题:您是否要从委托外部设置委托块(blockForMethodOne)?所以从哪里调用(从委托内部?)?在什么条件下会被称为?如果我理解正确你想根据某些条件为同一个块设置不同的行为,但是为什么?你可以在不同的条件下调用不同的方法。
但如果你知道你在做什么)) - 你应该创建一个类(例如Delegate)来存储一些块,就像那样:
typedef void (^BlockCallback)(void);
@interface Delegate : NSObject
@property (nonatomic, copy) BlockCallback blockForMethodOne;
@end
它将存储在blockForMethodOne中,无论你在那里设置什么,但它不再是委托模式。设置块到某处(theObject.delegate.blockForMethodOne = ^ {通常的代码运行})将不会运行它,如果你不重新定义“blockForMethodOne”二传手,它的工作原理就像普通的属性(只储存它),所以你必须添加一些逻辑来以某种方式调用它,此时我没有看到你使用块进行任何好处。你也可以放置@property(非原子,复制)BlockCallback blockForMethodOne;在协议声明中,所以采用这个协议的任何类都应该有'blockForMethodOne',如果你愿意的话)
希望帮助
答案 1 :(得分:0)
我认为合适的解决方案是摆脱委托成员和前协议,并切换到基于纯块的API。
说,你的代表协议是:
@protocol FooDelegateProtocol <NSObject>
- (void) foo:(Foo*)foo didReceiveData:(NSData*)data;
@end
您可以按照以下方式重新定义协议
typedef void (^foo_receivedDataBlock)(NSData*);
@protocol FooProtocol <NSObject>
@property (nonatomic, copy) foo_receivedDataBlock receivedDataHandler;
@end
请注意,这不是委托的协议 - 但它是类Foo
本身的协议,需要实现它。
现在,代替一个委托,你有一堆属性是块。现在,您可以设置每个块,而不是设置类Foo
的对象的委托。对于每个委托方法,现在有一个相应的块。
现在, call-site 负责设置块。