Использование Super в объективной категории C? - PullRequest
24 голосов
/ 10 сентября 2009

Я бы хотел переопределить метод в классе Objective C, для которого у меня нет источника.

Я изучил это, и кажется, что Категории должны позволять мне это делать, но я хотел бы использовать результат старого метода в моем новом методе, используя super для получения результата старых методов.

Всякий раз, когда я пытаюсь это сделать, мой метод вызывается, но "super" - это ноль ... Есть идеи, почему? Я занимаюсь разработкой iPhone с XCode 2.2 SDK. Я определенно работаю с экземпляром класса, а метод класса является методом экземпляра.

@implementation SampleClass (filePathResolver)
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
    NSString *result = [super fullPathFromRelativePath: relPath];

  ... do some stuff with the old result

    return result;
}

Примечание и уточнение: Из того, что я вижу в Apple Docs, мне кажется, что это должно быть разрешено?

Категории документов на developer.apple.com: Когда категория переопределяет унаследованный метод, метод в категория может, как обычно, вызывать унаследованная реализация через сообщение супер. Тем не менее, если категория переопределяет метод, который уже существовал в классе категории, там нет способа вызвать оригинал осуществление.

Ответы [ 3 ]

29 голосов
/ 10 сентября 2009

Категории расширяют исходный класс, но не подклассируют его, поэтому вызов super не находит метод.

То, что вы хотите, называется Метод Swizzling . Но имейте в виду, что ваш код может что-то сломать. Есть статья на Theocacao, написанная Скоттом Стивенсоном о методе Swizzling в старой среде выполнения Objective-C, Какао с любовью Мэтта Галлахера имеет статью о методе Swizzling в новой Objective-C Среда выполнения 2.0 и простая замена для нее.

Кроме того, вы можете создать подкласс класса и затем использовать подкласс или использовать + (void)poseAsClass:(Class)aClass для замены суперкласса. Apple пишет:

Метод, определенный классом позирования можно через сообщение на super, включить метод суперкласса это переопределение.

Имейте в виду, что Apple устарела poseAsClass: в Mac OS X 10.5.

8 голосов
/ 10 сентября 2009

Если вы будете кодировать этот класс, просто переименуйте селектор в то, что может использовать ваш код, и вызовите оригинальный селектор на self:

@implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
    NSString *result = [self fullPathFromRelativePath: relPath];

  ... do some stuff with the old result

    return result;
}

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

1 голос
/ 21 апреля 2017

Не совсем в категории, но есть обходной путь, добавляющий метод динамически во время выполнения. Сэмюэль Дефаго в своей статье описывает изящный способ создания реализации IMP, вызывающей super, его оригинальную статью можно найти здесь

Соответствующий код:

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

    const char *types = method_getTypeEncoding(class_getInstanceMethod(clazz, selector));
    class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
        struct objc_super super = {
            .receiver = self,
            .super_class = class_getSuperclass(clazz)
        };

        id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper;
        return objc_msgSendSuper_typed(&super, selector, argp);
    }), types);
...