2014-12-15 3 views
6

여기에 선택을 지정하는 나는 애플의 "타이머 프로그래밍에 관한 주제"에서 본 예제 코드 생성 :왜있는 NSInvocation 두 번

NSMethodSignature *methodSignature = [self 
methodSignatureForSelector:@selector(invocationMethod:)]; 
NSInvocation *invocation = [NSInvocation 
invocationWithMethodSignature:methodSignature]; 
[invocation setTarget:self]; 
[invocation setSelector:@selector(invocationMethod:)]; 
NSDate *startDate = [NSDate date]; 
[invocation setArgument:&startDate atIndex:2]; 

당신이 볼 수 있듯이, 우리가 invocationMethod을 지정해야합니다 : 한 번 NSMethodSignature에, 그리고 나서 NSInvocationsetSelector에서 두 번째입니다. 내게있어, 이것은 중복되는 것 같습니다. 왜 애플이 이런 디자인을 한 것입니까?

답변

3

선택자는 문자열이며 메서드 이름입니다. 매개 변수 유형 또는 리턴 유형에 대한 정보가 없습니다. 메서드 시그니처는 형식 일뿐입니다. 메서드 이름에 대한 정보가 없습니다. 그들은 완전히 분리되어 있습니다.

methodSignatureForSelector:을 사용하여 대상 개체를 요청하여 메서드 서명을 만드는 경우에도 사람들이 항상 그렇게하고 싶어한다고 가정하면 안됩니다.

형식 서명 문자열에서 직접 메서드 서명을 구성 할 수 있습니다. 다른 메서드의 서명에서 가져 와서이 메서드에 적용 할 수 있습니다. 객체가 메서드를 아직 구현하지 않았기 때문에 메소드의 서명을 객체에 직접 요청하는 것이 적절하지 않을 수 있으며 나중에 호출 될 때 동적으로 추가합니다. 유형과 메소드 이름을 별도로 지정할 수있는 유연성을 갖는 데에는 여러 가지 이유가있을 수 있습니다.

1

메서드 서명을 사용하면 NSInvocation에서 NSInvocation에서 사용할 수있는 선택기의 구조를 알 수 있습니다. NSInvocation을 만들면 호출이 사용하는 선택기의 구조를 변경할 수 없지만 선택기는 변경할 수 있습니다. 따라서 하나의 인수가 사용 된 메서드의 구조를 만드는 데 사용되고 다른 하나는 실제로 호출되는 메서드입니다.

나중에 처음에 준 메소드 서명과 동일한 구조를 가진 경우 실제로 호출 된 메소드를 변경할 수 있습니다. 설득력있는 생성자를 사용하여 카테고리를 작성할 수 있습니다.

+ (instancetype)invocationWithTarget:(id)target andSelector:(SEL)selector { 
    NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector]; 
    NSInvocation *invocation = [self invocationWithMethodSignature:methodSignature]; 
    [invocation setTarget:target]; 
    [invocation setSelector:selector]; 
    return invocation; 
} 
+0

몇 가지 문제점 : 반환 유형'instancetype'을 지정했지만'NSInvocation'을 반환합니다. 'NSInvocation' 클래스에서 이것을 호출하지 않는다면 이것은 잘못된 것이다. 이름은'methodSignatureWithTarget : andSelector :'(BTW,'WithTarget' 다음에':'를 잊어 버렸습니다)이지만 호출을 반환합니다.따라서 이름은'invocationWithTarget : andSelector :'이어야합니다. – DarkDust

+0

@DarkDust 고마워, 그건 내가 서둘러 대답을 가르쳐 줄거야 (분명히 카테고리는 NSInvocation에 있어야한다). –

+1

쿨러가'NSObject','invocationWithSelector :'에 대한 카테고리 메소드가 될 것이라고 생각합니다. 감사합니다. – DarkDust

2

선택자는 매우 다른 두 가지로 전달됩니다.

첫째, 우리가 가지고

NSMethodSignature *methodSignature = [self methodSignatureForSelector:@selector(invocationMethod:)]; 

이 방법의 인수의 반환 값을 입력뿐만 아니라 개수 및 종류를 설명하는 method signature를 생성한다. 이 시그너처가 생성 된 선택기 (동일한 선택기가 여러 선택기에 유효 함, 예 : 선택자/이름이 다른 경우에도 -(void)foo:(NSString *)f;-(void)bar:(NSString *)b;은 모두 동일한 시그니처를 가짐)가 기억되지 않습니다.

그런 다음 실제 invocation을 만듭니다. 반환 값 형식과 인수의 수 및 유형을 알아야하므로 NSMethodSignature으로 초기화해야합니다. 그러나 어떤 객체와 셀렉터가 호출되어야하는지에 대해서는 아직 알지 못한다. 명시 적으로 말해야한다. 선택기가 통과 된 것은 두 번째입니다.

동일한 서명이있는 호출에서 선택기를 다른 것으로 설정할 수도 있으며 올바르게 작동합니다.

+0

. 내가 궁금하네요, 코드는 "반환 값 형식뿐만 아니라 메서드의 인수의 수와 유형에 대한 정보를 알 수 없습니다."[호출 setSelector : @selector (invocationMethod :)];가 호출 될 때? 이 방법으로 앞서 NSMethodSignature 객체를 생성 할 필요가 없다. –

+0

처음에는 메시지 전달, 동적 메서드 확인 및 다른 것들을 막을 수있는 불쾌한 일들에 대해 생각하고 있었지만 실제로 NSInvocation이 당신에게 할 수없는 이유를 설명하는 Objective-C 기능을 찾을 수 없었습니다. 제안했다. Apple/NeXT가 이러한 방식으로 구현 한 이유에 대해서만 추측 할 수 있습니다. 그러나 내 직감은 당신의 제안이 "NSInvocation"을 약간 "싫어하는"것이라고 생각합니다. 그래도 그걸 설명하는 데 어려움이 있습니다. – DarkDust