如何将类别添加到“隐藏”类

时间:2012-04-28 06:53:52

标签: objective-c ios objective-c-category

有没有办法将类别添加到您无法访问其头文件的类?

出于测试目的,我想向UITableViewCellDeleteConfirmationControl添加一个类别,但该类是(据我所知)私有框架的一部分。

我该怎么做?


详细说明(根据mihirios的要求):

我正在尝试扩展Frank测试框架,以模拟在您尝试删除UITableViewCell时点击确认按钮(大红色"删除"按钮)。 Frank向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;
}

这将查找表的数据源并调用其tableView:commitEditingStyle:forRowAtIndexPath:方法,该方法(根据UITableView的文档)是用户点击确认按钮时系统所执行的操作。 / p>

这样做有效,但我希望通过向其添加UITableViewCellDeleteConfirmationControl方法使tap看似是一个可点击的按钮,覆盖Frank的默认方法。 tap方法会找到包含确认按钮的单元格,然后调用[cell confirmDeletion]

当我尝试为UITableViewCellDeleteConfirmationControl声明一个类别时,编译器会抱怨它无法解析界面&#39; UITableViewCellDeleteConfirmationControl&#39;。&#34;

当我尝试使用某人使用类转储生成的头文件时,链接器会抱怨它无法找到符号_OBJC_CLASS _ $ _ UITableViewCellDeleteConfirmationControl。

3 个答案:

答案 0 :(得分:2)

出于测试目的,您始终可以使用NSClassFromString获取类对象,然后使用class_replaceMethod运行时方法来执行您需要的任何操作。有关详细信息,请参阅Objective-C Runtime Reference

答案 1 :(得分:2)

据我所知,您不能使用类别,但您可以在运行时手动添加方法。

可能的方法是,创建一个新类,实现您想要的方法,并使用适当的objc-runtime函数将此方法发送到UITableViewCellDeleteConfirmationControl。有一些事情需要注意,比如存储原始功能以备以后使用以防超载,也可以在你的“类别”级别你需要注意,当你想打电话给超级,因为这不起作用,你有改为使用objc-runtime函数objc_msgSendSuper。

只要您不需要打电话给超级,这样就可以了:

#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中,例如:

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

但我不知道为什么你不只是在控制器类中移动确认处理。

答案 2 :(得分:0)

只要编译器可以(最终)链接到相关类,您就可以为它创建一个类别。更重要的问题是如何设计类别,因为您似乎无法访问原始类的源。