选择器发送到在类别中重写的方法失败

时间:2011-10-25 15:36:55

标签: objective-c cocoa-touch categories

我正在尝试使用类别覆盖UIStoryboard方法。这是我的实施:

#import "UIStoryboard+SomeCategory.h"
#import <UIKit/UIKit.h>

@implementation UIStoryboard(SomeCategory)

-(id)instantiateInitialViewController
{
    NSLog(@"SUPER CLASS: %@", [super class]); // logs "UIStoryboard"
    NSLog(@"SUPER RTS  : %@", [super respondsToSelector:@selector(instantiateInitialViewController)] ? @"YES" : @"NO"); // logs "YES"
    return [super instantiateInitialViewController];
}

@end

当我添加:

 UIViewController *viewController = [super instantiateInitialViewController]

为什么我会收到编译错误:

Receiver type 'NSObject' for instance message does not declare a method with selector 'instantiateViewController'

4 个答案:

答案 0 :(得分:4)

如果在使用类别覆盖方法时使用super,则将在对象的超类上调用该方法,而不是在覆盖该方法的对象上调用该方法。 您尚未创建UIStoryboard 的子类,因此super引用NSObject - 这会在您的错误消息中准确反映出来。

我不知道你的日志消息是怎么回事。

使用类别覆盖方法意味着您无法调用原始方法。您需要在类别中创建UIStoryboard的子类或全新方法,并调用[self instantiateInitialViewController]

答案 1 :(得分:3)

您应该注意[super class][self superclass]不同。引用文档:

Objective-C提供了两个术语,可以在方法定义中用于引用执行方法自身和超级的对象。

它们在编译器搜索方法实现的方式上有所不同,在某些情况下,它们的含义也相同。

在这种情况下,您需要:

NSLog(@"SUPER CLASS: %@", [self superclass]); // logs "NSObject"

检查一个对象的超类类,你需要一个UIStoryBoard子类,而不是一个类,才能使用:

return [super instantiateInitialViewController];

为什么[super class]没有记录您期望的另一个主题。如果你有兴趣,这篇文章What is a meta-class in Objective-C?是一个很好的起点。

答案 2 :(得分:1)

你需要使用方法调配。有关如何将其用于您的目的的详细说明:http://b2cloud.com.au/how-to-guides/method-swizzling-to-override-in-a-category

答案 3 :(得分:0)

如果你真的想从UIViewController调用该方法,你的类别应该是:

@implementation UIViewController(SomeCategory)

即使这样,它也会调用你的UIViewController的super,所以它仍然无效。您还需要执行以下操作:

 UIViewController *viewController = [self instantiateInitialViewController]