2009-09-10 5 views
24

소스가없는 Objective C 클래스의 메서드를 재정의하고 싶습니다.Objective C 범주에서 Super를 사용하고 있습니까?

나는 그것을 조사해 보았고, 카테고리는 내가 이것을 할 수 있도록해야한다고 생각하지만, 나의 새로운 방법에서 이전 방법의 결과를 사용하고 싶다. 이전 방법 결과를 얻기 위해 super를 사용한다.

이 방법을 시도 할 때마다 내 메서드가 호출되지만 "슈퍼"는 아무 것도 아닙니다 ... 어떤 이유가 있습니까? XCode 2.2 SDK로 iPhone 개발을하고 있습니다. 나는 확실히 클래스의 인스턴스를 다루고 있는데, 클래스의 메소드는 인스턴스 메소드이다.

@implementation SampleClass (filePathResolver) 
-(NSString*) fullPathFromRelativePath:(NSString*) relPath 
{ 
    NSString *result = [super fullPathFromRelativePath: relPath]; 

    ... do some stuff with the old result 

    return result; 
} 

참고 및 설명 : Apple Docs에서 볼 수 있듯이 이것이 허용되어야합니다. 카테고리 상속 된 메소드를 재정의 할 때

Categories docs at developer.apple.com: 는 카테고리에있어서, 평소와 같이, 슈퍼에 메시지 통해 상속 구현을 호출 할 수있다. 그러나 카테고리 이 카테고리의 클래스에 이미 이있는 메소드를 덮어 쓰는 경우 은 원래 구현을 호출 할 수 없습니다.

+0

혹시이 문제를 해결하기위한 방안을 찾으셨습니까? UILabel의 setText : 메소드에 전달 될 때 텍스트 매개 변수를 수정하려고합니다. UILabel (거대한 코드베이스)을 서브 클래스하고 싶지 않기 때문에 Category가 가장 적절할 것입니다. 슈퍼 오브젝트가 실제로 UILabel 인 경우 super setText를 호출하면 트릭을 수행 할 수 있다고 생각하지만, 카테고리에 정의 된 setText :를 호출하는 무한 루프로 이어질 가능성이 큽니다. 따라서 이것은 아마도 카테고리에 대한 불가능한 묘기 일 것임을 분명히합니다. –

+0

안녕하세요! 나는이 페이지에 게시 된 것보다 다른 해결책을 찾지 못했습니다. 메서드 swizzling 또는 카테고리에 다른 메서드 사용 - –

답변

28

범주는 원래 클래스를 확장하지만 서브 클래스를 지정하지 않으므로 super을 호출해도 메서드가 없습니다.

원하는 것은 Method Swizzling입니다. 그러나 코드가 무언가를 깨뜨릴 수 있다는 점에 유의하십시오. 이전 Objective-C 런타임의 메서드 Swizzling에 대한 Theocacao written by Scot Stevenson에 대한 기사가 있습니다. Cocoa with Love by Matt Gallagher에는 새로운 Objective-C 2.0 런타임의 메서드 Swizzling에 대한 기사와 간단한 대체 방법이 있습니다.

또는 클래스를 서브 클래스화한 다음 하위 클래스를 사용하거나 + (void)poseAsClass:(Class)aClass을 사용하여 수퍼 클래스를 바꿀 수 있습니다. 애플은 쓴다 :

, super에 메시지를 통해, 는 슈퍼 클래스의 방법 그것을 재정의를 통합 할 수있는 포즈 클래스 에 의해 정의 된 방법.

Apple은 Mac OS X 10.5에서 더 이상 지원되지 않습니다.

+0

"swizzling"이라는 프로그래밍 개념이 다소 혼란 스럽지만 재미있는 개념입니다. –

+1

위의 설명으로 추가 한 것처럼 범주가 상속 된 메서드를 재정의하는 경우 범주의 메서드는 상속 된 구현을 super를 통해 메시지를 통해 호출 할 수 있지만 범주가 이미있는 메서드를 재정의하는 경우 카테고리의 클래스를 사용하면 원래 구현을 호출 할 방법이 없습니다. –

+0

문제를 해결할 수있는 유일한 방법이 아닌 경우 메서드 변경을 원하지 않는 경우도 있습니다. 그런 다음에도 흔들림이 많은 취약성과 함께 나타납니다. 유지 보수 문제 – bbum

8

이 클래스에 코딩 할 경우, 단순히 코드를 사용할 수있는 무언가에 대한 선택의 이름을 변경하고, self에 원래의 선택 호출이 기본 구현을 재정의하려면

@implementation SampleClass (filePathResolver) 
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath 
{ 
    NSString *result = [self fullPathFromRelativePath: relPath]; 

    ... do some stuff with the old result 

    return result; 
} 

을 해당 클래스의 선택자 인 경우 method swizzling 접근 방식을 사용해야합니다.

+0

예, 그 클래스에 대해 작성된 코드를 모두 제어 할 수는 없으므로 ... 저에게 효과가있는 것은 아닙니다.하지만 제안에 감사드립니다! –

+1

^예, 그렇습니다. 메서드 swizzling은 거대한 해킹과 프로그램의 잠재적 인 미래 브레이크 포인트와 같은 느낌을 갖지만 클래스에 대해 작성된 코드를 제어 할 수없는 상황에서 정확하게 작동해야합니다. – n13

+0

글쎄, 나는 그 클래스에서 "fullPathFromRelativePath"를 호출하는 것을 제어하지 않는 다른 코드가 있음을 의미한다. 나는 다른 코드가하는 것을 바꿀 수 없기 때문에,이 경우 swizzling이 도움이되지 않을 것이다. –

1

정확하게 카테고리에는 없지만 런타임에 메소드를 동적으로 추가하여 해결 방법이 있습니다.그의 기사에서 사무엘 Défago 슈퍼를 호출 블록 IMP 구현을 만들 수있는 깔끔한 방법을 설명, 자신의 원래 문서는 찾을 수 있습니다 here

관련 코드는 다음과 같습니다

#import <objc/runtime.h> 
#import <objc/message.h> 

    const char *types = method_getTypeEncoding(class_getInstanceMethod(clazz, selector)); 
    class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) { 
     struct objc_super super = { 
      .receiver = self, 
      .super_class = class_getSuperclass(clazz) 
     }; 

     id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper; 
     return objc_msgSendSuper_typed(&super, selector, argp); 
    }), types); 
관련 문제