2012-02-11 2 views
4

전달 된 모든 클래스의 메서드를 읽고 이상적인 방법으로 런타임에 단일 선택기로 매핑하여 원래의 선택기로 전달하는 클래스를 설정했습니다.여러 메서드 swizzles에 대한 메서드 IMP 복사

이것은 현재 작동하지만 한 번에 하나의 방법으로 만 수행 할 수 있습니다. 문제는 첫 번째 방법을 뒤집어 쓰면 내 IMP가 그 방법을 포착하고 전달하는 것이 이제 다른 방법 IMP와 바뀌 었다는 것입니다. 다른 플레이어를 대체하기 위해 새로 교환 된 IMP를 사용하기 때문에이 모든 시도는 실패합니다.

1) 그래서 MethodA, MethodB 및 CustomCatchAllMethod가 있습니다.

2) MethodA를 CustomCatchAllMEthod와 교체합니다. MethodA -> CustomCatchAllMethod, CustomCatchAllMethod -> MethodA

3) 이제 CustomCatchAllMethod를 사용하여 MethodB로 바꾸려고 시도하지만 CustomCatchAllMethod now = MethodA이므로 MethodB는 MethodA와 MethodA-> MethodB가됩니다.

그럼 내가 가로 채기를 원하는 각 새 선택기에 대해 내 IMP의 새 인스턴스를 가져 오거나 복사하려면 어떻게합니까? 다른 하나와 하나의 방법을 차단하고자 할 때 일반적인 방법 - 스위 즐링 패턴에만 작동

void swizzle(Class classImCopying, SEL orig){ 
SEL new = @selector(catchAll:); 
Method origMethod = class_getInstanceMethod(classImCopying, orig); 
Method newMethod = class_getInstanceMethod(catchAllClass,new); 
method_exchangeImplementations(origMethod, newMethod); 
} 

//In some method elsewhere 

//I want this to make both methodA and methodB point to catchAll: 
swizzle(someClass, @selector(methodA:)); 
swizzle(someClass, @selector(methodB:)); 

답변

3

그건 :

다음은 위의 흐름의 대략적인 모형이다. 귀하의 경우 기본적으로 catchAll:에 대한 구현을 사방에 삽입하는 대신 이동합니다.

IMP imp = method_getImplementation(newMethod); 
method_setImplementation(origMethod, imp); 

이 하나의 문제를 잎이 생각 : 어떻게 원래의 구현에 전달

제대로 이것 당신은 사용해야 할 것이다하려면?
원래 패턴은 exchangeImplementations에 사용 된 패턴입니다.

  • 주위에 원래 IMP s의 테이블을 유지하거나
  • 은 몇 가지 일반적인 접두사와 원래의 방법을 이름을 변경, 그래서 당신은 catchAll:
  • 에서 그들에게 전화를 구축 할 수 있습니다 : 당신이 할 수 귀하의 경우에는

    같은 방법으로 모든 것을 전달할 때는 동일한 인수에 대응하는 방법을 처리 할 수 ​​

참고.

+0

고마워요! 나는 내가 그걸 해결할 수 있는지 알아볼거야. 나는 이미 호출을 전달하고 IMPS를 저장하기에 너무 정교한 시스템을 가지고있어서 너무 큰 문제는 없어야한다. –

+0

그건 정말 트릭을 했어, 너무 간단, 내가 그것을 놓친 걸 믿을 수 없어. 다시 한 번 감사드립니다! –

0

당신은, 블록과 원래의 IMP를 캡처 블록의 IMP를 얻을 수 및 방법의 구현으로 설정할 수 있습니다.

Method method = class_getInstanceMethod(class, setterSelector); 
SEL selector = method_getName(method); 
IMP originalImp = method_getImplementation(method); 

id(^block)(id self, id arg) = ^id(id self, id arg) { 
    return ((id(*)(id, SEL, id))originalImp)(self, selector, arg); 
}; 

IMP newImp = imp_implementationWithBlock(block); 
method_setImplementation(method, newImp);