У меня есть объект, который определяет набор протоколов и методов делегирования.
Другой объект (ы) отвечает на них в обычном шаблоне делегата шаблона.
@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
}
Я видел ответы, но они недостаточно хороши .
Что-то, что могло бы динамически генерировать селектор и блокировку, было бы намного лучше (прокси-делегат)
Любая идея, как создать это?
Изменить:
Основываясь на некоторых блогах, я создал этот пример класса, который будет отвечать на любые методы делегата и пересылать их.
@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];
}
сообщения всегда отправляются на прокси, который попытается передать их дальше
мойОбъект:
[self.delegateManager callADelegateMethod:self];
делегатменеджер отвечает за передачу сообщения вперед
кажется, что это можно было бы расширить, выполнив что-то вроде
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];
}
в делегатменеджере
-(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
}
Вопрос в том, как создать ключ, который будет хорош для этого поиска?