2012-11-22 1 views
7

이것은 내가 말할 수있는 한 "블록의 유형을 확인할 수 있습니까?"와 다른 점입니다.Objective-C 유형을 블록 검사합니까?

알려지지 않은 서명의 블록 객체가 주어지면 호출하기 전에 받아 들여지는 인수를 알 수 있습니까?

사전에있는 개체와 관련된 여러 콜백이있는 상황이 있습니다. 이러한 콜백 중 일부는 다른 인수 집합을 기대합니다. 여기의 예제는 극도로 간소화되었지만 요점을 파악할 수 있다고 생각합니다.

블록이 이전에 typedef 된 유형인지 어떻게 알 수 있습니까?

//MyClass.m 

// I start by declare two block types 
typedef void (^callbackWithOneParam)(NSString*); 
typedef void (^callbackWithTwoParams)(NSString*, NSObject*); 

........ 

// I create a dictionary mapping objects to callback blocks 

self.dict = @{ 
    @"name": "Foo", 
    @"callback": ^(NSString *aString) { 
    // do stuff with string 
    } 
}, { 
    @"name": "Bar", 
    @"callback": ^(NSString *aString, NSObject *anObject) { 
    // do stuff with string AND object 
    } 
} 

..... 

// Later, this method is called. 
// It looks up the "name" parameter in our dictionary, 
// and invokes the associated callback accordingly. 

-(void) invokeCallbackForName:(NSString*)name { 
    // What is the type of the result of this expression? 
    [self.dict objectForKey: name] 

    // I want to say: (pseudocode) 
    thecallback = [self.dict objectForKey: name]; 
    if (thecallback is of type "callbackWithOneParam") { 
     thecallback(@"some param") 
    } 
    else if (thecallback is of type "callbackWithTwoParams") { 
     thecallback(@"some param", [[NSObject alloc] init]); 
    } 
} 
+0

당신이 캔트 생각합니다. 귀하의 상황에서 NSObject를 추가로 사용하고 사용하지 않으면 nil을 넣을 수 있습니다. – SAKrisT

+2

이 예제에서는 사전 내의 모든 블록에 일관된 서명을 사용하는 것이 훨씬 더 바람직합니다. 그런 다음 각 블록 내의 코드가 사용되거나 무시 될 매개 변수를 독립적으로 결정할 수 있습니다. 또한 블록을 호출하기 전에'-objectForKey :'의 반환 값을 블록 서명으로 형변환해야합니다. 사전에 추가하기 전에 각 블록을 힙에 복사해야합니다. – Darren

+0

대런은 지난 두 문장에 대해 자세히 설명해 주셔서 감사합니다. –

답변

2

솔직히 콜백의 유형이 다른 경우 다른 키를 사용해야합니다. @"callbackWithOneParam"@"callbackWithTwoParams" 키를 사용하지 않으시겠습니까? 나에게 그것은 콜백 해석 방법을 알려주는 일반 "콜백"키와 별도의 "유형"키를 갖는 것보다 우수합니다.

하지만 실제로 이것이 요구하는 것은 사전 대신 사용자 지정 클래스의 개체를 사용하는 것입니다. 일반 객체가 편리하지 않고 더 많은 문제를 해결하기 시작한 경계를 넘었습니다.

+0

+1은 사전에 대해 커스텀 클래스를 추천합니다. – BergQuester

-1

"Foo"또는 "Bar"인지 확인하십시오. 아마 클래스의 일부 형태를 갖는 블록은 당신이 인수의 유형을 알고 있어야 호출 할 때

if ([myObject class] == [MyClass class]) 
+0

이 목적으로'isKindOfClass :'또는'isMemberClass :'를 사용해야합니다. –

0

을하지 않고 내가 할 수 밤은 느낌이 함수 매개 변수를 확인하는만큼 많은 노력을 할 것이다. 귀하의 경우, "이름"이 인수가 무엇인지 결정하는 데 충분하지 않은 경우 나에게 말할 다른 유형의 키를 추가 할 것입니다. 당신이 그렇지 않으면 당신은 아마 당신의 프로그램이 다운됩니다 올바른 유형에 블록을 캐스팅하는 것이 필수적 있다는

