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

多くの場合 - 特定のデリゲート メソッド (プロトコルの実装) の動作を変更したい

ブロックベースの構文では、考慮事項に基づいて委任オブジェクトに新しい「ブロック」を簡単に割り当てることができます。

しかし、標準のデリゲート パターンでは、これは不可能です。この問題を解決する 1 つの方法は、大きなディスパッチ テーブルを作成することです (応答するデリゲート内に "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