2012-07-07 3 views
2

꽤 새로운 objective-c가 있지만 꽤 일반적인 상황 인 것 같습니다. ClassA에게 ClassB 만 객체에 대한 메서드를 실행하도록 ClassA에 요청하려고합니다. (그리고 또한 ClassA에 알려지지 않은 방법을 사용하여) 알 수 있습니다.Objective-C : performSelector 대 forwardInvocation :

내가이 일을 두 가지 방법을 발견했습니다 : performSelector :forwardInvocation :을 -하지만 난 자세한 내용은 각각의 나의 이해를 돈독히하고 싶습니다.

aSelector 인수 : 나는 사과 개발자 문서에 메모 발견 [performSelector의를 :] 더 인수를 취하지 않는 방법을 식별해야합니다. 개체가 아닌 다른 것을 반환하는 메서드의 경우 NSInvocation을 사용하십시오. : (int)를 nonObjectMethodNameforwardInvocation을 사용 - 말을하면서, (ID) performSelector를 사용하는 것이을 methodName로 - 로 시작하는 방법이 있다는 것을 의미

..does?

또한 반환하는 방법은 무엇입니까? (void)? 또는 비 id 객체를 반환하는 메소드. (NSString)?

+0

주를 읽어야합니다. – NSResponder

답변

6

번호 -forwardInvocation:은 메시지 전달 메커니즘의 일부로 사용됩니다. 메시지 전달에 대해서는 걱정하지 마십시오. 실제로 프록시 객체에서만 사용되며 확률은 좋으며 사용하지 않아도되고 사용하는 것을 알 수 있습니다.

-performSelector:

는 메시지의 반환 형식이 id 또는 호환 가정하고 그 반환 타입 등 long long 32 비트 시스템으로 포인터보다 넓은 예 (다른 메시지를 보내는 데 사용되는 경우 매우 안전하지 않다, 또는 이러한 float 또는 대형 struct.)

간접적 그런 메시지를 보내려면, 당신은 NSInvocation 클래스의 인스턴스를 만든 다음 그것을 -invoke을 보낼 수있는 다른 레지스터/주소를 통해 돌아왔다. 그런 다음 리턴 값은 호출 오브젝트에 저장되며이를 통해 액세스 할 수 있습니다. 이 시나리오에서는 -forwardInvocation:을 사용하지 않습니다.

일반적으로 말하면, -performSelector:을 사용하고 있다면, 아마도 당신은 반 패턴을 다루고있을 것입니다. 이 경우 ClassA이 공식적으로 알 수없는 메시지를 보내려고합니다. 다른 해결책은 이러한 개인적인 방법을 드러내는 것입니다. 당신이 ClassAClassB를 소유하는 경우


, 당신은 당신이 사용하고자하는 개인 방법을 포함 ClassB위한 "개인"헤더를 만들 수 있습니다. 다른 사람 (예 : Apple)이 ClassB을 소유하고있는 경우 문서화되지 않은 API를 다루고 있으며 Apple에서 이러한 API를 사용하는 앱을 거부하므로 다른 접근 방법을 찾아야 할 수도 있습니다.

개인 헤더를 만들려면 Xcode로 이동하여 새 헤더 파일을 만드십시오. "ClassB + Internal.h"또는 "ClassB + PrivateMethodsForMeOnly.h"와 같은 이름을 지정하십시오.프로젝트에 비공개로 처리하십시오. ClassB으로 동료 (동일한 하위 프로젝트 또는 라이브러리 또는 구성 요소)가 아니면 다른 사람이 사용하지 않습니다. 이 새로운 헤더에 다음을 추가

#import "ClassB.h" // so we get the original class definition 

@interface ClassB (PrivateMethodsForMeOnly) 
- (double)someMethod; 
- (const struct low_level_c_type_t)otherMethod:(int)i; 
// etc. etc. etc. 
@end 

그리고 ClassA.m에서을 (하지ClassA.h 당신은 ClassA를 사용하는 모든 사람들에게이 방법을 노출하지 않으려면!) 섹션을 포함하여에 다음 줄을 추가합니다 :

#import "ClassB+PrivateMethodsForMeOnly.h" 

ClassA은 새 카테고리의 메소드에 액세스 할 수 있습니다.

+1

+1 개인 헤더 댄스. – Peres

+0

좋은 설명. – Tatvamasi

+0

개인 헤더 댄스는 프레임 워크 또는 라이브러리를 제작할 때 매우 유용합니다. 단일 프로젝트에서는 모든 클래스가 서로 완전하게 액세스 할 수 있기 때문에 약간 바보입니다. 여전히 이러한 강성을 강요하면 클래스 계층 구조에 대해 좀 더 생각하게됩니다. 이는 결코 시간 낭비가 아닙니다. –

0

네, 몇 가지 질문이 있습니다.

우선 "forwardInvocation"을 잊어 버리십시오. 이는 프록시 객체 만 만들면 충분합니다.

호출은 [NSInvocation invocationWithMethodSignature ...]로 생성 된 다음 선택기, 인수 및 대상 개체로 채워 지므로 결국 호출하게됩니다. 이것이 메소드 호출을 보내고 저장할 수있는 방법입니다.

performselector는 몇 가지 변형이 있으며, 일부는 매개 변수를 사용하고, 지연 후 호출하거나 다른 스레드에서이 메서드를 실행합니다. 더 직접적인 호출입니다. NSInvocation은 필요할 때까지 다른 객체와 같이 유지할 수있는 객체입니다. 반면 "performselector"는 메서드를 거의 실행합니다.

반환 값은 일반적으로 설명서의 내용에 충실합니다. 그것이 메서드가 id를 반환해야한다고 알려주면 객체를 반환합니다 (객체 포인터는 ok이므로 NSString *은 괜찮습니다.) 반환 값 nil도 괜찮습니다.

performselector를 호출하는 것이 모두 공통적 인 것은 아닙니다. 대부분의 경우 "[MyObject SomeMethod : SomeParameter];"와 같이 호출을 하드 코딩합니다. performSelector 스타일의 메소드 호출은 특수한 경우를위한 것입니다. GUI 객체의 대상/액션 항목은 호출 될 선택기가 객체에 저장되는 경우와 같은 경우이기 때문에 분명히 하드 코딩 할 수 없습니다.

0

-forwardInvocation:의 목적은 객체가 단지 포기하는 대신 다른 객체를 인식하지 못하도록 메시지를 보내도록하는 것입니다. NSInvocation에는 선택기뿐 아니라 메시지의 모든 매개 변수가 포함됩니다. NSProxy은 그것을 사용하지만 정확하게 기억한다면 분산 객체보다 먼저 사용했습니다. "이 클래스가 처리 할 수없는 모든 것"에 대한 위임을 구현하는 한 가지 방법입니다. withObject가 : 또한 존재

당신은 -performSelector이있는 section on message forwarding in the Objective-C docs.