Korzystanie z Super w obiektywnej kategorii C?

Chciałbym nadpisać metodę w klasie Objective C, do której nie mam źródła.

Przyjrzałem się temu i wydaje się, że kategorie powinny mi na to pozwolić, ale chciałbym użyć wyniku starej metody w mojej nowej metodzie, używając super, aby uzyskać wynik starej metody.

Za każdym razem, gdy próbuję, moja metoda jest nazywana, ale "super" jest zerowa... Wiesz dlaczego? Robię rozwój iPhone ' a z Xcode 2.2 SDK. Na pewno pracuję z przykładem klasy, A metoda klasy jest metodą instancyjną.

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

  ... do some stuff with the old result

    return result;
}

Uwaga i Wyjaśnienie: z tego, co widzę w dokumentach Apple, wydaje mi się, że powinno to być dozwolone?

Kategorie dokumenty na developer.apple.com: Gdy Kategoria nadpisuje metodę dziedziczoną, metoda w kategoria może, jak zwykle, wywoływać dziedziczona implementacja poprzez wiadomość za super. Jeżeli jednak kategoria nadpisuje metodę, która już dostępne w kategorii Klasa, tam nie sposób powołać się na oryginał wdrożenie.

Author: Brad Parks, 2009-09-10

3 answers

Kategorie rozszerzają oryginalną klasę, ale nie podklasują jej, dlatego wywołanie super nie znajduje metody.

To, co chcesz nazywa się metoda Swizzling . Ale pamiętaj, że Twój kod może coś złamać. Jest artykuł na temat Theocacao napisany przez Scotta Stevensona o metodzie Swizzling w starym runtime Objective-C, Cocoa with Love autorstwa Matta Gallaghera mA artykuł o metodzie Swizzling w nowym runtime Objective-C 2.0 i prosty zastępstwo.

Alternatywnie, możesz podklasować klasę, A następnie użyć podklasy lub użyć + (void)poseAsClass:(Class)aClass by zastąpić superklasę. Apple pisze:

Metoda określona przez klasę pozowania can, poprzez wiadomość do super, włącz metodę superclass it / align = "left" /

Należy pamiętać, że firma Apple wycofała poseAsClass: w systemie Mac OS X 10.5.

 29
Author: Georg Schölly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-24 12:53:28

Jeśli będziesz kodować z tą klasą, po prostu zmień nazwę selektora na coś, czego Twój kod może użyć, i wywołaj oryginalny selektor na self:

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

  ... do some stuff with the old result

    return result;
}

Jeśli chcesz nadpisać domyślną implementację tego selektora dla danej klasy, musisz użyć metody swizzling .

 8
Author: Jason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-10 13:16:00

Nie do końca w kategorii, ale istnieje obejście przez dodanie metody dynamicznie w czasie wykonywania. Samuel Défago w swoim artykule opisuje zgrabny sposób tworzenia blokowej implementacji IMP nazywającej super, jego oryginalny artykuł można znaleźć Tutaj

Odpowiedni kod to:

#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);
 1
Author: Kamil.S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-21 11:09:33