0

我有一个对象,它定义了一组协议和委托方法

另一个对象以通常的模式委托模式响应它们

   @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];

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];
}

在委托管理器中

-(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
}

问题是如何创建一个有利于此查找的密钥?

4

2 回答 2

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'重新定义setter,它就像常规属性一样工作(只是存储它),所以你有添加一些逻辑以某种方式调用它,此时我没有看到你使用块方法的任何好处。您也可以放置 @property (nonatomic, copy) BlockCallback blockForMethodOne; 在协议声明中,因此任何采用此协议的类都应具有“blockForMethodOne”,如果您愿意)

希望有所帮助

于 2013-11-12T13:33:44.767 回答
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设置每个块。对于每个委托方法,现在都有一个相应的块。

现在,调用站点负责设置块。

于 2013-11-12T13:51:10.197 回答