// Callback dictionary 

_callbacks = @{ 
    @{@"name":@"foo", @"type":@(1), @"callback":^(int i) { NSLog(@"%d", i); }}, 
    @{@"name":@"bar", @"type":@(2), @"callback":^(int i, int j) { NSLog(@"%d", i+j); }}, 
    @{@"name":@"zap", @"type":@(3), @"callback":^(int i, int j, int k) { NSLog(@"%d", i+j+k); }}, 
    @{@"name":@"cab", @"type":@(4), @"callback":^(NSString *s) { NSLog(@"%lu",s.length); }}, 
    @{@"name":@"fog", @"type":@(5), @"callback":^(void) { NSLog(@"I can't see"); }} 
} 


-(void) invokeCallbackForName:(NSString*)name withArguments:(NSArray*)args { 

    NSDictionary *info = _callbacks[name]; 

    if (info != nil) { 
     id block = info[@"callback"]; 
     int type = [info[@"type"] intValue]; 
     switch (type) { 

      case 1: { 
       int arg1 = [args[0] intValue]; 
       ((void(^)(int)) block)(arg1); 
       break; 
      } 
      case 2: { 
       int arg1 = [args[0] intValue]; 
       int arg2 = [args[1] intValue]; 
       ((void(^)(int,int)) block)(arg1,arg2); 
       break; 
      } 
      case 3: { 
       int arg1 = [args[0] intValue]; 
       int arg2 = [args[1] intValue]; 
       int arg3 = [args[2] intValue]; 
       ((void(^)(int,int,int)) block)(arg1,arg2,arg3); 
       break; 
      } 
      case 5: { 
       NSString *arg1 = [args[0] intValue]; 
       ((void(^)(NSString*)) block)(arg1); 
       break; 
      } 
      default: 
       [NSExceptien raise:NSInvalidArgumentException format:@"Unsupported callback type"]; 

     } 
    } 
} 

참고 예를 들면 다음과 같습니다. 왜냐하면 블록은 올바른 순서로 스택에 인수를 넣고 모든 반환 유형을 허용하는 컴파일러에 의존하기 때문입니다.

0

는 개인적으로, 나는 독창적 인 CTBlockDescription ...

CTBlockDescription 당신이 인수를 포함한 블록을 검사하고 런타임에 시간 기능을 컴파일 할 수 있습니다 사용합니다.

[CTBlockDescription.alloc initWithBlock:bk].blockSignature.description; 

<NSMethodSignature: 0x253f080> 
    number of arguments = 3 
    frame size = 12 
    is special struct return? NO 
    return value: -------- -------- -------- -------- 
     type encoding (c) 'c' 
     flags {isSigned} 
     modifiers {} 
     frame {offset = 0, offset adjust = 0, size = 4, size adjust = -3} 
     memory {offset = 0, size = 1} 
    argument 0: -------- -------- -------- -------- 
     type encoding (@) '@?' 
     flags {isObject, isBlock} 
     modifiers {} 
     frame {offset = 0, offset adjust = 0, size = 4, size adjust = 0} 
     memory {offset = 0, size = 4} 
    argument 1: -------- -------- -------- -------- 
     type encoding (c) 'c' 
     flags {isSigned} 
     modifiers {} 
     frame {offset = 4, offset adjust = 0, size = 4, size adjust = -3} 
     memory {offset = 0, size = 1} 
    argument 2: -------- -------- -------- -------- 
     type encoding (@) '@' 
     flags {isObject} 
     modifiers {} 
     frame {offset = 8, offset adjust = 0, size = 4, size adjust = 0} 
     memory {offset = 0, size = 4} 

화려한


BOOL(^bk)(BOOL,id) = ^BOOL(BOOL ani, id obj) { return YES; }; 

...

관련 문제