2

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

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

我怎样才能做到这一点?


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

我正在尝试扩展 Frank 测试框架以模拟点击当您尝试删除UITableViewCell. FranktapUIControl. 出于某种原因,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)当用户点击确认按钮时系统会执行此操作。

这行得通,但我更愿意UITableViewCellDeleteConfirmationControl通过向它添加一个方法来使其看起来像一个可点击的按钮tap,覆盖弗兰克的默认方法。该tap方法将找到包含确认按钮的单元格,然后调用[cell confirmDeletion].

当我尝试为 声明一个类别时UITableViewCellDeleteConfirmationControl,编译器抱怨它“无法解析接口 'UITableViewCellDeleteConfirmationControl'”。

当我尝试使用某人使用类转储生成的头文件时,链接器抱怨它找不到符号_OBJC_CLASS_$_UITableViewCellDeleteConfirmationControl。

4

3 回答 3

2

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

于 2012-04-28T07:14:57.617 回答
2

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

一种可能的方法是,创建一个新类,实现您想要的方法,然后使用适当的 objc 运行时函数将此方法发送到 UITableViewCellDeleteConfirmationControl。有一些事情需要注意,比如存储原始函数以供以后在重载时使用,同样在你的“类别”类中,当你想调用 super 时你必须注意,因为这不起作用,你有改为使用 objc 运行时函数 objc_msgSendSuper。

只要您不需要调用 super 就可以了:

#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]));
}

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

于 2012-04-28T07:24:33.387 回答
0

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

于 2012-04-28T07:00:07.677 回答