2012-04-28 3 views
2

액세스 할 수없는 헤더 파일의 클래스에 범주를 추가 할 수 있습니까?"숨겨진"클래스에 범주를 추가하는 방법

테스트 목적으로 UITableViewCellDeleteConfirmationControl에 카테고리를 추가하고 싶지만 클래스는 (내가 알 수있는 한) 개인 프레임 워크의 일부입니다.

어떻게하면됩니까?


정교화 (mihirios의 요청에 따라) : 당신은을 삭제하려고하면

나는 나타나는 확인 버튼 (큰 빨간 "삭제"버튼)을 눌러 시뮬레이션하기 위해 프랭크 테스트 프레임 워크를 확장하기 위해 노력하고 있어요 UITableViewCell. 프랭크는 tap 방법을 UIControl에 추가합니다. 어떤 이유로, 컨트롤을 두드리는 Frank의 일반적인 방법은 UITableViewCellDeleteConfirmationControl 클래스 (하위 클래스 UIControl)에서는 작동하지 않습니다.

해결 방법을 만들었습니다. 다음 방법으로 UITableViewCell에 카테고리를 추가했습니다.

- (BOOL)confirmDeletion { 
    if (![self showingDeleteConfirmation]) { 
     return NO; 
    } 
    UITableView *tableView = (UITableView *)[self superview]; 
    id <UITableViewDataSource> dataSource = [tableView dataSource]; 
    NSIndexPath *indexPath = [tableView indexPathForCell:self]; 
    [dataSource tableView:tableView 
     commitEditingStyle:UITableViewCellEditingStyleDelete 
     forRowAtIndexPath:indexPath]; 
    return YES; 
} 

이 테이블의 데이터 소스를 찾아 사용자가 확인 버튼을 탭하면 시스템이 무엇 인 (UITableView에 대한 설명서에 따라) 그 tableView:commitEditingStyle:forRowAtIndexPath: 메소드를 호출합니다.

이 방법이 효과적이지만 tap 메서드를 추가하여 UITableViewCellDeleteConfirmationControl을 탭 가능한 버튼으로 표시하고 Frank의 기본값을 재정의하는 것을 선호합니다. tap 메서드는 확인 버튼이 포함 된 셀을 찾은 다음 [cell confirmDeletion]을 호출합니다.

UITableViewCellDeleteConfirmationControl에 대한 카테고리를 선언하려고하면 컴파일러에서 " 'UITableViewCellDeleteConfirmationControl'인터페이스를 확인할 수 없습니다."라는 오류가 발생합니다.

누군가 클래스 덤프를 사용하여 생성 한 헤더 파일을 사용하려고하면 링커가 _OBJC_CLASS _ $ _ UITableViewCellDeleteConfirmationControl 기호를 찾을 수 없다는 불만을 표시합니다.

+0

질문을 자세히 작성 하시겠습니까? – iMash

답변

2

테스트 목적으로 NSClassFromString을 사용하여 클래스 개체를 가져온 다음 class_replaceMethod 런타임 메서드를 사용하여 필요한 모든 작업을 수행 할 수 있습니다. 자세한 내용은 Objective-C Runtime Reference을 참조하십시오.

+0

감사! 그것은 깨끗하고 비교적 (상대적으로) 간단합니다. 내 구현은 다음과 같습니다. https://github.com/dhemery/vigor/blob/master/vigor/categories/FEXTappableConfirmationButton.m –

0

컴파일러가 문제의 클래스에 (최종적으로) 링크 할 수있는 한 범주를 만들 수 있습니다. 더 중요한 질문은 원래 클래스의 소스에 액세스 할 수 없기 때문에 카테고리를 디자인하는 것입니다.

+0

카테고리 작성을 위해 클래스의 소스에 액세스 할 필요가 없습니다. –

+1

글쎄, * 어떻게 * 카테고리를 만드십니까? 간단한'@interface Foo (Bar) '를 사용하면 컴파일러는'Foo'에 대한 인터페이스 선언을 가지고 있지 않다고 불평합니다. – zoul

2

내가 아는 한 범주를 사용할 수는 없지만 런타임 중에 수동으로 메서드를 추가 할 수 있습니다.

가능한 방법은 새 클래스를 만들고 원하는 메서드를 구현 한 다음 적절한 objc-runtime 함수를 사용하여이 메서드를 UITableViewCellDeleteConfirmationControl에 전송하는 것입니다. 주의해야 할 사항이 있습니다. 과부하의 경우 나중에 사용하기 위해 원본 함수를 저장하는 것과 같은 것입니다. 또한 '카테고리'클래스에서 super를 호출 할 때주의해야합니다. 작동하지 않을 수도 있습니다. objc-runtime function objc_msgSendSuper를 대신 사용하십시오.

이 잘 할 것이다 슈퍼 호출 할 필요가 없습니다 않는 한 :

@autoreleasepool { 
     implementInstanceMethods([MyCategory class], NSClassFromString(@"UITableViewCellDeleteConfirmationControl")); 
     return UIApplicationMain(argc, argv, nil, NSStringFromClass([YourAppDelegate class])); 
} 

: 예를 들어,

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

void implementInstanceMethods(Class src, Class dest) { 
    unsigned int count; 
    Method *methods = class_copyMethodList(src, &count); 

    for (int i = 0; i < count; ++i) { 
     IMP imp = method_getImplementation(methods[i]); 
     SEL selector = method_getName(methods[i]); 
     NSString *selectorName = NSStringFromSelector(selector); 
     const char *types = method_getTypeEncoding(methods[i]); 

    class_replaceMethod(dest, selector, imp, types);   
    } 
    free(methods); 
} 

좋은 점 방법이 main.m에 전화 하지만 왜 컨트롤러 클래스에서 확인 처리를 이동하지 않는지 나는 알지 못합니다.

+0

컨트롤러 클래스에 넣지 않는 이유 : 이것은 범용 테스트 프레임 워크 용입니다. 특정 응용 프로그램에 대해서는 아무 것도 모릅니다. –

관련 문제