Селектор, Отправленный методу, переопределенному в Категории, терпит неудачу - PullRequest
0 голосов
/ 25 октября 2011

Я пытаюсь переопределить метод 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 ]

4 голосов
/ 25 октября 2011

Если вы используете super при переопределении методов с использованием категории, метод будет вызываться для суперкласса объекта, а не для объекта, для которого вы переопределяете метод. Вы не создали подкласс UIStoryboard, поэтому super относится к NSObject - что точно отражено в вашем сообщении об ошибке.

Хотя я не знаю, что происходит с вашими сообщениями в журнале.

Использование категории для переопределения метода означает, что вы не можете вызвать оригинальный метод. Вам нужно будет создать подкласс UIStoryboard или совершенно новый метод в категории, который вызывает [self instantiateInitialViewController].

3 голосов
/ 25 октября 2011

Обратите внимание, что [super class] - это не то же самое, что [self superclass]. Цитирование документов:

Objective-C предоставляет два термина, которые могут использоваться в определении метода для ссылки на объект, который выполняет метод - self и super.

Они отличаются тем, как компилятор будет искать реализацию метода, и в некоторых случаях они будут означать одно и то же.

В этом случае вы хотите:

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

для проверки класса суперкласса объекта, и вам понадобится подкласс UIStoryBoard, а не категория, чтобы иметь возможность использовать:

return [super instantiateInitialViewController];

Почему [super class] не записывает то, что вы ожидаете, это другая тема. Если вам интересно, этот пост Что такое метакласс в Objective-C? является хорошей отправной точкой.

1 голос
/ 28 декабря 2011

Вам нужно использовать метод Swizzling. хорошее объяснение того, как использовать его для ваших целей здесь: http://b2cloud.com.au/how-to-guides/method-swizzling-to-override-in-a-category

0 голосов
/ 25 октября 2011

Если вы действительно хотите вызвать этот метод из UIViewController, ваша категория должна быть:

@implementation UIViewController(SomeCategory)

Даже в этом случае он вызовет super вашего UIViewController, поэтому он все равно не будет работать.Вам также необходимо сделать следующее:

 UIViewController *viewController = [self instantiateInitialViewController]
...